{# _hub.html — reusable two-pane hub layout macro ================================================= CONTRACT (for Config agent and other consumers): ------------------------------------------------ Import this file and call the `hub` macro with `call` syntax: {% from "_hub.html" import hub %} {% call hub(sections) %} ... page content goes here ... {% endcall %} `sections` is a list of dicts, each with: - label (str) — display text for the nav link - href (str) — URL the link points to (e.g. "/cv", "/profile") - active (bool) — True for the currently-active section (highlights it) Exactly one section should have active=True per page render. Helper pattern — define a Python helper in app.py returning the list: def _cv_sections(active: str) -> list[dict]: return [ {"label": "Render", "href": "/cv", "active": active == "render"}, {"label": "Profile", "href": "/profile", "active": active == "profile"}, {"label": "Templates", "href": "/templates", "active": active == "templates"}, ] Then pass `hub_sections=_cv_sections("render")` in the template context and call `{% call hub(hub_sections) %}…{% endcall %}`. CSS classes used (all defined in static/style.css): .hub — outer flex container .hub-nav — left vertical nav column .hub-nav a — nav link base style .hub-nav a.active — highlighted active link .hub-content — right content pane (flex: 1) HTMX compatibility: the hub wraps inside {% block content %} of a page that extends base.html. Full-page loads render the full hub. HTMX fragment swaps that target only the content area will see the hub-nav too (it lives inside the content block). This is intentional — section-nav always travels with the content on swap. Dependencies: none beyond Jinja2 (no JS required). Plain CSS only. #} {% macro hub(sections) %}
{{ caller() }}
{% endmacro %}