sidebar in the admin
This commit is contained in:
75
assets/views/admin/partials/category_filter.html
Normal file
75
assets/views/admin/partials/category_filter.html
Normal file
@@ -0,0 +1,75 @@
|
||||
{# Category-filter sidebar for admin product listings. Clicking a category
|
||||
reloads the page with `?category=<id>` so the table server-side filters to
|
||||
that category and its descendants. Expects in context:
|
||||
- category_groups: [{ id, name, count, children: [{ id, name, count }] }]
|
||||
(from views::shop::admin_category_groups)
|
||||
- selected_category: "all" | "none" | "<id>" — the active filter
|
||||
- total_count, uncategorized_count: ints
|
||||
- category_base: page path, e.g. "/admin/catalog/products"
|
||||
- category_suffix: extra query appended after the category param, e.g.
|
||||
"&audience=business", or "" — set by the including template.
|
||||
|
||||
The link treatment mirrors shop/_sidebar.html (Penguin UI), but active state
|
||||
is server-driven via aria-current (these links share a path, differing only
|
||||
by query, so markActiveNav() can't pick the active one — hence no data-nav).
|
||||
Numeric compare uses `| int(default=0)` because Tera string==number is false. #}
|
||||
{% set sel = selected_category | int(default=0) %}
|
||||
{% set link_cls = "flex flex-1 items-center gap-2 truncate rounded-radius px-2 py-1.5 text-sm font-medium text-on-surface underline-offset-2 transition hover:bg-primary/5 hover:text-on-surface-strong focus:outline-hidden focus-visible:underline aria-[current=page]:bg-primary/10 aria-[current=page]:text-on-surface-strong dark:text-on-surface-dark dark:hover:bg-primary-dark/5 dark:hover:text-on-surface-dark-strong dark:aria-[current=page]:bg-primary-dark/10 dark:aria-[current=page]:text-on-surface-dark-strong" %}
|
||||
<aside class="w-full shrink-0 md:w-56">
|
||||
<p class="px-2 pb-2 text-xs font-semibold uppercase tracking-wide text-on-surface/60 dark:text-on-surface-dark/60">
|
||||
{{ t(key="categories", lang=lang | default(value='sk')) }}
|
||||
</p>
|
||||
<div class="flex flex-col gap-1">
|
||||
<a href="{{ category_base }}?category=all{{ category_suffix }}"
|
||||
{% if selected_category == "all" %}aria-current="page"{% endif %} class="{{ link_cls }}">
|
||||
<span class="flex-1 truncate">{{ t(key="all-products", lang=lang | default(value='sk')) }}</span>
|
||||
<span class="text-xs text-on-surface/50 dark:text-on-surface-dark/50">{{ total_count }}</span>
|
||||
</a>
|
||||
{% for group in category_groups %}
|
||||
{% set open_group = sel == group.id %}
|
||||
{% for child in group.children %}{% if sel == child.id %}{% set_global open_group = true %}{% endif %}{% endfor %}
|
||||
{% if group.children | length > 0 %}
|
||||
<div x-data="{ open: {% if open_group %}true{% else %}false{% endif %} }" class="flex flex-col">
|
||||
<div class="flex items-stretch">
|
||||
<a href="{{ category_base }}?category={{ group.id }}{{ category_suffix }}"
|
||||
{% if sel == group.id %}aria-current="page"{% endif %} class="{{ link_cls }} rounded-l-radius">
|
||||
<span class="flex-1 truncate">{{ group.name }}</span>
|
||||
<span class="text-xs text-on-surface/50 dark:text-on-surface-dark/50">{{ group.count }}</span>
|
||||
</a>
|
||||
<button type="button" x-on:click="open = ! open" x-bind:aria-expanded="open ? 'true' : 'false'"
|
||||
aria-label="{{ group.name }}"
|
||||
class="inline-flex w-8 shrink-0 items-center justify-center rounded-r-radius text-on-surface/60 transition hover:bg-primary/5 hover:text-on-surface-strong focus:outline-hidden focus-visible:underline dark:text-on-surface-dark/60 dark:hover:bg-primary-dark/5 dark:hover:text-on-surface-dark-strong">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"
|
||||
class="size-5 shrink-0 transition-transform rotate-0" x-bind:class="open ? 'rotate-180' : 'rotate-0'" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<ul x-show="open" x-cloak x-transition class="ml-3 mt-0.5 flex flex-col gap-0.5 border-l border-outline pl-1 dark:border-outline-dark">
|
||||
{% for child in group.children %}
|
||||
<li class="flex">
|
||||
<a href="{{ category_base }}?category={{ child.id }}{{ category_suffix }}"
|
||||
{% if sel == child.id %}aria-current="page"{% endif %}
|
||||
class="flex flex-1 items-center gap-2 truncate rounded-radius px-2 py-1.5 text-sm text-on-surface underline-offset-2 transition hover:bg-primary/5 hover:text-on-surface-strong focus:outline-hidden focus-visible:underline aria-[current=page]:bg-primary/10 aria-[current=page]:text-on-surface-strong dark:text-on-surface-dark dark:hover:bg-primary-dark/5 dark:hover:text-on-surface-dark-strong dark:aria-[current=page]:bg-primary-dark/10 dark:aria-[current=page]:text-on-surface-dark-strong">
|
||||
<span class="flex-1 truncate">{{ child.name }}</span>
|
||||
<span class="text-xs text-on-surface/50 dark:text-on-surface-dark/50">{{ child.count }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% else %}
|
||||
<a href="{{ category_base }}?category={{ group.id }}{{ category_suffix }}"
|
||||
{% if sel == group.id %}aria-current="page"{% endif %} class="{{ link_cls }}">
|
||||
<span class="flex-1 truncate">{{ group.name }}</span>
|
||||
<span class="text-xs text-on-surface/50 dark:text-on-surface-dark/50">{{ group.count }}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<a href="{{ category_base }}?category=none{{ category_suffix }}"
|
||||
{% if selected_category == "none" %}aria-current="page"{% endif %} class="{{ link_cls }}">
|
||||
<span class="flex-1 truncate">{{ t(key="uncategorized", lang=lang | default(value='sk')) }}</span>
|
||||
<span class="text-xs text-on-surface/50 dark:text-on-surface-dark/50">{{ uncategorized_count }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
Reference in New Issue
Block a user