diff --git a/examples/reference/templates/Bootstrap.ipynb b/examples/reference/templates/Bootstrap.ipynb
index 4d21c5a992..bec0c2851a 100644
--- a/examples/reference/templates/Bootstrap.ipynb
+++ b/examples/reference/templates/Bootstrap.ipynb
@@ -35,6 +35,7 @@
"* **`busy_indicator`** (BooleanIndicator): Visual indicator of application busy state.\n",
"* **`header_background`** (str): Optional header background color override.\n",
"* **`header_color`** (str): Optional header text color override.\n",
+ "* **`logo`** (str): URI of logo to add to the header (if local file, logo is base64 encoded as URI).\n",
"* **`theme`** (Theme): A Theme class (available in `panel.template.theme`)\n",
"* **`title`** (str): A title to show in the header.\n",
"\n",
diff --git a/examples/reference/templates/GoldenLayout.ipynb b/examples/reference/templates/GoldenLayout.ipynb
index e2c0d12af0..47e69b41b8 100644
--- a/examples/reference/templates/GoldenLayout.ipynb
+++ b/examples/reference/templates/GoldenLayout.ipynb
@@ -35,6 +35,7 @@
"* **`busy_indicator`** (BooleanIndicator): Visual indicator of application busy state.\n",
"* **`header_background`** (str): Optional header background color override.\n",
"* **`header_color`** (str): Optional header text color override.\n",
+ "* **`logo`** (str): URI of logo to add to the header (if local file, logo is base64 encoded as URI).\n",
"* **`theme`** (Theme): A Theme class (available in `panel.template.theme`)\n",
"* **`title`** (str): A title to show in the header.\n",
"\n",
diff --git a/examples/reference/templates/Material.ipynb b/examples/reference/templates/Material.ipynb
index 27ef72e6f7..88631cbb12 100644
--- a/examples/reference/templates/Material.ipynb
+++ b/examples/reference/templates/Material.ipynb
@@ -35,6 +35,7 @@
"* **`busy_indicator`** (BooleanIndicator): Visual indicator of application busy state.\n",
"* **`header_background`** (str): Optional header background color override.\n",
"* **`header_color`** (str): Optional header text color override.\n",
+ "* **`logo`** (str): URI of logo to add to the header (if local file, logo is base64 encoded as URI).\n",
"* **`theme`** (Theme): A Theme class (available in `panel.template.theme`)\n",
"* **`title`** (str): A title to show in the header.\n",
"\n",
diff --git a/examples/reference/templates/Vanilla.ipynb b/examples/reference/templates/Vanilla.ipynb
index a5175eb416..04632da4e5 100644
--- a/examples/reference/templates/Vanilla.ipynb
+++ b/examples/reference/templates/Vanilla.ipynb
@@ -35,6 +35,7 @@
"* **`busy_indicator`** (BooleanIndicator): Visual indicator of application busy state.\n",
"* **`header_background`** (str): Optional header background color override.\n",
"* **`header_color`** (str): Optional header text color override.\n",
+ "* **`logo`** (str): URI of logo to add to the header (if local file, logo is base64 encoded as URI).\n",
"* **`theme`** (Theme): A Theme class (available in `panel.template.theme`)\n",
"* **`title`** (str): A title to show in the header.\n",
"\n",
diff --git a/panel/pane/image.py b/panel/pane/image.py
index 810a0f4cae..d151239d35 100644
--- a/panel/pane/image.py
+++ b/panel/pane/image.py
@@ -84,6 +84,13 @@ def _img(self):
r = requests.request(url=self.object, method='GET')
return r.content
+ def _b64(self):
+ data = self._img()
+ if not isinstance(data, bytes):
+ data = data.encode('utf-8')
+ b64 = base64.b64encode(data).decode("utf-8")
+ return "data:image/"+self.imgtype+f";base64,{b64}"
+
def _imgshape(self, data):
"""Calculate and return image width,height"""
raise NotImplementedError
@@ -207,6 +214,13 @@ def _img(self):
return self.object
return super(SVG, self)._img()
+ def _b64(self):
+ data = self._img()
+ if not isinstance(data, bytes):
+ data = data.encode('utf-8')
+ b64 = base64.b64encode(data).decode("utf-8")
+ return f"data:image/svg+xml;base64,{b64}"
+
def _imgshape(self, data):
return (self.width, self.height)
diff --git a/panel/template/base.py b/panel/template/base.py
index ce736b3c9f..ce4d730a9d 100644
--- a/panel/template/base.py
+++ b/panel/template/base.py
@@ -4,6 +4,7 @@
"""
from __future__ import absolute_import, division, unicode_literals
+import os
import sys
import uuid
@@ -25,6 +26,7 @@
from ..layout import Column, ListLike
from ..models.comm_manager import CommManager
from ..pane import panel as _panel, HTML, Str, HoloViews
+from ..pane.image import ImageBase
from ..viewable import ServableMixin, Viewable
from ..widgets import Button
from ..widgets.indicators import BooleanIndicator, LoadingSpinner
@@ -319,6 +321,10 @@ class BasicTemplate(BaseTemplate):
modal = param.ClassSelector(class_=ListLike, constant=True, doc="""
A list-like container which populates the modal""")
+ logo = param.String(constant=True, doc="""
+ URI of logo to add to the header (if local file, logo is
+ base64 encoded as URI).""")
+
title = param.String(doc="A title to show in the header.")
header_background = param.String(doc="Optional header background color override")
@@ -388,6 +394,14 @@ def _init_doc(self, doc=None, comm=None, title=None, notebook=False, location=Tr
def _update_vars(self, *args):
self._render_variables['app_title'] = self.title
+ if os.path.isfile(self.logo):
+ img = _panel(self.logo)
+ if not isinstance(img, ImageBase):
+ raise ValueError("Could not determine file type of logo: {self.logo}.")
+ logo = img._b64()
+ else:
+ logo = self.logo
+ self._render_variables['app_logo'] = logo
self._render_variables['header_background'] = self.header_background
self._render_variables['header_color'] = self.header_color
diff --git a/panel/template/bootstrap/bootstrap.css b/panel/template/bootstrap/bootstrap.css
index a65fb8bfc6..590dcff682 100644
--- a/panel/template/bootstrap/bootstrap.css
+++ b/panel/template/bootstrap/bootstrap.css
@@ -31,6 +31,13 @@ body {
a.navbar-brand {
padding-left: 10px;
+ display: flex;
+ align-items: center;
+ font-size: 1.5em;
+}
+
+img.app-logo {
+ padding-right: 10px;
}
p.bk.card-button {
@@ -75,3 +82,4 @@ p.bk.card-button {
display: flex;
margin-left: auto;
}
+
diff --git a/panel/template/bootstrap/bootstrap.html b/panel/template/bootstrap/bootstrap.html
index 871ad0b384..993a879388 100644
--- a/panel/template/bootstrap/bootstrap.html
+++ b/panel/template/bootstrap/bootstrap.html
@@ -16,7 +16,12 @@
{% endif %}
- {{ app_title }}
+
+ {% if app_logo %}
+
+ {% endif %}
+ {{ app_title }}
+
{% for doc in docs %}
{% for root in doc.roots %}
{% if "header" in root.tags %}
diff --git a/panel/template/golden/golden.css b/panel/template/golden/golden.css
index 0947059d5b..5e38c0bca5 100644
--- a/panel/template/golden/golden.css
+++ b/panel/template/golden/golden.css
@@ -34,13 +34,22 @@ body {
color: white;
}
+.app-header {
+ display: flex;
+}
+
+img.app-logo {
+ padding-left: 10px;
+}
+
.header-adjust {
padding-top: 64px;
}
.header-title {
font-size: 1.5em;
- padding-left: 1.5em;
+ line-height: 2em;
+ padding-left: 1em;
font: 1.5em Arial, sans-serif;
color: white;
text-align: center;
diff --git a/panel/template/golden/golden.html b/panel/template/golden/golden.html
index 2d836a0268..5d6f2c0659 100644
--- a/panel/template/golden/golden.html
+++ b/panel/template/golden/golden.html
@@ -11,8 +11,13 @@
{% block contents %}