diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 6ede255a00a20c..92c311829c0654 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -18,7 +18,7 @@ concurrency: jobs: docs: name: build docs - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: commaai/timeout@v1 diff --git a/docs/css/tooltip.css b/docs/css/tooltip.css new file mode 100644 index 00000000000000..b9a54f793f9fe5 --- /dev/null +++ b/docs/css/tooltip.css @@ -0,0 +1,44 @@ +[data-tooltip] { + position: relative; + display: inline-block; + border-bottom: 1px dotted black; +} + +[data-tooltip] .tooltip-content { + width: max-content; + max-width: 25em; + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + background-color: white; + color: #404040; + box-shadow: 0 4px 14px 0 rgba(0,0,0,.2), 0 0 0 1px rgba(0,0,0,.05); + padding: 10px; + font: 14px/1.5 Lato, proxima-nova, Helvetica Neue, Arial, sans-serif; + text-decoration: none; + opacity: 0; + visibility: hidden; + transition: opacity 0.1s, visibility 0s; + z-index: 1000; + pointer-events: none; /* Prevent accidental interaction */ +} + +[data-tooltip]:hover .tooltip-content { + opacity: 1; + visibility: visible; + pointer-events: auto; /* Allow interaction when visible */ +} + +.tooltip-content .tooltip-glossary-link { + display: inline-block; + margin-top: 8px; + font-size: 12px; + color: #007bff; + text-decoration: none; +} + +.tooltip-content .tooltip-glossary-link:hover { + color: #0056b3; + text-decoration: underline; +} diff --git a/docs/glossary.toml b/docs/glossary.toml new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/docs/hooks/glossary.py b/docs/hooks/glossary.py new file mode 100644 index 00000000000000..e2fa3d51e04cb9 --- /dev/null +++ b/docs/hooks/glossary.py @@ -0,0 +1,68 @@ +import re +import tomllib + +def load_glossary(file_path="docs/glossary.toml"): + with open(file_path, "rb") as f: + glossary_data = tomllib.load(f) + return glossary_data.get("glossary", {}) + +def generate_anchor_id(name): + return name.replace(" ", "-").replace("_", "-").lower() + +def format_markdown_term(name, definition): + anchor_id = generate_anchor_id(name) + markdown = f"* [**{name.replace('_', ' ').title()}**](#{anchor_id})" + if definition.get("abbreviation"): + markdown += f" *({definition['abbreviation']})*" + if definition.get("description"): + markdown += f": {definition['description']}\n" + return markdown + +def glossary_markdown(vocabulary): + markdown = "" + for category, terms in vocabulary.items(): + markdown += f"## {category.replace('_', ' ').title()}\n\n" + for name, definition in terms.items(): + markdown += format_markdown_term(name, definition) + return markdown + +def format_tooltip_html(term_key, definition, html): + display_term = term_key.replace("_", " ").title() + clean_description = re.sub(r"\[(.+)]\(.+\)", r"\1", definition["description"]) + glossary_link = ( + f"Glossaryđź”—" + ) + return re.sub( + re.escape(display_term), + lambda + match: f"{match.group(0)}{clean_description} {glossary_link}", + html, + flags=re.IGNORECASE, + ) + +def apply_tooltip(_term_key, _definition, pattern, html): + return re.sub( + pattern, + lambda match: format_tooltip_html(_term_key, _definition, match.group(0)), + html, + flags=re.IGNORECASE, + ) + +def tooltip_html(vocabulary, html): + for _category, terms in vocabulary.items(): + for term_key, definition in terms.items(): + if definition.get("description"): + pattern = rf"(?)(?!\([^)]*\))" + html = apply_tooltip(term_key, definition, pattern, html) + return html + +# Page Hooks +def on_page_markdown(markdown, **kwargs): + glossary = load_glossary() + return markdown.replace("{{GLOSSARY_DEFINITIONS}}", glossary_markdown(glossary)) + +def on_page_content(html, **kwargs): + if kwargs.get("page").title == "Glossary": + return html + glossary = load_glossary() + return tooltip_html(glossary, html) diff --git a/mkdocs.yml b/mkdocs.yml index 58527ea7ee021d..a66d1c76d45bba 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -8,6 +8,10 @@ strict: true docs_dir: docs site_dir: docs_site/ +hooks: + - docs/hooks/glossary.py +extra_css: + - css/tooltip.css theme: name: readthedocs navigation_depth: 3