@php /** * Table footer: "showing X of Y" plus the rows-per-page picker, sitting alongside the pager. * * Every dashboard list was hand-built, so none of them told the reader how much of the data * they were looking at or let them ask for more. This renders that once. The picker writes * ?per_page= and paginate() reads it back off a whitelist, so a table only has to include * this partial - no controller change is needed. * * The layout is fixed and the same on every table: the count and the rows-per-page picker * form one group on the left, the pager sits on the right. Only the PAGER is conditional — * a table with a single page of results simply has none, and none is invented for it. * * Printable documents (an invoice, a Z-report) and fixed system tables are not collections, * so their views omit this partial entirely rather than closing with a footer. * * @var array $pager metadata from paginate(): total, perPage, pages, page, offset * @var string $base base path (e.g. "/admin/orders"); current path if omitted * @var bool $showPager set false to render the counts without the page links */ $pager = $pager ?? []; $total = (int) ($pager['total'] ?? 0); $perPage = (int) ($pager['perPage'] ?? 10); $page = (int) ($pager['page'] ?? 1); $base = $base ?? \App\Support\App::path(); // Which query parameters this table drives — "page"/"per_page" normally, prefixed names // when a screen carries two independent lists (see paginate()). $pageKey = (string) ($pager['pageKey'] ?? 'page'); $perPageKey = (string) ($pager['perPageKey'] ?? 'per_page'); // Nothing to say about an empty table - the empty-state row already speaks for it. if ($total === 0) { return; } $from = (int) ($pager['offset'] ?? 0) + 1; $to = min($total, $from + $perPage - 1); // Preserve every active filter when changing page size, and always return to page 1: // keeping the old page number could land the reader past the end of the resized list. // Only THIS table's cursor is dropped, so a second list on the same screen keeps its place. $query = request()->query(); unset($query[$pageKey], $query[$perPageKey]); $carry = $query ? '&' . http_build_query($query) : ''; // Two lists on one screen share a base path, so the picker's id is keyed on the parameter // it writes as well — otherwise both selects would answer to the same id. $selectId = 'qm-perpage-' . md5($base . '|' . $perPageKey); @endphp
@php /* Size picker first, then its "/ page" unit, then the count — the control the reader can act on leads, and the label reads as a unit against the number in the select ("25 / page") instead of as a heading. The label keeps its `for`, so association and click-to-focus are unaffected by sitting after the field. */ @endphp

{{ t_raw('table.showing_range', [':from' => number_format($from), ':to' => number_format($to), ':total' => number_format($total)]) }}

@if (($showPager ?? true) && (int) ($pager['pages'] ?? 1) > 1)
@partial('pagination', ['pager' => $pager, 'base' => $base])
@endif