small fixes
This commit is contained in:
@@ -29,14 +29,29 @@
|
||||
if (currentTheme() === 'system') applyTheme('system');
|
||||
});
|
||||
// Mark the active top-nav link via aria-current (styled with Tailwind).
|
||||
//
|
||||
// Pages that live under a category but not at its URL (a product detail
|
||||
// page) declare it via <main data-active-category>; without that the
|
||||
// category sidebar would show nothing selected the moment you open a
|
||||
// product. `window.activeCategory` is read by the sidebar's accordion
|
||||
// groups, which are hx-preserve'd and so initialise only once — the
|
||||
// `nav-category` event is what reaches them on later navigations.
|
||||
function markActiveNav() {
|
||||
var path = location.pathname;
|
||||
var main = document.querySelector('main[data-active-category]');
|
||||
var cat = main ? main.getAttribute('data-active-category') : '';
|
||||
var catPath = cat ? '/category/' + cat : null;
|
||||
window.activeCategory = cat;
|
||||
document.querySelectorAll('a[data-nav]').forEach(function (a) {
|
||||
var h = a.getAttribute('data-nav');
|
||||
var on = h === path || (h !== '/' && path.indexOf(h) === 0);
|
||||
// A declared category wins outright: on /shop/{slug} the prefix rule
|
||||
// would otherwise light up "all products" alongside the category.
|
||||
var on = h === path || h === catPath
|
||||
|| (!catPath && h !== '/' && path.indexOf(h) === 0);
|
||||
if (on) a.setAttribute('aria-current', 'page');
|
||||
else a.removeAttribute('aria-current');
|
||||
});
|
||||
if (cat) window.dispatchEvent(new CustomEvent('nav-category', { detail: cat }));
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', markActiveNav);
|
||||
document.addEventListener('htmx:afterSwap', markActiveNav);
|
||||
@@ -250,7 +265,7 @@
|
||||
</aside>
|
||||
{% endif %}
|
||||
|
||||
<main class="min-w-0 flex-1">
|
||||
<main data-active-category="{% block nav_category %}{% endblock nav_category %}" class="min-w-0 flex-1">
|
||||
{% block content %}{% endblock content %}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
categories, each `{ name, slug, children: [{ name, slug }] }`. A category
|
||||
with children is expandable (accordion); one without is a plain link.
|
||||
Active state is set client-side by markActiveNav() via data-nav +
|
||||
aria-current; groups auto-expand when the current page is the category or
|
||||
one of its subcategories.
|
||||
aria-current; groups auto-expand when the current page is the category, one
|
||||
of its subcategories, or a product inside it (which markActiveNav announces
|
||||
as window.activeCategory + the `nav-category` event, since this partial is
|
||||
hx-preserve'd and therefore only ever initialises once).
|
||||
|
||||
Adapted from the vendored Penguin UI component
|
||||
penguinui-components/sidebar/sidebar-with-collapsible-menus.html: Penguin's
|
||||
@@ -27,8 +29,10 @@
|
||||
</a>
|
||||
{% for group in category_groups %}
|
||||
{% if group.children | length > 0 %}
|
||||
<div x-data="{ open: false }" class="flex flex-col"
|
||||
x-init="open = ['{{ group.slug }}'{% for child in group.children %}, '{{ child.slug }}'{% endfor %}].some(s => location.pathname === '/category/' + s)">
|
||||
<div class="flex flex-col"
|
||||
x-data="{ open: false, slugs: ['{{ group.slug }}'{% for child in group.children %}, '{{ child.slug }}'{% endfor %}] }"
|
||||
x-init="open = slugs.some(s => location.pathname === '/category/' + s) || slugs.includes(window.activeCategory)"
|
||||
x-on:nav-category.window="if (slugs.includes($event.detail)) open = true">
|
||||
<div class="flex items-stretch">
|
||||
<a href="/category/{{ group.slug }}" data-nav="/category/{{ group.slug }}"
|
||||
class="flex flex-1 items-center gap-2 truncate rounded-l-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-cta aria-[current=page]:text-on-cta aria-[current=page]:font-semibold aria-[current=page]:shadow-sm dark:text-on-surface-dark dark:hover:bg-primary-dark/5 dark:hover:text-on-surface-dark-strong dark:aria-[current=page]:bg-cta-dark dark:aria-[current=page]:text-on-cta-dark">
|
||||
|
||||
@@ -3,6 +3,27 @@
|
||||
|
||||
{% block title %}{{ product.name }}{% endblock title %}
|
||||
|
||||
{# Keeps this product's category selected and expanded in the sidebar, which
|
||||
otherwise matches on the URL alone and so goes blank on /shop/{slug}. #}
|
||||
{% block nav_category %}{% if category %}{{ category.slug }}{% endif %}{% endblock nav_category %}
|
||||
|
||||
{# Same trail as the category listing, extended with the product itself, so the
|
||||
path back up the tree survives the click into a product. #}
|
||||
{% block breadcrumbs %}
|
||||
{% set L = lang | default(value='sk') %}
|
||||
<nav aria-label="breadcrumb" class="mb-5 text-sm">
|
||||
<ol class="flex flex-wrap items-center gap-1.5 text-on-surface/60 dark:text-on-surface-dark/60">
|
||||
{{ ui::crumb(label=t(key="nav-home", lang=L), href="/") }}
|
||||
{{ ui::crumb(label=t(key="nav-shop", lang=L), href="/shop") }}
|
||||
{% for crumb in breadcrumbs %}
|
||||
{{ ui::crumb(label=crumb.name, href="/category/" ~ crumb.slug) }}
|
||||
{% endfor %}
|
||||
{% if category %}{{ ui::crumb(label=category.name, href="/category/" ~ category.slug) }}{% endif %}
|
||||
{{ ui::crumb_current(label=product.name) }}
|
||||
</ol>
|
||||
</nav>
|
||||
{% endblock breadcrumbs %}
|
||||
|
||||
{% block content %}
|
||||
<div class="space-y-12">
|
||||
<div class="grid gap-10 lg:grid-cols-2">
|
||||
|
||||
Reference in New Issue
Block a user