{# The interactive region of a list page: toolbar + table + footer. Rendered both inside the full page and directly as an HTMX fragment -- same markup either way, so search, filter, sort and pagination never disagree between a load and a partial swap. Everything that *narrows* the table is on the left, everything that *acts on* it is on the right, so the two never interleave. Filtering lives in a right-hand drawer, so a ModelAdmin with six filters costs the toolbar one trigger rather than six. Below lg the toolbar becomes one stacked full-width column, which is what ui('toolbar', 'item') is for on each control. #} {% from "admin/components/icons.html" import icon %} {% from "admin/components/ui/dropdown-menu.html" import dropdown_menu %}
{% include "admin/components/search.html" %} {% include "admin/components/ui/filter-panel.html" %} {% include "admin/components/ui/bulk-actions.html" %}
{% if permissions.can_export %} {# One DropdownMenu instead of a button per format: the row of export buttons grew with every format added. #} {{ dropdown_menu( _("Export"), icon_name="download", text=_("Export"), full_width=True, items=[ {"label": _("CSV"), "url": base_path ~ "/" ~ model_admin.get_slug() ~ "/export/csv" ~ export_query}, {"label": _("XLSX"), "url": base_path ~ "/" ~ model_admin.get_slug() ~ "/export/xlsx" ~ export_query}, ], ) }} {% endif %} {% if permissions.can_create %} {# Icon-only, and so not a toolbar "item": the label is what stretches a stacked control to full width, and a lone plus in a full-width bar reads as floating. aria-label carries the name the visible text used to. #} {{ icon("plus", "size-4") }} {% endif %}
{% include "admin/components/ui/table.html" %} {% include "admin/components/ui/pagination.html" %}