{% 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 %}