taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit d0e6c55fdfd82cfd7cb1e1fcd8fd076b47c51055
parent 3259d51444c68c1b23402521f4269ed57b1c79f1
Author: Florian Dold <dold@taler.net>
Date:   Wed,  4 Nov 2026 00:54:56 +0100

merchant web UI: keep active menu item visible

Diffstat:
Mpackages/taler-merchant-webui/src/ui/Menu.tsx | 27+++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/packages/taler-merchant-webui/src/ui/Menu.tsx b/packages/taler-merchant-webui/src/ui/Menu.tsx @@ -15,6 +15,7 @@ */ import type { VNode } from "preact"; +import { useLayoutEffect, useRef } from "preact/hooks"; import { useLocation } from "wouter-preact"; import { Link } from "../routing/Link.js"; import { TalerLogo } from "./TalerLogo.js"; @@ -109,6 +110,21 @@ export function Menu({ const [location] = useLocation(); const { t, lang, setLanguage, languages } = useTranslation(); const showAdvanced = preferences.value.advancedTools; + const desktopSidebar = useRef<HTMLElement>(null); + const mobileSidebar = useRef<HTMLElement>(null); + + useLayoutEffect(() => { + // Reveal the current route after mounting or opening the drawer, without + // moving keyboard focus or scrolling an already visible link. + for (const sidebar of [desktopSidebar.current, mobileSidebar.current]) { + if (!sidebar?.getClientRects().length) continue; + sidebar.querySelector('[aria-current="page"]')?.scrollIntoView({ + block: "nearest", + inline: "nearest", + behavior: "instant", + }); + } + }, [location, isMobileOpen, showAdvanced, showAdministration, lang]); const isActivePath = (path: string) => { if (path === "/orders") @@ -172,6 +188,7 @@ export function Menu({ <li key={entry.href}> <Link href={entry.href} + aria-current={isActive(entry) ? "page" : undefined} onClick={onCloseMobile} class={`flex items-center justify-between px-3 py-2 rounded-md text-sm font-medium transition-colors ${ isActive(entry) @@ -231,14 +248,20 @@ export function Menu({ return ( <> {/* Desktop Sidebar (visible on md screens and up) */} - <aside class="hidden md:flex w-64 h-screen sticky top-0 bg-gray-900 text-gray-200 flex-col p-4 border-r border-gray-800 shrink-0 overflow-hidden"> + <aside + ref={desktopSidebar} + class="hidden md:flex w-64 h-screen sticky top-0 bg-gray-900 text-gray-200 flex-col p-4 border-r border-gray-800 shrink-0 overflow-hidden" + > {renderNavContent()} </aside> {/* Mobile Drawer (visible on small screens when open) */} {isMobileOpen && ( <div class="fixed inset-0 z-50 flex md:hidden bg-gray-900/80 backdrop-blur-xs"> - <aside class="w-72 h-full bg-gray-900 text-gray-200 flex flex-col p-4 border-r border-gray-800 shadow-2xl overflow-hidden"> + <aside + ref={mobileSidebar} + class="w-72 h-full bg-gray-900 text-gray-200 flex flex-col p-4 border-r border-gray-800 shadow-2xl overflow-hidden" + > {renderNavContent()} </aside> <button