Replace ~268 hardcoded text-stone-* classes with theme-aware token utilities (text-text, text-text-secondary, text-text-muted) across all templates and JS components. Adjust dark mode token values to meet WCAG AA contrast ratios on dark surfaces.
98 lines
5.4 KiB
HTML
98 lines
5.4 KiB
HTML
{% macro search_header(navigator, target_selector) %}
|
|
<div class="border-b px-4 py-3">
|
|
<input
|
|
type="search"
|
|
placeholder="Search..."
|
|
value="{{ navigator.search_value() }}"
|
|
class="input-field w-full text-sm"
|
|
data-search-url="{{ navigator.search_href_prefix()|safe }}"
|
|
data-on:input__debounce.300ms="history.pushState(null, '', el.dataset.searchUrl + el.value); @get(el.dataset.searchUrl + el.value, {responseOverrides: {selector: '{{ target_selector }}', mode: 'replace'}})"
|
|
{% if navigator.has_search() %}data-init="el.focus(); el.selectionStart = el.value.length"{% endif %}
|
|
/>
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
{% macro pagination_header(items, navigator, target_selector) %}
|
|
<div
|
|
class="pagination-controls hidden md:flex flex-wrap items-center justify-between gap-x-3 border-t px-4 py-1.5 text-xs leading-none text-text-secondary"
|
|
>
|
|
<span>
|
|
Showing {{ items.start_index() }}–{{ items.end_index() }} of {{ items.total }}
|
|
results
|
|
</span>
|
|
<div class="flex flex-wrap items-center gap-3">
|
|
<div class="flex items-center gap-2">
|
|
<button
|
|
type="button"
|
|
class="inline-flex items-center gap-1 rounded-full border px-3 py-1 font-semibold transition hover:text-accent hover:border-accent disabled:cursor-not-allowed disabled:opacity-40"
|
|
{% if items.has_previous() %}
|
|
data-on:click="history.pushState(null, '', '{{ navigator.page_href(items.previous_page().unwrap())|safe }}'); @get('{{ navigator.fragment_page_href(items.previous_page().unwrap())|safe }}', {responseOverrides: {selector: '{{ target_selector }}', mode: 'replace'}})"
|
|
{% else %}
|
|
disabled
|
|
{% endif %}
|
|
>
|
|
<span aria-hidden="true">←</span>
|
|
<span>Previous</span>
|
|
</button>
|
|
{% if items.is_showing_all() %}
|
|
<span class="font-semibold text-text">Showing all results</span>
|
|
{% else %}
|
|
<span class="font-semibold text-text"
|
|
>Page {{ items.page }} of {{ items.total_pages() }}</span
|
|
>
|
|
{% endif %}
|
|
<button
|
|
type="button"
|
|
class="inline-flex items-center gap-1 rounded-full border px-3 py-1 font-semibold transition hover:text-accent hover:border-accent disabled:cursor-not-allowed disabled:opacity-40"
|
|
{% if items.has_next() %}
|
|
data-on:click="history.pushState(null, '', '{{ navigator.page_href(items.next_page().unwrap())|safe }}'); @get('{{ navigator.fragment_page_href(items.next_page().unwrap())|safe }}', {responseOverrides: {selector: '{{ target_selector }}', mode: 'replace'}})"
|
|
{% else %}
|
|
disabled
|
|
{% endif %}
|
|
>
|
|
<span>Next</span>
|
|
<span aria-hidden="true">→</span>
|
|
</button>
|
|
</div>
|
|
<label class="flex items-center gap-2 text-xs font-semibold text-text-secondary">
|
|
<span>Rows</span>
|
|
<select
|
|
class="rounded-md border bg-surface px-2 py-1 text-xs font-semibold text-text transition hover:border-accent"
|
|
data-on:change="history.pushState(null, '', evt.target.selectedOptions[0].dataset.url); @get(evt.target.selectedOptions[0].dataset.href, {responseOverrides: {selector: '{{ target_selector }}', mode: 'replace'}})"
|
|
>
|
|
<option value="5" data-href="{{ navigator.fragment_rows_href("5")|safe }}" data-url="{{ navigator.rows_href("5")|safe }}" {% if items.is_page_size(5) %}selected{% endif %}>5</option>
|
|
<option value="10" data-href="{{ navigator.fragment_rows_href("10")|safe }}" data-url="{{ navigator.rows_href("10")|safe }}" {% if items.is_page_size(10) %}selected{% endif %}>10</option>
|
|
<option value="20" data-href="{{ navigator.fragment_rows_href("20")|safe }}" data-url="{{ navigator.rows_href("20")|safe }}" {% if items.is_page_size(20) %}selected{% endif %}>20</option>
|
|
<option value="50" data-href="{{ navigator.fragment_rows_href("50")|safe }}" data-url="{{ navigator.rows_href("50")|safe }}" {% if items.is_page_size(50) %}selected{% endif %}>50</option>
|
|
<option value="all" data-href="{{ navigator.fragment_rows_href("all")|safe }}" data-url="{{ navigator.rows_href("all")|safe }}" {% if items.is_showing_all() %}selected{% endif %}>All</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
{% macro sortable_header(label, key, navigator, target_selector) %}
|
|
{% set is_sorted = navigator.is_sorted_by(key) %}
|
|
<th
|
|
scope="col"
|
|
class="px-4 py-3"
|
|
aria-sort="{% if is_sorted %}{% if navigator.sort_direction() == "asc" %}ascending{% else %}descending{% endif %}{% else %}none{% endif %}"
|
|
>
|
|
<button
|
|
type="button"
|
|
class="flex items-center gap-1 text-text hover:text-accent"
|
|
data-on:click="history.pushState(null, '', '{{ navigator.sort_href(key)|safe }}'); @get('{{ navigator.fragment_sort_href(key)|safe }}', {responseOverrides: {selector: '{{ target_selector }}', mode: 'replace'}})"
|
|
>
|
|
<span>{{ label }}</span>
|
|
{% if is_sorted %}
|
|
{% if navigator.sort_direction() == "asc" %}
|
|
<span aria-hidden="true">↑</span>
|
|
{% else %}
|
|
<span aria-hidden="true">↓</span>
|
|
{% endif %}
|
|
{% else %}
|
|
<span aria-hidden="true">↕</span>
|
|
{% endif %}
|
|
</button>
|
|
</th>
|
|
{% endmacro %}
|