From 83f2e338bfaa47eb7baf28c8d3e371f0ee49d398 Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Sun, 8 May 2022 14:58:45 +0200 Subject: [PATCH 01/17] NEW: Add headers --- docs/_templates/sections/header.html | 2 - docs/conf.py | 48 ++++++ src/sphinx_book_theme/__init__.py | 21 +++ src/sphinx_book_theme/_components.py | 92 ++++++++++++ .../assets/styles/abstracts/_variables.scss | 1 + .../assets/styles/components/_buttons.scss | 2 +- .../assets/styles/index.scss | 3 +- .../styles/sections/_header-announcement.scss | 12 ++ .../styles/sections/_header-primary.scss | 141 ++++++++++++++++++ .../assets/styles/sections/_headers.scss | 22 --- .../styles/sections/_sidebar-primary.scss | 6 +- .../theme/sphinx_book_theme/layout.html | 8 +- .../sphinx_book_theme/sections/header.html | 44 ++++++ .../theme/sphinx_book_theme/theme.conf | 1 + 14 files changed, 368 insertions(+), 35 deletions(-) delete mode 100644 docs/_templates/sections/header.html create mode 100644 src/sphinx_book_theme/_components.py create mode 100644 src/sphinx_book_theme/assets/styles/sections/_header-announcement.scss create mode 100644 src/sphinx_book_theme/assets/styles/sections/_header-primary.scss delete mode 100644 src/sphinx_book_theme/assets/styles/sections/_headers.scss diff --git a/docs/_templates/sections/header.html b/docs/_templates/sections/header.html deleted file mode 100644 index 6630c176..00000000 --- a/docs/_templates/sections/header.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/docs/conf.py b/docs/conf.py index b9fd713f..1d862f7b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -127,6 +127,54 @@ "so double-check your custom CSS rules!⚠️" ), # For testing + "header": { + "brand": { + "type": "image", + "src": "https://executablebooks.org/en/latest/_static/logo.svg", + "url": "https://sphinx-book-theme.readthedocs.io", + }, + "start": [ + { + "type": "text", + "content": "Jupyter Book", + "url": "https://jupyterbook.org", + }, + { + "type": "dropdown", + "content": "EBP Projects", + "items": [ + {"content": "google", "url": "https://google.com"}, + {"content": "jupyter", "url": "https://jupyter.org"}, + ], + }, + { + "type": "dropdown", + "content": "MyST Markdown", + "items": [ + {"content": "google", "url": "https://google.com"}, + {"content": "jupyter", "url": "https://jupyter.org"}, + ], + }, + ], + "end": [ + {"type": "button", "content": "end", "url": "https://google.com"}, + { + "type": "icon-links", + "icons": [ + { + "url": "https://twitter.com/executablebooks", + "name": "Twitter", + "icon": "fab fa-twitter-square", + }, + { + "url": "https://github.com/orgs/executablebooks/discussions", + "name": "Forum", + "icon": "fas fa-comments", + }, + ], + }, + ], + } # "use_fullscreen_button": False, # "home_page_in_toc": True, # "single_page": True, diff --git a/src/sphinx_book_theme/__init__.py b/src/sphinx_book_theme/__init__.py index 4b60d0a2..cc305967 100644 --- a/src/sphinx_book_theme/__init__.py +++ b/src/sphinx_book_theme/__init__.py @@ -14,6 +14,7 @@ from .header_buttons import prep_header_buttons, add_header_buttons from .header_buttons.launch import add_launch_buttons from ._transforms import HandleFootnoteTransform +from ._components import COMPONENT_FUNCS __version__ = "0.3.2" """sphinx-book-theme version""" @@ -62,6 +63,26 @@ def add_metadata_to_page(app, pagename, templatename, context, doctree): context.get("theme_search_bar_text", "Search the docs ...") ) + # Define the function render the above + def render_component(component): + component_copy = component.copy() + + # We use `type` to denote different kinds of components + kind = component_copy.pop("type") + if kind not in COMPONENT_FUNCS: + SPHINX_LOGGER.warn(f"Unknown component type: {kind}") + return + try: + output = COMPONENT_FUNCS[kind](app, context, **component_copy) + except Exception as exc: + msg = f"Component render failure for:\n{component}\n\n" + msg += f"Exception: {exc}" + SPHINX_LOGGER.warn(msg) + return + return output + + context["theme_render_component"] = render_component + @lru_cache(maxsize=None) def _gen_hash(path: str) -> str: diff --git a/src/sphinx_book_theme/_components.py b/src/sphinx_book_theme/_components.py new file mode 100644 index 00000000..163461bb --- /dev/null +++ b/src/sphinx_book_theme/_components.py @@ -0,0 +1,92 @@ +"""Functions to compile HTML components to be placed on a page. + +These are meant to be used by Jinja templates via the Sphinx HTML context. + +A dictionary defines the components that are available to the theme. +Keys of this dictionary should be the `"type"` values that users provide in +their configuration. +The remaining values in the user configuration are passed as kwargs to the func. +""" +from sphinx.util import logging + +SPHINX_LOGGER = logging.getLogger(__name__) + + +# Add functions to render header components +def component_text(app, context, content="", url="", classes=[]): + classes = " ".join(classes) + html = f"{content}" + if url: + html = f'{html}' + return html + + +def component_button(app, context, content="", url="", onclick="", classes=[]): + if url and onclick: + raise Exception("Button component cannot have both url and onclick specified.") + classes = " ".join(classes) + if onclick: + onclick = ' onclick="{onclick}"' + + classes = " ".join(classes) + html = f""" + + """ + if url: + html = f'{html}' + + return html + + +def component_image(app, context, src="", url="", classes=[]): + if not src.startswith("http"): + src = context["pathto"](src, 1) + html = f""" + + """ + if url: + html = f"{html}" + return html + + +def component_html(app, context, html=""): + return html + + +def component_dropdown(app, context, content="", items=[]): + dropdown_items = [] + for component in items: + link = f""" + {component['content']} + """ + dropdown_items.append(link) + dropdown_items = "\n".join(dropdown_items) + html = f""" + + """ # noqa + return html + + +def component_icon_links(app, context, icons, classes=[]): + context = {"theme_icon_links": icons} + # Add the pydata theme icon-links macro as a function we can re-use + return app.builder.templates.render("icon-links.html", context) + + +COMPONENT_FUNCS = { + "text": component_text, + "button": component_button, + "html": component_html, + "image": component_image, + "icon-links": component_icon_links, + "dropdown": component_dropdown, +} diff --git a/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss b/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss index bb2bbbfe..b0b1ff9e 100644 --- a/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss +++ b/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss @@ -22,6 +22,7 @@ $zindex-offcanvas: 1100; // We increase this to be over the tooltips $header-article-height: 3em; $leftbar-width-mobile: 75%; $leftbar-width-wide: 275px; +$leftbar-padding: 1rem 1rem 0 1.5rem; $toc-width-mobile: 75%; // Main content, to leave room for the margin $content-max-width: 70%; diff --git a/src/sphinx_book_theme/assets/styles/components/_buttons.scss b/src/sphinx_book_theme/assets/styles/components/_buttons.scss index fba7a86d..ba536373 100644 --- a/src/sphinx_book_theme/assets/styles/components/_buttons.scss +++ b/src/sphinx_book_theme/assets/styles/components/_buttons.scss @@ -41,7 +41,7 @@ } .menu-dropdown__content { - // Hide by default, we'll show on hover + // Hide by default, we'll show on click position: absolute; visibility: hidden; opacity: 0; diff --git a/src/sphinx_book_theme/assets/styles/index.scss b/src/sphinx_book_theme/assets/styles/index.scss index 8219bd1a..463bd851 100644 --- a/src/sphinx_book_theme/assets/styles/index.scss +++ b/src/sphinx_book_theme/assets/styles/index.scss @@ -20,8 +20,9 @@ @import "sections/article"; @import "sections/footer-article"; @import "sections/footer-content"; +@import "sections/header-announcement"; @import "sections/header-article"; -@import "sections/headers"; +@import "sections/header-primary"; @import "sections/sidebar-primary"; @import "sections/sidebar-secondary"; @import "sections/sidebars-toggle"; diff --git a/src/sphinx_book_theme/assets/styles/sections/_header-announcement.scss b/src/sphinx_book_theme/assets/styles/sections/_header-announcement.scss new file mode 100644 index 00000000..873fef86 --- /dev/null +++ b/src/sphinx_book_theme/assets/styles/sections/_header-announcement.scss @@ -0,0 +1,12 @@ +.announcement { + width: 100%; + text-align: center; + background-color: #616161; + color: white; + padding: 0.4em 12.5%; // Horizontal padding so the width is 75% + + @media (max-width: $breakpoint-md) { + // Announcements can take a bit more width on mobile + padding: 0.4em 2%; + } +} diff --git a/src/sphinx_book_theme/assets/styles/sections/_header-primary.scss b/src/sphinx_book_theme/assets/styles/sections/_header-primary.scss new file mode 100644 index 00000000..34ff1ab7 --- /dev/null +++ b/src/sphinx_book_theme/assets/styles/sections/_header-primary.scss @@ -0,0 +1,141 @@ +/** + * A few different header CSS rules + */ +@mixin max-height-header() { + // Fix max height so our header items don't spill over + max-height: 4rem; + @media (max-width: $breakpoint-md) { + max-height: 3rem; + } +} + +// The parent div that will expand / contract +.header { + display: flex; + border-bottom: $border-thin; + + // On narrow screens, cap the height unless you click the hamburger menu + @include max-height-header; + @media (max-width: $breakpoint-md) { + transition: max-height $animation-time ease-out; + overflow-y: hidden; + } + + // Navigation links + a, + div.dropdown button { + color: $non-content-grey; + + &:hover { + color: rgba(var(--pst-color-link), 1); + text-decoration: none; + } + } +} + +// Header content should take up the whole remaining horizontal space +.header__content { + flex-grow: 1; +} + +.header__content, +.header__brand, +.header__start, +.header__end { + display: flex; + flex-wrap: nowrap; + gap: 0.5rem; + + // On narrow screens, the header items show flow vertically and snap to left + @media (max-width: $breakpoint-md) { + flex-direction: column; + } +} + +// Ensure the header items don't touch the screen edge +.header__start { + padding-left: 1rem; +} +.header__end { + padding-right: 1rem; +} + +@media (max-width: $breakpoint-md) { + // Only apply on narrow screens since we want it centered on sidebar on wide + .header__brand, + .header__end { + padding-left: 1rem; + padding-right: 0; + } +} + +// Only show up on narrow screens, and push to the far right +.headerbtn.header-toggle-button { + display: none; + @media (max-width: $breakpoint-md) { + display: block; + margin-top: 0.7em; // HACK: to make this vertically-centered w/o using flexbox + margin-left: auto; + padding-right: 0; // Override headerbtn padding so header has same right/left pad + } +} + +input#__header { + // Inputs never display, only used to control behavior + display: none; + + // On narrow screens, checking the button opens the header + &:checked ~ div.header { + @media (max-width: $breakpoint-md) { + max-height: 20em; + } + } +} + +// Header content contains the components +.header__content { + flex-grow: 1; +} + +// This is the logo or a bold docs title +.header__brand { + font-size: 1.5em; + + // Wide screens: header start has same width as the sidebar + center over logo + @media (min-width: $breakpoint-md) { + width: $leftbar-width-wide; + justify-content: center; + } +} + +.header__end { + @media (min-width: $breakpoint-md) { + // Header end is right-justified + margin-left: auto; + } +} + +ul#navbar-icon-links { + flex-direction: row; + gap: 0.5em; +} + +.header-content-item { + display: flex; + align-items: center; + + // Spacing is horizontal on wide, vertical on narrow + // Items should snap to left on mobile + @media (max-width: $breakpoint-md) { + align-items: start; + } + + img { + padding: 0.4rem 0em; + @include max-height-header; + } + + .dropdown-menu { + z-index: $zindex-sticky + 1; + } +} diff --git a/src/sphinx_book_theme/assets/styles/sections/_headers.scss b/src/sphinx_book_theme/assets/styles/sections/_headers.scss deleted file mode 100644 index e8504158..00000000 --- a/src/sphinx_book_theme/assets/styles/sections/_headers.scss +++ /dev/null @@ -1,22 +0,0 @@ -/** - * A few different header CSS rules - */ -.header-item { - width: 100%; - text-align: center; - - &:empty { - display: none; - } - - &.announcement { - background-color: #616161; - color: white; - padding: 0.4em 12.5%; // Horizontal padding so the width is 75% - - @media (max-width: $breakpoint-md) { - // Announcements can take a bit more width on mobile - padding: 0.4em 2%; - } - } -} diff --git a/src/sphinx_book_theme/assets/styles/sections/_sidebar-primary.scss b/src/sphinx_book_theme/assets/styles/sections/_sidebar-primary.scss index 5ea829e3..d90c183a 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_sidebar-primary.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_sidebar-primary.scss @@ -35,7 +35,7 @@ // Apply some basic padding so the dropdown buttons don't overlap w/ scrollbar .bd-sidebar__top, .bd-sidebar__bottom { - padding: 0 1rem 0rem 1.5rem; + padding: $leftbar-padding; } // This should always snap to the bottom even if there's no sidebar content @@ -83,10 +83,6 @@ } div.navbar-brand-box { - @media (min-width: $breakpoint-md) { - padding-top: 2em; - } - a.navbar-brand { width: 100%; height: auto; diff --git a/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html b/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html index 37f19bce..e164607f 100644 --- a/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html +++ b/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html @@ -16,12 +16,12 @@
Toggle in-page Table of Contents
-
+
{%- include "sections/announcement.html" -%}
-
- {%- include "sections/header.html" -%} -
+ +{%- include "sections/header.html" -%} + {{ super() }} {% endblock %} diff --git a/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html b/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html index e69de29b..54551c50 100644 --- a/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html +++ b/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html @@ -0,0 +1,44 @@ +{% if theme_header %} +{% set start_items = theme_header.get("start", {}) %} +{% set end_items = theme_header.get("end", {}) %} + +{%- if start_items or middle_items or end_items %} + +
+
+ + {% if theme_header.get("brand") %} +
+
+ {{ theme_render_component(theme_header.get("brand")) }} +
+
+ {% endif %} + + +
+ {% for item in start_items %} +
+ {{ theme_render_component(item) }} +
+ {% endfor %} +
+ + +
+ {% for item in end_items %} +
+ {{ theme_render_component(item) }} +
+ {% endfor %} +
+
+ {# Dropdown button for mobile, will show on the right #} + +
+{% endif -%} + +{% endif %} diff --git a/src/sphinx_book_theme/theme/sphinx_book_theme/theme.conf b/src/sphinx_book_theme/theme/sphinx_book_theme/theme.conf index 122d36ba..66025eae 100644 --- a/src/sphinx_book_theme/theme/sphinx_book_theme/theme.conf +++ b/src/sphinx_book_theme/theme/sphinx_book_theme/theme.conf @@ -14,6 +14,7 @@ repository_url = repository_branch = launch_buttons = {} home_page_in_toc = False +header = logo_only = # DEPRECATE after a few release cycles navbar_footer_text = From 4d8d398fd8293ed2f2a8608748215d50a436857d Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Mon, 9 May 2022 14:22:00 +0200 Subject: [PATCH 02/17] Fixing pixel scroll helper --- src/sphinx_book_theme/assets/styles/base/_base.scss | 3 --- .../assets/styles/sections/_header-primary.scss | 4 ++-- src/sphinx_book_theme/theme/sphinx_book_theme/layout.html | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/sphinx_book_theme/assets/styles/base/_base.scss b/src/sphinx_book_theme/assets/styles/base/_base.scss index 75653d23..3d6a0166 100644 --- a/src/sphinx_book_theme/assets/styles/base/_base.scss +++ b/src/sphinx_book_theme/assets/styles/base/_base.scss @@ -3,11 +3,8 @@ *********************************************/ // For the helper pixel that we can watch to decide whether we've scrolled .sbt-scroll-pixel-helper { - position: absolute; width: 0px; height: 0px; - top: 0; - left: 0; } // Hide an element without display: none but so that it takes no space diff --git a/src/sphinx_book_theme/assets/styles/sections/_header-primary.scss b/src/sphinx_book_theme/assets/styles/sections/_header-primary.scss index 34ff1ab7..e79eb930 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_header-primary.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_header-primary.scss @@ -44,7 +44,7 @@ .header__end { display: flex; flex-wrap: nowrap; - gap: 0.5rem; + gap: 0.75rem; // On narrow screens, the header items show flow vertically and snap to left @media (max-width: $breakpoint-md) { @@ -117,7 +117,7 @@ input#__header { ul#navbar-icon-links { flex-direction: row; - gap: 0.5em; + gap: 0.75rem; } .header-content-item { diff --git a/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html b/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html index e164607f..41f8c6e9 100644 --- a/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html +++ b/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html @@ -49,11 +49,11 @@ {% endblock %} {% block docs_main %} - -
{% block docs_body %} + +
{% include "sections/header-article.html" %}
From 9b49ecd17826fe0ba532e4220534a017a69ef92a Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Mon, 9 May 2022 20:35:37 +0200 Subject: [PATCH 03/17] Header content variables --- docs/conf.py | 52 +-- docs/config-header.yml | 40 +++ docs/customize/header.md | 314 +++++++++++++++++- .../assets/styles/abstracts/_variables.scss | 6 +- .../assets/styles/components/_buttons.scss | 4 +- .../styles/sections/_header-article.scss | 2 +- .../styles/sections/_header-primary.scss | 37 ++- .../sphinx_book_theme/sections/header.html | 4 +- 8 files changed, 390 insertions(+), 69 deletions(-) create mode 100644 docs/config-header.yml diff --git a/docs/conf.py b/docs/conf.py index 1d862f7b..4ecad5b0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,6 +2,7 @@ import os from pathlib import Path from urllib import request +from yaml import safe_load project = "Sphinx Book Theme" copyright = "2020" @@ -103,6 +104,8 @@ "repository_branch": "master", } +header_config = safe_load(Path("./config-header.yml").read_text()) + html_theme_options = { "path_to_docs": "docs", "repository_url": "https://github.com/executablebooks/sphinx-book-theme", @@ -126,55 +129,8 @@ "⚠️The latest release refactored our HTML, " "so double-check your custom CSS rules!⚠️" ), + "header": header_config, # For testing - "header": { - "brand": { - "type": "image", - "src": "https://executablebooks.org/en/latest/_static/logo.svg", - "url": "https://sphinx-book-theme.readthedocs.io", - }, - "start": [ - { - "type": "text", - "content": "Jupyter Book", - "url": "https://jupyterbook.org", - }, - { - "type": "dropdown", - "content": "EBP Projects", - "items": [ - {"content": "google", "url": "https://google.com"}, - {"content": "jupyter", "url": "https://jupyter.org"}, - ], - }, - { - "type": "dropdown", - "content": "MyST Markdown", - "items": [ - {"content": "google", "url": "https://google.com"}, - {"content": "jupyter", "url": "https://jupyter.org"}, - ], - }, - ], - "end": [ - {"type": "button", "content": "end", "url": "https://google.com"}, - { - "type": "icon-links", - "icons": [ - { - "url": "https://twitter.com/executablebooks", - "name": "Twitter", - "icon": "fab fa-twitter-square", - }, - { - "url": "https://github.com/orgs/executablebooks/discussions", - "name": "Forum", - "icon": "fas fa-comments", - }, - ], - }, - ], - } # "use_fullscreen_button": False, # "home_page_in_toc": True, # "single_page": True, diff --git a/docs/config-header.yml b/docs/config-header.yml new file mode 100644 index 00000000..40a9c593 --- /dev/null +++ b/docs/config-header.yml @@ -0,0 +1,40 @@ +brand: + type: image + src: https://executablebooks.org/en/latest/_static/logo.svg + url: https://sphinx-book-theme.readthedocs.io +start: + - type: dropdown + content: Projects + items: + - content: Jupyter Book + url: https://jupyterbook.org + - content: MyST Markdown + url: https://myst-parser.readthedocs.io + - content: MyST-NB + url: https://myst-nb.readthedocs.io + + - type: dropdown + content: Community + items: + - content: Community guide + url: https://executablebooks.org + - content: Forum + url: https://github.com/orgs/executablebooks/discussions + - content: Feature Voting + url: https://executablebooks.org/en/latest/feature-vote.html + +end: + - type: icon-links + icons: + - icon: fab fa-twitter-square + name: Twitter + url: https://twitter.com/executablebooks + - icon: fab fa-github-square + name: GitHub + url: https://github.com/executablebooks + - icon: fas fa-comments + name: Forum + url: https://github.com/orgs/executablebooks/discussions + - type: button + content: Book gallery + url: http://gallery.jupyterbook.org/ diff --git a/docs/customize/header.md b/docs/customize/header.md index 0dc58c2b..ef813dde 100644 --- a/docs/customize/header.md +++ b/docs/customize/header.md @@ -1,7 +1,312 @@ # Header content -By default, this theme does not contain any header content, it only has a sidebar and a main content window. -However, you can define your own HTML in a header that will be inserted **above everything else**. +A header extends the interface of your documentation to provide high-level information and links for readers at the top of the page. +They are often used to provide organization-wide branding, cross-links between documentation, and links to social media and external websites. + +Your header will be displayed above the sidebar and article content, but will disappear as readers scroll down. +On mobile displays, the header will be collapsed with a button to expand vertically. + +## Enable and configure the header + +Enable headers in your documentation by providing **a header configuration** in `conf.py`: + +```python +html_theme_options = { + "header": { } +} +``` + +For one example, see the header configuration of this documentation, in YAML format. + +````{admonition} YAML configuration for this theme's header +:class: dropdown +Below is YAML configuration for this theme's header. +It is read by `conf.py` and converted into a Python dictionary at build time. + +```{literalinclude} ../config-header.yml +:language: yaml +``` +```` + +See the rest of these sections for how to add various elements to your header. + +## Header sections + +There are three major sections that you can control with your header: + +- [`brand`](header:brand): A special section for displaying a logo or site brand. +- [`start`](header:start): Left-aligned header components. +- [`end`](header:end): Right-aligned header components. + +Each section has its own configuration, which is specified via keys in the `header` configuration, like so: + +```python +html_theme_options = { + "header": { + "brand": { }, + "start": [ ], + "end": [ ], + } +} +``` + +Where the values of `"start":` and `"end":` are both [lists of component configuration items](header:components). + +(header:brand)= +### `brand` section + +The "brand" section is another place to put your title / logo if you don't want it to be in the primary sidebar (or, a place to put a higher-level logo like an organization-wide logo). +It is centered above your sidebar, and displayed to the left on mobile. + +#### Add an image logo + +To add a logo image to the brand section, see this sample configuration: + +```python +html_theme_options = { + "header": { + "brand": { + # Specifies that the brand area will use an image logo + "type": "image", + # Source of the image to be used + "src": "https://executablebooks.org/en/latest/_static/logo.svg", + # Link for the image + "url": "https://sphinx-book-theme.readthedocs.io", + }, + } +} +``` + +#### Add brand text + +To add text instead of an image, use the following configuration. +You can put arbitrary HTML in the `content` configuration: + +```python +html_theme_options = { + "header": { + "brand": { + # Specifies that we will use text instead of an image logo + "type": "text", + # Text that will be displayed + "content": "My documentation!", + # Link for the image + "url": "https://sphinx-book-theme.readthedocs.io", + }, + } +} +``` + +(header:start)= +### `start` section + +Your header's start section will be left-aligned with your article content (when the sidebar is present). +On mobile devices, it will be hidden under a collapsible button. + +To add components to your header's start section, use the following configuration: + +```python +html_theme_options = { + "header": { + "start": [ ] + } +} +``` + +(header:end)= +### `end` section + + +Your header's end section will be right-aligned with the page. +On mobile devices, it will be hidden under a collapsible button. + +To add components to your header's end section, use the following configuration: + +```python +html_theme_options = { + "header": { + "end": [ ] + } +} +``` + +(header:components)= +## Components + +Components are small UI elements that can be added to your header's sections. + +Add components to the two major sections of your header ([`start`](header:start) and [`end`](header:end)) by providing **lists of component configuration**. +Each component configuration takes a **`type:`** key to specify what type of component it is, as well as a collection of **`key:val`** parameters that modify the component's behavior. + +For example, the following configuration adds two link components to the "start" section of a header, in `conf.py`: + +```python +html_theme_options = { + "header": { + "start": [ + { + "type": "text", + "url": "https://executablebooks.org", + "content": "Executable Books" + }, + { + "type": "text", + "url": "https://jupyterbook.org", + "content": "Jupyter Book" + }, + ] + } +} +``` + +The rest of these sections describe the components you can use: + +### Link and text components + +To add text and link components to header sections, use the following component configuration: + +```python + +# Provided as a list item to `start:` or `end:` +{ + # Specifies a `text` component + "type": "text", + # The URL to which the link points + "url": "https://jupyterbook.org", + # The text to be displayed + "content": "Jupyter Book", + # An optional list of classes to add + "classes": ["one", "two"] +}, +``` + +To add text without a link, simply omit the `url:` parameter. + +### Dropdown menus + +Dropdown menus provide a clickable button that will display a list of links. +It is a useful way to provide more links in your header without using too much horizontal space. + +To add dropdown components to header sections, use the following component configuration: + +```python +# Provided as a list item to `start:` or `end:` +{ + # Specifies a `dropdown` type + "type": "dropdown", + # Text to be displayed on the button + "content": "EBP Projects", + # A list of dropdown links. Each defines a content string and a url + "items": [ + { + "url": "https://executablebooks.org", + "content": "Executable Books" + }, + { + "url": "https://jupyterbook.org", + "content": "Jupyter Book" + }, + ], + # An optional list of classes to add + "classes": ["one", "two"] +}, +``` + +### Icon links + +You can add a list of icon links to your header that link to external sites and services. +These are often used to link to social media accoutns like GitHub, Twitter, discussion forums, etc. +They will be displayed horizontally whether on wide or narrow screens. + +There are two kinds of icons you can control with `icon-links`: + +- **FontAwesome icons**: FontAwesome icon classes like `fas fa-arrow-right`. See [the FontAwesome documentation](https://fontawesome.com/icons) for a list of classes and icons. +- **A path to an image**: Any local image you include with your documentation. + +To add icon link components to header sections, use the following component configuration: + +```python +# Provided as a list item to `start:` or `end:` +{ + # Specifies the `icon-links` component + "type": "icon-links", + # A list of icon links to include + "icons": [ + # Configuration for icon one uses FontAwesome + { + # Specifies that this icon is a FontAwesome icon + "type": "fontawesome", + # A url for icon one + "url": "https://twitter.com/executablebooks", + # A tooltip for icon one + "name": "Twitter", + # A FontAwesome icon class + "icon": "fab fa-twitter-square", + }, + # Configuration for icon two uses a local image path + { + # Specifies that this icon is a local image + "type": "local", + # A url for icon two + "url": "https://github.com/orgs/executablebooks/discussions", + # A tooltip for icon two + "name": "Discussions image", + # A path to a local image relative to conf.py + "icon": "./path/to/image.png", + }, + ], +}, +``` + +### Buttons + +Buttons are larger and more visually-noticeable. +They can either be links, or they can trigger arbitrary JavaScript that you provide. +Use them as call-to-action items, or as a way to trigger events on your page if you are using custom JavaScript. + +To add buttons components to header sections, use the following component configuration: + +```python + +# Provided as a list item to `start:` or `end:` +{ + # Specifies the `button` component + "type": "button", + # The text that will be displayed inside the button. + "content": "end", + # If provided, the button will be a link to another page. + "url": "https://google.com", + # If provided, clicking the button will trigger this JavaScript. + "onclick": "SomeFunction()", + # An optional list of classes to add + "classes": ["one", "two"] +} +``` + +Note tha **url** and **onclick** cannot both be provided in the same button's configuration. + +### HTML Snippets + +You may provide custom HTML snippets that are inserted into the header as-is. +These are useful to define your own components or styling. + +To add raw HTML components to header sections, use the following component configuration: + +```python +# Provided as a list item to `start:` or `end:` +{ + # Specifies a `html` component + "type": "html", + # The HTML to be inserted + "html": "My custom span", +}, +``` + +## Over-write the header entirely + +Instead of using any of the above functionality, you can also provide your own raw HTML for the header. +Use it if you need to have much more flexibility and control over the header. + To do so, you must define your own Sphinx Template in a specific location. The contents of this template will be inserted into the theme. Here is how to do this: @@ -23,8 +328,3 @@ Here is how to do this: $ echo "

Some text!

" > _templates/sections/header.html ``` - Build your documentation, and you should see content of this file show up above your site. - -## Style the header - -Note that the header has very little styling applied to it by default. -So you should [add custom styles to the theme](custom-css.md) in order to achieve the look and feel you want. diff --git a/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss b/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss index b0b1ff9e..b4a2127e 100644 --- a/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss +++ b/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss @@ -65,7 +65,11 @@ $border-thin: 1px solid rgba(0, 0, 0, 0.1); // Variables for this theme --sbt-sidebar-font-size: var(--sbt-font-size-small-1); - --sbt-header-article-font-size: var(--sbt-font-size-small-1); --sbt-prevnext-font-size: var(--sbt-font-size-small-1); --sbt-footer-font-size: var(--sbt-font-size-small-1); + + // Header variables + --theme-header-article-font-size: var(--sbt-font-size-small-1); + --theme-header-button-color: #5a5a5a; + --theme-header-button-color-hover: black; } diff --git a/src/sphinx_book_theme/assets/styles/components/_buttons.scss b/src/sphinx_book_theme/assets/styles/components/_buttons.scss index ba536373..0c3d9120 100644 --- a/src/sphinx_book_theme/assets/styles/components/_buttons.scss +++ b/src/sphinx_book_theme/assets/styles/components/_buttons.scss @@ -94,12 +94,12 @@ div.header-article-main { a, button, label { - color: $non-content-grey; + color: var(--theme-header-button-color); // Over-ride bootstrap defaults for clicking &:hover, &:focus { - color: black; + color: var(--theme-header-button-color-hover); box-shadow: none; text-decoration: none; } diff --git a/src/sphinx_book_theme/assets/styles/sections/_header-article.scss b/src/sphinx_book_theme/assets/styles/sections/_header-article.scss index 70cfc82f..f2b9f70a 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_header-article.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_header-article.scss @@ -6,7 +6,7 @@ height: $header-article-height; // Fix the height so the TOC doesn't grow it background-color: white; transition: left 0.2s; - font-size: var(--sbt-header-article-font-size); + font-size: var(--theme-header-article-font-size); @include header-height-mobile; diff --git a/src/sphinx_book_theme/assets/styles/sections/_header-primary.scss b/src/sphinx_book_theme/assets/styles/sections/_header-primary.scss index e79eb930..863e7835 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_header-primary.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_header-primary.scss @@ -1,11 +1,15 @@ /** * A few different header CSS rules */ + +$header-default-height-wide: 4rem; +$header-default-height-narrow: 3rem; + @mixin max-height-header() { // Fix max height so our header items don't spill over - max-height: 4rem; + max-height: $header-default-height-wide; @media (max-width: $breakpoint-md) { - max-height: 3rem; + max-height: $header-default-height-narrow; } } @@ -16,7 +20,9 @@ // On narrow screens, cap the height unless you click the hamburger menu @include max-height-header; + min-height: $header-default-height-wide; @media (max-width: $breakpoint-md) { + min-height: $header-default-height-narrow; transition: max-height $animation-time ease-out; overflow-y: hidden; } @@ -24,18 +30,32 @@ // Navigation links a, div.dropdown button { - color: $non-content-grey; + color: var(--theme-header-button-color); &:hover { - color: rgba(var(--pst-color-link), 1); + color: var(--theme-header-button-color-hover); text-decoration: none; } } + + // Button component styling (won't apply to dropdowns) + button.btn-outline-primary { + color: rgba(var(--pst-color-primary), 1); + border-color: rgba(var(--pst-color-primary), 1); + + &:hover { + color: white; + background-color: rgba(var(--pst-color-primary), 1); + } + } } // Header content should take up the whole remaining horizontal space .header__content { + display: flex; flex-grow: 1; + max-width: 1400px; // Bootstrap max-width for xl container, to match article + margin: 0 auto; } .header__content, @@ -56,9 +76,6 @@ .header__start { padding-left: 1rem; } -.header__end { - padding-right: 1rem; -} @media (max-width: $breakpoint-md) { // Only apply on narrow screens since we want it centered on sidebar on wide @@ -76,7 +93,6 @@ display: block; margin-top: 0.7em; // HACK: to make this vertically-centered w/o using flexbox margin-left: auto; - padding-right: 0; // Override headerbtn padding so header has same right/left pad } } @@ -109,9 +125,14 @@ input#__header { } .header__end { + @media (max-width: $breakpoint-md) { + padding-bottom: 1rem; + } + @media (min-width: $breakpoint-md) { // Header end is right-justified margin-left: auto; + padding-right: 1.5rem; } } diff --git a/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html b/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html index 54551c50..82e0ef3d 100644 --- a/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html +++ b/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html @@ -4,8 +4,8 @@ {%- if start_items or middle_items or end_items %} -
-
+
+
{% if theme_header.get("brand") %}
From 811349b3c4754739bcd225c1efa6b0742d6a543c Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Thu, 12 May 2022 10:36:38 +0200 Subject: [PATCH 04/17] Fixing dropdown unique id --- src/sphinx_book_theme/_components.py | 7 +++++-- .../assets/styles/sections/_header-primary.scss | 9 ++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/sphinx_book_theme/_components.py b/src/sphinx_book_theme/_components.py index 163461bb..398f7784 100644 --- a/src/sphinx_book_theme/_components.py +++ b/src/sphinx_book_theme/_components.py @@ -8,6 +8,7 @@ The remaining values in the user configuration are passed as kwargs to the func. """ from sphinx.util import logging +import hashlib SPHINX_LOGGER = logging.getLogger(__name__) @@ -63,12 +64,14 @@ def component_dropdown(app, context, content="", items=[]): """ dropdown_items.append(link) dropdown_items = "\n".join(dropdown_items) + dropdown_id = "menu-dropdown-" + dropdown_id += hashlib.md5(dropdown_items.encode("utf-8")).hexdigest()[:5] html = f"""
{# Dropdown button for mobile, will show on the right #} - + {{ theme_render_component({ + "type": "button", + "label_for": "__header", + "icon": "fas fa-bars", + "title": "Toggle Header", + "id": "header-toggle-button" + }) }}
{% endif -%} diff --git a/tests/test_build/build__header-article.html b/tests/test_build/build__header-article.html index 74bc3326..fd19d29d 100644 --- a/tests/test_build/build__header-article.html +++ b/tests/test_build/build__header-article.html @@ -2,7 +2,7 @@
diff --git a/tests/test_build/header__repo-buttons--all-off.html b/tests/test_build/header__repo-buttons--all-off.html index 0d1f51e2..8a31bf57 100644 --- a/tests/test_build/header__repo-buttons--all-off.html +++ b/tests/test_build/header__repo-buttons--all-off.html @@ -1,6 +1,6 @@
diff --git a/tests/test_build/header__repo-buttons--all-on.html b/tests/test_build/header__repo-buttons--all-on.html index 2dbc8d5d..5c64b3a8 100644 --- a/tests/test_build/header__repo-buttons--all-on.html +++ b/tests/test_build/header__repo-buttons--all-on.html @@ -1,6 +1,6 @@
diff --git a/tests/test_build/header__repo-buttons--custom-branch.html b/tests/test_build/header__repo-buttons--custom-branch.html index 1a4f37c5..93f07b58 100644 --- a/tests/test_build/header__repo-buttons--custom-branch.html +++ b/tests/test_build/header__repo-buttons--custom-branch.html @@ -8,10 +8,10 @@
- + @@ -40,22 +40,22 @@
  • - + - + .ipynb
  • diff --git a/tests/test_build/header__repo-buttons--one-on.html b/tests/test_build/header__repo-buttons--one-on.html index 63c3c4c8..b5f8eb4e 100644 --- a/tests/test_build/header__repo-buttons--one-on.html +++ b/tests/test_build/header__repo-buttons--one-on.html @@ -1,12 +1,12 @@
    - + @@ -20,22 +20,22 @@
    • - + - + .ipynb
    • diff --git a/tests/test_build/test_header_launchbtns.html b/tests/test_build/test_header_launchbtns.html index 6ab4a501..2c356c99 100644 --- a/tests/test_build/test_header_launchbtns.html +++ b/tests/test_build/test_header_launchbtns.html @@ -7,51 +7,51 @@
      • - + - + Binder
      • - + - + JupyterHub
      • - + - + Colab
      • - + - + Deepnote
      • diff --git a/tests/test_build/test_topbar_launchbtns.html b/tests/test_build/test_topbar_launchbtns.html index 6ab4a501..2c356c99 100644 --- a/tests/test_build/test_topbar_launchbtns.html +++ b/tests/test_build/test_topbar_launchbtns.html @@ -7,51 +7,51 @@
        • - + - + Binder
        • - + - + JupyterHub
        • - + - + Colab
        • - + - + Deepnote
        • From e0846ba66713ca6909508c5b70fce21fa4e5fc76 Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Mon, 16 May 2022 15:29:36 +0200 Subject: [PATCH 06/17] More image updates --- docs/_data/config-header.yml | 8 +- docs/customize/header.md | 4 +- src/sphinx_book_theme/_components.py | 205 +++++++++++++++------------ 3 files changed, 119 insertions(+), 98 deletions(-) diff --git a/docs/_data/config-header.yml b/docs/_data/config-header.yml index c4c1f514..6666e32f 100644 --- a/docs/_data/config-header.yml +++ b/docs/_data/config-header.yml @@ -1,6 +1,6 @@ brand: - type: image - src: https://executablebooks.org/en/latest/_static/logo.svg + type: link + image: https://executablebooks.org/en/latest/_static/logo.svg url: https://sphinx-book-theme.readthedocs.io start: - type: dropdown @@ -23,8 +23,10 @@ start: - content: Feature Voting url: https://executablebooks.org/en/latest/feature-vote.html - - type: button + - type: link content: Book gallery + external: true + newwindow: true url: http://gallery.jupyterbook.org/ diff --git a/docs/customize/header.md b/docs/customize/header.md index 0d2a6fdc..45d670c7 100644 --- a/docs/customize/header.md +++ b/docs/customize/header.md @@ -67,9 +67,9 @@ html_theme_options = { "header": { "brand": { # Specifies that the brand area will use an image logo - "type": "image", + "type": "link", # Source of the image to be used - "src": "https://executablebooks.org/en/latest/_static/logo.svg", + "image": "https://executablebooks.org/en/latest/_static/logo.svg", # Link for the image "url": "https://sphinx-book-theme.readthedocs.io", }, diff --git a/src/sphinx_book_theme/_components.py b/src/sphinx_book_theme/_components.py index adb69fc3..785e37bd 100644 --- a/src/sphinx_book_theme/_components.py +++ b/src/sphinx_book_theme/_components.py @@ -14,20 +14,115 @@ # Add functions to render header components -def component_text(app, context, content="", url="", classes=[]): - classes = " ".join(classes) - html = f"{content}" - if url: - html = f'{html}' +def component_link( + app, + context, + content="", + icon="", + image="", + doc="", + url="", + newwindow=False, + external=False, + classes=[], +): + kwargs = {"class": classes.copy()} + if external is True: + kwargs["target"] = "_blank" + if newwindow is True: + classes.append("external-link") + + html = component_button( + app, + context, + content=content, + icon=icon, + image=image, + classes=classes, + url=url, + kwargs=kwargs, + ) + return html + + +def component_dropdown( + app, context, content="", icon="", side="left", items=[], **kwargs +): + # Items to go inside dropdown + dropdown_items = [] + for component in items: + # Pop the `button` type in case it was incorrectly given, since we force button + if "type" in component: + component.pop("type") + dropdown_items.append( + component_button( + app, + context, + **component, + ) + ) + dropdown_items = "\n".join(dropdown_items) + + # These control the look of the button + button_classes = [] + if content: + button_classes.append("dropdown-toggle") + + # Unique ID to trigger the show event + dropdown_id = "menu-dropdown-" + dropdown_id += hashlib.md5(dropdown_items.encode("utf-8")).hexdigest()[:5] + + # Generate the button HTML + dropdown_kwargs = { + "data-toggle": "dropdown", + "aria-haspopup": "true", + "aria-expanded": "false", + "type": "button", + } + html_button = component_button( + app, + context, + content=content, + icon=icon, + kwargs=dropdown_kwargs, + classes=button_classes, + button_id=dropdown_id, + **kwargs, + ) + + dropdown_classes = ["dropdown-menu"] + if side == "right": + dropdown_classes.append("dropdown-menu-right") + dropdown_classes = " ".join(dropdown_classes) + + html_dropdown = f""" + + """ # noqa + return html_dropdown + + +def component_html(app, context, html=""): return html +def component_icon_links(app, context, icons, classes=[]): + context = {"theme_icon_links": icons} + # Add the pydata theme icon-links macro as a function we can re-use + return app.builder.templates.render("icon-links.html", context) + + def component_button( app, context, content="", title="", icon="", + image="", url="", onclick="", button_id="", @@ -39,13 +134,13 @@ def component_button( ): kwargs = kwargs.copy() kwargs.update({"type": "button", "class": ["btn", "icon-button"]}) - kwargs["class"].extend(classes) + kwargs["class"].extend(classes.copy()) btn_content = "" if url and onclick: raise Exception("Button component cannot have both url and onclick specified.") - if not (icon or content): - raise Exception("Button must have either icon or content specified.") + if not (icon or content or image): + raise Exception("Button must have either icon, content, or image specified.") if onclick: kwargs["onclick"] = onclick @@ -62,6 +157,13 @@ def component_button( icon = f'' btn_content += f'{icon}' + if image: + if not image.startswith("http"): + image = context["pathto"](image, 1) + btn_content += f""" + + """ + if not content: kwargs["class"].append("icon-button-no-content") else: @@ -116,93 +218,10 @@ def component_button( return html -def component_dropdown( - app, context, content="", icon="", side="left", items=[], **kwargs -): - # Items to go inside dropdown - dropdown_items = [] - for component in items: - # Pop the `button` type in case it was incorrectly given, since we force button - if "type" in component: - component.pop("type") - dropdown_items.append( - component_button( - app, - context, - **component, - ) - ) - dropdown_items = "\n".join(dropdown_items) - - # These control the look of the button - button_classes = [] - if content: - button_classes.append("dropdown-toggle") - - # Unique ID to trigger the show event - dropdown_id = "menu-dropdown-" - dropdown_id += hashlib.md5(dropdown_items.encode("utf-8")).hexdigest()[:5] - - # Generate the button HTML - dropdown_kwargs = { - "data-toggle": "dropdown", - "aria-haspopup": "true", - "aria-expanded": "false", - "type": "button", - } - html_button = component_button( - app, - context, - content=content, - icon=icon, - kwargs=dropdown_kwargs, - classes=button_classes, - button_id=dropdown_id, - **kwargs, - ) - - dropdown_classes = ["dropdown-menu"] - if side == "right": - dropdown_classes.append("dropdown-menu-right") - dropdown_classes = " ".join(dropdown_classes) - - html_dropdown = f""" - - """ # noqa - return html_dropdown - - -def component_image(app, context, src="", url="", classes=[]): - if not src.startswith("http"): - src = context["pathto"](src, 1) - html = f""" - - """ - if url: - html = f"{html}" - return html - - -def component_html(app, context, html=""): - return html - - -def component_icon_links(app, context, icons, classes=[]): - context = {"theme_icon_links": icons} - # Add the pydata theme icon-links macro as a function we can re-use - return app.builder.templates.render("icon-links.html", context) - - COMPONENT_FUNCS = { - "text": component_text, + "link": component_link, "button": component_button, - "html": component_html, - "image": component_image, "icon-links": component_icon_links, "dropdown": component_dropdown, + "html": component_html, } From 44cd965e33f54fc5b6cf7e0d4650fab7f66e5e87 Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Mon, 16 May 2022 20:38:50 +0200 Subject: [PATCH 07/17] Fixing script --- src/sphinx_book_theme/assets/scripts/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sphinx_book_theme/assets/scripts/index.js b/src/sphinx_book_theme/assets/scripts/index.js index 187ca6bc..794cb936 100644 --- a/src/sphinx_book_theme/assets/scripts/index.js +++ b/src/sphinx_book_theme/assets/scripts/index.js @@ -56,7 +56,7 @@ var toggleFullScreen = () => { * the screen. */ var scrollToActive = () => { - var navbar = document.getElementById("site-navigation"); + var navbar = document.querySelector("#site-navigation .bd-sidebar__content"); var active_pages = navbar.querySelectorAll(".active"); var active_page = active_pages[active_pages.length - 1]; // Only scroll the navbar if the active link is lower than 50% of the page From 1ce96e74b90ea498f95ef4d422dda71e431f4610 Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Tue, 17 May 2022 10:05:42 +0200 Subject: [PATCH 08/17] Updates --- docs/_data/config-header.yml | 25 +- docs/customize/header.md | 172 +++++++------ src/sphinx_book_theme/_components.py | 226 ++++++++---------- .../assets/styles/sections/_header.scss | 61 +++-- .../theme/sphinx_book_theme/layout.html | 12 +- .../sphinx_book_theme/sections/header.html | 61 +++-- 6 files changed, 283 insertions(+), 274 deletions(-) diff --git a/docs/_data/config-header.yml b/docs/_data/config-header.yml index 6666e32f..0a3b9432 100644 --- a/docs/_data/config-header.yml +++ b/docs/_data/config-header.yml @@ -1,5 +1,5 @@ brand: - type: link + type: button image: https://executablebooks.org/en/latest/_static/logo.svg url: https://sphinx-book-theme.readthedocs.io start: @@ -23,22 +23,23 @@ start: - content: Feature Voting url: https://executablebooks.org/en/latest/feature-vote.html - - type: link + - type: button content: Book gallery - external: true - newwindow: true url: http://gallery.jupyterbook.org/ end: - - type: icon-links - icons: - - icon: fab fa-twitter-square - name: Twitter + - type: group + items: + - type: button + icon: fab fa-twitter-square + title: Twitter url: https://twitter.com/executablebooks - - icon: fab fa-github-square - name: GitHub + - type: button + icon: fab fa-github-square + title: GitHub url: https://github.com/executablebooks - - icon: fas fa-comments - name: Forum + - type: button + icon: fas fa-comments + title: Forum url: https://github.com/orgs/executablebooks/discussions diff --git a/docs/customize/header.md b/docs/customize/header.md index 45d670c7..7dde68a7 100644 --- a/docs/customize/header.md +++ b/docs/customize/header.md @@ -161,26 +161,101 @@ html_theme_options = { The rest of these sections describe the components you can use: -### Link and text components +### Buttons + +Buttons are flexible UI components that trigger various actions when clicked. +They can be links, or they can trigger arbitrary JavaScript that you provide. +Use them as call-to-action items, or as a way to trigger events on your page if you are using custom JavaScript. + +Clicking a button can trigger one of two actions: + +- **Link to an internal or external page** +- **Trigger a JavaScript function** + +Buttons have three visual sections that you may control, that roughly follow this structure: + +```html + +``` + +- **`icon`**: A small, square icon. May be configured with **FontAwesome** icons or a path to an image (local or remove). +- **`image`**: A larger image that may be rectangular. May be configured with **FontAwesome** icons or a path to an image (local or remove). +- **`content`**: Arbitrary text (or extra HTML) to put inside the button. -To add text and link components to header sections, use the following component configuration: +To add buttons components to header sections, use the following component configuration: ```python # Provided as a list item to `start:` or `end:` { - # Specifies a `text` component - "type": "text", - # The URL to which the link points - "url": "https://jupyterbook.org", - # The text to be displayed - "content": "Jupyter Book", + # Specifies the `button` component + "type": "button", + + ## Controls button behavior ## + # If provided, the button will be a link to another page. + "url": "https://google.com", + # If provided, clicking the button will trigger this JavaScript. + "onclick": "SomeFunction()", + + ## Controls button style ## + # An icon that will be displayed before the text + # Can be a set of fontawesome classes, or a path to an image + "icon": "fas fa-bars", + # An image path that will be displayed before the text + "image": "https://executablebooks.org/en/latest/_static/logo.svg", + # The text that will be displayed inside the button. + "content": "My button's text", # An optional list of classes to add "classes": ["one", "two"] -}, +} ``` -To add text without a link, simply omit the `url:` parameter. +Note tha **url** and **onclick** cannot both be provided in the same button's configuration. + +#### Button icons + +There are two kinds of icons you can control with the `icon` parameter: + +- **FontAwesome icons**: FontAwesome icon classes like `fas fa-arrow-right`. See [the FontAwesome documentation](https://fontawesome.com/icons) for a list of classes and icons. For example: + + ```python + # Provided as a list item to `start:` or `end:` + { + # Specifies the `button` component + "type": "button", + "icon": "fab fa-github" + "url": "https://github.com" + } + ``` +- **A path to an image**: Any local image you include with your documentation. + + For example, with a remote image: + + ```python + # Provided as a list item to `start:` or `end:` + { + # Specifies the `button` component + "type": "button", + "image": "https://executablebooks.org/en/latest/_static/logo.svg" + "url": "https://executablebooks.org" + } + ``` + + With a local image: + + ```python + # Provided as a list item to `start:` or `end:` + { + # Specifies the `button` component + "type": "button", + "image": "./_static/myimage.png" + "url": "https://executablebooks.org" + } + ``` + +Finally, if a button is configured **only with an icon**, it will have a special class `icon-button` added to it that will make it contract slightly in size and spacing. ### Dropdown menus @@ -196,7 +271,7 @@ To add dropdown components to header sections, use the following component confi "type": "dropdown", # Text to be displayed on the button "content": "EBP Projects", - # A list of dropdown links. Each defines a content string and a url + # A list of dropdown links. Each is a configuration for a button. "items": [ { "url": "https://executablebooks.org", @@ -212,79 +287,38 @@ To add dropdown components to header sections, use the following component confi }, ``` -### Icon links +### Groups -You can add a list of icon links to your header that link to external sites and services. -These are often used to link to social media accoutns like GitHub, Twitter, discussion forums, etc. -They will be displayed horizontally whether on wide or narrow screens. +Groups are a way of telling the theme that several UI components should be grouped together. +They will have a wrapping container, will have less spacing between them, and will be displayed _horizontally_ on narrow screens. -There are two kinds of icons you can control with `icon-links`: - -- **FontAwesome icons**: FontAwesome icon classes like `fas fa-arrow-right`. See [the FontAwesome documentation](https://fontawesome.com/icons) for a list of classes and icons. -- **A path to an image**: Any local image you include with your documentation. - -To add icon link components to header sections, use the following component configuration: +For example, to group several icon buttons together use a configuration like so: ```python # Provided as a list item to `start:` or `end:` { - # Specifies the `icon-links` component - "type": "icon-links", - # A list of icon links to include - "icons": [ - # Configuration for icon one uses FontAwesome + # Specifies a `group` type + "type": "group", + # A list of group items. Each is a configuration for a button. + "items": [ { - # Specifies that this icon is a FontAwesome icon - "type": "fontawesome", - # A url for icon one - "url": "https://twitter.com/executablebooks", - # A tooltip for icon one - "name": "Twitter", - # A FontAwesome icon class - "icon": "fab fa-twitter-square", + "icon": "fab fa-github", + "url": "https://github.com }, - # Configuration for icon two uses a local image path { - # Specifies that this icon is a local image - "type": "local", - # A url for icon two - "url": "https://github.com/orgs/executablebooks/discussions", - # A tooltip for icon two - "name": "Discussions image", - # A path to a local image relative to conf.py - "icon": "./path/to/image.png", + "icon": "fab fa-twitter", + "url": "https://twitter.com + }, + { + "icon": "fab fa-discourse", + "url": "https://discourse.com }, ], -}, -``` - -### Buttons - -Buttons are larger and more visually-noticeable. -They can either be links, or they can trigger arbitrary JavaScript that you provide. -Use them as call-to-action items, or as a way to trigger events on your page if you are using custom JavaScript. - -To add buttons components to header sections, use the following component configuration: - -```python - -# Provided as a list item to `start:` or `end:` -{ - # Specifies the `button` component - "type": "button", - # The text that will be displayed inside the button. - "content": "end", - # If provided, the button will be a link to another page. - "url": "https://google.com", - # If provided, clicking the button will trigger this JavaScript. - "onclick": "SomeFunction()", # An optional list of classes to add "classes": ["one", "two"] -} +}, ``` -Note tha **url** and **onclick** cannot both be provided in the same button's configuration. - ### HTML Snippets You may provide custom HTML snippets that are inserted into the header as-is. diff --git a/src/sphinx_book_theme/_components.py b/src/sphinx_book_theme/_components.py index 785e37bd..b6726917 100644 --- a/src/sphinx_book_theme/_components.py +++ b/src/sphinx_book_theme/_components.py @@ -13,109 +13,6 @@ SPHINX_LOGGER = logging.getLogger(__name__) -# Add functions to render header components -def component_link( - app, - context, - content="", - icon="", - image="", - doc="", - url="", - newwindow=False, - external=False, - classes=[], -): - kwargs = {"class": classes.copy()} - if external is True: - kwargs["target"] = "_blank" - if newwindow is True: - classes.append("external-link") - - html = component_button( - app, - context, - content=content, - icon=icon, - image=image, - classes=classes, - url=url, - kwargs=kwargs, - ) - return html - - -def component_dropdown( - app, context, content="", icon="", side="left", items=[], **kwargs -): - # Items to go inside dropdown - dropdown_items = [] - for component in items: - # Pop the `button` type in case it was incorrectly given, since we force button - if "type" in component: - component.pop("type") - dropdown_items.append( - component_button( - app, - context, - **component, - ) - ) - dropdown_items = "\n".join(dropdown_items) - - # These control the look of the button - button_classes = [] - if content: - button_classes.append("dropdown-toggle") - - # Unique ID to trigger the show event - dropdown_id = "menu-dropdown-" - dropdown_id += hashlib.md5(dropdown_items.encode("utf-8")).hexdigest()[:5] - - # Generate the button HTML - dropdown_kwargs = { - "data-toggle": "dropdown", - "aria-haspopup": "true", - "aria-expanded": "false", - "type": "button", - } - html_button = component_button( - app, - context, - content=content, - icon=icon, - kwargs=dropdown_kwargs, - classes=button_classes, - button_id=dropdown_id, - **kwargs, - ) - - dropdown_classes = ["dropdown-menu"] - if side == "right": - dropdown_classes.append("dropdown-menu-right") - dropdown_classes = " ".join(dropdown_classes) - - html_dropdown = f""" - - """ # noqa - return html_dropdown - - -def component_html(app, context, html=""): - return html - - -def component_icon_links(app, context, icons, classes=[]): - context = {"theme_icon_links": icons} - # Add the pydata theme icon-links macro as a function we can re-use - return app.builder.templates.render("icon-links.html", context) - - def component_button( app, context, @@ -129,12 +26,12 @@ def component_button( label_for="", id="", tooltip_placement="", - kwargs={}, + attributes={}, classes=[], ): - kwargs = kwargs.copy() - kwargs.update({"type": "button", "class": ["btn", "icon-button"]}) - kwargs["class"].extend(classes.copy()) + attributes = attributes.copy() + attributes.update({"type": "button", "class": ["btn", "icon-button"]}) + attributes["class"].extend(classes.copy()) btn_content = "" if url and onclick: raise Exception("Button component cannot have both url and onclick specified.") @@ -143,10 +40,10 @@ def component_button( raise Exception("Button must have either icon, content, or image specified.") if onclick: - kwargs["onclick"] = onclick + attributes["onclick"] = onclick if id: - kwargs["id"] = id + attributes["id"] = id if icon: if icon.startswith("fa"): @@ -165,14 +62,14 @@ def component_button( """ if not content: - kwargs["class"].append("icon-button-no-content") + attributes["class"].append("icon-button-no-content") else: btn_content += content if button_id: - kwargs["id"] = button_id + attributes["id"] = button_id - kwargs["aria-label"] = title + attributes["aria-label"] = title # Handle tooltips title = context["translate"](title) @@ -180,30 +77,30 @@ def component_button( # If we're already using data-toggle, wrap the button content in a span. # This lets us use another data-toggle. - if "data-toggle" in kwargs: + if "data-toggle" in attributes: btn_content = f""" {btn_content} """ # noqa else: - kwargs["data-placement"] = tooltip_placement - kwargs["title"] = title + attributes["data-placement"] = tooltip_placement + attributes["title"] = title - # Convert all the options for the button into a string of HTML kwargs - kwargs["class"] = " ".join(kwargs["class"]) - kwargs_str = " ".join([f'{key}="{val}"' for key, val in kwargs.items()]) + # Convert all the options for the button into a string of HTML attributes + attributes["class"] = " ".join(attributes["class"]) + attributes_str = " ".join([f'{key}="{val}"' for key, val in attributes.items()]) # Generate the button HTML if label_for: html = f""" - -
          +
          {%- include "sections/announcement.html" -%}
          - -{%- include "sections/header.html" -%} - +
          + {%- include "sections/header.html" -%} +
          {{ super() }} {% endblock %} @@ -49,11 +49,11 @@ {% endblock %} {% block docs_main %} + +
          {% block docs_body %} - -
          {% include "sections/header-article.html" %}
          diff --git a/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html b/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html index f026f000..80666f72 100644 --- a/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html +++ b/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html @@ -4,44 +4,43 @@ {%- if start_items or middle_items or end_items %} -
          -
          - - {% if theme_header.get("brand") %} -
          -
          - {{ theme_render_component(theme_header.get("brand")) }} -
          +
          + + {% if theme_header.get("brand") %} +
          +
          + {{ theme_render_component(theme_header.get("brand")) }}
          - {% endif %} +
          + {% endif %} - -
          - {% for item in start_items %} -
          - {{ theme_render_component(item) }} -
          - {% endfor %} + +
          + {% for item in start_items %} +
          + {{ theme_render_component(item) }}
          + {% endfor %} +
          - -
          - {% for item in end_items %} -
          - {{ theme_render_component(item) }} -
          - {% endfor %} + +
          + {% for item in end_items %} +
          + {{ theme_render_component(item) }}
          + {% endfor %}
          - {# Dropdown button for mobile, will show on the right #} - {{ theme_render_component({ - "type": "button", - "label_for": "__header", - "icon": "fas fa-bars", - "title": "Toggle Header", - "id": "header-toggle-button" - }) }}
          + + +{{ theme_render_component({ + "type": "button", + "label_for": "__header", + "icon": "fas fa-bars", + "title": "Toggle Header", + "id": "header-toggle-button" +}) }} {% endif -%} {% endif %} From f1418c19d637877cff90e130c921a58f3c94860b Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Fri, 20 May 2022 22:14:24 +0200 Subject: [PATCH 09/17] More tweaks --- docs/_data/config-header.yml | 10 +- docs/_static/custom.css | 5 +- src/sphinx_book_theme/__init__.py | 3 +- src/sphinx_book_theme/_components.py | 100 ++++++++++++------ .../assets/styles/components/_buttons.scss | 91 +++++++++++----- .../styles/sections/_header-article.scss | 7 +- .../header_buttons/__init__.py | 2 - .../header_buttons/launch.py | 1 - 8 files changed, 148 insertions(+), 71 deletions(-) diff --git a/docs/_data/config-header.yml b/docs/_data/config-header.yml index 0a3b9432..afae02e1 100644 --- a/docs/_data/config-header.yml +++ b/docs/_data/config-header.yml @@ -39,7 +39,9 @@ end: icon: fab fa-github-square title: GitHub url: https://github.com/executablebooks - - type: button - icon: fas fa-comments - title: Forum - url: https://github.com/orgs/executablebooks/discussions + - type: button + icon: fas fa-comments + outline: true + content: Discussion + classes: text-primary + url: https://github.com/orgs/executablebooks/discussions diff --git a/docs/_static/custom.css b/docs/_static/custom.css index f0483400..ac67b7b1 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,3 +1,6 @@ :root { - --sd-color-primary: #f37726; + /* WONT WORK UNTIL THE NEXT PYDATA THEME IS RELEASED + --sbt-color-primary: #f37726; + --sd-color-primary: var(--sbt-color-primary); + */ } diff --git a/src/sphinx_book_theme/__init__.py b/src/sphinx_book_theme/__init__.py index cc305967..ae17a4c4 100644 --- a/src/sphinx_book_theme/__init__.py +++ b/src/sphinx_book_theme/__init__.py @@ -76,9 +76,8 @@ def render_component(component): output = COMPONENT_FUNCS[kind](app, context, **component_copy) except Exception as exc: msg = f"Component render failure for:\n{component}\n\n" - msg += f"Exception: {exc}" SPHINX_LOGGER.warn(msg) - return + raise exc return output context["theme_render_component"] = render_component diff --git a/src/sphinx_book_theme/_components.py b/src/sphinx_book_theme/_components.py index b6726917..fb375eaf 100644 --- a/src/sphinx_book_theme/_components.py +++ b/src/sphinx_book_theme/_components.py @@ -16,22 +16,66 @@ def component_button( app, context, - content="", - title="", - icon="", - image="", - url="", - onclick="", - button_id="", - label_for="", - id="", - tooltip_placement="", + content=None, + title=None, + icon=None, + image=None, + outline=None, + id=None, + tooltip_placement=None, + url=None, + onclick=None, + button_id=None, + label_for=None, attributes={}, classes=[], ): + """Render a clickable button. + + There are three possible actions that will be triggered, + corresponding to different kwargs having values. + + Meta Parameters + --------------- + app: An instance of sphinx.Application + context: A Sphinx build context dictionary + + General parameters + ------------------ + content: Content to populate inside the button. + title: A tooltip / accessibility-friendly title. + icon: A tiny square icon. A set of FontAwesome icon classes, or path to an image. + image: A larger image of any aspect ratio. A path to a local or remote image. + button_id: The ID to be added to this button. + outline: Whether to outline the button. + tooltip_placement: Whether the tooltip will be to the left, right, top, or bottom. + attributes: A dictionary of any key:val attributes to add to the button. + classes: A list of CSS classes to add to the button. + + Action-specific parameters + -------------------------- + url: The URL to which a button will direct when clicked. + onclick: JavaScript that will be called when a person clicks. + label_for: The input this label should trigger when clicked (button is a label). + """ + # Set up attributes and classes that will be used to create HTML attributes at end attributes = attributes.copy() - attributes.update({"type": "button", "class": ["btn", "icon-button"]}) - attributes["class"].extend(classes.copy()) + attributes.update({"type": "button"}) + + # Update classes with custom added ones + default_classes = ["btn", "icon-button"] + if classes: + if isinstance(classes, str): + classes = [classes] + else: + classes = [] + classes.extend(default_classes) + + # Give an outline if desired. + if outline: + classes.append("btn-outline") + + # Checks for proper arguments btn_content = "" if url and onclick: raise Exception("Button component cannot have both url and onclick specified.") @@ -62,33 +106,23 @@ def component_button( """ if not content: - attributes["class"].append("icon-button-no-content") + classes.append("icon-button-no-content") else: - btn_content += content + btn_content += f'{content}' if button_id: attributes["id"] = button_id - attributes["aria-label"] = title - - # Handle tooltips - title = context["translate"](title) - tooltip_placement = "bottom" if not tooltip_placement else tooltip_placement - - # If we're already using data-toggle, wrap the button content in a span. - # This lets us use another data-toggle. - if "data-toggle" in attributes: - btn_content = f""" - - {btn_content} - - """ # noqa - else: + # Handle tooltips if a title is given + if title: + title = context["translate"](title) + tooltip_placement = "bottom" if not tooltip_placement else tooltip_placement + attributes["aria-label"] = title attributes["data-placement"] = tooltip_placement attributes["title"] = title # Convert all the options for the button into a string of HTML attributes - attributes["class"] = " ".join(attributes["class"]) + attributes["class"] = " ".join(classes) attributes_str = " ".join([f'{key}="{val}"' for key, val in attributes.items()]) # Generate the button HTML @@ -163,13 +197,17 @@ def component_dropdown( dropdown_id = "menu-dropdown-" dropdown_id += hashlib.md5(dropdown_items.encode("utf-8")).hexdigest()[:5] - # Generate the button HTML + # Generate the dropdown button HTML dropdown_attributes = { "data-toggle": "dropdown", "aria-haspopup": "true", "aria-expanded": "false", "type": "button", } + if "title" in kwargs: + SPHINX_LOGGER.warn("Cannot use title / tooltip with dropdown menu. Removing.") + kwargs.pop("title") + html_button = component_button( app, context, diff --git a/src/sphinx_book_theme/assets/styles/components/_buttons.scss b/src/sphinx_book_theme/assets/styles/components/_buttons.scss index 5f54e592..00bbe507 100644 --- a/src/sphinx_book_theme/assets/styles/components/_buttons.scss +++ b/src/sphinx_book_theme/assets/styles/components/_buttons.scss @@ -13,14 +13,6 @@ } } -// TODO NEW RULES THAT I NEED TO INCORPORATE ABOVE and in other places -// Used when there's a solo icon with no text, so make the icon a bit bigger - -div.dropdown-menu button.btn { - display: flex; - align-items: center; -} - .icon-button { padding: 0.2em 0.2em; margin-bottom: 0; @@ -39,32 +31,73 @@ div.dropdown-menu button.btn { font-size: 1.3rem; } -.dropdown-menu { - // Copied from dropdown menu style above - border-radius: $box-border-radius; - box-shadow: 0px 3px 10px 0px rgba(0, 0, 0, 0.25); +div.dropdown { + // Control the dropdown menu display - button { - padding-left: 0.5rem; - width: 100%; - border-radius: 0; - - &:hover { - background-color: #eee; - } + // First, overwrite the Bootstrap default so we can make nicer animations + // These make it "displayed" but hidden + .dropdown-menu { + display: block; + visibility: hidden; + opacity: 0; + transition: visibility 50ms ease-out, opacity 150ms ease-out 50ms; } - a:hover { - text-decoration: none; + + // On hover, we display the contents via visibility and opacity + &:hover div.dropdown-menu, + div.dropdown-menu:hover { + visibility: visible; + opacity: 1; + // Remove the delay when hovering, which makes it appear instantly, but delay in disappear + transition-delay: 0ms; } - span.btn__icon-container { - display: flex; - margin-right: 0.5rem; + // Other styling on the dropdown menu + .dropdown-menu { + // Copied from dropdown menu style above + border-radius: $box-border-radius; + box-shadow: 0px 3px 10px 0px rgba(0, 0, 0, 0.25); + + button { + display: flex; + align-items: center; + padding-left: 0.5rem; + width: 100%; + border-radius: 0; + + &:hover { + background-color: #eee; + } + } - img, - i { - width: 1.2rem; // Slightly wider to make the font match the images - font-size: 1rem; + a:hover { + text-decoration: none; } + + span.btn__icon-container { + display: flex; + margin-right: 0.5rem; + + img, + i { + width: 1.2rem; // Slightly wider to make the font match the images + font-size: 1rem; + } + } + } +} + +// Extra spacing when we have both icons and content +span.btn__icon-container ~ .btn__content-container { + margin-left: 0.5em; +} + +// Outline buttons need extra spacing +button.btn-outline { + outline: 1px solid $non-content-grey; + padding: 0.3rem 0.5rem; + + &:hover { + background-color: #ededed; } } diff --git a/src/sphinx_book_theme/assets/styles/sections/_header-article.scss b/src/sphinx_book_theme/assets/styles/sections/_header-article.scss index dc763366..055ea700 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_header-article.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_header-article.scss @@ -22,11 +22,16 @@ .header-article__right { display: flex; align-items: center; - gap: 0.5rem; } .header-article__right { margin-left: auto; + + button, + label, + div { + padding-left: 0.25rem; + } } } } diff --git a/src/sphinx_book_theme/header_buttons/__init__.py b/src/sphinx_book_theme/header_buttons/__init__.py index 1a61c005..47131aa7 100644 --- a/src/sphinx_book_theme/header_buttons/__init__.py +++ b/src/sphinx_book_theme/header_buttons/__init__.py @@ -118,7 +118,6 @@ def add_header_buttons(app, pagename, templatename, context, doctree): header_buttons.append( { "type": "dropdown", - "title": "Source repositories", "icon": "fab fa-github", "items": repo_buttons, "side": "right", @@ -171,7 +170,6 @@ def add_header_buttons(app, pagename, templatename, context, doctree): header_buttons.append( { "type": "dropdown", - "title": "Download this page", "icon": "fas fa-download", "items": download_buttons, "side": "right", diff --git a/src/sphinx_book_theme/header_buttons/launch.py b/src/sphinx_book_theme/header_buttons/launch.py index 2a5dfada..678bf13c 100644 --- a/src/sphinx_book_theme/header_buttons/launch.py +++ b/src/sphinx_book_theme/header_buttons/launch.py @@ -180,7 +180,6 @@ def add_launch_buttons( header_buttons.append( { "type": "dropdown", - "title": "Launch interactive content", "icon": "fas fa-rocket", "items": launch_buttons_list, "side": "right", From c3bd6a20d7e6792acb61c746d6fc8ba6d1b55e85 Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Sat, 21 May 2022 03:49:27 +0200 Subject: [PATCH 10/17] Improving header behavior --- docs/_data/config-header.yml | 2 + .../assets/styles/components/_buttons.scss | 2 +- .../styles/sections/_header-article.scss | 2 +- .../assets/styles/sections/_header.scss | 84 +++++++++---------- .../sphinx_book_theme/sections/header.html | 25 +++--- 5 files changed, 58 insertions(+), 57 deletions(-) diff --git a/docs/_data/config-header.yml b/docs/_data/config-header.yml index afae02e1..6471d85d 100644 --- a/docs/_data/config-header.yml +++ b/docs/_data/config-header.yml @@ -2,6 +2,8 @@ brand: type: button image: https://executablebooks.org/en/latest/_static/logo.svg url: https://sphinx-book-theme.readthedocs.io + # For testing + # content: Test site name start: - type: dropdown content: Projects diff --git a/src/sphinx_book_theme/assets/styles/components/_buttons.scss b/src/sphinx_book_theme/assets/styles/components/_buttons.scss index 00bbe507..30d82077 100644 --- a/src/sphinx_book_theme/assets/styles/components/_buttons.scss +++ b/src/sphinx_book_theme/assets/styles/components/_buttons.scss @@ -14,7 +14,7 @@ } .icon-button { - padding: 0.2em 0.2em; + padding: 0 0.2em; margin-bottom: 0; color: var(--theme-header-button-color); diff --git a/src/sphinx_book_theme/assets/styles/sections/_header-article.scss b/src/sphinx_book_theme/assets/styles/sections/_header-article.scss index 055ea700..f032e3e9 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_header-article.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_header-article.scss @@ -30,7 +30,7 @@ button, label, div { - padding-left: 0.25rem; + padding-left: 0.3rem; } } } diff --git a/src/sphinx_book_theme/assets/styles/sections/_header.scss b/src/sphinx_book_theme/assets/styles/sections/_header.scss index a4a8baf8..3f6a7e5b 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_header.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_header.scss @@ -2,16 +2,7 @@ * A few different header CSS rules */ -$header-default-height-wide: 4rem; -$header-default-height-narrow: 3rem; - -@mixin max-height-header() { - // Fix max height so our header items don't spill over - max-height: $header-default-height-wide; - @media (max-width: $breakpoint-md) { - max-height: $header-default-height-narrow; - } -} +$header-default-height: 4rem; // Header container places the collapse button properly .header { @@ -26,12 +17,10 @@ $header-default-height-narrow: 3rem; max-width: 1400px; // Bootstrap max-width for xl container, to match article margin: 0 auto; padding: 0 0.5rem; - @include max-height-header; + max-height: $header-default-height; + min-height: $header-default-height; - // On narrow screens, cap the height unless you click the hamburger menu - min-height: $header-default-height-wide; @media (max-width: $breakpoint-md) { - min-height: $header-default-height-narrow; transition: max-height $animation-time ease-out; overflow-y: hidden; padding-bottom: 0.5rem; @@ -61,7 +50,6 @@ $header-default-height-narrow: 3rem; } .header__content, -.header__brand, .header__start, .header__end { display: flex; @@ -74,10 +62,6 @@ $header-default-height-narrow: 3rem; } } -.header__brand { - padding: 0 1.5rem; -} - .header__brand, .header__start, .header__end { @@ -87,17 +71,6 @@ $header-default-height-narrow: 3rem; } } -// Only show up on narrow screens, and push to the far right -#header-toggle-button { - display: none; - @media (max-width: $breakpoint-md) { - display: block; - margin-right: 0.5rem; - // HACK to keep it centered in a way that won't move when expanded - margin-top: 0.2rem; - } -} - input#__header { // Inputs never display, only used to control behavior display: none; @@ -112,20 +85,49 @@ input#__header { // This is the logo or a bold docs title .header__brand { + display: flex; font-size: 1.5em; - // Wide screens: header start has same width as the sidebar + center over logo - @media (min-width: $breakpoint-md) { - width: $leftbar-width-wide; - justify-content: center; + // Align the brand vertically + .header-content-item { + height: $header-default-height; + align-items: center; + } + + // So the brand logo aligns with the toggle button + button { + padding: 0; + } + + // Only show up on narrow screens, and push to the far right + #header-toggle-button { + display: none; + font-size: 1.5rem; // A bit bigger since it's prominent at top + @media (max-width: $breakpoint-md) { + display: flex; + align-items: center; + height: $header-default-height; + margin-left: auto; + margin-right: 0.4rem; + } } } +// Wide screens: header start has same width as the sidebar + center over logo +@media (min-width: $breakpoint-md) { + width: $leftbar-width-wide; + justify-content: center; +} + .header__end { // Header end is right-justified on wide screens @media (min-width: $breakpoint-md) { margin-left: auto; } + + @media (max-width: $breakpoint-md) { + margin-bottom: 1rem; + } } ul#navbar-icon-links { @@ -138,7 +140,12 @@ ul#navbar-icon-links { align-items: center; // Ensure that the items don't break out of their containers - @include max-height-header; + max-height: $header-default-height; + + // Images are capped a bit smaller so they have whitespace in the header + img { + max-height: $header-default-height * 0.8; + } // Spacing is horizontal on wide, vertical on narrow // Items should snap to left on mobile @@ -146,13 +153,6 @@ ul#navbar-icon-links { align-items: start; } - // Images are capped a bit smaller so they have whitespace in the header - img { - @media (max-width: $breakpoint-md) { - max-height: 2rem; - } - } - .dropdown-menu { z-index: $zindex-sticky + 1; } diff --git a/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html b/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html index 80666f72..534b3348 100644 --- a/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html +++ b/src/sphinx_book_theme/theme/sphinx_book_theme/sections/header.html @@ -6,13 +6,23 @@
          - {% if theme_header.get("brand") %}
          + {% if theme_header.get("brand") %}
          {{ theme_render_component(theme_header.get("brand")) }}
          + {% endif %} + + + {{ theme_render_component({ + "type": "button", + "label_for": "__header", + "icon": "fas fa-bars", + "title": "Toggle Header", + "id": "header-toggle-button" + }) }} + {% endif -%}
          - {% endif %}
          @@ -32,15 +42,4 @@ {% endfor %}
          - - -{{ theme_render_component({ - "type": "button", - "label_for": "__header", - "icon": "fas fa-bars", - "title": "Toggle Header", - "id": "header-toggle-button" -}) }} -{% endif -%} - {% endif %} From a7a57fce069f5934c43e40703c8f9ea53c14721e Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Sat, 21 May 2022 03:56:38 +0200 Subject: [PATCH 11/17] Safari bug --- .../assets/styles/components/_buttons.scss | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/sphinx_book_theme/assets/styles/components/_buttons.scss b/src/sphinx_book_theme/assets/styles/components/_buttons.scss index 30d82077..a34b7f22 100644 --- a/src/sphinx_book_theme/assets/styles/components/_buttons.scss +++ b/src/sphinx_book_theme/assets/styles/components/_buttons.scss @@ -13,22 +13,16 @@ } } -.icon-button { - padding: 0 0.2em; - margin-bottom: 0; - color: var(--theme-header-button-color); - - // Over-ride bootstrap defaults for clicking - &:hover, - &:focus { - color: var(--theme-header-button-color-hover); - box-shadow: none; - text-decoration: none; - } -} +/** + * Header sections + */ -.icon-button-no-content { - font-size: 1.3rem; +// Reset default styling of labels and buttons so we can customize +label { + border-radius: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; } div.dropdown { @@ -92,6 +86,29 @@ span.btn__icon-container ~ .btn__content-container { margin-left: 0.5em; } +/* + * Button types classes + */ +// Basic button class +.icon-button { + padding: 0 0.2em; + margin-bottom: 0; + color: var(--theme-header-button-color); + + // Over-ride bootstrap defaults for clicking + &:hover, + &:focus { + color: var(--theme-header-button-color-hover); + box-shadow: none; + text-decoration: none; + } +} + +// If no content, make the icon a bit bigger +.icon-button-no-content { + font-size: 1.3rem; +} + // Outline buttons need extra spacing button.btn-outline { outline: 1px solid $non-content-grey; From f2589a4b22d2ecc00209e2d3ef5f72c8fb5058ca Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Sat, 21 May 2022 04:04:39 +0200 Subject: [PATCH 12/17] Safari --- src/sphinx_book_theme/assets/styles/components/_buttons.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sphinx_book_theme/assets/styles/components/_buttons.scss b/src/sphinx_book_theme/assets/styles/components/_buttons.scss index a34b7f22..c2fdce98 100644 --- a/src/sphinx_book_theme/assets/styles/components/_buttons.scss +++ b/src/sphinx_book_theme/assets/styles/components/_buttons.scss @@ -18,7 +18,7 @@ */ // Reset default styling of labels and buttons so we can customize -label { +[type="button"] { border-radius: 0; -webkit-appearance: none; -moz-appearance: none; From 9de14aedee8fc4d710b4a0e0e6e195a39f702d04 Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Sat, 21 May 2022 04:10:19 +0200 Subject: [PATCH 13/17] Safari --- src/sphinx_book_theme/assets/styles/components/_buttons.scss | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sphinx_book_theme/assets/styles/components/_buttons.scss b/src/sphinx_book_theme/assets/styles/components/_buttons.scss index c2fdce98..eb5b4b00 100644 --- a/src/sphinx_book_theme/assets/styles/components/_buttons.scss +++ b/src/sphinx_book_theme/assets/styles/components/_buttons.scss @@ -17,12 +17,9 @@ * Header sections */ -// Reset default styling of labels and buttons so we can customize +// Reset default button styling on Safari because it has opinionated / clashing design [type="button"] { - border-radius: 0; -webkit-appearance: none; - -moz-appearance: none; - appearance: none; } div.dropdown { From 5da99b30f583c875448aba583a6e61c9aa288c1d Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Sun, 22 May 2022 07:50:52 +0200 Subject: [PATCH 14/17] Button spacing --- .../assets/styles/abstracts/_variables.scss | 1 + .../assets/styles/components/_buttons.scss | 11 +++++------ .../styles/sections/_header-article.scss | 9 ++------- .../assets/styles/sections/_header.scss | 19 ++++++++++++++----- .../styles/sections/_sidebar-primary.scss | 2 +- .../theme/sphinx_book_theme/layout.html | 2 +- 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss b/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss index b4a2127e..2dc3e3ba 100644 --- a/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss +++ b/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss @@ -72,4 +72,5 @@ $border-thin: 1px solid rgba(0, 0, 0, 0.1); --theme-header-article-font-size: var(--sbt-font-size-small-1); --theme-header-button-color: #5a5a5a; --theme-header-button-color-hover: black; + --theme-header-background-color: white; } diff --git a/src/sphinx_book_theme/assets/styles/components/_buttons.scss b/src/sphinx_book_theme/assets/styles/components/_buttons.scss index eb5b4b00..9b9a5cc9 100644 --- a/src/sphinx_book_theme/assets/styles/components/_buttons.scss +++ b/src/sphinx_book_theme/assets/styles/components/_buttons.scss @@ -67,7 +67,6 @@ div.dropdown { span.btn__icon-container { display: flex; - margin-right: 0.5rem; img, i { @@ -78,11 +77,6 @@ div.dropdown { } } -// Extra spacing when we have both icons and content -span.btn__icon-container ~ .btn__content-container { - margin-left: 0.5em; -} - /* * Button types classes */ @@ -99,6 +93,11 @@ span.btn__icon-container ~ .btn__content-container { box-shadow: none; text-decoration: none; } + + // Spacing for the icon if it's present with text + .btn__icon-container + .btn__content-container { + margin-left: 0.5rem; + } } // If no content, make the icon a bit bigger diff --git a/src/sphinx_book_theme/assets/styles/sections/_header-article.scss b/src/sphinx_book_theme/assets/styles/sections/_header-article.scss index f032e3e9..62b815a1 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_header-article.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_header-article.scss @@ -4,7 +4,7 @@ *********************************************/ .header-article { height: $header-article-height; // Fix the height so the TOC doesn't grow it - background-color: white; + background-color: var(--theme-header-background-color); transition: left 0.2s; font-size: var(--theme-header-article-font-size); @@ -26,12 +26,7 @@ .header-article__right { margin-left: auto; - - button, - label, - div { - padding-left: 0.3rem; - } + gap: 0.5rem; } } } diff --git a/src/sphinx_book_theme/assets/styles/sections/_header.scss b/src/sphinx_book_theme/assets/styles/sections/_header.scss index 3f6a7e5b..c1bf5092 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_header.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_header.scss @@ -8,6 +8,7 @@ $header-default-height: 4rem; .header { display: flex; border-bottom: $border-thin; + background-color: var(--theme-header-background-color); } // Header content contains the components @@ -113,10 +114,18 @@ input#__header { } } -// Wide screens: header start has same width as the sidebar + center over logo -@media (min-width: $breakpoint-md) { - width: $leftbar-width-wide; - justify-content: center; +.header__start, +.header__end { + // Increase the text size on mobile + @media (max-width: $breakpoint-md) { + button { + font-size: 1.1rem; + } + + button.icon-button-no-content { + font-size: 1.5rem; + } + } } .header__end { @@ -144,7 +153,7 @@ ul#navbar-icon-links { // Images are capped a bit smaller so they have whitespace in the header img { - max-height: $header-default-height * 0.8; + max-height: $header-default-height * 0.7; } // Spacing is horizontal on wide, vertical on narrow diff --git a/src/sphinx_book_theme/assets/styles/sections/_sidebar-primary.scss b/src/sphinx_book_theme/assets/styles/sections/_sidebar-primary.scss index d90c183a..4a391746 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_sidebar-primary.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_sidebar-primary.scss @@ -5,7 +5,7 @@ padding-top: 0; width: $leftbar-width-wide; font-size: var(--sbt-sidebar-font-size); - top: 0px !important; + top: 0px; background: white; border-right: $border-thin; transition: margin-left $animation-time ease 0s, diff --git a/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html b/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html index 37f19bce..af0588e8 100644 --- a/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html +++ b/src/sphinx_book_theme/theme/sphinx_book_theme/layout.html @@ -19,7 +19,7 @@
          {%- include "sections/announcement.html" -%}
          -
          +
          {%- include "sections/header.html" -%}
          {{ super() }} From 0bce8472c010bee9a106c41486e28e09dccff2e6 Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Sun, 22 May 2022 08:49:38 +0200 Subject: [PATCH 15/17] Header spacing --- .../assets/styles/abstracts/_variables.scss | 2 ++ src/sphinx_book_theme/assets/styles/sections/_header.scss | 3 ++- .../assets/styles/sections/_sidebar-primary.scss | 2 +- .../assets/styles/sections/_sidebar-secondary.scss | 8 ++++---- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss b/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss index 2dc3e3ba..92155c58 100644 --- a/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss +++ b/src/sphinx_book_theme/assets/styles/abstracts/_variables.scss @@ -67,6 +67,8 @@ $border-thin: 1px solid rgba(0, 0, 0, 0.1); --sbt-sidebar-font-size: var(--sbt-font-size-small-1); --sbt-prevnext-font-size: var(--sbt-font-size-small-1); --sbt-footer-font-size: var(--sbt-font-size-small-1); + --sbt-header-font-size: var(--sbt-font-size-regular); + --sbt-font-size-menu-mobile: 1.1rem; // Header variables --theme-header-article-font-size: var(--sbt-font-size-small-1); diff --git a/src/sphinx_book_theme/assets/styles/sections/_header.scss b/src/sphinx_book_theme/assets/styles/sections/_header.scss index c1bf5092..898ab234 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_header.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_header.scss @@ -119,7 +119,7 @@ input#__header { // Increase the text size on mobile @media (max-width: $breakpoint-md) { button { - font-size: 1.1rem; + font-size: var(--sbt-font-size-menu-mobile); } button.icon-button-no-content { @@ -162,6 +162,7 @@ ul#navbar-icon-links { align-items: start; } + // To put this on top of other sticky content on the page .dropdown-menu { z-index: $zindex-sticky + 1; } diff --git a/src/sphinx_book_theme/assets/styles/sections/_sidebar-primary.scss b/src/sphinx_book_theme/assets/styles/sections/_sidebar-primary.scss index 4a391746..82b4c813 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_sidebar-primary.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_sidebar-primary.scss @@ -18,7 +18,7 @@ position: fixed; width: $leftbar-width-mobile; max-width: 300px; - font-size: 1.2em; + font-size: var(--sbt-font-size-menu-mobile); z-index: $zindex-offcanvas; } diff --git a/src/sphinx_book_theme/assets/styles/sections/_sidebar-secondary.scss b/src/sphinx_book_theme/assets/styles/sections/_sidebar-secondary.scss index da6e8fd5..b11cc539 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_sidebar-secondary.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_sidebar-secondary.scss @@ -27,11 +27,11 @@ background-color: white; border-left: $border-thin; - // Fonts are a bit bigger on mobile, and nested headers get smaller - font-size: 1.4em; - + // Fonts and spacing + font-size: var(--sbt-font-size-menu-mobile); li { - font-size: 0.8em; + // This makes the nested list items smaller + font-size: 0.9em; } } From a304b27f0cf54c8acec27bb6a2a18685a9b42771 Mon Sep 17 00:00:00 2001 From: Chris Holdgraf Date: Tue, 24 May 2022 15:27:27 +0200 Subject: [PATCH 16/17] Passing tests --- docs/_data/config-header.yml | 1 - src/sphinx_book_theme/_components.py | 14 +- .../assets/styles/components/_buttons.scss | 2 +- .../assets/styles/sections/_article.scss | 5 + .../styles/sections/_footer-content.scss | 4 + .../assets/styles/sections/_header.scss | 19 ++- .../header_buttons/__init__.py | 3 +- .../header_buttons/launch.py | 3 +- tests/test_build.py | 44 +++--- ....html => article__margin--marginnote.html} | 0 ...te.html => article__margin--sidenote.html} | 0 tests/test_build/build__header-article.html | 116 --------------- tests/test_build/header-article.html | 112 ++++++++++++++ .../header-article__launch-buttons.html | 51 +++++++ ...-article__repo-buttons--custom-branch.html | 66 +++++++++ .../header__repo-buttons--all-off.html | 58 ++++---- .../header__repo-buttons--all-on.html | 138 +++++++++--------- .../header__repo-buttons--custom-branch.html | 66 --------- .../header__repo-buttons--one-on.html | 70 ++++----- ...ry__nav.html => sidebar-primary__nav.html} | 0 ...debar-secondary--page-multipletitles.html} | 0 ... => sidebar-secondary--page-onetitle.html} | 0 ...r-secondary--page-onetitlenoheadings.html} | 0 ... sidebar-secondary__toc--customtitle.html} | 0 tests/test_build/test_header_launchbtns.html | 61 -------- tests/test_build/test_topbar_launchbtns.html | 61 -------- 26 files changed, 421 insertions(+), 473 deletions(-) rename tests/test_build/{test_marginnote.html => article__margin--marginnote.html} (100%) rename tests/test_build/{test_sidenote.html => article__margin--sidenote.html} (100%) delete mode 100644 tests/test_build/build__header-article.html create mode 100644 tests/test_build/header-article.html create mode 100644 tests/test_build/header-article__launch-buttons.html create mode 100644 tests/test_build/header-article__repo-buttons--custom-branch.html delete mode 100644 tests/test_build/header__repo-buttons--custom-branch.html rename tests/test_build/{build__sidebar-primary__nav.html => sidebar-primary__nav.html} (100%) rename tests/test_build/{build__pagetoc--page-multipletitles.html => sidebar-secondary--page-multipletitles.html} (100%) rename tests/test_build/{build__pagetoc--page-onetitle.html => sidebar-secondary--page-onetitle.html} (100%) rename tests/test_build/{build__pagetoc--page-onetitlenoheadings.html => sidebar-secondary--page-onetitlenoheadings.html} (100%) rename tests/test_build/{test_right_sidebar_title.html => sidebar-secondary__toc--customtitle.html} (100%) delete mode 100644 tests/test_build/test_header_launchbtns.html delete mode 100644 tests/test_build/test_topbar_launchbtns.html diff --git a/docs/_data/config-header.yml b/docs/_data/config-header.yml index 6471d85d..da60fbd5 100644 --- a/docs/_data/config-header.yml +++ b/docs/_data/config-header.yml @@ -45,5 +45,4 @@ end: icon: fas fa-comments outline: true content: Discussion - classes: text-primary url: https://github.com/orgs/executablebooks/discussions diff --git a/src/sphinx_book_theme/_components.py b/src/sphinx_book_theme/_components.py index fb375eaf..a1e6d822 100644 --- a/src/sphinx_book_theme/_components.py +++ b/src/sphinx_book_theme/_components.py @@ -117,6 +117,7 @@ def component_button( if title: title = context["translate"](title) tooltip_placement = "bottom" if not tooltip_placement else tooltip_placement + attributes["data-toggle"] = "tooltip" attributes["aria-label"] = title attributes["data-placement"] = tooltip_placement attributes["title"] = title @@ -171,9 +172,9 @@ def component_group(app, context, items=None, **kwargs): def component_dropdown( - app, context, content="", icon="", side="left", items=[], **kwargs + app, context, content="", icon="", side="left", classes=None, items=[], **kwargs ): - # Items to go inside dropdown + # Render the items inside the dropdown dropdown_items = [] for component in items: # Pop the `button` type in case it was incorrectly given, since we force button @@ -188,10 +189,10 @@ def component_dropdown( ) dropdown_items = "\n".join(dropdown_items) - # These control the look of the button - button_classes = [] + # Set up the classes for the dropdown + classes = [] if not classes else classes if content: - button_classes.append("dropdown-toggle") + classes.append("dropdown-toggle") # Unique ID to trigger the show event dropdown_id = "menu-dropdown-" @@ -199,7 +200,6 @@ def component_dropdown( # Generate the dropdown button HTML dropdown_attributes = { - "data-toggle": "dropdown", "aria-haspopup": "true", "aria-expanded": "false", "type": "button", @@ -214,7 +214,7 @@ def component_dropdown( content=content, icon=icon, attributes=dropdown_attributes, - classes=button_classes, + classes=classes, button_id=dropdown_id, **kwargs, ) diff --git a/src/sphinx_book_theme/assets/styles/components/_buttons.scss b/src/sphinx_book_theme/assets/styles/components/_buttons.scss index 9b9a5cc9..899a5c9d 100644 --- a/src/sphinx_book_theme/assets/styles/components/_buttons.scss +++ b/src/sphinx_book_theme/assets/styles/components/_buttons.scss @@ -52,7 +52,7 @@ div.dropdown { button { display: flex; align-items: center; - padding-left: 0.5rem; + padding-left: 1rem; width: 100%; border-radius: 0; diff --git a/src/sphinx_book_theme/assets/styles/sections/_article.scss b/src/sphinx_book_theme/assets/styles/sections/_article.scss index b87e9c89..a7b5290c 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_article.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_article.scss @@ -12,6 +12,11 @@ body { padding-top: 1.5em; } +.content-container { + display: flex; + flex-direction: column; +} + // On wide screens, make space for the right margin @media (min-width: $breakpoint-md) { #main-content { diff --git a/src/sphinx_book_theme/assets/styles/sections/_footer-content.scss b/src/sphinx_book_theme/assets/styles/sections/_footer-content.scss index 6c147a44..97865889 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_footer-content.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_footer-content.scss @@ -1,6 +1,10 @@ /********************************************* * Footer - content * *********************************************/ +div.footer-content { + margin-top: auto; +} + footer { font-size: var(--sbt-font-size-small-1); } diff --git a/src/sphinx_book_theme/assets/styles/sections/_header.scss b/src/sphinx_book_theme/assets/styles/sections/_header.scss index 898ab234..2dcd27cf 100644 --- a/src/sphinx_book_theme/assets/styles/sections/_header.scss +++ b/src/sphinx_book_theme/assets/styles/sections/_header.scss @@ -17,7 +17,7 @@ $header-default-height: 4rem; flex-grow: 1; max-width: 1400px; // Bootstrap max-width for xl container, to match article margin: 0 auto; - padding: 0 0.5rem; + padding: 0 1rem; max-height: $header-default-height; min-height: $header-default-height; @@ -55,7 +55,6 @@ $header-default-height: 4rem; .header__end { display: flex; flex-wrap: nowrap; - gap: 0.75rem; // On narrow screens, the header items show flow vertically and snap to left @media (max-width: $breakpoint-md) { @@ -63,9 +62,16 @@ $header-default-height: 4rem; } } +// More rem for the content container +.header__content { + gap: 1rem; +} + .header__brand, .header__start, .header__end { + gap: 0.75rem; + // On narrow screens the header content sections display vertically @media (max-width: $breakpoint-md) { padding-left: 0.5rem; @@ -116,15 +122,16 @@ input#__header { .header__start, .header__end { + // Solo icon buttons should be a bit bigger + .icon-button-no-content { + font-size: 1.5rem; + } + // Increase the text size on mobile @media (max-width: $breakpoint-md) { button { font-size: var(--sbt-font-size-menu-mobile); } - - button.icon-button-no-content { - font-size: 1.5rem; - } } } diff --git a/src/sphinx_book_theme/header_buttons/__init__.py b/src/sphinx_book_theme/header_buttons/__init__.py index 47131aa7..d9b38a89 100644 --- a/src/sphinx_book_theme/header_buttons/__init__.py +++ b/src/sphinx_book_theme/header_buttons/__init__.py @@ -121,11 +121,12 @@ def add_header_buttons(app, pagename, templatename, context, doctree): "icon": "fab fa-github", "items": repo_buttons, "side": "right", + "classes": ["repo-buttons"], } ) elif len(repo_buttons) == 1: # Remove the text since it's just a single button, want just an icon. - repo_buttons[0]["text"] = "" + repo_buttons[0]["content"] = "" header_buttons.extend(repo_buttons) # Download buttons for various source content. diff --git a/src/sphinx_book_theme/header_buttons/launch.py b/src/sphinx_book_theme/header_buttons/launch.py index 678bf13c..af58ac8e 100644 --- a/src/sphinx_book_theme/header_buttons/launch.py +++ b/src/sphinx_book_theme/header_buttons/launch.py @@ -181,8 +181,9 @@ def add_launch_buttons( { "type": "dropdown", "icon": "fas fa-rocket", - "items": launch_buttons_list, "side": "right", + "classes": ["launch-buttons"], + "items": launch_buttons_list, } ) diff --git a/tests/test_build.py b/tests/test_build.py index 6accf30f..7f1054e3 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -1,6 +1,6 @@ import os from pathlib import Path -from shutil import copytree, rmtree +from shutil import copytree from subprocess import check_call from bs4 import BeautifulSoup @@ -94,7 +94,7 @@ def test_build_book(sphinx_build_factory, file_regression): sidebar = index_html.find(attrs={"id": "bd-docs-nav"}) file_regression.check( sidebar.prettify(), - basename="build__sidebar-primary__nav", + basename="sidebar-primary__nav", extension=".html", encoding="utf8", ) @@ -114,7 +114,7 @@ def test_build_book(sphinx_build_factory, file_regression): file_regression.check( header_article.prettify(), - basename="build__header-article", + basename="header-article", extension=".html", encoding="utf8", ) @@ -130,7 +130,7 @@ def test_build_book(sphinx_build_factory, file_regression): page_toc = page_html.find("div", attrs={"class": "bd-toc"}) file_regression.check( page_toc.prettify(), - basename=f"build__pagetoc--{page.with_suffix('').name}", + basename=f"sidebar-secondary--{page.with_suffix('').name}", extension=".html", encoding="utf8", ) @@ -215,13 +215,18 @@ def test_header_repository_buttons( ) -def test_header_launchbtns(sphinx_build_factory, file_regression): +def test_header_article_launchbtns(sphinx_build_factory, file_regression): """Test launch buttons.""" sphinx_build = sphinx_build_factory("base").build(assert_pass=True) launch_btns = sphinx_build.html_tree("section1", "ntbk.html").select( - ".menu-dropdown-launch-buttons" + ".launch-buttons + .dropdown-menu" + ) + file_regression.check( + launch_btns[0].prettify(), + basename="header-article__launch-buttons", + extension=".html", + encoding="utf8", ) - file_regression.check(launch_btns[0].prettify(), extension=".html", encoding="utf8") def test_repo_custombranch(sphinx_build_factory, file_regression): @@ -243,7 +248,7 @@ def test_repo_custombranch(sphinx_build_factory, file_regression): # The Binder link should point to `foo`, as should the `edit` button file_regression.check( header[0].prettify(), - basename="header__repo-buttons--custom-branch", + basename="header-article__repo-buttons--custom-branch", extension=".html", encoding="utf8", ) @@ -320,13 +325,12 @@ def test_right_sidebar_title(sphinx_build_factory, file_regression): sidebar_title = sphinx_build.html_tree("page1.html").find_all( "div", attrs={"class": "tocsection"} )[0] - - file_regression.check(sidebar_title.prettify(), extension=".html", encoding="utf8") - - # Testing the exception for empty title - rmtree(str(sphinx_build.src)) - - confoverrides = {"html_theme_options.toc_title": ""} + file_regression.check( + sidebar_title.prettify(), + basename="sidebar-secondary__toc--customtitle", + extension=".html", + encoding="utf8", + ) def test_logo_only(sphinx_build_factory): @@ -351,7 +355,10 @@ def test_sidenote(sphinx_build_factory, file_regression): sidenote_html = page2.select("section > #sidenotes") file_regression.check( - sidenote_html[0].prettify(), extension=".html", encoding="utf8" + sidenote_html[0].prettify(), + basename="article__margin--sidenote", + extension=".html", + encoding="utf8", ) @@ -365,5 +372,8 @@ def test_marginnote(sphinx_build_factory, file_regression): marginnote_html = page2.select("section > #marginnotes") file_regression.check( - marginnote_html[0].prettify(), extension=".html", encoding="utf8" + marginnote_html[0].prettify(), + basename="article__margin--marginnote", + extension=".html", + encoding="utf8", ) diff --git a/tests/test_build/test_marginnote.html b/tests/test_build/article__margin--marginnote.html similarity index 100% rename from tests/test_build/test_marginnote.html rename to tests/test_build/article__margin--marginnote.html diff --git a/tests/test_build/test_sidenote.html b/tests/test_build/article__margin--sidenote.html similarity index 100% rename from tests/test_build/test_sidenote.html rename to tests/test_build/article__margin--sidenote.html diff --git a/tests/test_build/build__header-article.html b/tests/test_build/build__header-article.html deleted file mode 100644 index fd19d29d..00000000 --- a/tests/test_build/build__header-article.html +++ /dev/null @@ -1,116 +0,0 @@ -
          -
          -
          - -
          -
          - - - -
          -
          - -
          -
          -
          diff --git a/tests/test_build/header-article.html b/tests/test_build/header-article.html new file mode 100644 index 00000000..b53e1ab6 --- /dev/null +++ b/tests/test_build/header-article.html @@ -0,0 +1,112 @@ +
          +
          +
          + +
          +
          + + + +
          +
          + +
          +
          +
          diff --git a/tests/test_build/header-article__launch-buttons.html b/tests/test_build/header-article__launch-buttons.html new file mode 100644 index 00000000..b8861350 --- /dev/null +++ b/tests/test_build/header-article__launch-buttons.html @@ -0,0 +1,51 @@ + diff --git a/tests/test_build/header-article__repo-buttons--custom-branch.html b/tests/test_build/header-article__repo-buttons--custom-branch.html new file mode 100644 index 00000000..51548ce6 --- /dev/null +++ b/tests/test_build/header-article__repo-buttons--custom-branch.html @@ -0,0 +1,66 @@ +
          + + + + + + +
          diff --git a/tests/test_build/header__repo-buttons--all-off.html b/tests/test_build/header__repo-buttons--all-off.html index 8a31bf57..1d2252d5 100644 --- a/tests/test_build/header__repo-buttons--all-off.html +++ b/tests/test_build/header__repo-buttons--all-off.html @@ -1,40 +1,38 @@
          - - diff --git a/tests/test_build/header__repo-buttons--all-on.html b/tests/test_build/header__repo-buttons--all-on.html index 5c64b3a8..8e7c2159 100644 --- a/tests/test_build/header__repo-buttons--all-on.html +++ b/tests/test_build/header__repo-buttons--all-on.html @@ -1,83 +1,81 @@
          - -