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 %}