From d80aaa203b80e5320038087c537f92bf62990918 Mon Sep 17 00:00:00 2001 From: Elmehdi Aitbrahim Date: Sat, 29 Aug 2026 02:28:54 -0400 Subject: [PATCH] feat(nav): collapse 11 flat links into 4 hover/focus dropdown groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The flat nav wrapped to two lines at desktop widths. Four top-level groups now own dropdown submenus (Product, Docs, Community, Company) built on the language switcher's pattern: the .nav-group wrapper owns hover/focus-within, the panel is opacity-gated so its links keep their tab stops, and a single delegated Escape listener (the theme toggle's script pattern) covers the one dismissal gesture CSS cannot see. Compare leaves the nav per #131 — the page stays live at /compare/ for organic traffic; nothing else in the chrome links to it. The hamburger panel below the md breakpoint keeps its mechanics and lists all ten items under their group headings. Closes #131 --- src/components/Header.astro | 106 ++++++++++++++++++++----- src/i18n/ui.ts | 24 +++++- src/styles/global.css | 154 +++++++++++++++++++++++++++++++++--- 3 files changed, 248 insertions(+), 36 deletions(-) diff --git a/src/components/Header.astro b/src/components/Header.astro index 17d9a7c..bcc4271 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -11,18 +11,51 @@ interface Props { const { locale, pageKey } = Astro.props; const chrome = t(locale); -const navItems: { key: Exclude; label: string }[] = [ - { key: "features", label: chrome.nav.features }, - { key: "install", label: chrome.nav.install }, - { key: "docs", label: chrome.nav.docs }, - { key: "assistant", label: chrome.nav.assistant }, - { key: "news", label: chrome.nav.news }, - { key: "changelog", label: chrome.nav.changelog }, - { key: "community", label: chrome.nav.community }, - { key: "roadmap", label: chrome.nav.roadmap }, - { key: "compliance", label: chrome.nav.compliance }, - { key: "compare", label: chrome.nav.compare }, - { key: "about", label: chrome.nav.about }, +/** + * #131 — the eleven flat links collapsed into four top-level groups, each + * opening a dropdown on hover/focus-within (the language switcher's pattern). + * Compare left the nav on purpose: the page stays live at its URL but nothing + * in the chrome points at it anymore. + */ +const navGroups: { + key: string; + label: string; + items: { key: Exclude; label: string }[]; +}[] = [ + { + key: "product", + label: chrome.navGroups.product, + items: [ + { key: "features", label: chrome.nav.features }, + { key: "install", label: chrome.nav.install }, + { key: "assistant", label: chrome.nav.assistant }, + { key: "roadmap", label: chrome.nav.roadmap }, + ], + }, + { + key: "docs", + label: chrome.navGroups.docs, + items: [ + { key: "docs", label: chrome.nav.docs }, + { key: "changelog", label: chrome.nav.changelog }, + ], + }, + { + key: "community", + label: chrome.navGroups.community, + items: [ + { key: "news", label: chrome.nav.news }, + { key: "community", label: chrome.nav.community }, + ], + }, + { + key: "company", + label: chrome.navGroups.company, + items: [ + { key: "compliance", label: chrome.nav.compliance }, + { key: "about", label: chrome.nav.about }, + ], + }, ]; const menuLabel = locale === "ar" ? "القائمة" : locale === "fr" ? "Menu" : "Menu"; @@ -94,14 +127,34 @@ const localeCodes: Record = { en: "EN", ar: "AR", fr: "FR" };