working profile pic, but its trash, redoing the navbar icons now

This commit is contained in:
Priec
2026-06-19 22:34:11 +02:00
parent 454d5cb349
commit 673b28c361
4 changed files with 71 additions and 45 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -57,6 +57,9 @@
</script>
<link href="/static/css/app.css?v=2026-06-16" rel="stylesheet" type="text/css">
<script src="/static/vendor/htmx/htmx-1.9.12.min.js"></script>
<!-- Alpine Focus plugin (x-trap / $focus) — must load before Alpine core;
required by the Penguin UI keyboard-accessible dropdowns. -->
<script defer src="/static/vendor/alpine/alpine-focus-3.14.9.min.js"></script>
<script defer src="/static/vendor/alpine/alpinejs-3.14.9.min.js"></script>
</head>
<body hx-boost="true"
@@ -95,8 +98,13 @@
<!-- right side: cart + settings + mobile toggle -->
<div class="ml-auto flex items-center gap-1">
<!-- cart with live item-count badge read from the `cart` cookie -->
<a href="/cart" data-nav="/cart"
<!-- customer profile dropdown (avatar + name + account type) -->
{% if logged_in_customer %}
{% include "partials/profile_menu.html" %}
{% endif %}
<!-- cart with live item-count badge read from the `cart` cookie.
hx-boost=false: a plain full-page navigation to /cart, no SPA swap. -->
<a href="/cart" data-nav="/cart" hx-boost="false"
x-data="{ count: 0 }"
x-init="count = cartCount(); ['htmx:afterSwap', 'htmx:afterRequest'].forEach(function (e) { window.addEventListener(e, function () { count = cartCount() }) })"
aria-label="{{ t(key='cart-title', lang=lang | default(value='sk')) }}"
@@ -106,12 +114,6 @@
<span x-show="count > 0" x-cloak x-text="count"
class="absolute -right-1 -top-1 inline-flex min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-semibold leading-4 text-on-primary dark:bg-primary-dark dark:text-on-primary-dark"></span>
</a>
<!-- customer profile dropdown (avatar + name + account type) -->
{% if logged_in_customer %}
<div x-data="{ open: false }" @keydown.escape="open = false" class="relative">
{% include "partials/profile_menu.html" %}
</div>
{% endif %}
<!-- settings (language + theme) dropdown -->
<div x-data="{ open: false }" @keydown.escape="open = false" class="relative">

View File

@@ -1,46 +1,55 @@
{# Customer profile dropdown shown in the storefront navbar next to the cart.
Trigger shows an initials avatar, the customer's name and their account type
(personal / company); clicking opens a quick-navigation menu.
{# Customer profile dropdown in the storefront navbar.
The host template provides the wrapper
<div x-data="{ open: false }" @keydown.escape="open = false" class="relative">. #}
Penguin UI markup (navbar/with-user-profile.html dropdown + avatar rendered as
avatar-with-initials.html, primary variant, since we have no photo), but with
the same minimal core-Alpine toggle as settings_dropdown.html — plain
open / @click.outside, NOT Penguin's x-trap / $focus keyboard nav (that needs
the Alpine Focus plugin we don't rely on). Self-contained Alpine state.
{# initials from the name, e.g. "Filip Priec" -> "FP" #}
IMPORTANT: the dropdown <ul> needs an inline style="display: none" in addition
to x-cloak. Because it has id="userMenu", htmx hx-boost "settles" it by id
across boosted navigations, and that interferes with Alpine re-applying x-show,
leaving the menu visible (open=false) after navigating. The inline display:none
keeps it hidden until x-show explicitly opens it. (settings_dropdown has no id,
so it is not settled and does not need this.) #}
{# initials from the full name, e.g. "Filip Priec" -> "FP" #}
{% set _name = customer_name | default(value='') | trim %}
{% set _parts = _name | split(pat=' ') %}
{% set _initials = _parts.0 | truncate(length=1, end='') | upper %}
{% if _parts | length > 1 %}{% set _second = _parts | last | truncate(length=1, end='') | upper %}{% set _initials = _initials ~ _second %}{% endif %}
{% if customer_account_type == "company" %}{% set _type_label = t(key="account-company", lang=lang | default(value='sk')) %}{% else %}{% set _type_label = t(key="account-personal", lang=lang | default(value='sk')) %}{% endif %}
<button type="button" @click="open = !open" :aria-expanded="open"
aria-label="{{ t(key='nav-account', lang=lang | default(value='sk')) }}"
class="flex items-center gap-2 rounded-radius border border-outline bg-surface-alt py-1 pl-1 pr-2 text-left transition hover:border-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:border-outline-dark dark:bg-surface-dark-alt dark:hover:border-primary-dark">
<span class="inline-flex size-7 shrink-0 items-center justify-center rounded-full bg-primary text-xs font-semibold text-on-primary dark:bg-primary-dark dark:text-on-primary-dark">{{ _initials }}</span>
<span class="hidden min-w-0 flex-col leading-tight sm:flex">
<span class="truncate text-xs font-semibold text-on-surface-strong dark:text-on-surface-dark-strong">{{ _name }}</span>
<span class="truncate text-[10px] text-on-surface/60 dark:text-on-surface-dark/60">{{ _type_label }}</span>
</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="hidden size-4 text-on-surface/60 sm:block dark:text-on-surface-dark/60" :class="open && 'rotate-180'"><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>
{% set _person_icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" aria-hidden="true" fill="currentColor" class="size-5"><path fill-rule="evenodd" d="M7.5 6a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0zM3.751 20.105a8.25 8.25 0 0116.498 0 .75.75 0 01-.437.695A18.683 18.683 0 0112 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 01-.437-.695z" clip-rule="evenodd"/></svg>' %}
<div x-show="open" x-cloak @click.outside="open = false" x-transition.origin.top.right
class="absolute right-0 mt-2 flex w-56 flex-col overflow-hidden rounded-radius border border-outline bg-surface-alt py-1 shadow-lg dark:border-outline-dark dark:bg-surface-dark-alt"
role="menu">
<div class="flex items-center gap-3 border-b border-outline px-4 py-3 dark:border-outline-dark">
<span class="inline-flex size-9 shrink-0 items-center justify-center rounded-full bg-primary text-sm font-semibold text-on-primary dark:bg-primary-dark dark:text-on-primary-dark">{{ _initials }}</span>
<span class="flex min-w-0 flex-col leading-tight">
<span class="truncate text-sm font-semibold text-on-surface-strong dark:text-on-surface-dark-strong">{{ _name }}</span>
<span class="truncate text-xs text-on-surface/60 dark:text-on-surface-dark/60">{{ _type_label }}</span>
</span>
</div>
<a href="/account/orders" data-nav="/account/orders" role="menuitem"
class="px-4 py-2 text-sm text-on-surface transition hover:bg-primary/5 hover:text-on-surface-strong focus-visible:bg-primary/10 focus-visible:outline-hidden dark:text-on-surface-dark dark:hover:bg-primary-dark/5 dark:hover:text-on-surface-dark-strong">{{ t(key="account-orders", lang=lang | default(value='sk')) }}</a>
<a href="/account/profile" data-nav="/account/profile" role="menuitem"
class="px-4 py-2 text-sm text-on-surface transition hover:bg-primary/5 hover:text-on-surface-strong focus-visible:bg-primary/10 focus-visible:outline-hidden dark:text-on-surface-dark dark:hover:bg-primary-dark/5 dark:hover:text-on-surface-dark-strong">{{ t(key="profile-title", lang=lang | default(value='sk')) }}</a>
<a href="/account/password" data-nav="/account/password" role="menuitem"
class="px-4 py-2 text-sm text-on-surface transition hover:bg-primary/5 hover:text-on-surface-strong focus-visible:bg-primary/10 focus-visible:outline-hidden dark:text-on-surface-dark dark:hover:bg-primary-dark/5 dark:hover:text-on-surface-dark-strong">{{ t(key="account-change-password", lang=lang | default(value='sk')) }}</a>
<form method="post" action="/logout" hx-boost="false" class="border-t border-outline dark:border-outline-dark">
<button type="submit" role="menuitem"
class="block w-full px-4 py-2 text-left text-sm font-medium text-danger transition hover:bg-primary/5 focus-visible:bg-primary/10 focus-visible:outline-hidden">{{ t(key="logout", lang=lang | default(value='sk')) }}</button>
</form>
<div x-data="{ open: false }"
x-on:keydown.esc.window="open = false"
class="relative flex items-center">
<!-- Toggle Button: plain circular avatar (name/type live in the dropdown) -->
<button type="button" x-on:click="open = !open"
x-bind:aria-expanded="open" aria-haspopup="true" aria-controls="userMenu"
aria-label="{{ t(key='nav-account', lang=lang | default(value='sk')) }}"
class="flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-full border border-primary bg-primary text-sm font-bold tracking-wider text-on-primary/90 transition hover:opacity-90 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:border-primary-dark dark:bg-primary-dark dark:text-on-primary-dark/90 dark:focus-visible:outline-primary-dark">
{%- if _initials %}{{ _initials }}{% else %}{{ _person_icon | safe }}{% endif -%}
</button>
<!-- User Dropdown -->
<ul x-cloak x-show="open" x-transition.opacity style="display: none"
x-on:click.outside="open = false"
id="userMenu" class="absolute right-0 top-12 flex w-60 min-w-48 flex-col overflow-hidden rounded-radius border border-outline bg-surface-alt py-1.5 shadow-lg dark:border-outline-dark dark:bg-surface-dark-alt" role="menu">
<li class="border-b border-outline dark:border-outline-dark">
<div class="flex items-center gap-3 px-4 py-2.5">
<span class="flex size-11 shrink-0 items-center justify-center overflow-hidden rounded-full border border-primary bg-primary text-base font-bold tracking-wider text-on-primary/90 dark:border-primary-dark dark:bg-primary-dark dark:text-on-primary-dark/90">
{%- if _initials %}{{ _initials }}{% else %}{{ _person_icon | safe }}{% endif -%}
</span>
<div class="flex min-w-0 flex-col">
<span class="truncate text-sm font-medium text-on-surface-strong dark:text-on-surface-dark-strong">{{ _name }}</span>
<p class="truncate text-xs text-on-surface dark:text-on-surface-dark">{{ _type_label }}</p>
</div>
</div>
</li>
<li><a href="/account/orders" data-nav="/account/orders" role="menuitem" class="block bg-surface-alt px-4 py-2 text-sm text-on-surface hover:bg-surface-dark-alt/5 hover:text-on-surface-strong focus-visible:bg-surface-dark-alt/10 focus-visible:text-on-surface-strong focus-visible:outline-hidden dark:bg-surface-dark-alt dark:text-on-surface-dark dark:hover:bg-surface-alt/5 dark:hover:text-on-surface-dark-strong dark:focus-visible:bg-surface-alt/10 dark:focus-visible:text-on-surface-dark-strong">{{ t(key="account-orders", lang=lang | default(value='sk')) }}</a></li>
<li><a href="/account/profile" data-nav="/account/profile" role="menuitem" class="block bg-surface-alt px-4 py-2 text-sm text-on-surface hover:bg-surface-dark-alt/5 hover:text-on-surface-strong focus-visible:bg-surface-dark-alt/10 focus-visible:text-on-surface-strong focus-visible:outline-hidden dark:bg-surface-dark-alt dark:text-on-surface-dark dark:hover:bg-surface-alt/5 dark:hover:text-on-surface-dark-strong dark:focus-visible:bg-surface-alt/10 dark:focus-visible:text-on-surface-dark-strong">{{ t(key="profile-title", lang=lang | default(value='sk')) }}</a></li>
<li><a href="/account/password" data-nav="/account/password" role="menuitem" class="block bg-surface-alt px-4 py-2 text-sm text-on-surface hover:bg-surface-dark-alt/5 hover:text-on-surface-strong focus-visible:bg-surface-dark-alt/10 focus-visible:text-on-surface-strong focus-visible:outline-hidden dark:bg-surface-dark-alt dark:text-on-surface-dark dark:hover:bg-surface-alt/5 dark:hover:text-on-surface-dark-strong dark:focus-visible:bg-surface-alt/10 dark:focus-visible:text-on-surface-dark-strong">{{ t(key="account-change-password", lang=lang | default(value='sk')) }}</a></li>
<li><form method="post" action="/logout" hx-boost="false"><button type="submit" role="menuitem" class="block w-full bg-surface-alt px-4 py-2 text-left text-sm text-on-surface hover:bg-surface-dark-alt/5 hover:text-on-surface-strong focus-visible:bg-surface-dark-alt/10 focus-visible:text-on-surface-strong focus-visible:outline-hidden dark:bg-surface-dark-alt dark:text-on-surface-dark dark:hover:bg-surface-alt/5 dark:hover:text-on-surface-dark-strong dark:focus-visible:bg-surface-alt/10 dark:focus-visible:text-on-surface-dark-strong">{{ t(key="logout", lang=lang | default(value='sk')) }}</button></form></li>
</ul>
</div>