Files
LLeMbas/src/lembas/web/templates/admin/models.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

152 lines
6.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "admin/_layout.html" %}
{% from "_macros.html" import icon, model_avatar %}
{% set section = "models" %}
{% block title %}Models - LLeMbas{% endblock %}
{% block heading %}Models{% endblock %}
{% block admin_content %}
<p class="admin-lede">
Every model discovered across your connections. The order here is the order
users see in the picker. <strong>Pinning</strong> does not reorder anything —
it puts a shortcut in the chat sidebar. The <strong>default</strong> is what a
new chat starts with.
</p>
{% if saved %}
<div class="alert alert--success">{{ icon("check", "icon--sm") }} <span>{{ saved }}</span></div>
{% endif %}
{% if not total %}
<div class="empty" style="padding: var(--sp-10) 0">
{{ icon("server", "empty__mark") }}
<p class="empty__text">
No models yet. <a href="/admin/connections">Add a connection</a> and run
“Test &amp; refresh”.
</p>
</div>
{% else %}
{# Filters are links, so a filtered view is a real URL you can keep or share. #}
<div class="filter-bar">
<div class="filter-tabs">
{% for key, label in filters.items() %}
<a class="filter-tab {{ 'is-active' if key == active_filter }}"
href="/admin/models?filter={{ key }}{% if q %}&q={{ q|urlencode }}{% endif %}{% if connection_id %}&connection={{ connection_id }}{% endif %}">
{{ label }} <span class="filter-tab__count">{{ counts[key] }}</span>
</a>
{% endfor %}
</div>
<form class="filter-form" method="get" action="/admin/models">
<input type="hidden" name="filter" value="{{ active_filter }}">
<input class="input" type="search" name="q" value="{{ q }}"
placeholder="Search models…" aria-label="Search models">
<select class="select" name="connection" aria-label="Connection">
<option value="">All connections</option>
{% for conn in connections %}
<option value="{{ conn.id }}" {{ 'selected' if conn.id == connection_id }}>
{{ conn.name }}
</option>
{% endfor %}
</select>
<button class="btn" type="submit">{{ icon("search", "icon--sm") }} Filter</button>
{% if q or connection_id or active_filter != "all" %}
<a class="btn btn--ghost" href="/admin/models">Clear</a>
{% endif %}
</form>
</div>
{% if not models %}
<div class="empty" style="padding: var(--sp-8) 0">
<p class="empty__text">Nothing matches that filter.</p>
</div>
{% else %}
<form method="post" action="/admin/models/bulk">
<div class="bulk-bar">
<label class="checkbox">
<input type="checkbox" data-select-all="#model-rows"
aria-label="Select every model on this page">
<span class="bulk-bar__label">Select all</span>
</label>
<span class="spacer"></span>
<span class="bulk-bar__label">With selected:</span>
<button class="btn btn--sm" name="action" value="enable" type="submit">Enable</button>
<button class="btn btn--sm" name="action" value="disable" type="submit">Disable</button>
<button class="btn btn--sm" name="action" value="public" type="submit">Make public</button>
<button class="btn btn--sm" name="action" value="private" type="submit">Restrict</button>
</div>
<div class="model-rows" id="model-rows">
{% for model in models %}
<div class="model-row {{ 'is-off' if not model.enabled }}">
<input class="model-row__check" type="checkbox" name="model_ids" value="{{ model.id }}"
aria-label="Select {{ model.label }}">
<span class="model-row__pos">{{ page_start + loop.index }}</span>
{{ model_avatar(model, cls="model-row__avatar") }}
<div class="model-row__main">
<div class="model-row__title">
<a class="model-row__name" href="/admin/models/{{ model.id }}/edit">{{ model.label }}</a>
{% if model.model_id == default_model %}
<span class="badge badge--leaf">default</span>
{% endif %}
{% if model.pinned %}<span class="badge">pinned</span>{% endif %}
{% if not model.enabled %}<span class="badge badge--danger">disabled</span>{% endif %}
{% if not model.public %}<span class="badge">restricted</span>{% endif %}
{% for name, on in (model.capabilities_json or {}).items() %}
{% if on %}<span class="badge badge--leaf">{{ name }}</span>{% endif %}
{% endfor %}
</div>
<code class="model-row__id">{{ model.model_id }} · {{ model.connection.name }}</code>
</div>
<div class="model-row__actions">
{# formaction lets these post elsewhere without nesting a second form. #}
<button class="btn btn--icon btn--sm" type="submit" aria-label="Move up"
formaction="/admin/models/{{ model.id }}/move" name="direction" value="up"
{{ 'disabled' if page == 1 and loop.first }}>
{{ icon("arrow-up", "icon--sm") }}
</button>
<button class="btn btn--icon btn--sm" type="submit" aria-label="Move down"
formaction="/admin/models/{{ model.id }}/move" name="direction" value="down"
{{ 'disabled' if page == pages and loop.last }}>
{{ icon("arrow-down", "icon--sm") }}
</button>
<a class="btn btn--sm" href="/admin/models/{{ model.id }}/edit">Edit</a>
</div>
</div>
{% endfor %}
</div>
</form>
<div class="list-footer">
<span class="text-xs faint">
Showing {{ page_start + 1 }}{{ page_start + models|length }} of {{ matched }}
{%- if matched != total %} (filtered from {{ total }}){% endif %}
</span>
{% if pages > 1 %}
{% set base = "/admin/models?filter=" ~ active_filter ~ ("&q=" ~ q|urlencode if q else "") ~ ("&connection=" ~ connection_id if connection_id else "") %}
<div class="btn-row">
{% if page > 1 %}
<a class="btn btn--sm" href="{{ base }}&page={{ page - 1 }}">Previous</a>
{% else %}
<span class="btn btn--sm" aria-disabled="true" style="opacity: .45">Previous</span>
{% endif %}
<span class="text-xs faint">Page {{ page }} of {{ pages }}</span>
{% if page < pages %}
<a class="btn btn--sm" href="{{ base }}&page={{ page + 1 }}">Next</a>
{% else %}
<span class="btn btn--sm" aria-disabled="true" style="opacity: .45">Next</span>
{% endif %}
</div>
{% endif %}
</div>
{% endif %}
{% endif %}
{% endblock %}