|
| 1 | +"""Functions to compile HTML components to be placed on a page. |
| 2 | +
|
| 3 | +These are meant to be used by Jinja templates via the Sphinx HTML context. |
| 4 | +
|
| 5 | +A dictionary defines the components that are available to the theme. |
| 6 | +Keys of this dictionary should be the `"type"` values that users provide in |
| 7 | +their configuration. |
| 8 | +The remaining values in the user configuration are passed as kwargs to the func. |
| 9 | +""" |
| 10 | +from sphinx.util import logging |
| 11 | + |
| 12 | +SPHINX_LOGGER = logging.getLogger(__name__) |
| 13 | + |
| 14 | + |
| 15 | +# Add functions to render header components |
| 16 | +def component_text(app, context, content="", url="", classes=[]): |
| 17 | + classes = " ".join(classes) |
| 18 | + html = f"<span class='component-text {classes}'>{content}</span>" |
| 19 | + if url: |
| 20 | + html = f'<a href="{url}" class="link-primary">{html}</a>' |
| 21 | + return html |
| 22 | + |
| 23 | + |
| 24 | +def component_button(app, context, content="", url="", onclick="", classes=[]): |
| 25 | + if url and onclick: |
| 26 | + raise Exception("Button component cannot have both url and onclick specified.") |
| 27 | + classes = " ".join(classes) |
| 28 | + if onclick: |
| 29 | + onclick = ' onclick="{onclick}"' |
| 30 | + |
| 31 | + classes = " ".join(classes) |
| 32 | + html = f""" |
| 33 | + <button class="btn btn-outline-primary {classes}"{onclick} type="button"> |
| 34 | + {content} |
| 35 | + </button> |
| 36 | + """ |
| 37 | + if url: |
| 38 | + html = f'<a href="{url}">{html}</a>' |
| 39 | + |
| 40 | + return html |
| 41 | + |
| 42 | + |
| 43 | +def component_image(app, context, src="", url="", classes=[]): |
| 44 | + if not src.startswith("http"): |
| 45 | + src = context["pathto"](src, 1) |
| 46 | + html = f""" |
| 47 | + <img src={src}> |
| 48 | + """ |
| 49 | + if url: |
| 50 | + html = f"<a href={url}>{html}</a>" |
| 51 | + return html |
| 52 | + |
| 53 | + |
| 54 | +def component_html(app, context, html=""): |
| 55 | + return html |
| 56 | + |
| 57 | + |
| 58 | +def component_dropdown(app, context, content="", items=[]): |
| 59 | + dropdown_items = [] |
| 60 | + for component in items: |
| 61 | + link = f""" |
| 62 | + <a href="{component['url']}" class="dropdown-item">{component['content']}</a> |
| 63 | + """ |
| 64 | + dropdown_items.append(link) |
| 65 | + dropdown_items = "\n".join(dropdown_items) |
| 66 | + html = f""" |
| 67 | + <div class="dropdown"> |
| 68 | + <button class="btn dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
| 69 | + {content} |
| 70 | + </button> |
| 71 | + <div class="dropdown-menu" aria-labelledby="dropdownMenuButton"> |
| 72 | + {dropdown_items} |
| 73 | + </div> |
| 74 | + </div> |
| 75 | + """ # noqa |
| 76 | + return html |
| 77 | + |
| 78 | + |
| 79 | +def component_icon_links(app, context, icons, classes=[]): |
| 80 | + context = {"theme_icon_links": icons} |
| 81 | + # Add the pydata theme icon-links macro as a function we can re-use |
| 82 | + return app.builder.templates.render("icon-links.html", context) |
| 83 | + |
| 84 | + |
| 85 | +COMPONENT_FUNCS = { |
| 86 | + "text": component_text, |
| 87 | + "button": component_button, |
| 88 | + "html": component_html, |
| 89 | + "image": component_image, |
| 90 | + "icon-links": component_icon_links, |
| 91 | + "dropdown": component_dropdown, |
| 92 | +} |
0 commit comments