Skip to content

Commit df1e7d4

Browse files
committed
More updates
1 parent 811349b commit df1e7d4

21 files changed

+330
-339
lines changed

docs/config-header.yml renamed to docs/_data/config-header.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ start:
2323
- content: Feature Voting
2424
url: https://executablebooks.org/en/latest/feature-vote.html
2525

26+
- type: button
27+
content: Book gallery
28+
url: http://gallery.jupyterbook.org/
29+
30+
2631
end:
2732
- type: icon-links
2833
icons:
@@ -35,6 +40,3 @@ end:
3540
- icon: fas fa-comments
3641
name: Forum
3742
url: https://github.com/orgs/executablebooks/discussions
38-
- type: button
39-
content: Book gallery
40-
url: http://gallery.jupyterbook.org/

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@
104104
"repository_branch": "master",
105105
}
106106

107-
header_config = safe_load(Path("./config-header.yml").read_text())
107+
header_config = safe_load(Path("./_data/config-header.yml").read_text())
108108

109109
html_theme_options = {
110110
"path_to_docs": "docs",

docs/customize/header.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ For one example, see the header configuration of this documentation, in YAML for
2323
Below is YAML configuration for this theme's header.
2424
It is read by `conf.py` and converted into a Python dictionary at build time.
2525
26-
```{literalinclude} ../config-header.yml
26+
```{literalinclude} ../_data/config-header.yml
2727
:language: yaml
2828
```
2929
````

src/sphinx_book_theme/_components.py

Lines changed: 145 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,161 @@ def component_text(app, context, content="", url="", classes=[]):
2222
return html
2323

2424

25-
def component_button(app, context, content="", url="", onclick="", classes=[]):
25+
def component_button(
26+
app,
27+
context,
28+
content="",
29+
title="",
30+
icon="",
31+
url="",
32+
onclick="",
33+
button_id="",
34+
label_for="",
35+
id="",
36+
tooltip_placement="",
37+
kwargs={},
38+
classes=[],
39+
):
40+
kwargs = kwargs.copy()
41+
kwargs.update({"type": "button", "class": ["btn", "icon-button"]})
42+
kwargs["class"].extend(classes)
43+
btn_content = ""
2644
if url and onclick:
2745
raise Exception("Button component cannot have both url and onclick specified.")
28-
classes = " ".join(classes)
46+
47+
if not (icon or content):
48+
raise Exception("Button must have either icon or content specified.")
49+
2950
if onclick:
30-
onclick = ' onclick="{onclick}"'
51+
kwargs["onclick"] = onclick
52+
53+
if id:
54+
kwargs["id"] = id
55+
56+
if icon:
57+
if icon.startswith("fa"):
58+
icon = f'<i class="{icon}"></i>'
59+
else:
60+
if not icon.startswith("http"):
61+
icon = context["pathto"](icon, 1)
62+
icon = f'<img src="{icon}">'
63+
btn_content += f'<span class="btn__icon-container">{icon}</span>'
64+
65+
if not content:
66+
kwargs["class"].append("icon-button-no-content")
67+
else:
68+
btn_content += content
69+
70+
if button_id:
71+
kwargs["id"] = button_id
72+
73+
kwargs["aria-label"] = title
74+
75+
# Handle tooltips
76+
title = context["translate"](title)
77+
tooltip_placement = "bottom" if not tooltip_placement else tooltip_placement
78+
79+
# If we're already using data-toggle, wrap the button content in a span.
80+
# This lets us use another data-toggle.
81+
if "data-toggle" in kwargs:
82+
btn_content = f"""
83+
<span data-toggle="tooltip" data-placement="{tooltip_placement}" title="{title}">
84+
{btn_content}
85+
</span>
86+
""" # noqa
87+
else:
88+
kwargs["data-placement"] = tooltip_placement
89+
kwargs["title"] = title
90+
91+
# Convert all the options for the button into a string of HTML kwargs
92+
kwargs["class"] = " ".join(kwargs["class"])
93+
kwargs_str = " ".join([f'{key}="{val}"' for key, val in kwargs.items()])
94+
95+
# Generate the button HTML
96+
if label_for:
97+
html = f"""
98+
<label for="{label_for}" {kwargs_str}>
99+
{btn_content}
100+
</label>
101+
"""
102+
else:
103+
html = f"""
104+
<button {kwargs_str}>
105+
{btn_content}
106+
</button>
107+
"""
31108

32-
classes = " ".join(classes)
33-
html = f"""
34-
<button class="btn btn-outline-primary {classes}"{onclick} type="button">
35-
{content}
36-
</button>
37-
"""
109+
# Wrap the whole thing in a link if one is specified
38110
if url:
111+
# If it doesn't look like a web URL, assume it's a local page
112+
if not url.startswith("http"):
113+
url = context["pathto"](url)
39114
html = f'<a href="{url}">{html}</a>'
40115

41116
return html
42117

43118

119+
def component_dropdown(
120+
app, context, content="", icon="", side="left", items=[], **kwargs
121+
):
122+
# Items to go inside dropdown
123+
dropdown_items = []
124+
for component in items:
125+
# Pop the `button` type in case it was incorrectly given, since we force button
126+
if "type" in component:
127+
component.pop("type")
128+
dropdown_items.append(
129+
component_button(
130+
app,
131+
context,
132+
**component,
133+
)
134+
)
135+
dropdown_items = "\n".join(dropdown_items)
136+
137+
# These control the look of the button
138+
button_classes = []
139+
if content:
140+
button_classes.append("dropdown-toggle")
141+
142+
# Unique ID to trigger the show event
143+
dropdown_id = "menu-dropdown-"
144+
dropdown_id += hashlib.md5(dropdown_items.encode("utf-8")).hexdigest()[:5]
145+
146+
# Generate the button HTML
147+
dropdown_kwargs = {
148+
"data-toggle": "dropdown",
149+
"aria-haspopup": "true",
150+
"aria-expanded": "false",
151+
"type": "button",
152+
}
153+
html_button = component_button(
154+
app,
155+
context,
156+
content=content,
157+
icon=icon,
158+
kwargs=dropdown_kwargs,
159+
classes=button_classes,
160+
button_id=dropdown_id,
161+
**kwargs,
162+
)
163+
164+
dropdown_classes = ["dropdown-menu"]
165+
if side == "right":
166+
dropdown_classes.append("dropdown-menu-right")
167+
dropdown_classes = " ".join(dropdown_classes)
168+
169+
html_dropdown = f"""
170+
<div class="dropdown">
171+
{html_button}
172+
<div class="{dropdown_classes}" aria-labelledby="{dropdown_id}">
173+
{dropdown_items}
174+
</div>
175+
</div>
176+
""" # noqa
177+
return html_dropdown
178+
179+
44180
def component_image(app, context, src="", url="", classes=[]):
45181
if not src.startswith("http"):
46182
src = context["pathto"](src, 1)
@@ -56,29 +192,6 @@ def component_html(app, context, html=""):
56192
return html
57193

58194

59-
def component_dropdown(app, context, content="", items=[]):
60-
dropdown_items = []
61-
for component in items:
62-
link = f"""
63-
<a href="{component['url']}" class="dropdown-item">{component['content']}</a>
64-
"""
65-
dropdown_items.append(link)
66-
dropdown_items = "\n".join(dropdown_items)
67-
dropdown_id = "menu-dropdown-"
68-
dropdown_id += hashlib.md5(dropdown_items.encode("utf-8")).hexdigest()[:5]
69-
html = f"""
70-
<div class="dropdown">
71-
<button class="btn dropdown-toggle" type="button" id="{dropdown_id}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
72-
{content}
73-
</button>
74-
<div class="dropdown-menu" aria-labelledby="{dropdown_id}">
75-
{dropdown_items}
76-
</div>
77-
</div>
78-
""" # noqa
79-
return html
80-
81-
82195
def component_icon_links(app, context, icons, classes=[]):
83196
context = {"theme_icon_links": icons}
84197
# Add the pydata theme icon-links macro as a function we can re-use

src/sphinx_book_theme/assets/scripts/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ var initTooltips = () => {
181181
$(document).ready(function () {
182182
$('[data-toggle="tooltip"]').tooltip({
183183
trigger: "hover",
184-
delay: { show: 500, hide: 100 },
184+
delay: { show: 750, hide: 100 },
185185
});
186186
});
187187
};

0 commit comments

Comments
 (0)