{% import "adminsite/_icons.html" as icons %} {% import "adminsite/_values.html" as values %}
{% if request.headers.get("hx-request") %} {% with oob = true %}{% include "adminsite/_records_total.html" %}{% endwith %} {% endif %}
{{ csrf_input | safe if csrf_input }}
{% if actions %} {% endif %} {% for path in columns %} {% set state = sort_state(request, path) %} {% set numeric = view.field_for(path).widget == 'number' %} {% endfor %} {% for row in page %} {% set key = view.identity_of(row) %} {% if actions %} {% endif %} {% for path in columns %} {% set item = view.field_for(path) %} {% set widget = item.widget %} {% set text = view.display(row, path) %} {% endfor %} {% else %} {% endfor %}
{{ view.label_plural }}
{% if view.sortable(path) %} {{ view.label_for(path) }} {% if state == "asc" %}{% endif %} {% if state == "desc" %}{% endif %} {% else %} {{ view.label_for(path) }} {% endif %} {{ _('Actions') }}
{% if loop.first %} {#- The first cell opens the record, or the form where a view has no record page, or is plain text where it has neither. -#} {% set opens = urls.detail(view, key) if can_detail else (urls.edit(view, key) if can_edit else "") %} {% set is_key = widget == "number" and path in view.schema.primary_key %} {% set shown = ("#" ~ text if is_key and text else (text or view.title_of(row))) %} {% if opens %} {{ shown }} {% else %} {{ shown }} {% endif %} {% elif widget == "image" and text %} {% set stored = view.value_at(row, path) %} {{ text }} {% elif widget == "file" and text %} {{ text }} {% elif widget in ("select", "checkbox") and text %} {{ values.badge(item, view.value_at(row, path), text) }} {% elif widget in ("text", "textarea", "json") %} {{ text }} {% else %} {{ text }} {% endif %}
{% with allowed = row_actions.get(key, []) if row_actions else [], title = view.title_of(row), edit_url = urls.edit(view, key) if can_edit else "", upward = loop.revindex <= 3 and loop.length > 5 %} {% include "adminsite/_row_actions.html" %} {% endwith %}
{{ _("No {things} to show.", things=view.label_plural|lower) }}
{#- On a phone each row is a card: its first column and its first badge on top, the rest below with the first amount at the end. -#} {%- set layout = namespace(badge=none, amount=none) -%} {%- for path in columns[1:] -%} {%- set kind = view.field_for(path).widget -%} {%- if layout.badge is none and kind in ("select", "checkbox") %}{% set layout.badge = path %}{% endif -%} {%- if layout.amount is none and kind == "number" %}{% set layout.amount = path %}{% endif -%} {%- endfor -%}
    {% for row in page %} {% set key = view.identity_of(row) %} {% set first = columns[0] %} {% set text = view.display(row, first) %} {% set is_key = view.field_for(first).widget == "number" and first in view.schema.primary_key %} {% set shown = ("#" ~ text if is_key and text else (text or view.title_of(row))) %} {% set opens = urls.detail(view, key) if can_detail else (urls.edit(view, key) if can_edit else "") %} {% set rest = [] %} {% for path in columns[1:] if path not in (layout.badge, layout.amount) and view.field_for(path).widget not in ("image", "file") %} {% set value = view.display(row, path) %} {% if value %}{% set ignored = rest.append(value|string) %}{% endif %} {% endfor %}
  • <{{ "a" if opens else "div" }} {% if opens %}href="{{ opens }}"{% endif %} class="flex flex-col gap-1 px-4 py-3 active:bg-subtle"> {{ shown }} {% if layout.badge and view.display(row, layout.badge) %} {{ values.badge(view.field_for(layout.badge), view.value_at(row, layout.badge), view.display(row, layout.badge)) }} {% endif %} {{ rest|join(" · ") }} {% if layout.amount %} {{ view.display(row, layout.amount) }} {% endif %}
  • {% else %}
  • {{ _("No {things} to show.", things=view.label_plural|lower) }}
  • {% endfor %}
{% if actions %} {#- Floats over the table while rows are ticked, so the actions are where the eye already is. -#}
{{ _('selected') }} {% if page.total is not none %} {{ _("All {count} matching rows are selected.", count=total_text) }} {% endif %} {% if page.total is not none %} {% endif %} {% for item in actions %} {% if item.needs_dialog %} {% else %} {% endif %} {% endfor %}
{% endif %}
{#- Each dialog is its own form, so a required input in one dialog never stops another action from submitting. On submit it copies the ticked rows across from the table. -#} {% for item in actions if item.needs_dialog %} {% endfor %} {% include "adminsite/_action_forms.html" %}
{% if page.keyset %} {% if page.total is not none %}{{ total_text }} {{ view.label_plural|lower }}{% endif %} {% elif page.total is not none %} {{ _("{first} to {last} of {total}", first=page.first_position, last=page.last_position, total=total_text) }} {% else %} {{ _("{first} to {last}", first=page.first_position, last=page.last_position) }} {% endif %} {% if page_sizes %} {% endif %} {% if page.keyset %} {% set previous = urls.here(page=None, after=None, before=page.previous_cursor or None) %} {% set next = urls.here(page=None, before=None, after=page.next_cursor or None) %} {% else %} {% set previous = urls.here(page=page_number - 1 if page_number > 2 else None) %} {% set next = urls.here(page=page_number + 1) %} {% endif %}