67 lines
9.5 KiB
HTML
67 lines
9.5 KiB
HTML
{#
|
|
Shared navbar, rendered on every page by base.html. Reads the `nav` field of
|
|
the surrounding page struct (crate::ui::Nav).
|
|
|
|
Penguin UI's default navbar, from
|
|
penguinui-components/navbar/default-navbar.html: the library's markup with
|
|
this app's brand and links in place of the demo's, and the same link list
|
|
repeated in the mobile menu exactly as the library repeats it. The active
|
|
link is the library's own "current page" styling (`font-bold text-primary`
|
|
plus aria-current) rather than the underline the old hand-written `.topbar`
|
|
drew, and logging out is a form posting to /logout, styled as a link so it
|
|
sits in the list with the others.
|
|
|
|
This replaced the hand-written dark `.topbar` bar, so the site chrome is now
|
|
the library's: white, bordered underneath, with a hamburger menu below `md`.
|
|
#}
|
|
<nav x-data="{ mobileMenuIsOpen: false }" x-on:click.away="mobileMenuIsOpen = false" class="flex items-center justify-between border-b border-outline px-6 py-4 dark:border-outline-dark" aria-label="{{ nav.tr("nav-main-menu") }}">
|
|
<!-- Brand -->
|
|
<a href="/" class="text-2xl font-bold text-on-surface-strong dark:text-on-surface-dark-strong">
|
|
<span>Komp <span class="text-primary dark:text-primary-dark">Accounting</span></span>
|
|
{% if !nav.role.is_empty() %}<span class="ml-2 align-middle text-xs font-medium text-on-surface dark:text-on-surface-dark">{{ nav.role }}</span>{% endif %}
|
|
</a>
|
|
<!-- Desktop Menu -->
|
|
<ul class="hidden items-center gap-4 md:flex">
|
|
{% if nav.can_admin %}<li><a href="/admin" class="{% if nav.active == "admin" %}font-bold text-primary dark:text-primary-dark{% else %}font-medium text-on-surface dark:text-on-surface-dark dark:hover:text-primary-dark{% endif %} underline-offset-2 hover:text-primary focus:outline-hidden focus:underline" {% if nav.active == "admin" %}aria-current="page"{% endif %}>{{ nav.tr("nav-admin") }}</a></li>{% endif %}
|
|
{% if nav.can_permissions %}<li><a href="/permissions" class="{% if nav.active == "permissions" %}font-bold text-primary dark:text-primary-dark{% else %}font-medium text-on-surface dark:text-on-surface-dark dark:hover:text-primary-dark{% endif %} underline-offset-2 hover:text-primary focus:outline-hidden focus:underline" {% if nav.active == "permissions" %}aria-current="page"{% endif %}>{{ nav.tr("nav-permissions") }}</a></li>{% endif %}
|
|
<li><a href="/" class="{% if nav.active == "analytics" %}font-bold text-primary dark:text-primary-dark{% else %}font-medium text-on-surface dark:text-on-surface-dark dark:hover:text-primary-dark{% endif %} underline-offset-2 hover:text-primary focus:outline-hidden focus:underline" {% if nav.active == "analytics" %}aria-current="page"{% endif %}>{{ nav.tr("nav-analytics") }}</a></li>
|
|
{% if nav.can_exchange_rates %}<li><a href="/admin/exchange-rates" class="{% if nav.active == "ecb" %}font-bold text-primary dark:text-primary-dark{% else %}font-medium text-on-surface dark:text-on-surface-dark dark:hover:text-primary-dark{% endif %} underline-offset-2 hover:text-primary focus:outline-hidden focus:underline" {% if nav.active == "ecb" %}aria-current="page"{% endif %}>{{ nav.tr("nav-rates") }}</a></li>{% endif %}
|
|
{% if nav.can_import %}<li><a href="/admin/import" class="font-medium text-on-surface underline-offset-2 hover:text-primary focus:outline-hidden focus:underline dark:text-on-surface-dark dark:hover:text-primary-dark">{{ nav.tr("nav-import") }}</a></li>{% endif %}
|
|
{% if nav.can_export %}<li><a href="/admin/export" class="font-medium text-on-surface underline-offset-2 hover:text-primary focus:outline-hidden focus:underline dark:text-on-surface-dark dark:hover:text-primary-dark">{{ nav.tr("nav-export") }}</a></li>{% endif %}
|
|
{% if nav.authenticated %}
|
|
<li><a href="/password" class="font-medium text-on-surface underline-offset-2 hover:text-primary focus:outline-hidden focus:underline dark:text-on-surface-dark dark:hover:text-primary-dark">{{ nav.tr("nav-password") }}</a></li>
|
|
<li><form hx-post="/logout" hx-swap="none"><button type="submit" class="font-medium text-on-surface underline-offset-2 hover:text-primary focus:outline-hidden focus:underline dark:text-on-surface-dark dark:hover:text-primary-dark">{{ nav.tr("nav-log-out") }}</button></form></li>
|
|
{% else %}
|
|
<li><a href="/login" class="{% if nav.active == "login" %}font-bold text-primary dark:text-primary-dark{% else %}font-medium text-on-surface dark:text-on-surface-dark dark:hover:text-primary-dark{% endif %} underline-offset-2 hover:text-primary focus:outline-hidden focus:underline" {% if nav.active == "login" %}aria-current="page"{% endif %}>{{ nav.tr("nav-login") }}</a></li>
|
|
<li><a href="/register" class="{% if nav.active == "register" %}font-bold text-primary dark:text-primary-dark{% else %}font-medium text-on-surface dark:text-on-surface-dark dark:hover:text-primary-dark{% endif %} underline-offset-2 hover:text-primary focus:outline-hidden focus:underline" {% if nav.active == "register" %}aria-current="page"{% endif %}>{{ nav.tr("nav-register") }}</a></li>
|
|
{% endif %}
|
|
<li>{% include "ui/theme_toggle.html" %}</li>
|
|
</ul>
|
|
<!-- Mobile Menu Button -->
|
|
<button x-on:click="mobileMenuIsOpen = !mobileMenuIsOpen" x-bind:aria-expanded="mobileMenuIsOpen" x-bind:class="mobileMenuIsOpen ? 'fixed top-6 right-6 z-20' : null" type="button" class="flex text-on-surface dark:text-on-surface-dark md:hidden" aria-label="{{ nav.tr("nav-mobile-menu") }}" aria-controls="mobileMenu">
|
|
<svg x-cloak x-show="!mobileMenuIsOpen" xmlns="http://www.w3.org/2000/svg" fill="none" aria-hidden="true" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="size-6">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
|
</svg>
|
|
<svg x-cloak x-show="mobileMenuIsOpen" xmlns="http://www.w3.org/2000/svg" fill="none" aria-hidden="true" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="size-6">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
<!-- Mobile Menu -->
|
|
<ul x-cloak x-show="mobileMenuIsOpen" x-transition:enter="transition motion-reduce:transition-none ease-out duration-300" x-transition:enter-start="-translate-y-full" x-transition:enter-end="translate-y-0" x-transition:leave="transition motion-reduce:transition-none ease-out duration-300" x-transition:leave-start="translate-y-0" x-transition:leave-end="-translate-y-full" id="mobileMenu" class="fixed max-h-svh overflow-y-auto inset-x-0 top-0 z-10 flex flex-col divide-y divide-outline rounded-b-radius border-b border-outline bg-surface-alt px-6 pb-6 pt-20 dark:divide-outline-dark dark:border-outline-dark dark:bg-surface-dark-alt md:hidden">
|
|
{% if nav.can_admin %}<li class="py-4"><a href="/admin" class="w-full text-lg {% if nav.active == "admin" %}font-bold text-primary dark:text-primary-dark{% else %}font-medium text-on-surface dark:text-on-surface-dark{% endif %} focus:underline" {% if nav.active == "admin" %}aria-current="page"{% endif %}>{{ nav.tr("nav-admin") }}</a></li>{% endif %}
|
|
{% if nav.can_permissions %}<li class="py-4"><a href="/permissions" class="w-full text-lg {% if nav.active == "permissions" %}font-bold text-primary dark:text-primary-dark{% else %}font-medium text-on-surface dark:text-on-surface-dark{% endif %} focus:underline" {% if nav.active == "permissions" %}aria-current="page"{% endif %}>{{ nav.tr("nav-permissions") }}</a></li>{% endif %}
|
|
<li class="py-4"><a href="/" class="w-full text-lg {% if nav.active == "analytics" %}font-bold text-primary dark:text-primary-dark{% else %}font-medium text-on-surface dark:text-on-surface-dark{% endif %} focus:underline" {% if nav.active == "analytics" %}aria-current="page"{% endif %}>{{ nav.tr("nav-analytics") }}</a></li>
|
|
{% if nav.can_exchange_rates %}<li class="py-4"><a href="/admin/exchange-rates" class="w-full text-lg {% if nav.active == "ecb" %}font-bold text-primary dark:text-primary-dark{% else %}font-medium text-on-surface dark:text-on-surface-dark{% endif %} focus:underline" {% if nav.active == "ecb" %}aria-current="page"{% endif %}>{{ nav.tr("nav-rates") }}</a></li>{% endif %}
|
|
{% if nav.can_import %}<li class="py-4"><a href="/admin/import" class="w-full text-lg font-medium text-on-surface focus:underline dark:text-on-surface-dark">{{ nav.tr("nav-import") }}</a></li>{% endif %}
|
|
{% if nav.can_export %}<li class="py-4"><a href="/admin/export" class="w-full text-lg font-medium text-on-surface focus:underline dark:text-on-surface-dark">{{ nav.tr("nav-export") }}</a></li>{% endif %}
|
|
{% if nav.authenticated %}
|
|
<li class="py-4"><a href="/password" class="w-full text-lg font-medium text-on-surface focus:underline dark:text-on-surface-dark">{{ nav.tr("nav-password") }}</a></li>
|
|
<li class="py-4"><form hx-post="/logout" hx-swap="none"><button type="submit" class="w-full text-left text-lg font-medium text-on-surface focus:underline dark:text-on-surface-dark">{{ nav.tr("nav-log-out") }}</button></form></li>
|
|
{% else %}
|
|
<li class="py-4"><a href="/login" class="w-full text-lg {% if nav.active == "login" %}font-bold text-primary dark:text-primary-dark{% else %}font-medium text-on-surface dark:text-on-surface-dark{% endif %} focus:underline" {% if nav.active == "login" %}aria-current="page"{% endif %}>{{ nav.tr("nav-login") }}</a></li>
|
|
<li class="py-4"><a href="/register" class="w-full text-lg {% if nav.active == "register" %}font-bold text-primary dark:text-primary-dark{% else %}font-medium text-on-surface dark:text-on-surface-dark{% endif %} focus:underline" {% if nav.active == "register" %}aria-current="page"{% endif %}>{{ nav.tr("nav-register") }}</a></li>
|
|
{% endif %}
|
|
<li class="py-4">{% include "ui/theme_toggle.html" %}</li>
|
|
</ul>
|
|
</nav>
|