Skip to content

Commit 8097ea3

Browse files
committed
Add theme explorer infrastructure
1 parent fe89f81 commit 8097ea3

File tree

9 files changed

+304
-2
lines changed

9 files changed

+304
-2
lines changed

docs/demos/__init__.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import os
2+
from pathlib import Path
3+
4+
import dash
5+
from jinja2 import Environment, FileSystemLoader
6+
7+
from .theme_explorer import app as theme_explorer
8+
9+
SERVE_LOCALLY = os.getenv("DBC_DOCS_MODE", "production") == "dev"
10+
11+
HERE = Path(__file__).parent
12+
TEMPLATES = HERE.parent / "templates"
13+
14+
INDEX_STRING_TEMPLATE = """{% extends "theme-explorer.html" %}
15+
{% block head %}
16+
{{ super() }}
17+
{{ "{%metas%}{%css%}" }}
18+
{% endblock %}
19+
{% block title %}
20+
<title>{{ "{%title%}" }}</title>
21+
{% endblock %}
22+
{% block content %}
23+
{{ "{%app_entry%}" }}
24+
{% endblock %}
25+
{% block code %}<CODE>{% endblock %}
26+
{% block scripts %}
27+
<footer>
28+
{{ "{%config%}{%scripts%}{%renderer%}" }}
29+
{{ super() }}
30+
</footer>
31+
{% endblock %}
32+
"""
33+
34+
35+
def register_apps():
36+
env = Environment(loader=FileSystemLoader(TEMPLATES.as_posix()))
37+
template = env.from_string(INDEX_STRING_TEMPLATE)
38+
template = template.render()
39+
40+
code = (HERE / "theme_explorer.py").read_text()
41+
42+
new_theme_explorer = dash.Dash(
43+
external_stylesheets=["/static/loading.css"],
44+
requests_pathname_prefix="/docs/themes/explorer/",
45+
suppress_callback_exceptions=True,
46+
serve_locally=SERVE_LOCALLY,
47+
index_string=template.replace("<CODE>", code),
48+
update_title=None,
49+
)
50+
51+
new_theme_explorer.title = "Theme explorer - dbc docs"
52+
new_theme_explorer.layout = theme_explorer.layout
53+
new_theme_explorer.callback_map = theme_explorer.callback_map
54+
new_theme_explorer._callback_list = new_theme_explorer._callback_list
55+
return {"/docs/themes/explorer": new_theme_explorer}

docs/demos/theme_explorer.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import dash
2+
import dash_bootstrap_components as dbc
3+
4+
app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
5+
6+
app.layout = dbc.Container(
7+
dbc.Alert("Testing, testing", color="success"), className="p-5"
8+
)
9+
10+
if __name__ == "__main__":
11+
app.run_server(debug=True)

docs/run.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from werkzeug.middleware.dispatcher import DispatcherMiddleware
22

33
from components_page import register_apps as register_component_apps
4+
from demos import register_apps as register_demo_apps
45
from examples import register_apps as register_example_apps
56
from markdown_to_html import convert_all_markdown_files
67
from server import create_server
@@ -10,7 +11,8 @@
1011
server = create_server()
1112
component_routes = register_component_apps()
1213
example_routes = register_example_apps()
13-
routes = {**component_routes, **example_routes}
14+
demo_routes = register_demo_apps()
15+
routes = {**component_routes, **example_routes, **demo_routes}
1416
application = DispatcherMiddleware(
1517
server, {slug: app.server for slug, app in routes.items()}
1618
)

docs/server.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@
88
{"name": "components", "href": "/docs/components", "label": "Components"},
99
]
1010

11+
THEMES_SIDENAV_ITEMS = DOCS_SIDENAV_ITEMS[:]
12+
THEMES_SIDENAV_ITEMS[1] = {
13+
"name": "themes",
14+
"href": "/docs/themes",
15+
"label": "Themes",
16+
"children": [
17+
{
18+
"name": "overview",
19+
"href": "/docs/themes/",
20+
"label": "Overview",
21+
},
22+
{
23+
"name": "explorer",
24+
"href": "/docs/themes/explorer",
25+
"label": "Theme explorer",
26+
}
27+
],
28+
}
29+
1130

1231
def create_server():
1332
server = Flask(__name__)
@@ -36,8 +55,9 @@ def themes():
3655
try:
3756
return render_template(
3857
"generated/docs/themes.html",
39-
sidenav_items=DOCS_SIDENAV_ITEMS,
58+
sidenav_items=THEMES_SIDENAV_ITEMS,
4059
sidenav_active="themes",
60+
active_child="overview",
4161
)
4262
except TemplateNotFound:
4363
abort(404)

docs/static/js/theme-switcher.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
var bootstrap =
2+
'https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css';
3+
var bootswatchBase = 'https://stackpath.bootstrapcdn.com/bootswatch/4.5.2/';
4+
var bootswatchSfx = '/bootstrap.min.css';
5+
6+
var validBootswatch = new Set([
7+
'cerulean',
8+
'cosmo',
9+
'cyborg',
10+
'darkly',
11+
'flatly',
12+
'journal',
13+
'litera',
14+
'lumen',
15+
'lux',
16+
'materia',
17+
'minty',
18+
'pulse',
19+
'sandstone',
20+
'simplex',
21+
'sketchy',
22+
'slate',
23+
'solar',
24+
'spacelab',
25+
'superhero',
26+
'united',
27+
'yeti'
28+
]);
29+
30+
function swapStyleSheet(sheetname) {
31+
if (sheetname === 'bootstrap') {
32+
document.getElementById('stylesheet').setAttribute('href', bootstrap);
33+
} else if (validBootswatch.has(sheetname)) {
34+
document
35+
.getElementById('stylesheet')
36+
.setAttribute('href', bootswatchBase + sheetname + bootswatchSfx);
37+
}
38+
}
39+
40+
function updateSourceCode(sheetname) {
41+
var container = document.getElementById('code-container');
42+
for (var j = 0; j < container.childNodes.length; j++) {
43+
var node = container.childNodes[j];
44+
if (node.nodeType === 3) {
45+
var text = node.nodeValue;
46+
var replacedText = text.replace(
47+
/dbc.themes.[A-Z]+/gi,
48+
'dbc.themes.' + sheetname.toUpperCase()
49+
);
50+
if (replacedText !== text) {
51+
container.replaceChild(document.createTextNode(replacedText), node);
52+
break;
53+
}
54+
}
55+
}
56+
}
57+
58+
function handleChange(e) {
59+
if (e.target.value) {
60+
var sheetname = e.target.value;
61+
swapStyleSheet(sheetname);
62+
updateSourceCode(sheetname);
63+
}
64+
}
65+
66+
document.getElementById('theme-switcher').onchange = handleChange;

docs/static/theme-explorer.css

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
.te-navbar {
2+
/* navbar */
3+
display: -ms-flexbox;
4+
display: flex;
5+
-ms-flex-wrap: wrap;
6+
flex-wrap: wrap;
7+
-ms-flex-align: center;
8+
align-items: center;
9+
-ms-flex-pack: justify;
10+
justify-content: space-between;
11+
padding: 0.5rem 1rem;
12+
13+
/* bg-dark */
14+
background-color: #343a40 !important;
15+
16+
/* sticky-top */
17+
position: -webkit-sticky;
18+
position: sticky;
19+
top: 0;
20+
z-index: 1020;
21+
22+
/* .navbar-expand */
23+
-ms-flex-flow: row nowrap;
24+
flex-flow: row nowrap;
25+
-ms-flex-pack: start;
26+
justify-content: flex-start;
27+
28+
margin: 0;
29+
font-size: 1rem;
30+
font-weight: 400;
31+
line-height: 1.5;
32+
text-align: left;
33+
}
34+
35+
.te-navbar-nav {
36+
display: flex;
37+
padding-left: 0;
38+
margin-bottom: 0;
39+
list-style: none;
40+
41+
-ms-flex-direction: row;
42+
flex-direction: row;
43+
}
44+
45+
.te-nav-link {
46+
/* navbar-expand nav-link */
47+
padding-right: 0.5rem;
48+
padding-left: 0.5rem;
49+
50+
/* navbar-dark nav-link */
51+
color: rgba(255, 255, 255, 0.5);
52+
53+
/* nav-link */
54+
display: block;
55+
padding: 0.5rem 1rem;
56+
57+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
58+
'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
59+
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
60+
}
61+
62+
.te-nav-link:hover,
63+
.te-nav-link:focus {
64+
text-decoration: none;
65+
color: rgba(255, 255, 255, 0.75);
66+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{% macro theme_explorer_navbar() -%}
2+
<nav class="te-navbar">
3+
<span
4+
class="mr-2 bg-white"
5+
style="padding:2px;border-radius:4px;margin-right: 0.5rem;"
6+
>
7+
<img
8+
src="/static/images/dbciconblack128.png"
9+
width="36"
10+
height="36"
11+
alt="dbc logo thumbnail"
12+
/>
13+
</span>
14+
<ul class="te-navbar-nav mr-auto">
15+
<li>
16+
<a class="te-nav-link" href="/docs/themes">Back to themes</a>
17+
</li>
18+
<li>
19+
<a href="#sourceCode" class="te-nav-link">Jump to source</a>
20+
</li>
21+
</ul>
22+
</nav>
23+
{%- endmacro %}

docs/templates/partials/head.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<meta charset="utf-8" />
22
<meta name="viewport" content="width=device-width, initial-scale=1" />
33
<link
4+
id="stylesheet"
45
rel="stylesheet"
56
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
67
/>

docs/templates/theme-explorer.html

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{% from "macros/theme-explorer-navbar.html" import theme_explorer_navbar %} {%
2+
extends "base.html" %} {% block head %} {% include "partials/head.html" %}
3+
<link rel="stylesheet" href="/static/theme-explorer.css" />
4+
{% endblock %} {% block header %}{{ theme_explorer_navbar() }}{% endblock %} {%
5+
block body %}
6+
<div class="form-group mx-2 mx-md-4 my-4">
7+
<label for="theme-switcher">Select theme</label
8+
><select
9+
name="theme-switcher"
10+
id="theme-switcher"
11+
class="custom-select"
12+
value="bootstrap"
13+
>
14+
<option value="bootstrap">Bootstrap</option>
15+
<option value="cerulean">Cerulean</option>
16+
<option value="cosmo">Cosmo</option>
17+
<option value="cyborg">Cyborg</option>
18+
<option value="darkly">Darkly</option>
19+
<option value="flatly">Flatly</option>
20+
<option value="journal">Journal</option>
21+
<option value="litera">Litera</option>
22+
<option value="lux">Lux</option>
23+
<option value="lumen">Lumen</option>
24+
<option value="materia">Materia</option>
25+
<option value="minty">Minty</option>
26+
<option value="pulse">Pulse</option>
27+
<option value="sandstone">Sandstone</option>
28+
<option value="simplex">Simplex</option>
29+
<option value="sketchy">Sketchy</option>
30+
<option value="slate">Slate</option>
31+
<option value="solar">Solar</option>
32+
<option value="spacelab">Spacelab</option>
33+
<option value="superhero">Superhero</option>
34+
<option value="united">United</option>
35+
<option value="yeti">Yeti</option>
36+
</select>
37+
</div>
38+
<main class="dbcd-main mb-5 mx-2 mx-md-4 my-4">
39+
<div
40+
style="transform:translateZ(0);box-shadow:0 0 2px 1px #9c9c9c;min-height:calc(700px);"
41+
>
42+
{% block content %}{% endblock %}
43+
</div>
44+
<div>
45+
<h2>Source Code</h2>
46+
<div
47+
id="sourceCode"
48+
class="position-relative"
49+
style="visibility:hidden;top:-110px"
50+
></div>
51+
<pre
52+
class="mt-3"
53+
><code id="code-container" class="language-python">{% block code %}{% endblock %}</code></pre>
54+
</div>
55+
</main>
56+
{% endblock %} {% block scripts %} {% include "partials/scripts.html" %}
57+
<script src="/static/js/theme-switcher.js"></script>
58+
{% endblock %}

0 commit comments

Comments
 (0)