Files
LLeMbas/src/lembas/web/templates/_macros.html
T
Jaroslav Beneš 17995c1275 Green instead of gold, and a leaf that reads at 16px
The brand accent was rune gold. It is now mallorn green: --gold becomes
--leaf in tokens.css and everywhere it resolved, and the mark's wafer is
the green of the leaves lembas travels wrapped in rather than the biscuit
inside. Yellow is left to mean exactly one thing in the interface -- a
warning -- instead of two.

Two knock-on choices the rename forced:

  - Code keywords move from the brand accent to --warning. Strings are
    --success, which is green; keywords in leaf green beside them is not
    a colour scheme.
  - --success itself leans teal now. Two greens a hue apart read as one
    colour rendered badly, and an unread dot has to be tellable from a
    brand badge at a glance.

The mark is redrawn, not just recoloured. The blade is ovate -- widest a
third up from the base, rounded where the stem meets it, drawn out only
at the tip -- because the old one was pointed at both ends and read as an
eye. It is also much larger relative to the tile: at 16px the silhouette
is all that survives, and a small leaf on a large tile is a green square
with a smudge on it. Veins sweep towards the tip and shorten as the blade
narrows. The score cross is thinner and fainter so it stays texture.

A single diagonal score was tried first and rejected: behind a diagonal
leaf it does not read as scoring, it reads as a line struck through the
mark.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 22:24:53 +02:00

89 lines
3.5 KiB
HTML

{#
Shared template macros.
Import at the top of any template that needs them:
{% from "_macros.html" import icon, brand, mark %}
#}
{# An icon from the inlined sprite. `name` omits the "i-" prefix. #}
{% macro icon(name, cls="") -%}
<svg class="icon {{ cls }}" aria-hidden="true"><use href="#i-{{ name }}"/></svg>
{%- endmacro %}
{#
The leaf-and-wafer mark, inlined rather than referenced as <img> so it can
scale with the surrounding font size. Gradient ids are suffixed with `uid`
because ids are document-global: two marks on one page with the same ids
means the second silently reuses the first one's gradients.
#}
{% macro mark(cls="brand-mark", uid="a") -%}
<svg class="{{ cls }}" viewBox="0 0 64 64" role="img" aria-label="LLeMbas">
<defs>
<linearGradient id="mk-{{ uid }}-w" x1="0" y1="0" x2="0.3" y2="1">
<stop offset="0" stop-color="#7FB758"/>
<stop offset="0.5" stop-color="#4C8C33"/>
<stop offset="1" stop-color="#2A5522"/>
</linearGradient>
<linearGradient id="mk-{{ uid }}-l" x1="0.1" y1="1" x2="0.9" y2="0">
<stop offset="0" stop-color="#9DB49A"/>
<stop offset="0.4" stop-color="#F3F8EE"/>
<stop offset="1" stop-color="#C6D8BE"/>
</linearGradient>
<clipPath id="mk-{{ uid }}-c"><rect x="5" y="5" width="54" height="54" rx="14"/></clipPath>
</defs>
<rect x="5" y="5" width="54" height="54" rx="14" fill="url(#mk-{{ uid }}-w)"/>
<g clip-path="url(#mk-{{ uid }}-c)" fill="none" stroke-linecap="round">
<g stroke="#1F4019" stroke-opacity="0.30" stroke-width="1.8">
<path d="M32 5 V59"/><path d="M5 32 H59"/>
</g>
<g stroke="#C7E7A6" stroke-opacity="0.20" stroke-width="0.9">
<path d="M33.1 5 V59"/><path d="M5 33.1 H59"/>
</g>
</g>
<rect x="6.1" y="6.1" width="51.8" height="51.8" rx="12.9" fill="none"
stroke="#1F4019" stroke-opacity="0.32" stroke-width="1.2"/>
<path d="M21.4 45.6 L16.3 51.2" stroke="#8B9E86" stroke-width="3"
stroke-linecap="round" fill="none"/>
<path d="M21 46 C19.6 40.5 20.4 34.2 23.4 30.5 C27.5 25.5 35 20.5 46 18
C43.5 26.5 40.5 36.5 36.1 41.9 C33 45.6 26.5 47 21 46 Z"
fill="url(#mk-{{ uid }}-l)"/>
<path d="M21 46 Q30.5 34.5 46 18" fill="none" stroke="#57734F"
stroke-opacity="0.5" stroke-width="1.5" stroke-linecap="round"/>
</svg>
{%- endmacro %}
{#
The wordmark as live text rather than the outlined SVG: it stays selectable,
searchable and readable to a screen reader, and scales with the user's font
size. The capitals spelling LLM take the leaf accent.
#}
{% macro wordmark() -%}
<span class="brand-llm">LL</span>e<span class="brand-llm">M</span>bas
{%- endmacro %}
{#
A model's avatar: the uploaded image, or a generated initial.
The fallback colour is derived from the model id, so every model gets a
stable, distinct-looking badge without an administrator having to upload
anything. Hue only -- saturation and lightness are fixed so the result always
sits legibly against both themes.
#}
{% macro model_avatar(model, cls="model-avatar") -%}
{% if model.image_path %}
<img class="{{ cls }}" src="/uploads/models/{{ model.image_path }}"
alt="" loading="lazy" width="32" height="32">
{% else %}
<span class="{{ cls }} model-avatar--initial"
style="--avatar-hue: {{ model.model_id | stable_hue }}"
aria-hidden="true">{{ model.initial }}</span>
{% endif %}
{%- endmacro %}
{% macro brand(href="/", uid="a") -%}
<a class="sidebar__brand" href="{{ href }}">
{{ mark(uid=uid) }}
<span>{{ wordmark() }}</span>
</a>
{%- endmacro %}