{#
The pieces of the shell's header. Separate from shell.html so an app can
import them without importing the template it extends.
#}
{% from "ui/attrs.html" import attrs %}
{% from "ui/icon.html" import icon %}
{#
brand(label, href, icon_name | icon_src) — the wordmark and home link.
Two ways to give it a mark, and they are mutually exclusive.
`icon_name` draws a Lucide glyph on a token-coloured tile. The tile uses
`bg-primary text-primary-foreground`, never `text-white`: the contrast token
keeps the mark legible after a rebrand to a light primary.
`icon_src` places artwork — a real logo, served from wherever the app keeps
it. No tile, because a logo brings its own ground and `bg-primary` behind it
would box it in. The mark then stops following `--primary`, which is the
trade a brand asset always makes.
`alt=""` is deliberate: the label sits beside the image inside the same
anchor, so a screen reader announcing both would say the name twice. `width`
and `height` are set so the row does not reflow when the image arrives.
#}
{% macro brand(label, href="/", icon_name=none, icon_src=none) -%}
{%- if icon_src %}
{% elif icon_name %}
{{- icon(icon_name, 16) -}}
{% endif -%}
{{ label }}
{%- endmacro %}
{#
nav_links(request, links) — top-level navigation.
`links` is a list of (route_name, label) pairs. Route names rather than URLs,
so the active state compares routes instead of string-matching paths, and
stays correct when a URL gains a query string.
#}
{% macro nav_links(request, links) -%}
{%- endmacro %}
{#
theme_toggle() — light/dark switch.
The only inline script fjkit ships besides the shell's flash-guard. Two
lines, and it has to run before any bundle would have loaded, so it is not in
a .js file.
#}
{% macro theme_toggle() -%}
{%- endmacro %}
{#
breadcrumb(trail, separator)
`trail` is a list of `(label, href)` pairs. A pair whose href is none is the
current page: it renders as `` rather than a link,
so the trail holds exactly one non-navigable entry and assistive tech is told
which. Passing the current page as a link is the usual way this component
goes wrong, and the parameter's shape prevents it.
Separators are their own `
` rather than CSS `::after`
content: some screen readers read generated content aloud, and a trail
punctuated by "greater than" five times is worse than silence. This follows
Basecoat's structure.
The separator mirrors under `dir="rtl"`; a dot has nothing to mirror, so the
flip skips it.
#}
{% set _CRUMB_SEPARATORS = {"chevron": "chevron-right", "slash": "slash", "dot": "dot"} %}
{% macro breadcrumb(trail, separator="chevron", label="Breadcrumb") -%}
{%- set glyph = _CRUMB_SEPARATORS.get(separator, "chevron-right") -%}
{%- endmacro %}