rizzo-css 0.0.11 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/.env.example +12 -0
  2. package/LICENSE +21 -0
  3. package/README.md +17 -3
  4. package/bin/rizzo-css.js +98 -42
  5. package/dist/rizzo.min.css +3 -2
  6. package/package.json +5 -3
  7. package/scaffold/astro-app/README.md +13 -2
  8. package/scaffold/astro-app/src/components/Accordion.astro +178 -0
  9. package/scaffold/astro-app/src/components/Alert.astro +131 -0
  10. package/scaffold/astro-app/src/components/Avatar.astro +59 -0
  11. package/scaffold/astro-app/src/components/Badge.astro +24 -0
  12. package/scaffold/astro-app/src/components/Breadcrumb.astro +61 -0
  13. package/scaffold/astro-app/src/components/Button.astro +3 -0
  14. package/scaffold/astro-app/src/components/Card.astro +18 -0
  15. package/scaffold/astro-app/src/components/Checkbox.astro +38 -0
  16. package/scaffold/astro-app/src/components/CodeBlock.astro +393 -0
  17. package/scaffold/astro-app/src/components/CopyToClipboard.astro +219 -0
  18. package/scaffold/astro-app/src/components/Divider.astro +37 -0
  19. package/scaffold/astro-app/src/components/Dropdown.astro +807 -0
  20. package/scaffold/astro-app/src/components/FormGroup.astro +59 -0
  21. package/scaffold/astro-app/src/components/FrameworkSwitcher.astro +72 -0
  22. package/scaffold/astro-app/src/components/Input.astro +59 -0
  23. package/scaffold/astro-app/src/components/Modal.astro +212 -0
  24. package/scaffold/astro-app/src/components/Navbar.astro +701 -0
  25. package/scaffold/astro-app/src/components/Pagination.astro +240 -0
  26. package/scaffold/astro-app/src/components/ProgressBar.astro +65 -0
  27. package/scaffold/astro-app/src/components/Radio.astro +38 -0
  28. package/scaffold/astro-app/src/components/Search.astro +1259 -0
  29. package/scaffold/astro-app/src/components/Select.astro +49 -0
  30. package/scaffold/astro-app/src/components/Settings.astro +382 -0
  31. package/scaffold/astro-app/src/components/Spinner.astro +30 -0
  32. package/scaffold/astro-app/src/components/Table.astro +181 -0
  33. package/scaffold/astro-app/src/components/Tabs.astro +223 -0
  34. package/scaffold/astro-app/src/components/Textarea.astro +58 -0
  35. package/scaffold/astro-app/src/components/ThemeSwitcher.astro +504 -0
  36. package/scaffold/astro-app/src/components/Toast.astro +30 -0
  37. package/scaffold/astro-app/src/components/Tooltip.astro +32 -0
  38. package/scaffold/astro-app/src/components/icons/Brush.astro +10 -0
  39. package/scaffold/astro-app/src/components/icons/Cake.astro +11 -0
  40. package/scaffold/astro-app/src/components/icons/Check.astro +29 -0
  41. package/scaffold/astro-app/src/components/icons/Cherry.astro +11 -0
  42. package/scaffold/astro-app/src/components/icons/ChevronDown.astro +29 -0
  43. package/scaffold/astro-app/src/components/icons/Circle.astro +29 -0
  44. package/scaffold/astro-app/src/components/icons/Close.astro +30 -0
  45. package/scaffold/astro-app/src/components/icons/Cmd.astro +26 -0
  46. package/scaffold/astro-app/src/components/icons/Copy.astro +30 -0
  47. package/scaffold/astro-app/src/components/icons/Eye.astro +30 -0
  48. package/scaffold/astro-app/src/components/icons/Filter.astro +29 -0
  49. package/scaffold/astro-app/src/components/icons/Flame.astro +28 -0
  50. package/scaffold/astro-app/src/components/icons/Flower.astro +11 -0
  51. package/scaffold/astro-app/src/components/icons/Gear.astro +30 -0
  52. package/scaffold/astro-app/src/components/icons/Heart.astro +28 -0
  53. package/scaffold/astro-app/src/components/icons/IceCream.astro +31 -0
  54. package/scaffold/astro-app/src/components/icons/Leaf.astro +29 -0
  55. package/scaffold/astro-app/src/components/icons/Lemon.astro +11 -0
  56. package/scaffold/astro-app/src/components/icons/Moon.astro +29 -0
  57. package/scaffold/astro-app/src/components/icons/Owl.astro +34 -0
  58. package/scaffold/astro-app/src/components/icons/Palette.astro +33 -0
  59. package/scaffold/astro-app/src/components/icons/Rainbow.astro +31 -0
  60. package/scaffold/astro-app/src/components/icons/Search.astro +30 -0
  61. package/scaffold/astro-app/src/components/icons/Shield.astro +28 -0
  62. package/scaffold/astro-app/src/components/icons/Snowflake.astro +34 -0
  63. package/scaffold/astro-app/src/components/icons/Sort.astro +30 -0
  64. package/scaffold/astro-app/src/components/icons/Sun.astro +29 -0
  65. package/scaffold/astro-app/src/components/icons/Sunset.astro +10 -0
  66. package/scaffold/astro-app/src/components/icons/Zap.astro +9 -0
  67. package/scaffold/astro-app/src/components/icons/devicons/Astro.astro +53 -0
  68. package/scaffold/astro-app/src/components/icons/devicons/Bash.astro +34 -0
  69. package/scaffold/astro-app/src/components/icons/devicons/Css3.astro +29 -0
  70. package/scaffold/astro-app/src/components/icons/devicons/Git.astro +24 -0
  71. package/scaffold/astro-app/src/components/icons/devicons/Html5.astro +27 -0
  72. package/scaffold/astro-app/src/components/icons/devicons/Javascript.astro +25 -0
  73. package/scaffold/astro-app/src/components/icons/devicons/Nodejs.astro +47 -0
  74. package/scaffold/astro-app/src/components/icons/devicons/Plaintext.astro +33 -0
  75. package/scaffold/astro-app/src/components/icons/devicons/React.astro +27 -0
  76. package/scaffold/astro-app/src/components/icons/devicons/Svelte.astro +25 -0
  77. package/scaffold/astro-app/src/components/icons/devicons/Vue.astro +26 -0
  78. package/scaffold/astro-app/src/config/frameworks.ts +26 -0
  79. package/scaffold/astro-app/src/config/themes.ts +54 -0
  80. package/scaffold/astro-app/src/layouts/DocsLayout.astro +204 -0
  81. package/scaffold/astro-app/src/layouts/Layout.astro +11 -2
  82. package/scaffold/astro-app/src/pages/components/accordion.astro +172 -0
  83. package/scaffold/astro-app/src/pages/components/alert.astro +250 -0
  84. package/scaffold/astro-app/src/pages/components/avatar.astro +102 -0
  85. package/scaffold/astro-app/src/pages/components/badge.astro +119 -0
  86. package/scaffold/astro-app/src/pages/components/breadcrumb.astro +124 -0
  87. package/scaffold/astro-app/src/pages/components/button.astro +74 -0
  88. package/scaffold/astro-app/src/pages/components/cards.astro +247 -0
  89. package/scaffold/astro-app/src/pages/components/copy-to-clipboard.astro +49 -0
  90. package/scaffold/astro-app/src/pages/components/divider.astro +74 -0
  91. package/scaffold/astro-app/src/pages/components/dropdown.astro +394 -0
  92. package/scaffold/astro-app/src/pages/components/forms.astro +367 -0
  93. package/scaffold/astro-app/src/pages/components/icons.astro +246 -0
  94. package/scaffold/astro-app/src/pages/components/modal.astro +152 -0
  95. package/scaffold/astro-app/src/pages/components/navbar.astro +80 -0
  96. package/scaffold/astro-app/src/pages/components/pagination.astro +126 -0
  97. package/scaffold/astro-app/src/pages/components/progress-bar.astro +94 -0
  98. package/scaffold/astro-app/src/pages/components/search.astro +155 -0
  99. package/scaffold/astro-app/src/pages/components/settings.astro +78 -0
  100. package/scaffold/astro-app/src/pages/components/spinner.astro +81 -0
  101. package/scaffold/astro-app/src/pages/components/table.astro +144 -0
  102. package/scaffold/astro-app/src/pages/components/tabs.astro +220 -0
  103. package/scaffold/astro-app/src/pages/components/theme-switcher.astro +67 -0
  104. package/scaffold/astro-app/src/pages/components/toast.astro +157 -0
  105. package/scaffold/astro-app/src/pages/components/tooltip.astro +209 -0
  106. package/scaffold/astro-app/src/pages/components.astro +290 -0
  107. package/scaffold/astro-app/src/pages/docs/accessibility.astro +9 -0
  108. package/scaffold/astro-app/src/pages/docs/colors.astro +9 -0
  109. package/scaffold/astro-app/src/pages/docs/design-system.astro +9 -0
  110. package/scaffold/astro-app/src/pages/docs/getting-started.astro +9 -0
  111. package/scaffold/astro-app/src/pages/docs/index.astro +15 -0
  112. package/scaffold/astro-app/src/pages/docs/themes/[theme].astro +14 -0
  113. package/scaffold/astro-app/src/pages/docs/theming.astro +10 -0
  114. package/scaffold/astro-app/src/pages/index.astro +5 -11
  115. package/scaffold/svelte/Table.svelte +6 -5
  116. package/scaffold/svelte/Tabs.svelte +3 -1
  117. package/scaffold/svelte-app/README.md +9 -2
  118. package/scaffold/svelte-app/src/app.html +1 -1
  119. package/scaffold/svelte-app/src/lib/rizzo/Accordion.svelte +128 -0
  120. package/scaffold/svelte-app/src/lib/rizzo/Alert.svelte +85 -0
  121. package/scaffold/svelte-app/src/lib/rizzo/Avatar.svelte +39 -0
  122. package/scaffold/svelte-app/src/lib/rizzo/Badge.svelte +31 -0
  123. package/scaffold/svelte-app/src/lib/rizzo/Breadcrumb.svelte +49 -0
  124. package/scaffold/svelte-app/src/lib/rizzo/Button.svelte +27 -0
  125. package/scaffold/svelte-app/src/lib/rizzo/Card.svelte +17 -0
  126. package/scaffold/svelte-app/src/lib/rizzo/Checkbox.svelte +37 -0
  127. package/scaffold/svelte-app/src/lib/rizzo/CopyToClipboard.svelte +79 -0
  128. package/scaffold/svelte-app/src/lib/rizzo/Divider.svelte +28 -0
  129. package/scaffold/svelte-app/src/lib/rizzo/Dropdown.svelte +254 -0
  130. package/scaffold/svelte-app/src/lib/rizzo/FormGroup.svelte +51 -0
  131. package/scaffold/svelte-app/src/lib/rizzo/Input.svelte +59 -0
  132. package/scaffold/svelte-app/src/lib/rizzo/Modal.svelte +157 -0
  133. package/scaffold/svelte-app/src/lib/rizzo/Pagination.svelte +93 -0
  134. package/scaffold/svelte-app/src/lib/rizzo/ProgressBar.svelte +58 -0
  135. package/scaffold/svelte-app/src/lib/rizzo/Radio.svelte +38 -0
  136. package/scaffold/svelte-app/src/lib/rizzo/Select.svelte +51 -0
  137. package/scaffold/svelte-app/src/lib/rizzo/Spinner.svelte +14 -0
  138. package/scaffold/svelte-app/src/lib/rizzo/Table.svelte +158 -0
  139. package/scaffold/svelte-app/src/lib/rizzo/Tabs.svelte +117 -0
  140. package/scaffold/svelte-app/src/lib/rizzo/Textarea.svelte +59 -0
  141. package/scaffold/svelte-app/src/lib/rizzo/ThemeSwitcher.svelte +315 -0
  142. package/scaffold/svelte-app/src/lib/rizzo/Toast.svelte +33 -0
  143. package/scaffold/svelte-app/src/lib/rizzo/Tooltip.svelte +19 -0
  144. package/scaffold/svelte-app/src/lib/rizzo/icons/Check.svelte +29 -0
  145. package/scaffold/svelte-app/src/lib/rizzo/icons/ChevronDown.svelte +29 -0
  146. package/scaffold/svelte-app/src/lib/rizzo/icons/Circle.svelte +29 -0
  147. package/scaffold/svelte-app/src/lib/rizzo/icons/Close.svelte +30 -0
  148. package/scaffold/svelte-app/src/lib/rizzo/icons/Cmd.svelte +27 -0
  149. package/scaffold/svelte-app/src/lib/rizzo/icons/Copy.svelte +30 -0
  150. package/scaffold/svelte-app/src/lib/rizzo/icons/Eye.svelte +30 -0
  151. package/scaffold/svelte-app/src/lib/rizzo/icons/Filter.svelte +29 -0
  152. package/scaffold/svelte-app/src/lib/rizzo/icons/Gear.svelte +30 -0
  153. package/scaffold/svelte-app/src/lib/rizzo/icons/IceCream.svelte +31 -0
  154. package/scaffold/svelte-app/src/lib/rizzo/icons/Moon.svelte +29 -0
  155. package/scaffold/svelte-app/src/lib/rizzo/icons/Owl.svelte +34 -0
  156. package/scaffold/svelte-app/src/lib/rizzo/icons/Palette.svelte +33 -0
  157. package/scaffold/svelte-app/src/lib/rizzo/icons/Rainbow.svelte +31 -0
  158. package/scaffold/svelte-app/src/lib/rizzo/icons/Search.svelte +30 -0
  159. package/scaffold/svelte-app/src/lib/rizzo/icons/Snowflake.svelte +34 -0
  160. package/scaffold/svelte-app/src/lib/rizzo/icons/Sort.svelte +30 -0
  161. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Astro.svelte +45 -0
  162. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Bash.svelte +28 -0
  163. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Css3.svelte +23 -0
  164. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Git.svelte +18 -0
  165. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Html5.svelte +21 -0
  166. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Javascript.svelte +19 -0
  167. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Nodejs.svelte +44 -0
  168. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Plaintext.svelte +24 -0
  169. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/React.svelte +21 -0
  170. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/SvelteIcon.svelte +19 -0
  171. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Vue.svelte +20 -0
  172. package/scaffold/svelte-app/src/lib/rizzo/index.ts +33 -0
  173. package/scaffold/svelte-app/src/lib/rizzo-docs/CodeBlock.svelte +239 -0
  174. package/scaffold/svelte-app/src/lib/rizzo-docs/SvelteDocPage.svelte +99 -0
  175. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/AccordionDoc.svelte +53 -0
  176. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/AlertDoc.svelte +114 -0
  177. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/AvatarDoc.svelte +92 -0
  178. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/BadgeDoc.svelte +60 -0
  179. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/BreadcrumbDoc.svelte +55 -0
  180. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ButtonDoc.svelte +55 -0
  181. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/CardsDoc.svelte +173 -0
  182. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ComingSoon.svelte +12 -0
  183. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ComponentsOverview.svelte +92 -0
  184. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/CopyToClipboardDoc.svelte +26 -0
  185. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/DividerDoc.svelte +105 -0
  186. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/DropdownDoc.svelte +161 -0
  187. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/FormsDoc.svelte +375 -0
  188. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/IconsDoc.svelte +246 -0
  189. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/Index.svelte +8 -0
  190. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ModalDoc.svelte +50 -0
  191. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/NavbarDoc.svelte +79 -0
  192. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/PaginationDoc.svelte +44 -0
  193. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ProgressBarDoc.svelte +95 -0
  194. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/SearchDoc.svelte +147 -0
  195. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/SettingsDoc.svelte +158 -0
  196. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/SpinnerDoc.svelte +41 -0
  197. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/TableDoc.svelte +116 -0
  198. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/TabsDoc.svelte +152 -0
  199. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ThemeSwitcherDoc.svelte +181 -0
  200. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/Theming.svelte +6 -0
  201. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ToastDoc.svelte +136 -0
  202. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/TooltipDoc.svelte +57 -0
  203. package/scaffold/svelte-app/src/routes/+page.svelte +2 -2
  204. package/scaffold/svelte-app/src/routes/components/+page.svelte +4 -0
  205. package/scaffold/svelte-app/src/routes/components/[slug]/+page.svelte +7 -0
  206. package/scaffold/vanilla/README.md +20 -8
  207. package/scaffold/vanilla/components/accordion.html +187 -0
  208. package/scaffold/vanilla/components/alert.html +187 -0
  209. package/scaffold/vanilla/components/avatar.html +187 -0
  210. package/scaffold/vanilla/components/badge.html +187 -0
  211. package/scaffold/vanilla/components/breadcrumb.html +187 -0
  212. package/scaffold/vanilla/components/button.html +187 -0
  213. package/scaffold/vanilla/components/cards.html +187 -0
  214. package/scaffold/vanilla/components/copy-to-clipboard.html +187 -0
  215. package/scaffold/vanilla/components/divider.html +187 -0
  216. package/scaffold/vanilla/components/dropdown.html +187 -0
  217. package/scaffold/vanilla/components/forms.html +187 -0
  218. package/scaffold/vanilla/components/icons.html +187 -0
  219. package/scaffold/vanilla/components/index.html +212 -0
  220. package/scaffold/vanilla/components/modal.html +187 -0
  221. package/scaffold/vanilla/components/navbar.html +187 -0
  222. package/scaffold/vanilla/components/pagination.html +187 -0
  223. package/scaffold/vanilla/components/progress-bar.html +187 -0
  224. package/scaffold/vanilla/components/search.html +187 -0
  225. package/scaffold/vanilla/components/settings.html +187 -0
  226. package/scaffold/vanilla/components/spinner.html +187 -0
  227. package/scaffold/vanilla/components/table.html +187 -0
  228. package/scaffold/vanilla/components/tabs.html +187 -0
  229. package/scaffold/vanilla/components/theme-switcher.html +187 -0
  230. package/scaffold/vanilla/components/toast.html +187 -0
  231. package/scaffold/vanilla/components/tooltip.html +187 -0
  232. package/scaffold/vanilla/index.html +17 -283
  233. package/scaffold/vanilla/js/main.js +748 -0
@@ -0,0 +1,701 @@
1
+ ---
2
+ import Gear from './icons/Gear.astro';
3
+ import Search from './Search.astro';
4
+ import { getFrameworkFromPath } from '../config/frameworks.js';
5
+ import type { ThemeIconKey } from '../config/themes';
6
+ import { THEMES_DARK, THEMES_LIGHT } from '../config/themes';
7
+ import Owl from './icons/Owl.astro';
8
+ import Palette from './icons/Palette.astro';
9
+ import Flame from './icons/Flame.astro';
10
+ import Sunset from './icons/Sunset.astro';
11
+ import Zap from './icons/Zap.astro';
12
+ import Shield from './icons/Shield.astro';
13
+ import Heart from './icons/Heart.astro';
14
+ import Sun from './icons/Sun.astro';
15
+ import Cake from './icons/Cake.astro';
16
+ import Lemon from './icons/Lemon.astro';
17
+ import Rainbow from './icons/Rainbow.astro';
18
+ import Leaf from './icons/Leaf.astro';
19
+ import Cherry from './icons/Cherry.astro';
20
+ import Brush from './icons/Brush.astro';
21
+
22
+ // Extend Window interface for openSettings
23
+ declare global {
24
+ interface Window {
25
+ openSettings?: () => void;
26
+ }
27
+ }
28
+
29
+ interface Props {
30
+ siteName?: string;
31
+ logo?: string;
32
+ }
33
+
34
+ const { siteName = 'Rizzo CSS', logo } = Astro.props;
35
+
36
+ // Get current URL pathname and framework for component links only
37
+ const currentPath = Astro.url.pathname;
38
+ const { framework } = getFrameworkFromPath(currentPath);
39
+ const docsPrefix = framework.pathPrefix;
40
+
41
+ /** Use only for component routes; docs and themes are general (no framework prefix). */
42
+ function componentHref(path: string): string {
43
+ if (!path.startsWith('/docs')) return path;
44
+ return docsPrefix + path.slice('/docs'.length) || docsPrefix || '/';
45
+ }
46
+
47
+ // Navigation links with optional sub-links (doc paths are rewritten by docHref)
48
+ interface NavLink {
49
+ href: string;
50
+ label: string;
51
+ subLinks?: Array<{ href: string; label: string }>;
52
+ /** Components dropdown: overview full width, then two columns of links */
53
+ componentsMenu?: {
54
+ overview: { href: string; label: string };
55
+ links: Array<{ href: string; label: string }>;
56
+ };
57
+ /** Themes dropdown: overview full width, then Dark | Light columns with icons */
58
+ themesMenu?: {
59
+ overview: { href: string; label: string };
60
+ dark: Array<{ href: string; label: string; icon: typeof Owl }>;
61
+ light: Array<{ href: string; label: string; icon: typeof Owl }>;
62
+ };
63
+ }
64
+
65
+ const themeIconMap: Record<ThemeIconKey, typeof Owl> = {
66
+ gear: Gear,
67
+ owl: Owl,
68
+ palette: Palette,
69
+ flame: Flame,
70
+ sunset: Sunset,
71
+ zap: Zap,
72
+ shield: Shield,
73
+ heart: Heart,
74
+ sun: Sun,
75
+ cake: Cake,
76
+ lemon: Lemon,
77
+ rainbow: Rainbow,
78
+ leaf: Leaf,
79
+ cherry: Cherry,
80
+ brush: Brush,
81
+ };
82
+
83
+ const navLinks: NavLink[] = [
84
+ { href: '/', label: 'Home' },
85
+ {
86
+ href: '/docs/getting-started',
87
+ label: 'Docs',
88
+ subLinks: [
89
+ { href: '/docs/getting-started', label: 'Getting Started' },
90
+ { href: '/docs/design-system', label: 'Design System' },
91
+ { href: '/docs/accessibility', label: 'Accessibility' },
92
+ { href: '/docs/colors', label: 'Colors' },
93
+ ],
94
+ },
95
+ {
96
+ href: componentHref('/docs/components'),
97
+ label: 'Components',
98
+ componentsMenu: {
99
+ overview: { href: componentHref('/docs/components'), label: 'Overview' },
100
+ links: [
101
+ { href: componentHref('/docs/components/accordion'), label: 'Accordion' },
102
+ { href: componentHref('/docs/components/alert'), label: 'Alert' },
103
+ { href: componentHref('/docs/components/avatar'), label: 'Avatar' },
104
+ { href: componentHref('/docs/components/badge'), label: 'Badge' },
105
+ { href: componentHref('/docs/components/breadcrumb'), label: 'Breadcrumb' },
106
+ { href: componentHref('/docs/components/button'), label: 'Button' },
107
+ { href: componentHref('/docs/components/cards'), label: 'Cards' },
108
+ { href: componentHref('/docs/components/copy-to-clipboard'), label: 'CopyToClipboard' },
109
+ { href: componentHref('/docs/components/divider'), label: 'Divider' },
110
+ { href: componentHref('/docs/components/dropdown'), label: 'Dropdown' },
111
+ { href: componentHref('/docs/components/forms'), label: 'Forms' },
112
+ { href: componentHref('/docs/components/icons'), label: 'Icons' },
113
+ { href: componentHref('/docs/components/modal'), label: 'Modal' },
114
+ { href: componentHref('/docs/components/navbar'), label: 'Navbar' },
115
+ { href: componentHref('/docs/components/pagination'), label: 'Pagination' },
116
+ { href: componentHref('/docs/components/progress-bar'), label: 'Progress Bar' },
117
+ { href: componentHref('/docs/components/search'), label: 'Search' },
118
+ { href: componentHref('/docs/components/settings'), label: 'Settings' },
119
+ { href: componentHref('/docs/components/spinner'), label: 'Spinner' },
120
+ { href: componentHref('/docs/components/table'), label: 'Table' },
121
+ { href: componentHref('/docs/components/tabs'), label: 'Tabs' },
122
+ { href: componentHref('/docs/components/theme-switcher'), label: 'Theme Switcher' },
123
+ { href: componentHref('/docs/components/toast'), label: 'Toast' },
124
+ { href: componentHref('/docs/components/tooltip'), label: 'Tooltip' },
125
+ ],
126
+ },
127
+ },
128
+ {
129
+ href: '/docs/theming',
130
+ label: 'Themes',
131
+ themesMenu: {
132
+ overview: { href: '/docs/theming', label: 'Overview' },
133
+ dark: THEMES_DARK.map((t) => ({
134
+ href: `/docs/themes/${t.value}`,
135
+ label: t.label,
136
+ icon: themeIconMap[t.iconKey],
137
+ })),
138
+ light: THEMES_LIGHT.map((t) => ({
139
+ href: `/docs/themes/${t.value}`,
140
+ label: t.label,
141
+ icon: themeIconMap[t.iconKey],
142
+ })),
143
+ },
144
+ },
145
+ ];
146
+ ---
147
+
148
+ <nav class="navbar" role="navigation" aria-label="Main navigation">
149
+ <div class="navbar__container">
150
+ <div class="navbar__brand">
151
+ {logo && (
152
+ <img src={logo} alt={`${siteName} logo`} class="navbar__logo" />
153
+ )}
154
+ <a href="/" class="navbar__brand-link" aria-label={`${siteName} home`}>
155
+ {siteName}
156
+ </a>
157
+ </div>
158
+
159
+ <div class="navbar__actions-desktop">
160
+ <Search />
161
+ <div class="tooltip-wrapper" aria-describedby="navbar-settings-tooltip">
162
+ <button
163
+ class="navbar__settings-btn"
164
+ type="button"
165
+ aria-label="Open settings"
166
+ onclick="window.openSettings && window.openSettings()"
167
+ >
168
+ <Gear class="navbar__settings-icon" width={20} height={20} />
169
+ <span class="navbar__settings-label">Settings</span>
170
+ </button>
171
+ <span class="tooltip tooltip--bottom" id="navbar-settings-tooltip" role="tooltip" aria-hidden="true">Settings</span>
172
+ </div>
173
+ </div>
174
+
175
+ <button
176
+ class="navbar__toggle"
177
+ type="button"
178
+ aria-expanded="false"
179
+ aria-controls="navbar-menu"
180
+ aria-label="Toggle navigation menu"
181
+ id="navbar-toggle"
182
+ >
183
+ <span class="sr-only">Menu</span>
184
+ <span class="navbar__toggle-icon" aria-hidden="true">
185
+ <span></span>
186
+ <span></span>
187
+ <span></span>
188
+ </span>
189
+ </button>
190
+
191
+ <div class="navbar__menu" id="navbar-menu" role="menu">
192
+ {navLinks.map((link) => {
193
+ const isActive = currentPath === link.href || (link.href !== '/' && currentPath.startsWith(link.href));
194
+ const hasSubLinks = (link.subLinks && link.subLinks.length > 0) || !!link.componentsMenu || !!link.themesMenu;
195
+ const subLinkId = hasSubLinks ? `navbar-submenu-${link.label.toLowerCase().replace(/\s+/g, '-')}` : undefined;
196
+
197
+ return (
198
+ <div class={`navbar__item ${hasSubLinks ? 'navbar__item--has-dropdown' : ''}`}>
199
+ {hasSubLinks ? (
200
+ <div
201
+ class="navbar__link"
202
+ role="menuitem"
203
+ tabindex={0}
204
+ aria-label={link.label}
205
+ aria-expanded="false"
206
+ aria-haspopup="true"
207
+ aria-controls={subLinkId}
208
+ data-dropdown-toggle={subLinkId}
209
+ data-dropdown-href={link.href}
210
+ >
211
+ {link.label}
212
+ <svg class="navbar__dropdown-icon" width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
213
+ <path d="M2 4l4 4 4-4"/>
214
+ </svg>
215
+ </div>
216
+ ) : (
217
+ <div
218
+ class="navbar__link"
219
+ role="menuitem"
220
+ tabindex={0}
221
+ aria-label={link.label}
222
+ aria-current={isActive ? 'page' : undefined}
223
+ data-nav-href={link.href}
224
+ >
225
+ {link.label}
226
+ </div>
227
+ )}
228
+ {link.componentsMenu ? (
229
+ <ul class="navbar__submenu navbar__submenu--components" id={subLinkId} role="menu" aria-label={`${link.label} submenu`}>
230
+ <li class="navbar__submenu-overview" role="none">
231
+ <div
232
+ class="navbar__sublink navbar__sublink--overview"
233
+ role="menuitem"
234
+ tabindex={-1}
235
+ aria-label={link.componentsMenu.overview.label}
236
+ aria-current={currentPath === link.componentsMenu.overview.href ? 'page' : undefined}
237
+ data-nav-href={link.componentsMenu.overview.href}
238
+ >
239
+ {link.componentsMenu.overview.label}
240
+ </div>
241
+ </li>
242
+ <li class="navbar__submenu-components-grid" role="none">
243
+ <div class="navbar__submenu-column">
244
+ {link.componentsMenu.links.slice(0, Math.ceil(link.componentsMenu.links.length / 2)).map((subLink) => {
245
+ const isSubActive = currentPath === subLink.href;
246
+ return (
247
+ <div
248
+ class="navbar__sublink"
249
+ role="menuitem"
250
+ tabindex={-1}
251
+ aria-label={subLink.label}
252
+ aria-current={isSubActive ? 'page' : undefined}
253
+ data-nav-href={subLink.href}
254
+ >
255
+ {subLink.label}
256
+ </div>
257
+ );
258
+ })}
259
+ </div>
260
+ <div class="navbar__submenu-column">
261
+ {link.componentsMenu.links.slice(Math.ceil(link.componentsMenu.links.length / 2)).map((subLink) => {
262
+ const isSubActive = currentPath === subLink.href;
263
+ return (
264
+ <div
265
+ class="navbar__sublink"
266
+ role="menuitem"
267
+ tabindex={-1}
268
+ aria-label={subLink.label}
269
+ aria-current={isSubActive ? 'page' : undefined}
270
+ data-nav-href={subLink.href}
271
+ >
272
+ {subLink.label}
273
+ </div>
274
+ );
275
+ })}
276
+ </div>
277
+ </li>
278
+ </ul>
279
+ ) : link.themesMenu ? (
280
+ <ul class="navbar__submenu navbar__submenu--themes" id={subLinkId} role="menu" aria-label={`${link.label} submenu`}>
281
+ <li class="navbar__submenu-overview" role="none">
282
+ <div
283
+ class="navbar__sublink navbar__sublink--overview"
284
+ role="menuitem"
285
+ tabindex={-1}
286
+ aria-label={link.themesMenu.overview.label}
287
+ aria-current={currentPath === link.themesMenu.overview.href ? 'page' : undefined}
288
+ data-nav-href={link.themesMenu.overview.href}
289
+ >
290
+ {link.themesMenu.overview.label}
291
+ </div>
292
+ </li>
293
+ <li class="navbar__submenu-themes-grid" role="none">
294
+ <div class="navbar__submenu-column">
295
+ <span class="navbar__submenu-column-label" aria-hidden="true">Dark themes</span>
296
+ {link.themesMenu.dark.map((theme) => {
297
+ const isSubActive = currentPath === theme.href;
298
+ const ThemeIcon = theme.icon;
299
+ return (
300
+ <div
301
+ class="navbar__sublink navbar__sublink--with-icon"
302
+ role="menuitem"
303
+ tabindex={-1}
304
+ aria-label={theme.label}
305
+ aria-current={isSubActive ? 'page' : undefined}
306
+ data-nav-href={theme.href}
307
+ >
308
+ <ThemeIcon width={16} height={16} class="navbar__sublink-icon" />
309
+ <span class="navbar__sublink-text">{theme.label}</span>
310
+ </div>
311
+ );
312
+ })}
313
+ </div>
314
+ <div class="navbar__submenu-column">
315
+ <span class="navbar__submenu-column-label" aria-hidden="true">Light themes</span>
316
+ {link.themesMenu.light.map((theme) => {
317
+ const isSubActive = currentPath === theme.href;
318
+ const ThemeIcon = theme.icon;
319
+ return (
320
+ <div
321
+ class="navbar__sublink navbar__sublink--with-icon"
322
+ role="menuitem"
323
+ tabindex={-1}
324
+ aria-label={theme.label}
325
+ aria-current={isSubActive ? 'page' : undefined}
326
+ data-nav-href={theme.href}
327
+ >
328
+ <ThemeIcon width={16} height={16} class="navbar__sublink-icon" />
329
+ <span class="navbar__sublink-text">{theme.label}</span>
330
+ </div>
331
+ );
332
+ })}
333
+ </div>
334
+ </li>
335
+ </ul>
336
+ ) : hasSubLinks && link.subLinks ? (
337
+ <ul class="navbar__submenu" id={subLinkId} role="menu" aria-label={`${link.label} submenu`}>
338
+ {link.subLinks.map((subLink) => {
339
+ const isSubActive = currentPath === subLink.href;
340
+ return (
341
+ <li role="none">
342
+ <div
343
+ class="navbar__sublink"
344
+ role="menuitem"
345
+ tabindex={-1}
346
+ aria-label={subLink.label}
347
+ aria-current={isSubActive ? 'page' : undefined}
348
+ data-nav-href={subLink.href}
349
+ >
350
+ {subLink.label}
351
+ </div>
352
+ </li>
353
+ );
354
+ })}
355
+ </ul>
356
+ ) : null}
357
+ </div>
358
+ );
359
+ })}
360
+ </div>
361
+ </div>
362
+ </nav>
363
+
364
+ <script>
365
+ (function initNavbar() {
366
+ const navbar = document.querySelector('.navbar');
367
+ if (!navbar) return;
368
+
369
+ const menuToggleBtn = document.getElementById('navbar-toggle');
370
+ const menu = navbar.querySelector('.navbar__menu');
371
+
372
+ if (!menuToggleBtn || !menu) return;
373
+
374
+ const toggleMenu = (open?: boolean) => {
375
+ const isOpen = open !== undefined ? open : menu.classList.contains('navbar__menu--open');
376
+ const willBeOpen = !isOpen;
377
+
378
+ // On mobile, close search if it's open when opening menu
379
+ const isMobile = window.innerWidth <= 1023;
380
+ if (isMobile && !isOpen) {
381
+ // Menu is about to open, close any open search instance
382
+ document.querySelectorAll('[data-search]').forEach((search) => {
383
+ const panel = search.querySelector('.search__panel');
384
+ if (panel?.getAttribute('aria-hidden') === 'false') {
385
+ const el = search as Element & { __searchInstance?: { closeSearch?: () => void } };
386
+ if (el?.__searchInstance?.closeSearch) {
387
+ el.__searchInstance.closeSearch();
388
+ } else {
389
+ const overlay = search.querySelector('[data-search-overlay]');
390
+ if (overlay instanceof HTMLElement) overlay.click();
391
+ }
392
+ }
393
+ });
394
+ }
395
+
396
+ // Toggle class on navbar to hide/show bottom border
397
+ if (willBeOpen) {
398
+ navbar.classList.add('navbar--menu-open');
399
+ } else {
400
+ navbar.classList.remove('navbar--menu-open');
401
+ }
402
+
403
+ menu.classList.toggle('navbar__menu--open', !isOpen);
404
+ menuToggleBtn.setAttribute('aria-expanded', (!isOpen).toString());
405
+ };
406
+
407
+ menuToggleBtn.addEventListener('click', (e) => {
408
+ const target = e.target as Element;
409
+ // Only skip if click was inside the menu (e.g. dropdown toggle) - not when clicking the hamburger
410
+ if (target.closest('#navbar-menu') && target.closest('[data-dropdown-toggle]')) {
411
+ return;
412
+ }
413
+ toggleMenu();
414
+ });
415
+
416
+ // Navigate when activating menu items that use data-nav-href (non-interactive element with role=menuitem)
417
+ const navHrefHandler = (e: Event) => {
418
+ const target = (e.target as Element).closest('[data-nav-href]');
419
+ if (target && target instanceof HTMLElement) {
420
+ const href = target.getAttribute('data-nav-href');
421
+ if (href) {
422
+ e.preventDefault();
423
+ window.location.href = href;
424
+ }
425
+ }
426
+ };
427
+ navbar.addEventListener('click', navHrefHandler);
428
+ navbar.addEventListener('keydown', (e: Event) => {
429
+ const keyEvent = e as KeyboardEvent;
430
+ if (keyEvent.key === 'Enter' || keyEvent.key === ' ') {
431
+ const target = (keyEvent.target as Element).closest('[data-nav-href]');
432
+ if (target && target instanceof HTMLElement) {
433
+ const href = target.getAttribute('data-nav-href');
434
+ if (href) {
435
+ keyEvent.preventDefault();
436
+ window.location.href = href;
437
+ }
438
+ }
439
+ }
440
+ });
441
+
442
+ // Dropdown menu handling
443
+ const dropdownToggles = navbar.querySelectorAll('[data-dropdown-toggle]');
444
+ dropdownToggles.forEach((dropdownToggleBtn) => {
445
+ const item = dropdownToggleBtn.closest('.navbar__item--has-dropdown');
446
+ if (!item) return;
447
+
448
+ const submenu = item.querySelector('.navbar__submenu');
449
+ const sublinks = submenu ? Array.from(submenu.querySelectorAll('.navbar__sublink')) : [];
450
+
451
+ // Adjust dropdown alignment to prevent overflow
452
+ const adjustDropdownPosition = () => {
453
+ if (!submenu || window.innerWidth <= 1023) return; // Skip on mobile
454
+
455
+ const submenuEl = submenu as HTMLElement;
456
+
457
+ // Temporarily make visible to measure
458
+ const wasVisible = submenuEl.style.visibility !== 'hidden';
459
+ if (!wasVisible) {
460
+ submenuEl.style.visibility = 'hidden';
461
+ submenuEl.style.opacity = '1';
462
+ submenuEl.style.display = 'block';
463
+ }
464
+
465
+ const itemRect = item.getBoundingClientRect();
466
+ const submenuWidth = submenuEl.offsetWidth || submenuEl.scrollWidth;
467
+ const viewportWidth = window.innerWidth;
468
+ const padding = 16; // Viewport padding
469
+
470
+ // Check if dropdown would overflow on the right
471
+ if (itemRect.left + submenuWidth > viewportWidth - padding) {
472
+ // Align to right edge of parent item
473
+ submenuEl.style.left = 'auto';
474
+ submenuEl.style.right = '0';
475
+ } else {
476
+ // Default: align to left edge
477
+ submenuEl.style.left = '0';
478
+ submenuEl.style.right = 'auto';
479
+ }
480
+
481
+ // Restore visibility state
482
+ if (!wasVisible) {
483
+ submenuEl.style.visibility = '';
484
+ submenuEl.style.opacity = '';
485
+ submenuEl.style.display = '';
486
+ }
487
+ };
488
+
489
+ const handleToggle = (e: Event) => {
490
+ e.preventDefault();
491
+ e.stopPropagation();
492
+ e.stopImmediatePropagation();
493
+
494
+ const isMobile = window.innerWidth <= 1023;
495
+ const isExpanded = item.getAttribute('aria-expanded') === 'true';
496
+
497
+ // On mobile, preserve scroll position to prevent jarring
498
+ let scrollTop = 0;
499
+ if (isMobile && menu) {
500
+ scrollTop = (menu as HTMLElement).scrollTop;
501
+ }
502
+
503
+ item.setAttribute('aria-expanded', (!isExpanded).toString());
504
+
505
+ // Adjust position when opening
506
+ if (!isExpanded) {
507
+ setTimeout(() => {
508
+ adjustDropdownPosition();
509
+
510
+ // Restore scroll position on mobile to prevent jarring
511
+ if (isMobile && menu) {
512
+ (menu as HTMLElement).scrollTop = scrollTop;
513
+ }
514
+ }, 0);
515
+ }
516
+
517
+ // Focus management - only on desktop
518
+ if (!isMobile && !isExpanded && sublinks.length > 0) {
519
+ setTimeout(() => (sublinks[0] as HTMLElement).focus(), 0);
520
+ }
521
+ };
522
+
523
+ // Always use capture phase to ensure we handle it before any other listeners
524
+ dropdownToggleBtn.addEventListener('click', handleToggle, true);
525
+
526
+ // Keyboard navigation on dropdown toggle
527
+ dropdownToggleBtn.addEventListener('keydown', (e: Event) => {
528
+ const keyEvent = e as KeyboardEvent;
529
+ if (keyEvent.key === 'Enter' || keyEvent.key === ' ') {
530
+ keyEvent.preventDefault();
531
+ handleToggle(e);
532
+ } else if (keyEvent.key === 'ArrowDown' && sublinks.length > 0) {
533
+ keyEvent.preventDefault();
534
+ const isExpanded = item.getAttribute('aria-expanded') === 'true';
535
+ if (!isExpanded) {
536
+ item.setAttribute('aria-expanded', 'true');
537
+ adjustDropdownPosition();
538
+ }
539
+ setTimeout(() => (sublinks[0] as HTMLElement).focus(), 0);
540
+ } else if (keyEvent.key === 'ArrowUp' && sublinks.length > 0) {
541
+ keyEvent.preventDefault();
542
+ const isExpanded = item.getAttribute('aria-expanded') === 'true';
543
+ if (!isExpanded) {
544
+ item.setAttribute('aria-expanded', 'true');
545
+ adjustDropdownPosition();
546
+ }
547
+ // Focus last item when ArrowUp from toggle
548
+ setTimeout(() => (sublinks[sublinks.length - 1] as HTMLElement).focus(), 0);
549
+ } else if (keyEvent.key === 'Escape') {
550
+ keyEvent.preventDefault();
551
+ item.setAttribute('aria-expanded', 'false');
552
+ }
553
+ });
554
+
555
+ // Keyboard navigation within submenu
556
+ if (submenu) {
557
+ submenu.addEventListener('keydown', (e: Event) => {
558
+ const keyEvent = e as KeyboardEvent;
559
+ const currentIndex = sublinks.findIndex(link => link === document.activeElement);
560
+
561
+ if (keyEvent.key === 'Escape') {
562
+ keyEvent.preventDefault();
563
+ item.setAttribute('aria-expanded', 'false');
564
+ (dropdownToggleBtn as HTMLElement).focus();
565
+ } else if (keyEvent.key === 'ArrowDown') {
566
+ keyEvent.preventDefault();
567
+ const nextIndex = (currentIndex + 1) % sublinks.length;
568
+ (sublinks[nextIndex] as HTMLElement).focus();
569
+ } else if (keyEvent.key === 'ArrowUp') {
570
+ keyEvent.preventDefault();
571
+ const prevIndex = currentIndex <= 0 ? sublinks.length - 1 : currentIndex - 1;
572
+ (sublinks[prevIndex] as HTMLElement).focus();
573
+ } else if (keyEvent.key === 'Home') {
574
+ keyEvent.preventDefault();
575
+ (sublinks[0] as HTMLElement).focus();
576
+ } else if (keyEvent.key === 'End') {
577
+ keyEvent.preventDefault();
578
+ (sublinks[sublinks.length - 1] as HTMLElement).focus();
579
+ } else if (keyEvent.key === 'Tab') {
580
+ // Close dropdown when Tab is pressed (allows natural tab flow)
581
+ item.setAttribute('aria-expanded', 'false');
582
+ } else if (keyEvent.key === 'Enter' || keyEvent.key === ' ') {
583
+ // Allow Enter/Space to activate links naturally
584
+ // The click handler will handle navigation
585
+ }
586
+ });
587
+ }
588
+
589
+ // Adjust on hover (for desktop)
590
+ if (window.innerWidth > 1023) {
591
+ item.addEventListener('mouseenter', () => {
592
+ // Small delay to ensure submenu is rendered
593
+ requestAnimationFrame(() => {
594
+ requestAnimationFrame(() => {
595
+ adjustDropdownPosition();
596
+ });
597
+ });
598
+ });
599
+ }
600
+
601
+ // Adjust on window resize
602
+ window.addEventListener('resize', adjustDropdownPosition);
603
+
604
+ // Close on outside click
605
+ document.addEventListener('click', (e) => {
606
+ const target = e.target;
607
+ // Don't close if clicking on the dropdown toggle or its children
608
+ const clickedToggle = target && target instanceof Element && (
609
+ target === dropdownToggleBtn ||
610
+ target.closest('[data-dropdown-toggle]') === dropdownToggleBtn
611
+ );
612
+ if (target && target instanceof Node && !item.contains(target) && !clickedToggle) {
613
+ item.setAttribute('aria-expanded', 'false');
614
+ }
615
+ });
616
+ });
617
+
618
+ // Close menu on outside click
619
+ document.addEventListener('click', (e) => {
620
+ const target = e.target as Node | null;
621
+ // Don't close if clicking inside the navbar (including dropdown toggles and their children)
622
+ if (target && navbar.contains(target as Node)) {
623
+ // Also check if it's specifically a dropdown toggle or submenu item
624
+ const element = target as Element;
625
+ if (element && (
626
+ element.closest('[data-dropdown-toggle]') ||
627
+ element.closest('.navbar__submenu') ||
628
+ element.closest('.navbar__sublink')
629
+ )) {
630
+ return; // Click is on dropdown-related element, don't close menu
631
+ }
632
+ return; // Click is inside navbar, don't close menu
633
+ }
634
+ // Only close if clicking completely outside the navbar
635
+ if (target && !navbar.contains(target as Node)) {
636
+ menu.classList.remove('navbar__menu--open');
637
+ menuToggleBtn.setAttribute('aria-expanded', 'false');
638
+ // Close all dropdowns
639
+ dropdownToggles.forEach((dt) => {
640
+ const item = dt.closest('.navbar__item--has-dropdown');
641
+ if (item) item.setAttribute('aria-expanded', 'false');
642
+ });
643
+ }
644
+ });
645
+
646
+ // Close menu on Escape key
647
+ document.addEventListener('keydown', (e: Event) => {
648
+ const keyEvent = e as KeyboardEvent;
649
+ if (keyEvent.key === 'Escape') {
650
+ if (menu.classList.contains('navbar__menu--open')) {
651
+ toggleMenu(false);
652
+ menuToggleBtn.focus();
653
+ }
654
+ // Close all dropdowns
655
+ dropdownToggles.forEach((dt) => {
656
+ const item = dt.closest('.navbar__item--has-dropdown');
657
+ if (item) {
658
+ item.setAttribute('aria-expanded', 'false');
659
+ (dt as HTMLElement).focus();
660
+ }
661
+ });
662
+ }
663
+ });
664
+
665
+ // Settings button keyboard handler
666
+ const settingsBtn = navbar.querySelector('.navbar__settings-btn');
667
+ if (settingsBtn) {
668
+ settingsBtn.addEventListener('click', () => {
669
+ if (window.openSettings) {
670
+ window.openSettings();
671
+ }
672
+ });
673
+ settingsBtn.addEventListener('keydown', (e: Event) => {
674
+ const keyEvent = e as KeyboardEvent;
675
+ if (keyEvent.key === 'Enter' || keyEvent.key === ' ') {
676
+ keyEvent.preventDefault();
677
+ if (window.openSettings) {
678
+ window.openSettings();
679
+ }
680
+ }
681
+ });
682
+ }
683
+
684
+ // Handle window resize
685
+ let resizeTimer: ReturnType<typeof setTimeout> | undefined;
686
+ window.addEventListener('resize', () => {
687
+ if (resizeTimer) clearTimeout(resizeTimer);
688
+ resizeTimer = setTimeout(() => {
689
+ if (window.innerWidth >= 1024) {
690
+ menu.classList.remove('navbar__menu--open');
691
+ menuToggleBtn.setAttribute('aria-expanded', 'false');
692
+ // Close all dropdowns
693
+ dropdownToggles.forEach((dt) => {
694
+ const item = dt.closest('.navbar__item--has-dropdown');
695
+ if (item) item.setAttribute('aria-expanded', 'false');
696
+ });
697
+ }
698
+ }, 250);
699
+ });
700
+ })();
701
+ </script>