laterite-admin 0.6.2

Laterite CMF admin surface: the Axum router, session middleware, and login shell
Documentation
{% extends "base.html" %}
{% block title %}{{ title }} - {{ shell.brand }}{% endblock %}
{% block content %}
<div class="lat-toolbar">
  <h1>{{ title }}</h1>
  <div class="lat-toolbar__actions">
    {# The export carries the current query, so the file matches this screen. #}
    <details class="lat-menu">
      <summary class="lat-btn lat-btn--secondary lat-btn--sm">{{ shell.t("Export") }}</summary>
      <div class="lat-menu__panel">
        <a href="{{ path }}/export?format=csv{{ export_query }}">{{ shell.t("CSV") }}</a>
        <a href="{{ path }}/export?format=json{{ export_query }}">{{ shell.t("JSON") }}</a>
      </div>
    </details>
    {% for b in toolbar %}
    <a class="lat-btn {% if b.primary %}lat-btn--primary{% else %}lat-btn--secondary{% endif %}" href="{{ b.href }}">{% if !b.icon.is_empty() %}<span class="lat-btn__icon">{{ b.icon|safe }}</span>{% endif %}{{ b.label }}</a>
    {% endfor %}
  </div>
</div>
{% if searchable || !filters.is_empty() || !pickers.is_empty() %}
<div class="lat-listbar">
  {% if searchable || !filters.is_empty() %}
  {# One GET form carries the search term, every filter, and the current sort, so
     Enter works with scripting off. With htmx it asks on typing or on a change.
     It sits outside #lat-list, so a swap never steals the caret or the focus.
     The column picker is a sibling, never nested: a form inside a form is
     dropped by the parser, taking its submit button's action with it. #}
  <form class="lat-listbar__form" method="get" action="{{ path }}"
        hx-get="{{ path }}" hx-target="#lat-list" hx-swap="outerHTML" hx-push-url="true"
        hx-trigger="input changed delay:300ms from:find input[name='q'], search from:find input[name='q'], change from:find select, submit">
    <input type="hidden" name="sort" value="{{ sort }}">
    <input type="hidden" name="dir" value="{{ dir }}">
    {% if searchable %}
    <input class="lat-input lat-listbar__search" type="search" name="q" value="{{ q }}"
           placeholder='{{ shell.t("Search") }}' aria-label='{{ shell.t("Search") }}'>
    {% endif %}
    {% for f in filters %}
    <label class="lat-listbar__filter">
      <span class="lat-listbar__label">{{ f.label }}</span>
      <select class="lat-input lat-select" name="{{ f.param }}">
        <option value="">{{ shell.t("Any") }}</option>
        {% for o in f.options %}
        <option value="{{ o.value }}"{% if o.value == f.value %} selected{% endif %}>{{ o.label }}</option>
        {% endfor %}
      </select>
    </label>
    {% endfor %}
    {# This bar sits outside the swapped region, so it cannot re-render per swap.
       The region declares whether anything narrows the list and CSS reads it. #}
    <a class="lat-listbar__clear" href="{{ path }}">{{ shell.t("Clear") }}</a>
    <noscript><button class="lat-btn lat-btn--secondary lat-btn--sm" type="submit">{{ shell.t("Apply") }}</button></noscript>
  </form>
  {% endif %}
  {# A native disclosure, so choosing columns needs no script at all. #}
  <details class="lat-listbar__columns">
    <summary class="lat-btn lat-btn--secondary lat-btn--sm">{{ shell.t("Columns") }}</summary>
    <div class="lat-colpicker">
      <form method="post" action="{{ path }}/columns">
        {% include "_csrf.html" %}
        {% for c in pickers %}
        <label class="lat-check">
          <input type="checkbox" name="column" value="{{ c.field }}"{% if c.shown %} checked{% endif %}>
          <span>{{ c.label }}</span>
        </label>
        {% endfor %}
        <button class="lat-btn lat-btn--primary lat-btn--sm" type="submit">{{ shell.t("Apply") }}</button>
      </form>
    </div>
  </details>
</div>
{% endif %}
{% if deletable %}
{# The form lives outside the table: rows are inside the swapped region and
   carry `form="lat-list-actions"`, so a swap replaces the checkboxes without
   destroying the form they belong to. #}
<form id="lat-list-actions" class="lat-bulkbar" method="post" action="{{ path }}/delete">
  {% include "_csrf.html" %}
  <button class="lat-btn lat-btn--danger lat-btn--sm" type="submit"
          data-lat-confirm='{{ shell.t("Delete the selected records? This cannot be undone.") }}'>
    {{ shell.t("Delete") }}
  </button>
</form>
{% endif %}
{% include "_list_table.html" %}
{% endblock %}