@atomng/ui 1.0.0

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 (299) hide show
  1. package/README.md +401 -0
  2. package/atomng-ui.d.ts.map +1 -0
  3. package/atoms/atomng-ui-atoms.d.ts.map +1 -0
  4. package/atoms/avatar/avatar.component.d.ts +24 -0
  5. package/atoms/avatar/avatar.component.d.ts.map +1 -0
  6. package/atoms/avatar/index.d.ts +3 -0
  7. package/atoms/avatar/index.d.ts.map +1 -0
  8. package/atoms/badge/badge.component.d.ts +23 -0
  9. package/atoms/badge/badge.component.d.ts.map +1 -0
  10. package/atoms/badge/index.d.ts +3 -0
  11. package/atoms/badge/index.d.ts.map +1 -0
  12. package/atoms/button/button.component.d.ts +47 -0
  13. package/atoms/button/button.component.d.ts.map +1 -0
  14. package/atoms/button/index.d.ts +3 -0
  15. package/atoms/button/index.d.ts.map +1 -0
  16. package/atoms/checkbox/checkbox.component.d.ts +28 -0
  17. package/atoms/checkbox/checkbox.component.d.ts.map +1 -0
  18. package/atoms/checkbox/index.d.ts +2 -0
  19. package/atoms/checkbox/index.d.ts.map +1 -0
  20. package/atoms/chip/chip.component.d.ts +17 -0
  21. package/atoms/chip/chip.component.d.ts.map +1 -0
  22. package/atoms/chip/index.d.ts +2 -0
  23. package/atoms/chip/index.d.ts.map +1 -0
  24. package/atoms/index.d.ts +14 -0
  25. package/atoms/index.d.ts.map +1 -0
  26. package/atoms/kbd/index.d.ts +2 -0
  27. package/atoms/kbd/index.d.ts.map +1 -0
  28. package/atoms/kbd/kbd.component.d.ts +14 -0
  29. package/atoms/kbd/kbd.component.d.ts.map +1 -0
  30. package/atoms/link/index.d.ts +2 -0
  31. package/atoms/link/index.d.ts.map +1 -0
  32. package/atoms/link/link.component.d.ts +15 -0
  33. package/atoms/link/link.component.d.ts.map +1 -0
  34. package/atoms/progress/index.d.ts +3 -0
  35. package/atoms/progress/index.d.ts.map +1 -0
  36. package/atoms/progress/progress.component.d.ts +20 -0
  37. package/atoms/progress/progress.component.d.ts.map +1 -0
  38. package/atoms/separator/index.d.ts +2 -0
  39. package/atoms/separator/index.d.ts.map +1 -0
  40. package/atoms/separator/separator.component.d.ts +13 -0
  41. package/atoms/separator/separator.component.d.ts.map +1 -0
  42. package/atoms/skeleton/index.d.ts +2 -0
  43. package/atoms/skeleton/index.d.ts.map +1 -0
  44. package/atoms/skeleton/skeleton.component.d.ts +13 -0
  45. package/atoms/skeleton/skeleton.component.d.ts.map +1 -0
  46. package/atoms/slider/index.d.ts +2 -0
  47. package/atoms/slider/index.d.ts.map +1 -0
  48. package/atoms/slider/slider.component.d.ts +27 -0
  49. package/atoms/slider/slider.component.d.ts.map +1 -0
  50. package/atoms/switch/index.d.ts +2 -0
  51. package/atoms/switch/index.d.ts.map +1 -0
  52. package/atoms/switch/switch.component.d.ts +25 -0
  53. package/atoms/switch/switch.component.d.ts.map +1 -0
  54. package/atoms/tooltip/index.d.ts +2 -0
  55. package/atoms/tooltip/index.d.ts.map +1 -0
  56. package/atoms/tooltip/tooltip.component.d.ts +15 -0
  57. package/atoms/tooltip/tooltip.component.d.ts.map +1 -0
  58. package/fesm2022/atomng-ui-atoms.mjs +778 -0
  59. package/fesm2022/atomng-ui-atoms.mjs.map +1 -0
  60. package/fesm2022/atomng-ui-molecules.mjs +1590 -0
  61. package/fesm2022/atomng-ui-molecules.mjs.map +1 -0
  62. package/fesm2022/atomng-ui-organisms.mjs +1346 -0
  63. package/fesm2022/atomng-ui-organisms.mjs.map +1 -0
  64. package/fesm2022/atomng-ui-tokens.mjs +499 -0
  65. package/fesm2022/atomng-ui-tokens.mjs.map +1 -0
  66. package/fesm2022/atomng-ui.mjs +4184 -0
  67. package/fesm2022/atomng-ui.mjs.map +1 -0
  68. package/index.d.ts +5 -0
  69. package/index.d.ts.map +1 -0
  70. package/lib/atoms/avatar/avatar.component.d.ts +24 -0
  71. package/lib/atoms/avatar/avatar.component.d.ts.map +1 -0
  72. package/lib/atoms/avatar/index.d.ts +3 -0
  73. package/lib/atoms/avatar/index.d.ts.map +1 -0
  74. package/lib/atoms/badge/badge.component.d.ts +23 -0
  75. package/lib/atoms/badge/badge.component.d.ts.map +1 -0
  76. package/lib/atoms/badge/index.d.ts +3 -0
  77. package/lib/atoms/badge/index.d.ts.map +1 -0
  78. package/lib/atoms/button/button.component.d.ts +47 -0
  79. package/lib/atoms/button/button.component.d.ts.map +1 -0
  80. package/lib/atoms/button/index.d.ts +3 -0
  81. package/lib/atoms/button/index.d.ts.map +1 -0
  82. package/lib/atoms/checkbox/checkbox.component.d.ts +28 -0
  83. package/lib/atoms/checkbox/checkbox.component.d.ts.map +1 -0
  84. package/lib/atoms/checkbox/index.d.ts +2 -0
  85. package/lib/atoms/checkbox/index.d.ts.map +1 -0
  86. package/lib/atoms/chip/chip.component.d.ts +17 -0
  87. package/lib/atoms/chip/chip.component.d.ts.map +1 -0
  88. package/lib/atoms/chip/index.d.ts +2 -0
  89. package/lib/atoms/chip/index.d.ts.map +1 -0
  90. package/lib/atoms/index.d.ts +14 -0
  91. package/lib/atoms/index.d.ts.map +1 -0
  92. package/lib/atoms/kbd/index.d.ts +2 -0
  93. package/lib/atoms/kbd/index.d.ts.map +1 -0
  94. package/lib/atoms/kbd/kbd.component.d.ts +14 -0
  95. package/lib/atoms/kbd/kbd.component.d.ts.map +1 -0
  96. package/lib/atoms/link/index.d.ts +2 -0
  97. package/lib/atoms/link/index.d.ts.map +1 -0
  98. package/lib/atoms/link/link.component.d.ts +15 -0
  99. package/lib/atoms/link/link.component.d.ts.map +1 -0
  100. package/lib/atoms/progress/index.d.ts +3 -0
  101. package/lib/atoms/progress/index.d.ts.map +1 -0
  102. package/lib/atoms/progress/progress.component.d.ts +20 -0
  103. package/lib/atoms/progress/progress.component.d.ts.map +1 -0
  104. package/lib/atoms/separator/index.d.ts +2 -0
  105. package/lib/atoms/separator/index.d.ts.map +1 -0
  106. package/lib/atoms/separator/separator.component.d.ts +13 -0
  107. package/lib/atoms/separator/separator.component.d.ts.map +1 -0
  108. package/lib/atoms/skeleton/index.d.ts +2 -0
  109. package/lib/atoms/skeleton/index.d.ts.map +1 -0
  110. package/lib/atoms/skeleton/skeleton.component.d.ts +13 -0
  111. package/lib/atoms/skeleton/skeleton.component.d.ts.map +1 -0
  112. package/lib/atoms/slider/index.d.ts +2 -0
  113. package/lib/atoms/slider/index.d.ts.map +1 -0
  114. package/lib/atoms/slider/slider.component.d.ts +27 -0
  115. package/lib/atoms/slider/slider.component.d.ts.map +1 -0
  116. package/lib/atoms/switch/index.d.ts +2 -0
  117. package/lib/atoms/switch/index.d.ts.map +1 -0
  118. package/lib/atoms/switch/switch.component.d.ts +25 -0
  119. package/lib/atoms/switch/switch.component.d.ts.map +1 -0
  120. package/lib/atoms/tooltip/index.d.ts +2 -0
  121. package/lib/atoms/tooltip/index.d.ts.map +1 -0
  122. package/lib/atoms/tooltip/tooltip.component.d.ts +15 -0
  123. package/lib/atoms/tooltip/tooltip.component.d.ts.map +1 -0
  124. package/lib/molecules/alert/alert.component.d.ts +22 -0
  125. package/lib/molecules/alert/alert.component.d.ts.map +1 -0
  126. package/lib/molecules/alert/index.d.ts +2 -0
  127. package/lib/molecules/alert/index.d.ts.map +1 -0
  128. package/lib/molecules/avatar-group/avatar-group.component.d.ts +22 -0
  129. package/lib/molecules/avatar-group/avatar-group.component.d.ts.map +1 -0
  130. package/lib/molecules/avatar-group/index.d.ts +2 -0
  131. package/lib/molecules/avatar-group/index.d.ts.map +1 -0
  132. package/lib/molecules/breadcrumb/breadcrumb.component.d.ts +17 -0
  133. package/lib/molecules/breadcrumb/breadcrumb.component.d.ts.map +1 -0
  134. package/lib/molecules/breadcrumb/index.d.ts +2 -0
  135. package/lib/molecules/breadcrumb/index.d.ts.map +1 -0
  136. package/lib/molecules/button-group/button-group.component.d.ts +11 -0
  137. package/lib/molecules/button-group/button-group.component.d.ts.map +1 -0
  138. package/lib/molecules/button-group/index.d.ts +2 -0
  139. package/lib/molecules/button-group/index.d.ts.map +1 -0
  140. package/lib/molecules/form-field/form-field.component.d.ts +18 -0
  141. package/lib/molecules/form-field/form-field.component.d.ts.map +1 -0
  142. package/lib/molecules/form-field/index.d.ts +2 -0
  143. package/lib/molecules/form-field/index.d.ts.map +1 -0
  144. package/lib/molecules/index.d.ts +13 -0
  145. package/lib/molecules/index.d.ts.map +1 -0
  146. package/lib/molecules/input/index.d.ts +2 -0
  147. package/lib/molecules/input/index.d.ts.map +1 -0
  148. package/lib/molecules/input/input.component.d.ts +50 -0
  149. package/lib/molecules/input/input.component.d.ts.map +1 -0
  150. package/lib/molecules/pagination/index.d.ts +2 -0
  151. package/lib/molecules/pagination/index.d.ts.map +1 -0
  152. package/lib/molecules/pagination/pagination.component.d.ts +18 -0
  153. package/lib/molecules/pagination/pagination.component.d.ts.map +1 -0
  154. package/lib/molecules/select/index.d.ts +3 -0
  155. package/lib/molecules/select/index.d.ts.map +1 -0
  156. package/lib/molecules/select/select.component.d.ts +56 -0
  157. package/lib/molecules/select/select.component.d.ts.map +1 -0
  158. package/lib/molecules/select-search/index.d.ts +2 -0
  159. package/lib/molecules/select-search/index.d.ts.map +1 -0
  160. package/lib/molecules/select-search/select-search.component.d.ts +63 -0
  161. package/lib/molecules/select-search/select-search.component.d.ts.map +1 -0
  162. package/lib/molecules/tabs/index.d.ts +2 -0
  163. package/lib/molecules/tabs/index.d.ts.map +1 -0
  164. package/lib/molecules/tabs/tabs.component.d.ts +23 -0
  165. package/lib/molecules/tabs/tabs.component.d.ts.map +1 -0
  166. package/lib/molecules/textarea/index.d.ts +2 -0
  167. package/lib/molecules/textarea/index.d.ts.map +1 -0
  168. package/lib/molecules/textarea/textarea.component.d.ts +27 -0
  169. package/lib/molecules/textarea/textarea.component.d.ts.map +1 -0
  170. package/lib/molecules/toast/index.d.ts +2 -0
  171. package/lib/molecules/toast/index.d.ts.map +1 -0
  172. package/lib/molecules/toast/toast.component.d.ts +19 -0
  173. package/lib/molecules/toast/toast.component.d.ts.map +1 -0
  174. package/lib/organisms/accordion/accordion.component.d.ts +25 -0
  175. package/lib/organisms/accordion/accordion.component.d.ts.map +1 -0
  176. package/lib/organisms/card/card.component.d.ts +14 -0
  177. package/lib/organisms/card/card.component.d.ts.map +1 -0
  178. package/lib/organisms/dropdown-menu/dropdown-menu.component.d.ts +29 -0
  179. package/lib/organisms/dropdown-menu/dropdown-menu.component.d.ts.map +1 -0
  180. package/lib/organisms/index.d.ts +8 -0
  181. package/lib/organisms/index.d.ts.map +1 -0
  182. package/lib/organisms/modal/modal.component.d.ts +19 -0
  183. package/lib/organisms/modal/modal.component.d.ts.map +1 -0
  184. package/lib/organisms/navigation-menu/navigation-menu.component.d.ts +24 -0
  185. package/lib/organisms/navigation-menu/navigation-menu.component.d.ts.map +1 -0
  186. package/lib/organisms/sidebar/sidebar.component.d.ts +68 -0
  187. package/lib/organisms/sidebar/sidebar.component.d.ts.map +1 -0
  188. package/lib/organisms/table/index.d.ts +3 -0
  189. package/lib/organisms/table/index.d.ts.map +1 -0
  190. package/lib/organisms/table/table-cell.directive.d.ts +17 -0
  191. package/lib/organisms/table/table-cell.directive.d.ts.map +1 -0
  192. package/lib/organisms/table/table.component.d.ts +50 -0
  193. package/lib/organisms/table/table.component.d.ts.map +1 -0
  194. package/lib/tokens/index.d.ts +2 -0
  195. package/lib/tokens/index.d.ts.map +1 -0
  196. package/lib/tokens/theme/color-presets.d.ts +24 -0
  197. package/lib/tokens/theme/color-presets.d.ts.map +1 -0
  198. package/lib/tokens/theme/index.d.ts +6 -0
  199. package/lib/tokens/theme/index.d.ts.map +1 -0
  200. package/lib/tokens/theme/theme-picker.component.d.ts +11 -0
  201. package/lib/tokens/theme/theme-picker.component.d.ts.map +1 -0
  202. package/lib/tokens/theme/theme-toggle.component.d.ts +15 -0
  203. package/lib/tokens/theme/theme-toggle.component.d.ts.map +1 -0
  204. package/lib/tokens/theme/theme.provider.d.ts +4 -0
  205. package/lib/tokens/theme/theme.provider.d.ts.map +1 -0
  206. package/lib/tokens/theme/theme.service.d.ts +48 -0
  207. package/lib/tokens/theme/theme.service.d.ts.map +1 -0
  208. package/molecules/alert/alert.component.d.ts +22 -0
  209. package/molecules/alert/alert.component.d.ts.map +1 -0
  210. package/molecules/alert/index.d.ts +2 -0
  211. package/molecules/alert/index.d.ts.map +1 -0
  212. package/molecules/atomng-ui-molecules.d.ts.map +1 -0
  213. package/molecules/avatar-group/avatar-group.component.d.ts +22 -0
  214. package/molecules/avatar-group/avatar-group.component.d.ts.map +1 -0
  215. package/molecules/avatar-group/index.d.ts +2 -0
  216. package/molecules/avatar-group/index.d.ts.map +1 -0
  217. package/molecules/breadcrumb/breadcrumb.component.d.ts +17 -0
  218. package/molecules/breadcrumb/breadcrumb.component.d.ts.map +1 -0
  219. package/molecules/breadcrumb/index.d.ts +2 -0
  220. package/molecules/breadcrumb/index.d.ts.map +1 -0
  221. package/molecules/button-group/button-group.component.d.ts +11 -0
  222. package/molecules/button-group/button-group.component.d.ts.map +1 -0
  223. package/molecules/button-group/index.d.ts +2 -0
  224. package/molecules/button-group/index.d.ts.map +1 -0
  225. package/molecules/form-field/form-field.component.d.ts +18 -0
  226. package/molecules/form-field/form-field.component.d.ts.map +1 -0
  227. package/molecules/form-field/index.d.ts +2 -0
  228. package/molecules/form-field/index.d.ts.map +1 -0
  229. package/molecules/index.d.ts +13 -0
  230. package/molecules/index.d.ts.map +1 -0
  231. package/molecules/input/index.d.ts +2 -0
  232. package/molecules/input/index.d.ts.map +1 -0
  233. package/molecules/input/input.component.d.ts +50 -0
  234. package/molecules/input/input.component.d.ts.map +1 -0
  235. package/molecules/pagination/index.d.ts +2 -0
  236. package/molecules/pagination/index.d.ts.map +1 -0
  237. package/molecules/pagination/pagination.component.d.ts +18 -0
  238. package/molecules/pagination/pagination.component.d.ts.map +1 -0
  239. package/molecules/select/index.d.ts +3 -0
  240. package/molecules/select/index.d.ts.map +1 -0
  241. package/molecules/select/select.component.d.ts +56 -0
  242. package/molecules/select/select.component.d.ts.map +1 -0
  243. package/molecules/select-search/index.d.ts +2 -0
  244. package/molecules/select-search/index.d.ts.map +1 -0
  245. package/molecules/select-search/select-search.component.d.ts +63 -0
  246. package/molecules/select-search/select-search.component.d.ts.map +1 -0
  247. package/molecules/tabs/index.d.ts +2 -0
  248. package/molecules/tabs/index.d.ts.map +1 -0
  249. package/molecules/tabs/tabs.component.d.ts +23 -0
  250. package/molecules/tabs/tabs.component.d.ts.map +1 -0
  251. package/molecules/textarea/index.d.ts +2 -0
  252. package/molecules/textarea/index.d.ts.map +1 -0
  253. package/molecules/textarea/textarea.component.d.ts +27 -0
  254. package/molecules/textarea/textarea.component.d.ts.map +1 -0
  255. package/molecules/toast/index.d.ts +2 -0
  256. package/molecules/toast/index.d.ts.map +1 -0
  257. package/molecules/toast/toast.component.d.ts +19 -0
  258. package/molecules/toast/toast.component.d.ts.map +1 -0
  259. package/organisms/accordion/accordion.component.d.ts +25 -0
  260. package/organisms/accordion/accordion.component.d.ts.map +1 -0
  261. package/organisms/atomng-ui-organisms.d.ts.map +1 -0
  262. package/organisms/card/card.component.d.ts +14 -0
  263. package/organisms/card/card.component.d.ts.map +1 -0
  264. package/organisms/dropdown-menu/dropdown-menu.component.d.ts +29 -0
  265. package/organisms/dropdown-menu/dropdown-menu.component.d.ts.map +1 -0
  266. package/organisms/index.d.ts +8 -0
  267. package/organisms/index.d.ts.map +1 -0
  268. package/organisms/modal/modal.component.d.ts +19 -0
  269. package/organisms/modal/modal.component.d.ts.map +1 -0
  270. package/organisms/navigation-menu/navigation-menu.component.d.ts +24 -0
  271. package/organisms/navigation-menu/navigation-menu.component.d.ts.map +1 -0
  272. package/organisms/sidebar/sidebar.component.d.ts +68 -0
  273. package/organisms/sidebar/sidebar.component.d.ts.map +1 -0
  274. package/organisms/table/index.d.ts +3 -0
  275. package/organisms/table/index.d.ts.map +1 -0
  276. package/organisms/table/table-cell.directive.d.ts +17 -0
  277. package/organisms/table/table-cell.directive.d.ts.map +1 -0
  278. package/organisms/table/table.component.d.ts +50 -0
  279. package/organisms/table/table.component.d.ts.map +1 -0
  280. package/package.json +81 -0
  281. package/tokens/_colors.scss +150 -0
  282. package/tokens/_spacing.scss +98 -0
  283. package/tokens/_typography.scss +59 -0
  284. package/tokens/atomng-ui-tokens.d.ts.map +1 -0
  285. package/tokens/index.d.ts +2 -0
  286. package/tokens/index.d.ts.map +1 -0
  287. package/tokens/index.scss +8 -0
  288. package/tokens/theme/color-presets.d.ts +24 -0
  289. package/tokens/theme/color-presets.d.ts.map +1 -0
  290. package/tokens/theme/index.d.ts +6 -0
  291. package/tokens/theme/index.d.ts.map +1 -0
  292. package/tokens/theme/theme-picker.component.d.ts +11 -0
  293. package/tokens/theme/theme-picker.component.d.ts.map +1 -0
  294. package/tokens/theme/theme-toggle.component.d.ts +15 -0
  295. package/tokens/theme/theme-toggle.component.d.ts.map +1 -0
  296. package/tokens/theme/theme.provider.d.ts +4 -0
  297. package/tokens/theme/theme.provider.d.ts.map +1 -0
  298. package/tokens/theme/theme.service.d.ts +48 -0
  299. package/tokens/theme/theme.service.d.ts.map +1 -0
@@ -0,0 +1,1346 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, model, ChangeDetectionStrategy, Component, output, HostListener, Input, Directive, computed, ContentChildren, inject, signal, effect } from '@angular/core';
3
+ import * as i1$1 from '@angular/common';
4
+ import { CommonModule, NgTemplateOutlet } from '@angular/common';
5
+ import { trigger, state, style, transition, animate } from '@angular/animations';
6
+ import * as i1 from '@angular/router';
7
+ import { RouterModule, Router, NavigationEnd, RouterLink, RouterLinkActive } from '@angular/router';
8
+ import { toSignal } from '@angular/core/rxjs-interop';
9
+ import { filter, map, startWith } from 'rxjs';
10
+ import * as i1$2 from 'lucide-angular';
11
+ import { MessageSquare, Contact, LogOut, CircleQuestionMark, LayoutDashboard, House, icons, LucideAngularModule, LucideIconProvider, LUCIDE_ICONS } from 'lucide-angular';
12
+
13
+ /**
14
+ * Accordion Organism — Source: Nuxt UI v3 ❖ Accordion
15
+ * Collapsible content sections with animation
16
+ * Single or multiple open panels supported
17
+ */
18
+ class AccordionComponent {
19
+ constructor() {
20
+ this.items = input.required();
21
+ this.variant = input('default');
22
+ this.multiple = input(true);
23
+ this.openIds = model([]);
24
+ }
25
+ isOpen(id) { return this.openIds().includes(id); }
26
+ toggle(id) {
27
+ this.openIds.update(ids => {
28
+ if (ids.includes(id)) {
29
+ return ids.filter(i => i !== id);
30
+ }
31
+ return this.multiple() ? [...ids, id] : [id];
32
+ });
33
+ }
34
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccordionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
35
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: AccordionComponent, isStandalone: true, selector: "ui-accordion", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, openIds: { classPropertyName: "openIds", publicName: "openIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openIds: "openIdsChange" }, ngImport: i0, template: `
36
+ <div class="ui-accordion ui-accordion--{{ variant() }}" role="list">
37
+ @for (item of items(); track item.id) {
38
+ <div
39
+ class="ui-accordion__item"
40
+ [class.ui-accordion__item--open]="isOpen(item.id)"
41
+ [class.ui-accordion__item--disabled]="item.disabled"
42
+ role="listitem"
43
+ >
44
+ <button
45
+ type="button"
46
+ class="ui-accordion__trigger"
47
+ [attr.aria-expanded]="isOpen(item.id)"
48
+ [attr.aria-controls]="'panel-' + item.id"
49
+ [disabled]="item.disabled"
50
+ (click)="toggle(item.id)"
51
+ >
52
+ <span class="ui-accordion__label">{{ item.label }}</span>
53
+ <span class="ui-accordion__icon" [class.ui-accordion__icon--open]="isOpen(item.id)" aria-hidden="true">
54
+
55
+ </span>
56
+ </button>
57
+
58
+ @if (isOpen(item.id)) {
59
+ <div
60
+ [@expand]
61
+ class="ui-accordion__panel"
62
+ [id]="'panel-' + item.id"
63
+ role="region"
64
+ [attr.aria-labelledby]="'trigger-' + item.id"
65
+ >
66
+ <div class="ui-accordion__content">{{ item.content }}</div>
67
+ </div>
68
+ }
69
+ </div>
70
+ }
71
+ </div>
72
+ `, isInline: true, styles: [".ui-accordion{width:100%}.ui-accordion__item{border-bottom:1px solid var(--color-border)}.ui-accordion__item:first-child{border-top:1px solid var(--color-border)}.ui-accordion__item--disabled{opacity:.5;pointer-events:none}.ui-accordion__trigger{display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--spacing-4) 0;border:none;background:transparent;cursor:pointer;font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text);text-align:left;transition:color var(--transition-fast)}.ui-accordion__trigger:hover{color:var(--color-primary-500)}.ui-accordion__trigger:focus-visible{outline:2px solid var(--color-ring);outline-offset:2px;border-radius:var(--radius-sm)}.ui-accordion__icon{flex-shrink:0;font-size:.75rem;transition:transform var(--transition-base);color:var(--color-text-muted)}.ui-accordion__icon--open{transform:rotate(180deg)}.ui-accordion__panel{overflow:hidden}.ui-accordion__content{padding:0 0 var(--spacing-4);font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted);line-height:var(--leading-relaxed)}.ui-accordion--ghost .ui-accordion__item{border-bottom:none;border-radius:var(--radius-lg);margin-bottom:var(--spacing-1);background:var(--color-neutral-50)}.ui-accordion--ghost .ui-accordion__item:first-child{border-top:none}.ui-accordion--ghost .ui-accordion__item .ui-accordion__trigger{padding:var(--spacing-3) var(--spacing-4)}.ui-accordion--ghost .ui-accordion__item .ui-accordion__content{padding:0 var(--spacing-4) var(--spacing-3)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], animations: [
73
+ trigger('expand', [
74
+ state('void', style({ height: '0', opacity: 0, overflow: 'hidden' })),
75
+ state('*', style({ height: '*', opacity: 1, overflow: 'hidden' })),
76
+ transition('void <=> *', animate('200ms ease')),
77
+ ])
78
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
79
+ }
80
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AccordionComponent, decorators: [{
81
+ type: Component,
82
+ args: [{ selector: 'ui-accordion', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
83
+ trigger('expand', [
84
+ state('void', style({ height: '0', opacity: 0, overflow: 'hidden' })),
85
+ state('*', style({ height: '*', opacity: 1, overflow: 'hidden' })),
86
+ transition('void <=> *', animate('200ms ease')),
87
+ ])
88
+ ], template: `
89
+ <div class="ui-accordion ui-accordion--{{ variant() }}" role="list">
90
+ @for (item of items(); track item.id) {
91
+ <div
92
+ class="ui-accordion__item"
93
+ [class.ui-accordion__item--open]="isOpen(item.id)"
94
+ [class.ui-accordion__item--disabled]="item.disabled"
95
+ role="listitem"
96
+ >
97
+ <button
98
+ type="button"
99
+ class="ui-accordion__trigger"
100
+ [attr.aria-expanded]="isOpen(item.id)"
101
+ [attr.aria-controls]="'panel-' + item.id"
102
+ [disabled]="item.disabled"
103
+ (click)="toggle(item.id)"
104
+ >
105
+ <span class="ui-accordion__label">{{ item.label }}</span>
106
+ <span class="ui-accordion__icon" [class.ui-accordion__icon--open]="isOpen(item.id)" aria-hidden="true">
107
+
108
+ </span>
109
+ </button>
110
+
111
+ @if (isOpen(item.id)) {
112
+ <div
113
+ [@expand]
114
+ class="ui-accordion__panel"
115
+ [id]="'panel-' + item.id"
116
+ role="region"
117
+ [attr.aria-labelledby]="'trigger-' + item.id"
118
+ >
119
+ <div class="ui-accordion__content">{{ item.content }}</div>
120
+ </div>
121
+ }
122
+ </div>
123
+ }
124
+ </div>
125
+ `, styles: [".ui-accordion{width:100%}.ui-accordion__item{border-bottom:1px solid var(--color-border)}.ui-accordion__item:first-child{border-top:1px solid var(--color-border)}.ui-accordion__item--disabled{opacity:.5;pointer-events:none}.ui-accordion__trigger{display:flex;align-items:center;justify-content:space-between;width:100%;padding:var(--spacing-4) 0;border:none;background:transparent;cursor:pointer;font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text);text-align:left;transition:color var(--transition-fast)}.ui-accordion__trigger:hover{color:var(--color-primary-500)}.ui-accordion__trigger:focus-visible{outline:2px solid var(--color-ring);outline-offset:2px;border-radius:var(--radius-sm)}.ui-accordion__icon{flex-shrink:0;font-size:.75rem;transition:transform var(--transition-base);color:var(--color-text-muted)}.ui-accordion__icon--open{transform:rotate(180deg)}.ui-accordion__panel{overflow:hidden}.ui-accordion__content{padding:0 0 var(--spacing-4);font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted);line-height:var(--leading-relaxed)}.ui-accordion--ghost .ui-accordion__item{border-bottom:none;border-radius:var(--radius-lg);margin-bottom:var(--spacing-1);background:var(--color-neutral-50)}.ui-accordion--ghost .ui-accordion__item:first-child{border-top:none}.ui-accordion--ghost .ui-accordion__item .ui-accordion__trigger{padding:var(--spacing-3) var(--spacing-4)}.ui-accordion--ghost .ui-accordion__item .ui-accordion__content{padding:0 var(--spacing-4) var(--spacing-3)}\n"] }]
126
+ }] });
127
+
128
+ /**
129
+ * Card Organism — Source: Nuxt UI v3 ❖ Card
130
+ * Content container with header, body, footer slots
131
+ */
132
+ class CardComponent {
133
+ constructor() {
134
+ this.title = input(null);
135
+ this.description = input(null);
136
+ this.variant = input('outline');
137
+ }
138
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
139
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: CardComponent, isStandalone: true, selector: "ui-card", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
140
+ <div [class]="'ui-card ui-card--' + variant()">
141
+ @if (title() || description()) {
142
+ <div class="ui-card__header">
143
+ @if (title()) {
144
+ <h3 class="ui-card__title">{{ title() }}</h3>
145
+ }
146
+ @if (description()) {
147
+ <p class="ui-card__description">{{ description() }}</p>
148
+ }
149
+ <ng-content select="[slot=header]" />
150
+ </div>
151
+ }
152
+ <div class="ui-card__body">
153
+ <ng-content />
154
+ </div>
155
+ <ng-content select="[slot=footer]" />
156
+ </div>
157
+ `, isInline: true, styles: [".ui-card{border-radius:var(--radius-xl);overflow:hidden}.ui-card--outline{border:1px solid var(--color-border);background:var(--color-bg);box-shadow:var(--shadow-xs)}.ui-card--soft{background:var(--color-neutral-50);border:1px solid transparent}.ui-card--subtle{background:var(--color-bg-muted)}.ui-card--ghost{background:transparent}.ui-card--none{background:transparent;border:none}.ui-card__header{padding:var(--spacing-4);border-bottom:1px solid var(--color-border)}.ui-card__title{font-family:var(--font-sans);font-size:var(--text-lg);font-weight:var(--font-semibold);color:var(--color-text);margin:0 0 var(--spacing-1)}.ui-card__description{font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted);margin:0}.ui-card__body{padding:var(--spacing-4)}.ui-card__footer{padding:var(--spacing-4);border-top:1px solid var(--color-border)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
158
+ }
159
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: CardComponent, decorators: [{
160
+ type: Component,
161
+ args: [{ selector: 'ui-card', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
162
+ <div [class]="'ui-card ui-card--' + variant()">
163
+ @if (title() || description()) {
164
+ <div class="ui-card__header">
165
+ @if (title()) {
166
+ <h3 class="ui-card__title">{{ title() }}</h3>
167
+ }
168
+ @if (description()) {
169
+ <p class="ui-card__description">{{ description() }}</p>
170
+ }
171
+ <ng-content select="[slot=header]" />
172
+ </div>
173
+ }
174
+ <div class="ui-card__body">
175
+ <ng-content />
176
+ </div>
177
+ <ng-content select="[slot=footer]" />
178
+ </div>
179
+ `, styles: [".ui-card{border-radius:var(--radius-xl);overflow:hidden}.ui-card--outline{border:1px solid var(--color-border);background:var(--color-bg);box-shadow:var(--shadow-xs)}.ui-card--soft{background:var(--color-neutral-50);border:1px solid transparent}.ui-card--subtle{background:var(--color-bg-muted)}.ui-card--ghost{background:transparent}.ui-card--none{background:transparent;border:none}.ui-card__header{padding:var(--spacing-4);border-bottom:1px solid var(--color-border)}.ui-card__title{font-family:var(--font-sans);font-size:var(--text-lg);font-weight:var(--font-semibold);color:var(--color-text);margin:0 0 var(--spacing-1)}.ui-card__description{font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted);margin:0}.ui-card__body{padding:var(--spacing-4)}.ui-card__footer{padding:var(--spacing-4);border-top:1px solid var(--color-border)}\n"] }]
180
+ }] });
181
+
182
+ /**
183
+ * DropdownMenu Organism — Source: Nuxt UI v3 ❖ DropdownMenu
184
+ * Contextual action menu triggered by a slot
185
+ */
186
+ class DropdownMenuComponent {
187
+ constructor(el) {
188
+ this.el = el;
189
+ this.items = input.required();
190
+ this.align = input('left');
191
+ this.open = model(false);
192
+ this.itemClick = output();
193
+ }
194
+ toggle() { this.open.update(v => !v); }
195
+ select(item) {
196
+ if (item.disabled)
197
+ return;
198
+ this.itemClick.emit(item);
199
+ this.open.set(false);
200
+ }
201
+ onDocumentClick(e) {
202
+ if (!this.el.nativeElement.contains(e.target)) {
203
+ this.open.set(false);
204
+ }
205
+ }
206
+ onEscape() { this.open.set(false); }
207
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DropdownMenuComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
208
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: DropdownMenuComponent, isStandalone: true, selector: "ui-dropdown-menu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", itemClick: "itemClick" }, host: { listeners: { "document:click": "onDocumentClick($event)", "keydown.escape": "onEscape()" } }, ngImport: i0, template: `
209
+ <div class="ui-dropdown" [class.ui-dropdown--open]="open()">
210
+ <div class="ui-dropdown__trigger" (click)="toggle()">
211
+ <ng-content />
212
+ </div>
213
+
214
+ @if (open()) {
215
+ <div
216
+ [@menu]
217
+ class="ui-dropdown__menu ui-dropdown__menu--{{ align() }}"
218
+ role="menu"
219
+ aria-orientation="vertical"
220
+ >
221
+ @for (item of items(); track item.id) {
222
+ @if (item.separator) {
223
+ <hr class="ui-dropdown__separator" role="separator" />
224
+ } @else {
225
+ <button
226
+ type="button"
227
+ role="menuitem"
228
+ [class]="'ui-dropdown__item' + (item.disabled ? ' ui-dropdown__item--disabled' : '') + (item.color === 'error' ? ' ui-dropdown__item--error' : '')"
229
+ [disabled]="item.disabled"
230
+ (click)="select(item)"
231
+ >
232
+ @if (item.icon) {
233
+ <span class="ui-dropdown__icon" aria-hidden="true">{{ item.icon }}</span>
234
+ }
235
+ {{ item.label }}
236
+ </button>
237
+ }
238
+ }
239
+ </div>
240
+ }
241
+ </div>
242
+ `, isInline: true, styles: [".ui-dropdown{position:relative;display:inline-flex}.ui-dropdown__trigger{cursor:pointer}.ui-dropdown__menu{position:absolute;top:calc(100% + 4px);z-index:var(--z-dropdown);min-width:160px;background:var(--color-bg);border:1px solid var(--color-border);border-radius:var(--radius-xl);box-shadow:var(--shadow-lg);padding:var(--spacing-1);outline:none}.ui-dropdown__menu--left{left:0}.ui-dropdown__menu--right{right:0}.ui-dropdown__item{display:flex;align-items:center;gap:var(--spacing-2);width:100%;padding:var(--spacing-2) var(--spacing-3);border:none;background:transparent;border-radius:var(--radius-md);font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text);cursor:pointer;text-align:left;transition:var(--transition-colors)}.ui-dropdown__item:hover:not(.ui-dropdown__item--disabled){background:var(--color-neutral-100)}.ui-dropdown__item--error{color:var(--color-error-600)}.ui-dropdown__item--error:hover{background:color-mix(in srgb,var(--color-error-500) 10%,transparent)}.ui-dropdown__item--disabled{opacity:.4;cursor:not-allowed}.ui-dropdown__icon{flex-shrink:0;width:1rem;height:1rem;display:flex;align-items:center;justify-content:center}.ui-dropdown__separator{margin:var(--spacing-1) 0;border:none;border-top:1px solid var(--color-border)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], animations: [
243
+ trigger('menu', [
244
+ transition(':enter', [style({ opacity: 0, transform: 'scale(0.95) translateY(-5px)' }), animate('150ms ease', style({ opacity: 1, transform: 'scale(1) translateY(0)' }))]),
245
+ transition(':leave', [animate('100ms ease', style({ opacity: 0, transform: 'scale(0.95) translateY(-5px)' }))]),
246
+ ])
247
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
248
+ }
249
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DropdownMenuComponent, decorators: [{
250
+ type: Component,
251
+ args: [{ selector: 'ui-dropdown-menu', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
252
+ trigger('menu', [
253
+ transition(':enter', [style({ opacity: 0, transform: 'scale(0.95) translateY(-5px)' }), animate('150ms ease', style({ opacity: 1, transform: 'scale(1) translateY(0)' }))]),
254
+ transition(':leave', [animate('100ms ease', style({ opacity: 0, transform: 'scale(0.95) translateY(-5px)' }))]),
255
+ ])
256
+ ], template: `
257
+ <div class="ui-dropdown" [class.ui-dropdown--open]="open()">
258
+ <div class="ui-dropdown__trigger" (click)="toggle()">
259
+ <ng-content />
260
+ </div>
261
+
262
+ @if (open()) {
263
+ <div
264
+ [@menu]
265
+ class="ui-dropdown__menu ui-dropdown__menu--{{ align() }}"
266
+ role="menu"
267
+ aria-orientation="vertical"
268
+ >
269
+ @for (item of items(); track item.id) {
270
+ @if (item.separator) {
271
+ <hr class="ui-dropdown__separator" role="separator" />
272
+ } @else {
273
+ <button
274
+ type="button"
275
+ role="menuitem"
276
+ [class]="'ui-dropdown__item' + (item.disabled ? ' ui-dropdown__item--disabled' : '') + (item.color === 'error' ? ' ui-dropdown__item--error' : '')"
277
+ [disabled]="item.disabled"
278
+ (click)="select(item)"
279
+ >
280
+ @if (item.icon) {
281
+ <span class="ui-dropdown__icon" aria-hidden="true">{{ item.icon }}</span>
282
+ }
283
+ {{ item.label }}
284
+ </button>
285
+ }
286
+ }
287
+ </div>
288
+ }
289
+ </div>
290
+ `, styles: [".ui-dropdown{position:relative;display:inline-flex}.ui-dropdown__trigger{cursor:pointer}.ui-dropdown__menu{position:absolute;top:calc(100% + 4px);z-index:var(--z-dropdown);min-width:160px;background:var(--color-bg);border:1px solid var(--color-border);border-radius:var(--radius-xl);box-shadow:var(--shadow-lg);padding:var(--spacing-1);outline:none}.ui-dropdown__menu--left{left:0}.ui-dropdown__menu--right{right:0}.ui-dropdown__item{display:flex;align-items:center;gap:var(--spacing-2);width:100%;padding:var(--spacing-2) var(--spacing-3);border:none;background:transparent;border-radius:var(--radius-md);font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text);cursor:pointer;text-align:left;transition:var(--transition-colors)}.ui-dropdown__item:hover:not(.ui-dropdown__item--disabled){background:var(--color-neutral-100)}.ui-dropdown__item--error{color:var(--color-error-600)}.ui-dropdown__item--error:hover{background:color-mix(in srgb,var(--color-error-500) 10%,transparent)}.ui-dropdown__item--disabled{opacity:.4;cursor:not-allowed}.ui-dropdown__icon{flex-shrink:0;width:1rem;height:1rem;display:flex;align-items:center;justify-content:center}.ui-dropdown__separator{margin:var(--spacing-1) 0;border:none;border-top:1px solid var(--color-border)}\n"] }]
291
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { onDocumentClick: [{
292
+ type: HostListener,
293
+ args: ['document:click', ['$event']]
294
+ }], onEscape: [{
295
+ type: HostListener,
296
+ args: ['keydown.escape']
297
+ }] } });
298
+
299
+ /**
300
+ * Modal Organism — Source: Nuxt UI v3 ❖ Modal
301
+ * Dialog overlay with backdrop, header, body, footer
302
+ */
303
+ class ModalComponent {
304
+ constructor() {
305
+ this.open = model(false);
306
+ this.title = input(null);
307
+ this.size = input('md');
308
+ this.hideHeader = input(false);
309
+ this.hideClose = input(false);
310
+ this.dismissible = input(true);
311
+ this.close = output();
312
+ }
313
+ onOverlayClick() {
314
+ if (this.dismissible()) {
315
+ this.open.set(false);
316
+ this.close.emit();
317
+ }
318
+ }
319
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
320
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: ModalComponent, isStandalone: true, selector: "ui-modal", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, hideHeader: { classPropertyName: "hideHeader", publicName: "hideHeader", isSignal: true, isRequired: false, transformFunction: null }, hideClose: { classPropertyName: "hideClose", publicName: "hideClose", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", close: "close" }, ngImport: i0, template: `
321
+ @if (open()) {
322
+ <div class="ui-modal-overlay" [@overlay] (click)="onOverlayClick()" role="presentation">
323
+ <div
324
+ [@dialog]
325
+ class="ui-modal ui-modal--{{ size() }}"
326
+ role="dialog"
327
+ [attr.aria-modal]="true"
328
+ [attr.aria-label]="title() ?? 'Dialog'"
329
+ (click)="$event.stopPropagation()"
330
+ >
331
+ @if (title() || !hideHeader()) {
332
+ <div class="ui-modal__header">
333
+ <h2 class="ui-modal__title">{{ title() }}</h2>
334
+ @if (!hideClose()) {
335
+ <button type="button" class="ui-modal__close" aria-label="Close" (click)="close.emit()">×</button>
336
+ }
337
+ </div>
338
+ }
339
+ <div class="ui-modal__body">
340
+ <ng-content />
341
+ </div>
342
+ <ng-content select="[slot=footer]" />
343
+ </div>
344
+ </div>
345
+ }
346
+ `, isInline: true, styles: [".ui-modal-overlay{position:fixed;inset:0;z-index:var(--z-modal);display:flex;align-items:center;justify-content:center;background:#00000080;padding:var(--spacing-4);backdrop-filter:blur(2px)}.ui-modal{position:relative;background:var(--color-bg);border-radius:var(--radius-2xl);box-shadow:var(--shadow-xl);display:flex;flex-direction:column;max-height:90vh;width:100%;overflow:hidden}.ui-modal--xs{max-width:320px}.ui-modal--sm{max-width:384px}.ui-modal--md{max-width:512px}.ui-modal--lg{max-width:640px}.ui-modal--xl{max-width:768px}.ui-modal--2xl{max-width:896px}.ui-modal--3xl{max-width:1024px}.ui-modal--4xl{max-width:1280px}.ui-modal--full{max-width:calc(100vw - 2rem);max-height:calc(100vh - 2rem)}.ui-modal__header{display:flex;align-items:center;justify-content:space-between;padding:var(--spacing-6) var(--spacing-6) var(--spacing-4);border-bottom:1px solid var(--color-border);flex-shrink:0}.ui-modal__title{font-family:var(--font-sans);font-size:var(--text-xl);font-weight:var(--font-semibold);color:var(--color-text);margin:0}.ui-modal__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;background:transparent;cursor:pointer;font-size:1.5rem;color:var(--color-text-muted);border-radius:var(--radius-md);transition:var(--transition-colors)}.ui-modal__close:hover{color:var(--color-text);background:var(--color-neutral-100)}.ui-modal__body{flex:1;overflow-y:auto;padding:var(--spacing-6);font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted)}.ui-modal__footer{flex-shrink:0;padding:var(--spacing-4) var(--spacing-6);border-top:1px solid var(--color-border);display:flex;justify-content:flex-end;gap:var(--spacing-3)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], animations: [
347
+ trigger('overlay', [
348
+ transition(':enter', [style({ opacity: 0 }), animate('150ms ease', style({ opacity: 1 }))]),
349
+ transition(':leave', [animate('150ms ease', style({ opacity: 0 }))]),
350
+ ]),
351
+ trigger('dialog', [
352
+ transition(':enter', [style({ opacity: 0, transform: 'scale(0.95) translateY(-10px)' }), animate('200ms ease', style({ opacity: 1, transform: 'scale(1) translateY(0)' }))]),
353
+ transition(':leave', [animate('150ms ease', style({ opacity: 0, transform: 'scale(0.95) translateY(-10px)' }))]),
354
+ ]),
355
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
356
+ }
357
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ModalComponent, decorators: [{
358
+ type: Component,
359
+ args: [{ selector: 'ui-modal', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
360
+ trigger('overlay', [
361
+ transition(':enter', [style({ opacity: 0 }), animate('150ms ease', style({ opacity: 1 }))]),
362
+ transition(':leave', [animate('150ms ease', style({ opacity: 0 }))]),
363
+ ]),
364
+ trigger('dialog', [
365
+ transition(':enter', [style({ opacity: 0, transform: 'scale(0.95) translateY(-10px)' }), animate('200ms ease', style({ opacity: 1, transform: 'scale(1) translateY(0)' }))]),
366
+ transition(':leave', [animate('150ms ease', style({ opacity: 0, transform: 'scale(0.95) translateY(-10px)' }))]),
367
+ ]),
368
+ ], template: `
369
+ @if (open()) {
370
+ <div class="ui-modal-overlay" [@overlay] (click)="onOverlayClick()" role="presentation">
371
+ <div
372
+ [@dialog]
373
+ class="ui-modal ui-modal--{{ size() }}"
374
+ role="dialog"
375
+ [attr.aria-modal]="true"
376
+ [attr.aria-label]="title() ?? 'Dialog'"
377
+ (click)="$event.stopPropagation()"
378
+ >
379
+ @if (title() || !hideHeader()) {
380
+ <div class="ui-modal__header">
381
+ <h2 class="ui-modal__title">{{ title() }}</h2>
382
+ @if (!hideClose()) {
383
+ <button type="button" class="ui-modal__close" aria-label="Close" (click)="close.emit()">×</button>
384
+ }
385
+ </div>
386
+ }
387
+ <div class="ui-modal__body">
388
+ <ng-content />
389
+ </div>
390
+ <ng-content select="[slot=footer]" />
391
+ </div>
392
+ </div>
393
+ }
394
+ `, styles: [".ui-modal-overlay{position:fixed;inset:0;z-index:var(--z-modal);display:flex;align-items:center;justify-content:center;background:#00000080;padding:var(--spacing-4);backdrop-filter:blur(2px)}.ui-modal{position:relative;background:var(--color-bg);border-radius:var(--radius-2xl);box-shadow:var(--shadow-xl);display:flex;flex-direction:column;max-height:90vh;width:100%;overflow:hidden}.ui-modal--xs{max-width:320px}.ui-modal--sm{max-width:384px}.ui-modal--md{max-width:512px}.ui-modal--lg{max-width:640px}.ui-modal--xl{max-width:768px}.ui-modal--2xl{max-width:896px}.ui-modal--3xl{max-width:1024px}.ui-modal--4xl{max-width:1280px}.ui-modal--full{max-width:calc(100vw - 2rem);max-height:calc(100vh - 2rem)}.ui-modal__header{display:flex;align-items:center;justify-content:space-between;padding:var(--spacing-6) var(--spacing-6) var(--spacing-4);border-bottom:1px solid var(--color-border);flex-shrink:0}.ui-modal__title{font-family:var(--font-sans);font-size:var(--text-xl);font-weight:var(--font-semibold);color:var(--color-text);margin:0}.ui-modal__close{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;background:transparent;cursor:pointer;font-size:1.5rem;color:var(--color-text-muted);border-radius:var(--radius-md);transition:var(--transition-colors)}.ui-modal__close:hover{color:var(--color-text);background:var(--color-neutral-100)}.ui-modal__body{flex:1;overflow-y:auto;padding:var(--spacing-6);font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-muted)}.ui-modal__footer{flex-shrink:0;padding:var(--spacing-4) var(--spacing-6);border-top:1px solid var(--color-border);display:flex;justify-content:flex-end;gap:var(--spacing-3)}\n"] }]
395
+ }] });
396
+
397
+ /**
398
+ * NavigationMenu Organism — Source: Nuxt UI v3 ❖ NavigationMenu
399
+ * Primary site navigation with active link detection
400
+ */
401
+ class NavigationMenuComponent {
402
+ constructor() {
403
+ this.items = input.required();
404
+ this.orientation = input('horizontal');
405
+ this.ariaLabel = input('Main navigation');
406
+ }
407
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: NavigationMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
408
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: NavigationMenuComponent, isStandalone: true, selector: "ui-navigation-menu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
409
+ <nav
410
+ class="ui-nav ui-nav--{{ orientation() }}"
411
+ [attr.aria-label]="ariaLabel()"
412
+ >
413
+ @for (item of items(); track item.id) {
414
+ @if (item.to) {
415
+ <a
416
+ [routerLink]="item.to"
417
+ routerLinkActive="ui-nav__item--active"
418
+ class="ui-nav__item"
419
+ [class.ui-nav__item--disabled]="item.disabled"
420
+ >
421
+ @if (item.icon) {
422
+ <span class="ui-nav__icon" aria-hidden="true">{{ item.icon }}</span>
423
+ }
424
+ <span class="ui-nav__label">{{ item.label }}</span>
425
+ @if (item.badge) {
426
+ <span class="ui-nav__badge" [attr.aria-label]="item.badge + ' notifications'">{{ item.badge }}</span>
427
+ }
428
+ </a>
429
+ } @else {
430
+ <a
431
+ [href]="item.href ?? '#'"
432
+ class="ui-nav__item"
433
+ [class.ui-nav__item--disabled]="item.disabled"
434
+ >
435
+ @if (item.icon) {
436
+ <span class="ui-nav__icon" aria-hidden="true">{{ item.icon }}</span>
437
+ }
438
+ <span class="ui-nav__label">{{ item.label }}</span>
439
+ </a>
440
+ }
441
+ }
442
+ </nav>
443
+ `, isInline: true, styles: [".ui-nav{display:flex;align-items:center}.ui-nav--horizontal{flex-direction:row;gap:var(--spacing-1)}.ui-nav--vertical{flex-direction:column;align-items:stretch;gap:var(--spacing-0-5)}.ui-nav__item{display:flex;align-items:center;gap:var(--spacing-2);padding:var(--spacing-2) var(--spacing-3);border-radius:var(--radius-md);font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text-muted);text-decoration:none;transition:var(--transition-colors);cursor:pointer}.ui-nav__item:hover{color:var(--color-text);background:var(--color-neutral-100)}.ui-nav__item--active{color:var(--color-primary-500);background:color-mix(in srgb,var(--color-primary-500) 10%,transparent)}.ui-nav__item--disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.ui-nav--vertical .ui-nav__item{justify-content:flex-start}.ui-nav__icon{flex-shrink:0;width:1.25rem;height:1.25rem;display:flex;align-items:center;justify-content:center}.ui-nav__label{flex:1}.ui-nav__badge{display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 .25rem;border-radius:var(--radius-full);background:var(--color-primary-500);color:#fff;font-size:.7rem;font-weight:var(--font-bold)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i1.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
444
+ }
445
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: NavigationMenuComponent, decorators: [{
446
+ type: Component,
447
+ args: [{ selector: 'ui-navigation-menu', standalone: true, imports: [CommonModule, RouterModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
448
+ <nav
449
+ class="ui-nav ui-nav--{{ orientation() }}"
450
+ [attr.aria-label]="ariaLabel()"
451
+ >
452
+ @for (item of items(); track item.id) {
453
+ @if (item.to) {
454
+ <a
455
+ [routerLink]="item.to"
456
+ routerLinkActive="ui-nav__item--active"
457
+ class="ui-nav__item"
458
+ [class.ui-nav__item--disabled]="item.disabled"
459
+ >
460
+ @if (item.icon) {
461
+ <span class="ui-nav__icon" aria-hidden="true">{{ item.icon }}</span>
462
+ }
463
+ <span class="ui-nav__label">{{ item.label }}</span>
464
+ @if (item.badge) {
465
+ <span class="ui-nav__badge" [attr.aria-label]="item.badge + ' notifications'">{{ item.badge }}</span>
466
+ }
467
+ </a>
468
+ } @else {
469
+ <a
470
+ [href]="item.href ?? '#'"
471
+ class="ui-nav__item"
472
+ [class.ui-nav__item--disabled]="item.disabled"
473
+ >
474
+ @if (item.icon) {
475
+ <span class="ui-nav__icon" aria-hidden="true">{{ item.icon }}</span>
476
+ }
477
+ <span class="ui-nav__label">{{ item.label }}</span>
478
+ </a>
479
+ }
480
+ }
481
+ </nav>
482
+ `, styles: [".ui-nav{display:flex;align-items:center}.ui-nav--horizontal{flex-direction:row;gap:var(--spacing-1)}.ui-nav--vertical{flex-direction:column;align-items:stretch;gap:var(--spacing-0-5)}.ui-nav__item{display:flex;align-items:center;gap:var(--spacing-2);padding:var(--spacing-2) var(--spacing-3);border-radius:var(--radius-md);font-family:var(--font-sans);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--color-text-muted);text-decoration:none;transition:var(--transition-colors);cursor:pointer}.ui-nav__item:hover{color:var(--color-text);background:var(--color-neutral-100)}.ui-nav__item--active{color:var(--color-primary-500);background:color-mix(in srgb,var(--color-primary-500) 10%,transparent)}.ui-nav__item--disabled{opacity:.4;cursor:not-allowed;pointer-events:none}.ui-nav--vertical .ui-nav__item{justify-content:flex-start}.ui-nav__icon{flex-shrink:0;width:1.25rem;height:1.25rem;display:flex;align-items:center;justify-content:center}.ui-nav__label{flex:1}.ui-nav__badge{display:inline-flex;align-items:center;justify-content:center;min-width:1.25rem;height:1.25rem;padding:0 .25rem;border-radius:var(--radius-full);background:var(--color-primary-500);color:#fff;font-size:.7rem;font-weight:var(--font-bold)}\n"] }]
483
+ }] });
484
+
485
+ class UiTableCellDirective {
486
+ constructor(tpl) {
487
+ this.tpl = tpl;
488
+ }
489
+ /** Type-safe static context guard for `let-row`. */
490
+ static ngTemplateContextGuard(_dir, ctx) {
491
+ return true;
492
+ }
493
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: UiTableCellDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); }
494
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.20", type: UiTableCellDirective, isStandalone: true, selector: "ng-template[uiCell]", inputs: { columnKey: ["uiCell", "columnKey"] }, ngImport: i0 }); }
495
+ }
496
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: UiTableCellDirective, decorators: [{
497
+ type: Directive,
498
+ args: [{
499
+ selector: 'ng-template[uiCell]',
500
+ standalone: true,
501
+ }]
502
+ }], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { columnKey: [{
503
+ type: Input,
504
+ args: [{ required: true, alias: 'uiCell' }]
505
+ }] } });
506
+
507
+ /**
508
+ * Table Organism — Source: Nuxt UI v3 ❖ Table
509
+ * Data table with sorting, selection, loading state.
510
+ *
511
+ * Custom cell templates via UiTableCellDirective:
512
+ * <ng-template uiCell="columnKey" let-row>
513
+ * <ui-badge>{{ row['field'] }}</ui-badge>
514
+ * </ng-template>
515
+ */
516
+ class TableComponent {
517
+ constructor() {
518
+ this.columns = input.required();
519
+ this.rows = input([]);
520
+ this.loading = input(false);
521
+ this.selectable = input(false);
522
+ this.caption = input(null);
523
+ this.emptyLabel = input('No data available.');
524
+ this.rowIdKey = input('id');
525
+ this.sortState = model(null);
526
+ this.selectedIds = model([]);
527
+ this.rowClick = output();
528
+ // ── Computed ───────────────────────────────────────────────────────────────
529
+ this.loadingRows = computed(() => Array.from({ length: 5 }, (_, i) => i));
530
+ this.allSelected = computed(() => this.rows().length > 0 && this.rows().every(r => this.isSelected(this.rowId(r))));
531
+ }
532
+ /** Returns the TemplateRef for a column key if a custom template was provided. */
533
+ getCellTpl(key) {
534
+ return this.cellDirs?.find(d => d.columnKey === key)?.tpl ?? null;
535
+ }
536
+ // ── Helpers ────────────────────────────────────────────────────────────────
537
+ rowId(row) {
538
+ return row[this.rowIdKey()];
539
+ }
540
+ isSelected(id) {
541
+ return this.selectedIds().includes(id);
542
+ }
543
+ toggleRow(id) {
544
+ this.selectedIds.update(ids => ids.includes(id) ? ids.filter(i => i !== id) : [...ids, id]);
545
+ }
546
+ toggleAll() {
547
+ if (this.allSelected()) {
548
+ this.selectedIds.set([]);
549
+ }
550
+ else {
551
+ this.selectedIds.set(this.rows().map(r => this.rowId(r)));
552
+ }
553
+ }
554
+ sort(key) {
555
+ this.sortState.update(state => {
556
+ if (state?.column === key) {
557
+ return state.direction === 'asc'
558
+ ? { column: key, direction: 'desc' }
559
+ : null;
560
+ }
561
+ return { column: key, direction: 'asc' };
562
+ });
563
+ }
564
+ getSortIcon(key) {
565
+ const s = this.sortState();
566
+ if (!s || s.column !== key)
567
+ return '↕';
568
+ return s.direction === 'asc' ? '↑' : '↓';
569
+ }
570
+ getSortAriaLabel(key) {
571
+ const s = this.sortState();
572
+ if (!s || s.column !== key)
573
+ return 'none';
574
+ return s.direction === 'asc' ? 'ascending' : 'descending';
575
+ }
576
+ onRowClick(row) {
577
+ this.rowClick.emit(row);
578
+ }
579
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
580
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: TableComponent, isStandalone: true, selector: "ui-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, caption: { classPropertyName: "caption", publicName: "caption", isSignal: true, isRequired: false, transformFunction: null }, emptyLabel: { classPropertyName: "emptyLabel", publicName: "emptyLabel", isSignal: true, isRequired: false, transformFunction: null }, rowIdKey: { classPropertyName: "rowIdKey", publicName: "rowIdKey", isSignal: true, isRequired: false, transformFunction: null }, sortState: { classPropertyName: "sortState", publicName: "sortState", isSignal: true, isRequired: false, transformFunction: null }, selectedIds: { classPropertyName: "selectedIds", publicName: "selectedIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortState: "sortStateChange", selectedIds: "selectedIdsChange", rowClick: "rowClick" }, queries: [{ propertyName: "cellDirs", predicate: UiTableCellDirective }], ngImport: i0, template: `
581
+ <div class="ui-table-wrap">
582
+ <table class="ui-table" [attr.aria-label]="caption()">
583
+ @if (caption()) {
584
+ <caption class="ui-table__caption">{{ caption() }}</caption>
585
+ }
586
+ <thead class="ui-table__head">
587
+ <tr>
588
+ @if (selectable()) {
589
+ <th class="ui-table__th ui-table__th--checkbox" scope="col">
590
+ <input type="checkbox" [checked]="allSelected()" (change)="toggleAll()" aria-label="Select all" />
591
+ </th>
592
+ }
593
+ @for (col of columns(); track col.key) {
594
+ <th
595
+ [class]="'ui-table__th' + (col.sortable ? ' ui-table__th--sortable' : '') + ' ui-table__th--' + (col.align ?? 'left')"
596
+ scope="col"
597
+ [attr.aria-sort]="getSortAriaLabel(col.key)"
598
+ [style.width]="col.width ?? null"
599
+ (click)="col.sortable ? sort(col.key) : null"
600
+ >
601
+ <span class="ui-table__th-inner">
602
+ {{ col.label }}
603
+ @if (col.sortable) {
604
+ <span class="ui-table__sort-icon" aria-hidden="true">
605
+ {{ getSortIcon(col.key) }}
606
+ </span>
607
+ }
608
+ </span>
609
+ </th>
610
+ }
611
+ </tr>
612
+ </thead>
613
+ <tbody class="ui-table__body">
614
+ @if (loading()) {
615
+ @for (i of loadingRows(); track i) {
616
+ <tr class="ui-table__row ui-table__row--loading">
617
+ @if (selectable()) {
618
+ <td><div class="ui-skeleton" style="width:18px;height:18px;border-radius:4px"></div></td>
619
+ }
620
+ @for (col of columns(); track col.key) {
621
+ <td class="ui-table__td">
622
+ <div class="ui-skeleton" style="height:16px;border-radius:4px"></div>
623
+ </td>
624
+ }
625
+ </tr>
626
+ }
627
+ } @else if (rows().length === 0) {
628
+ <tr>
629
+ <td [attr.colspan]="columns().length + (selectable() ? 1 : 0)" class="ui-table__empty">
630
+ <ng-content select="[slot=empty]" />
631
+ {{ emptyLabel() }}
632
+ </td>
633
+ </tr>
634
+ } @else {
635
+ @for (row of rows(); track rowId(row)) {
636
+ <tr
637
+ class="ui-table__row"
638
+ [class.ui-table__row--selected]="isSelected(rowId(row))"
639
+ (click)="onRowClick(row)"
640
+ >
641
+ @if (selectable()) {
642
+ <td class="ui-table__td ui-table__td--checkbox">
643
+ <input type="checkbox" [checked]="isSelected(rowId(row))"
644
+ (change)="toggleRow(rowId(row))" [attr.aria-label]="'Select row'" />
645
+ </td>
646
+ }
647
+ @for (col of columns(); track col.key) {
648
+ <td [class]="'ui-table__td ui-table__td--' + (col.align ?? 'left')">
649
+ @if (getCellTpl(col.key); as tpl) {
650
+ <ng-container
651
+ [ngTemplateOutlet]="tpl"
652
+ [ngTemplateOutletContext]="{ $implicit: row, row: row }"
653
+ />
654
+ } @else {
655
+ {{ row[col.key] }}
656
+ }
657
+ </td>
658
+ }
659
+ </tr>
660
+ }
661
+ }
662
+ </tbody>
663
+ </table>
664
+ </div>
665
+
666
+ <!-- Custom cell template slots (projected, not rendered directly) -->
667
+ <ng-content />
668
+ `, isInline: true, styles: [".ui-table-wrap{width:100%;overflow-x:auto;border:1px solid var(--color-border);border-radius:var(--radius-xl)}.ui-table{width:100%;border-collapse:collapse;font-family:var(--font-sans)}.ui-table__caption{font-size:var(--text-sm);font-weight:var(--font-semibold);color:var(--color-text);padding:var(--spacing-3) var(--spacing-4);text-align:left;caption-side:top}.ui-table__head{background:var(--color-neutral-50)}.ui-table__th{padding:var(--spacing-3) var(--spacing-4);font-size:var(--text-xs);font-weight:var(--font-semibold);color:var(--color-text-muted);text-transform:uppercase;letter-spacing:var(--tracking-wide);border-bottom:1px solid var(--color-border);white-space:nowrap}.ui-table__th--left{text-align:left}.ui-table__th--center{text-align:center}.ui-table__th--right{text-align:right}.ui-table__th--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.ui-table__th--sortable:hover{color:var(--color-text)}.ui-table__th--checkbox{width:40px}.ui-table__th-inner{display:inline-flex;align-items:center;gap:var(--spacing-1)}.ui-table__sort-icon{font-size:.75em;opacity:.6}.ui-table__body{background:var(--color-bg)}.ui-table__row{border-bottom:1px solid var(--color-border);transition:background var(--transition-fast)}.ui-table__row:last-child{border-bottom:none}.ui-table__row:hover{background:var(--color-neutral-50)}.ui-table__row--selected{background:color-mix(in srgb,var(--color-primary-500) 5%,transparent)}.ui-table__row--loading{pointer-events:none}.ui-table__td{padding:var(--spacing-3) var(--spacing-4);font-size:var(--text-sm);color:var(--color-text);max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-table__td--left{text-align:left}.ui-table__td--center{text-align:center}.ui-table__td--right{text-align:right}.ui-table__td--checkbox{width:40px}.ui-table__empty{padding:var(--spacing-12) var(--spacing-4);text-align:center;color:var(--color-text-muted);font-size:var(--text-sm)}.ui-skeleton{background:linear-gradient(90deg,var(--color-neutral-100) 25%,var(--color-neutral-200) 50%,var(--color-neutral-100) 75%);background-size:200% 100%;animation:ui-shimmer 1.5s ease-in-out infinite}@keyframes ui-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
669
+ }
670
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: TableComponent, decorators: [{
671
+ type: Component,
672
+ args: [{ selector: 'ui-table', standalone: true, imports: [CommonModule, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: `
673
+ <div class="ui-table-wrap">
674
+ <table class="ui-table" [attr.aria-label]="caption()">
675
+ @if (caption()) {
676
+ <caption class="ui-table__caption">{{ caption() }}</caption>
677
+ }
678
+ <thead class="ui-table__head">
679
+ <tr>
680
+ @if (selectable()) {
681
+ <th class="ui-table__th ui-table__th--checkbox" scope="col">
682
+ <input type="checkbox" [checked]="allSelected()" (change)="toggleAll()" aria-label="Select all" />
683
+ </th>
684
+ }
685
+ @for (col of columns(); track col.key) {
686
+ <th
687
+ [class]="'ui-table__th' + (col.sortable ? ' ui-table__th--sortable' : '') + ' ui-table__th--' + (col.align ?? 'left')"
688
+ scope="col"
689
+ [attr.aria-sort]="getSortAriaLabel(col.key)"
690
+ [style.width]="col.width ?? null"
691
+ (click)="col.sortable ? sort(col.key) : null"
692
+ >
693
+ <span class="ui-table__th-inner">
694
+ {{ col.label }}
695
+ @if (col.sortable) {
696
+ <span class="ui-table__sort-icon" aria-hidden="true">
697
+ {{ getSortIcon(col.key) }}
698
+ </span>
699
+ }
700
+ </span>
701
+ </th>
702
+ }
703
+ </tr>
704
+ </thead>
705
+ <tbody class="ui-table__body">
706
+ @if (loading()) {
707
+ @for (i of loadingRows(); track i) {
708
+ <tr class="ui-table__row ui-table__row--loading">
709
+ @if (selectable()) {
710
+ <td><div class="ui-skeleton" style="width:18px;height:18px;border-radius:4px"></div></td>
711
+ }
712
+ @for (col of columns(); track col.key) {
713
+ <td class="ui-table__td">
714
+ <div class="ui-skeleton" style="height:16px;border-radius:4px"></div>
715
+ </td>
716
+ }
717
+ </tr>
718
+ }
719
+ } @else if (rows().length === 0) {
720
+ <tr>
721
+ <td [attr.colspan]="columns().length + (selectable() ? 1 : 0)" class="ui-table__empty">
722
+ <ng-content select="[slot=empty]" />
723
+ {{ emptyLabel() }}
724
+ </td>
725
+ </tr>
726
+ } @else {
727
+ @for (row of rows(); track rowId(row)) {
728
+ <tr
729
+ class="ui-table__row"
730
+ [class.ui-table__row--selected]="isSelected(rowId(row))"
731
+ (click)="onRowClick(row)"
732
+ >
733
+ @if (selectable()) {
734
+ <td class="ui-table__td ui-table__td--checkbox">
735
+ <input type="checkbox" [checked]="isSelected(rowId(row))"
736
+ (change)="toggleRow(rowId(row))" [attr.aria-label]="'Select row'" />
737
+ </td>
738
+ }
739
+ @for (col of columns(); track col.key) {
740
+ <td [class]="'ui-table__td ui-table__td--' + (col.align ?? 'left')">
741
+ @if (getCellTpl(col.key); as tpl) {
742
+ <ng-container
743
+ [ngTemplateOutlet]="tpl"
744
+ [ngTemplateOutletContext]="{ $implicit: row, row: row }"
745
+ />
746
+ } @else {
747
+ {{ row[col.key] }}
748
+ }
749
+ </td>
750
+ }
751
+ </tr>
752
+ }
753
+ }
754
+ </tbody>
755
+ </table>
756
+ </div>
757
+
758
+ <!-- Custom cell template slots (projected, not rendered directly) -->
759
+ <ng-content />
760
+ `, styles: [".ui-table-wrap{width:100%;overflow-x:auto;border:1px solid var(--color-border);border-radius:var(--radius-xl)}.ui-table{width:100%;border-collapse:collapse;font-family:var(--font-sans)}.ui-table__caption{font-size:var(--text-sm);font-weight:var(--font-semibold);color:var(--color-text);padding:var(--spacing-3) var(--spacing-4);text-align:left;caption-side:top}.ui-table__head{background:var(--color-neutral-50)}.ui-table__th{padding:var(--spacing-3) var(--spacing-4);font-size:var(--text-xs);font-weight:var(--font-semibold);color:var(--color-text-muted);text-transform:uppercase;letter-spacing:var(--tracking-wide);border-bottom:1px solid var(--color-border);white-space:nowrap}.ui-table__th--left{text-align:left}.ui-table__th--center{text-align:center}.ui-table__th--right{text-align:right}.ui-table__th--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.ui-table__th--sortable:hover{color:var(--color-text)}.ui-table__th--checkbox{width:40px}.ui-table__th-inner{display:inline-flex;align-items:center;gap:var(--spacing-1)}.ui-table__sort-icon{font-size:.75em;opacity:.6}.ui-table__body{background:var(--color-bg)}.ui-table__row{border-bottom:1px solid var(--color-border);transition:background var(--transition-fast)}.ui-table__row:last-child{border-bottom:none}.ui-table__row:hover{background:var(--color-neutral-50)}.ui-table__row--selected{background:color-mix(in srgb,var(--color-primary-500) 5%,transparent)}.ui-table__row--loading{pointer-events:none}.ui-table__td{padding:var(--spacing-3) var(--spacing-4);font-size:var(--text-sm);color:var(--color-text);max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-table__td--left{text-align:left}.ui-table__td--center{text-align:center}.ui-table__td--right{text-align:right}.ui-table__td--checkbox{width:40px}.ui-table__empty{padding:var(--spacing-12) var(--spacing-4);text-align:center;color:var(--color-text-muted);font-size:var(--text-sm)}.ui-skeleton{background:linear-gradient(90deg,var(--color-neutral-100) 25%,var(--color-neutral-200) 50%,var(--color-neutral-100) 75%);background-size:200% 100%;animation:ui-shimmer 1.5s ease-in-out infinite}@keyframes ui-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"] }]
761
+ }], propDecorators: { cellDirs: [{
762
+ type: ContentChildren,
763
+ args: [UiTableCellDirective]
764
+ }] } });
765
+
766
+ // ── Catalogue complet des icônes Lucide + aliases pratiques ──
767
+ // `icons` contient les 1 700+ icônes en clés PascalCase.
768
+ // Les aliases couvrent les noms courants qui n'existent pas dans Lucide.
769
+ // LucideAngularComponent convertit kebab-case → PascalCase avant la recherche.
770
+ // Ex : name="home" → cherche "Home" → House
771
+ const SIDEBAR_ICONS = {
772
+ ...icons,
773
+ // Aliases courants absents du catalogue Lucide officiel
774
+ Home: House, // name="home"
775
+ Dashboard: LayoutDashboard, // name="dashboard"
776
+ Help: CircleQuestionMark, // name="help"
777
+ Logout: LogOut, // name="logout"
778
+ Contacts: Contact, // name="contacts"
779
+ Feedback: MessageSquare, // name="feedback"
780
+ };
781
+ /**
782
+ * Sidebar Organism — Source: Nuxt UI v4 ❖ DashboardSidebar
783
+ *
784
+ * Sidebar de dashboard avec :
785
+ * - Mode expanded (254px) ↔ collapsed (64px) avec animation CSS
786
+ * - Header : logo ou slot personnalisé
787
+ * - Navigation : groupes d'items avec icônes, badges, sous-menus, liens externes
788
+ * - Search button avec shortcut clavier (⌘ K)
789
+ * - Footer : utilisateur courant (avatar + nom)
790
+ * - Compatible dark mode via `[data-theme="dark"]`
791
+ *
792
+ * @example
793
+ * <ui-sidebar [navGroups]="groups" [user]="currentUser" />
794
+ * <ui-sidebar [(collapsed)]="sidebarCollapsed" [navGroups]="groups" />
795
+ */
796
+ class SidebarComponent {
797
+ constructor() {
798
+ this.router = inject(Router);
799
+ // ── Inputs ────────────────────────────────────────────────
800
+ this.navGroups = input([]);
801
+ this.footerGroups = input([]);
802
+ this.user = input(null);
803
+ this.logoSrc = input(null);
804
+ this.logoAlt = input('Logo');
805
+ this.collapsible = input(true);
806
+ this.showSearch = input(true);
807
+ this.searchPlaceholder = input('Search...');
808
+ // ── Two-way binding ───────────────────────────────────────
809
+ this.collapsed = model(false);
810
+ // ── Outputs ───────────────────────────────────────────────
811
+ this.searchClick = output();
812
+ this.itemClick = output();
813
+ this.userClick = output();
814
+ // ── URL courante (réactive) ───────────────────────────────
815
+ this.currentUrl = toSignal(this.router.events.pipe(filter(e => e instanceof NavigationEnd), map(() => this.router.url), startWith(this.router.url)), { initialValue: this.router.url });
816
+ // ── Internal state (open sub-menus) ───────────────────────
817
+ this.openItems = signal(new Set());
818
+ // Auto-ouvre les sous-menus dont un enfant correspond à la route active
819
+ effect(() => {
820
+ const url = this.currentUrl();
821
+ const allGroups = [...this.navGroups(), ...this.footerGroups()];
822
+ allGroups.forEach(group => group.items.forEach(item => {
823
+ const hasActiveChild = item.children?.some(child => child.href && url.startsWith(child.href)) ?? false;
824
+ if (hasActiveChild) {
825
+ this.openItems.update(set => new Set(set).add(item.id));
826
+ }
827
+ }));
828
+ });
829
+ }
830
+ isItemOpen(id) {
831
+ return this.openItems().has(id);
832
+ }
833
+ /**
834
+ * Un item parent (button) est actif si au moins un de ses enfants
835
+ * correspond à l'URL courante.
836
+ */
837
+ isParentActive(item) {
838
+ const url = this.currentUrl();
839
+ return item.children?.some(child => child.href ? url.startsWith(child.href) : false) ?? false;
840
+ }
841
+ toggleItem(id) {
842
+ this.openItems.update(set => {
843
+ const next = new Set(set);
844
+ next.has(id) ? next.delete(id) : next.add(id);
845
+ return next;
846
+ });
847
+ }
848
+ toggleCollapse() {
849
+ this.collapsed.update(v => !v);
850
+ }
851
+ navigate(item) {
852
+ this.itemClick.emit(item);
853
+ if (!item.href || item.disabled)
854
+ return;
855
+ if (item.external) {
856
+ window.open(item.href, '_blank', 'noopener,noreferrer');
857
+ }
858
+ else {
859
+ this.router.navigate([item.href]);
860
+ }
861
+ }
862
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
863
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.20", type: SidebarComponent, isStandalone: true, selector: "ui-sidebar", inputs: { navGroups: { classPropertyName: "navGroups", publicName: "navGroups", isSignal: true, isRequired: false, transformFunction: null }, footerGroups: { classPropertyName: "footerGroups", publicName: "footerGroups", isSignal: true, isRequired: false, transformFunction: null }, user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null }, logoSrc: { classPropertyName: "logoSrc", publicName: "logoSrc", isSignal: true, isRequired: false, transformFunction: null }, logoAlt: { classPropertyName: "logoAlt", publicName: "logoAlt", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange", searchClick: "searchClick", itemClick: "itemClick", userClick: "userClick" }, providers: [
864
+ { provide: LUCIDE_ICONS, multi: true, useValue: new LucideIconProvider(SIDEBAR_ICONS) },
865
+ ], ngImport: i0, template: `
866
+ <aside
867
+ class="ui-sidebar"
868
+ [class.ui-sidebar--collapsed]="collapsed()"
869
+ [class.ui-sidebar--collapsible]="collapsible()"
870
+ [attr.aria-label]="'Sidebar navigation'"
871
+ >
872
+
873
+ <!-- ── Header ─────────────────────────────────────────────── -->
874
+ <div class="ui-sidebar__header">
875
+ <div class="ui-sidebar__logo">
876
+ @if (logoSrc()) {
877
+ <img [src]="logoSrc()" [alt]="logoAlt()" class="ui-sidebar__logo-img" />
878
+ } @else {
879
+ <span class="ui-sidebar__logo-text">{{ logoAlt() }}</span>
880
+ }
881
+ </div>
882
+
883
+ @if (collapsible()) {
884
+ <!-- Figma: toggle uses i-lucide-chevrons-up-down, consistent in expanded & collapsed states -->
885
+ <button
886
+ type="button"
887
+ class="ui-sidebar__toggle"
888
+ [attr.aria-label]="collapsed() ? 'Expand sidebar' : 'Collapse sidebar'"
889
+ (click)="toggleCollapse()"
890
+ >
891
+ <lucide-icon name="chevrons-up-down" [size]="16" aria-hidden="true" />
892
+ </button>
893
+ }
894
+ </div>
895
+
896
+ <!-- ── Body ───────────────────────────────────────────────── -->
897
+ <div class="ui-sidebar__body">
898
+
899
+ <!-- Top section: search + primary nav groups -->
900
+ <div class="ui-sidebar__top">
901
+
902
+ <!-- Search button -->
903
+ @if (showSearch()) {
904
+ <button
905
+ type="button"
906
+ class="ui-sidebar__search"
907
+ [attr.aria-label]="searchPlaceholder()"
908
+ (click)="searchClick.emit()"
909
+ >
910
+ <lucide-icon name="search" [size]="20" aria-hidden="true" class="ui-sidebar__search-icon" />
911
+ <span class="ui-sidebar__search-label">{{ searchPlaceholder() }}</span>
912
+ <span class="ui-sidebar__search-kbd" aria-hidden="true">
913
+ <kbd class="ui-sidebar__kbd">⌘</kbd>
914
+ <kbd class="ui-sidebar__kbd">K</kbd>
915
+ </span>
916
+ </button>
917
+ }
918
+
919
+ <!-- Primary nav groups -->
920
+ @for (group of navGroups(); track $index) {
921
+ <nav class="ui-sidebar__group" [attr.aria-label]="group.label ?? 'Navigation'">
922
+ @if (group.label && !collapsed()) {
923
+ <p class="ui-sidebar__group-label">{{ group.label }}</p>
924
+ }
925
+ @for (item of group.items; track item.id) {
926
+ <div class="ui-sidebar__nav-item-wrap">
927
+
928
+ @if (item.children?.length) {
929
+ <!-- ── Collapsible parent item ── -->
930
+ <button
931
+ type="button"
932
+ class="ui-sidebar__item"
933
+ [class.ui-sidebar__item--active]="isParentActive(item)"
934
+ [class.ui-sidebar__item--disabled]="item.disabled"
935
+ [attr.aria-expanded]="isItemOpen(item.id)"
936
+ [disabled]="item.disabled ?? null"
937
+ (click)="toggleItem(item.id)"
938
+ >
939
+ @if (item.icon) {
940
+ <lucide-icon [name]="item.icon" [size]="20" aria-hidden="true" class="ui-sidebar__item-icon" />
941
+ }
942
+ <span class="ui-sidebar__item-label">{{ item.label }}</span>
943
+ @if (item.badge != null && !collapsed()) {
944
+ <span class="ui-sidebar__badge" [attr.aria-label]="item.badge + ' notifications'">
945
+ {{ item.badge }}
946
+ </span>
947
+ }
948
+ @if (!collapsed()) {
949
+ <span class="ui-sidebar__chevron"
950
+ [class.ui-sidebar__chevron--open]="isItemOpen(item.id)"
951
+ aria-hidden="true">
952
+ <lucide-icon name="chevron-down" [size]="20" />
953
+ </span>
954
+ }
955
+ </button>
956
+
957
+ <!-- Sub-items (only in expanded mode) -->
958
+ @if (isItemOpen(item.id) && !collapsed()) {
959
+ <div class="ui-sidebar__children" [@expand]>
960
+ @for (child of item.children; track child.id) {
961
+ <!-- Figma: NavigationMenuItem child has border-l + px-[6px] on outer wrapper -->
962
+ <div class="ui-sidebar__child-wrap"
963
+ [class.ui-sidebar__child-wrap--active]="childRla.isActive">
964
+ <button
965
+ type="button"
966
+ #childRla="routerLinkActive"
967
+ routerLinkActive
968
+ [routerLink]="!child.external ? (child.href ?? null) : null"
969
+ [routerLinkActiveOptions]="{ exact: true }"
970
+ class="ui-sidebar__child"
971
+ [class.ui-sidebar__child--active]="child.external ? !!child.active : childRla.isActive"
972
+ [class.ui-sidebar__child--disabled]="child.disabled"
973
+ [disabled]="child.disabled ?? null"
974
+ (click)="navigate(child)"
975
+ >
976
+ @if (child.icon) {
977
+ <lucide-icon [name]="child.icon" [size]="16" aria-hidden="true" class="ui-sidebar__child-icon" />
978
+ }
979
+ <span class="ui-sidebar__child-label">{{ child.label }}</span>
980
+ </button>
981
+ </div>
982
+ }
983
+ </div>
984
+ }
985
+
986
+ } @else {
987
+ <!-- ── Simple item ── -->
988
+ <button
989
+ type="button"
990
+ #navRla="routerLinkActive"
991
+ routerLinkActive
992
+ [routerLink]="!item.external ? (item.href ?? null) : null"
993
+ [routerLinkActiveOptions]="{ exact: false }"
994
+ class="ui-sidebar__item"
995
+ [class.ui-sidebar__item--active]="item.external ? !!item.active : navRla.isActive"
996
+ [class.ui-sidebar__item--disabled]="item.disabled"
997
+ [disabled]="item.disabled ?? null"
998
+ (click)="navigate(item)"
999
+ >
1000
+ @if (item.icon) {
1001
+ <lucide-icon [name]="item.icon" [size]="20" aria-hidden="true" class="ui-sidebar__item-icon" />
1002
+ }
1003
+ <span class="ui-sidebar__item-label">
1004
+ {{ item.label }}
1005
+ @if (item.external) {
1006
+ <lucide-icon name="arrow-up-right" [size]="12" aria-hidden="true" class="ui-sidebar__external" />
1007
+ }
1008
+ </span>
1009
+ @if (item.badge != null && !collapsed()) {
1010
+ <span class="ui-sidebar__badge" [attr.aria-label]="item.badge + ' notifications'">
1011
+ {{ item.badge }}
1012
+ </span>
1013
+ }
1014
+ </button>
1015
+ }
1016
+
1017
+ </div>
1018
+ }
1019
+ </nav>
1020
+ }
1021
+ </div>
1022
+
1023
+ <!-- Bottom section: secondary / footer nav groups -->
1024
+ @if (footerGroups().length) {
1025
+ <div class="ui-sidebar__bottom">
1026
+ @for (group of footerGroups(); track $index) {
1027
+ <nav class="ui-sidebar__group" [attr.aria-label]="group.label ?? 'Footer navigation'">
1028
+ @for (item of group.items; track item.id) {
1029
+ <button
1030
+ type="button"
1031
+ #footerRla="routerLinkActive"
1032
+ routerLinkActive
1033
+ [routerLink]="!item.external ? (item.href ?? null) : null"
1034
+ [routerLinkActiveOptions]="{ exact: false }"
1035
+ class="ui-sidebar__item"
1036
+ [class.ui-sidebar__item--active]="item.external ? !!item.active : footerRla.isActive"
1037
+ [class.ui-sidebar__item--disabled]="item.disabled"
1038
+ [disabled]="item.disabled ?? null"
1039
+ (click)="navigate(item)"
1040
+ >
1041
+ @if (item.icon) {
1042
+ <lucide-icon [name]="item.icon" [size]="20" aria-hidden="true" class="ui-sidebar__item-icon" />
1043
+ }
1044
+ <span class="ui-sidebar__item-label">
1045
+ {{ item.label }}
1046
+ @if (item.external) {
1047
+ <lucide-icon name="arrow-up-right" [size]="12" aria-hidden="true" class="ui-sidebar__external" />
1048
+ }
1049
+ </span>
1050
+ </button>
1051
+ }
1052
+ </nav>
1053
+ }
1054
+ </div>
1055
+ }
1056
+
1057
+ </div>
1058
+
1059
+ <!-- ── Footer ─────────────────────────────────────────────── -->
1060
+ @if (user()) {
1061
+ <div class="ui-sidebar__footer">
1062
+ <button
1063
+ type="button"
1064
+ class="ui-sidebar__user"
1065
+ [attr.aria-label]="'Account: ' + user()!.name"
1066
+ (click)="userClick.emit(user()!)"
1067
+ >
1068
+ @if (user()!.avatar) {
1069
+ <img
1070
+ class="ui-sidebar__avatar"
1071
+ [src]="user()!.avatar"
1072
+ [alt]="user()!.name"
1073
+ />
1074
+ } @else {
1075
+ <span class="ui-sidebar__avatar-fallback" aria-hidden="true">
1076
+ {{ user()!.name.charAt(0).toUpperCase() }}
1077
+ </span>
1078
+ }
1079
+ <span class="ui-sidebar__user-name">{{ user()!.name }}</span>
1080
+ </button>
1081
+ </div>
1082
+ }
1083
+
1084
+ </aside>
1085
+ `, isInline: true, styles: [".ui-sidebar{--sidebar-border-accented: #cad5e2;position:relative;display:flex;flex-direction:column;width:254px;height:100%;min-height:0;background:var(--color-bg);border-right:1px solid var(--color-border);overflow:hidden;transition:width var(--transition-slow)}.ui-sidebar--collapsed{width:64px}.ui-sidebar__header{position:relative;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;height:64px;padding:0 var(--spacing-4);border-bottom:1px solid var(--color-border);z-index:3}.ui-sidebar--collapsed .ui-sidebar__header{justify-content:center;padding:0 var(--spacing-2)}.ui-sidebar__logo{display:flex;align-items:center;overflow:hidden;white-space:nowrap;min-width:0}.ui-sidebar__logo-img{display:block;height:20px;width:auto;max-width:130px;object-fit:contain;flex-shrink:0;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__logo-img{max-width:32px;height:32px;object-fit:cover;border-radius:var(--radius-md)}.ui-sidebar__logo-text{font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);color:var(--color-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__logo-text{opacity:0;width:0}.ui-sidebar__toggle{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:28px;height:28px;border:1px solid var(--color-border);border-radius:var(--radius-md);background:transparent;color:var(--color-text-subtle);cursor:pointer;transition:background-color var(--transition-colors),color var(--transition-colors),border-color var(--transition-colors);padding:0}.ui-sidebar__toggle:hover{background:var(--color-bg-subtle);color:var(--color-text);border-color:var(--color-border-accent, var(--color-border))}.ui-sidebar__toggle:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar--collapsed .ui-sidebar__toggle{width:32px;height:32px}.ui-sidebar__toggle lucide-icon{display:flex}.ui-sidebar__body{display:flex;flex-direction:column;flex:1 0 0;justify-content:space-between;overflow-y:auto;overflow-x:hidden;min-height:0;padding:var(--spacing-2) var(--spacing-4) var(--spacing-4-5, 18px);scrollbar-width:thin;scrollbar-color:var(--color-border) transparent;z-index:2}.ui-sidebar--collapsed .ui-sidebar__body{padding:var(--spacing-2)}.ui-sidebar__body::-webkit-scrollbar{width:4px}.ui-sidebar__body::-webkit-scrollbar-track{background:transparent}.ui-sidebar__body::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:2px}.ui-sidebar__top{display:flex;flex-direction:column;gap:var(--spacing-4)}.ui-sidebar__bottom{display:flex;flex-direction:column;margin-top:var(--spacing-4)}.ui-sidebar__search{display:flex;align-items:center;gap:var(--spacing-1-5);width:100%;height:32px;padding:0 var(--spacing-2-5);border:1px solid var(--sidebar-border-accented);border-radius:var(--radius-md);background:var(--color-bg);color:var(--color-text);font-family:var(--font-sans);font-size:var(--text-sm, 14px);cursor:pointer;transition:background-color var(--transition-colors),border-color var(--transition-colors);text-align:left;flex-shrink:0}.ui-sidebar__search:hover{background:var(--color-bg-subtle);border-color:var(--sidebar-border-accented);color:var(--color-text)}.ui-sidebar__search:focus-visible{outline:none;border-color:var(--color-primary-500);box-shadow:0 0 0 1px var(--color-primary-500)}.ui-sidebar--collapsed .ui-sidebar__search{width:100%;height:36px;padding:0;border:1px solid var(--sidebar-border-accented);justify-content:center;border-radius:var(--radius-md)}lucide-icon.ui-sidebar__search-icon{display:flex;align-items:center;flex-shrink:0;width:20px;height:20px}lucide-icon.ui-sidebar__search-icon svg{width:100%;height:100%}.ui-sidebar__search-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:opacity var(--transition-fast),width var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__search-label{display:none}.ui-sidebar__search-kbd{display:flex;align-items:center;gap:2px;flex-shrink:0;margin-left:auto}.ui-sidebar--collapsed .ui-sidebar__search-kbd{display:none}.ui-sidebar__kbd{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0 var(--spacing-1);border:1px solid var(--sidebar-border-accented);border-radius:var(--radius-sm, 4px);background:var(--color-bg);font-size:10px;font-family:var(--font-mono, monospace);color:var(--color-text);line-height:1}.ui-sidebar__group{display:flex;flex-direction:column}.ui-sidebar__group-label{padding:var(--spacing-1) var(--spacing-2-5);font-size:var(--text-xs, 11px);font-weight:var(--font-medium, 500);color:var(--color-text-subtle);text-transform:uppercase;letter-spacing:.06em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:var(--spacing-1)}.ui-sidebar__nav-item-wrap{display:flex;flex-direction:column;padding-right:6px}.ui-sidebar__nav-item-wrap:has(.ui-sidebar__item--active){padding-right:0}.ui-sidebar--collapsed .ui-sidebar__nav-item-wrap{padding-right:0}.ui-sidebar__item{display:flex;align-items:center;gap:var(--spacing-1-5);width:100%;padding:var(--spacing-1-5) var(--spacing-2-5);border-radius:var(--radius-md);background:transparent;border:none;color:var(--color-text-muted);font-family:var(--font-sans);font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);text-decoration:none;cursor:pointer;white-space:nowrap;overflow:hidden;text-align:left;transition:background-color var(--transition-colors),color var(--transition-colors);min-height:32px}.ui-sidebar__item:hover:not(.ui-sidebar__item--disabled):not(.ui-sidebar__item--active){background:var(--color-bg-subtle);color:var(--color-text)}.ui-sidebar__item:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar__item--active{background:var(--color-bg-muted);color:var(--color-primary-500);font-weight:var(--font-semibold, 600)}.ui-sidebar__item--active:hover{background:color-mix(in srgb,var(--color-primary-500) 8%,var(--color-bg))}.ui-sidebar__item--active .ui-sidebar__item-icon svg{stroke:var(--color-primary-500)}.ui-sidebar__item--disabled{opacity:.45;cursor:not-allowed;pointer-events:none}.ui-sidebar--collapsed .ui-sidebar__item{justify-content:center;padding:var(--spacing-1-5);min-height:36px}lucide-icon.ui-sidebar__item-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:20px;height:20px}lucide-icon.ui-sidebar__item-icon svg{width:100%;height:100%;flex-shrink:0}.ui-sidebar__item--active lucide-icon.ui-sidebar__item-icon svg{stroke:var(--color-primary-500)}.ui-sidebar__item-label{display:flex;align-items:center;gap:var(--spacing-1);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__item-label{display:none}lucide-icon.ui-sidebar__external{display:inline-flex;align-items:center;width:12px;height:12px;flex-shrink:0;opacity:.5}lucide-icon.ui-sidebar__external svg{width:100%;height:100%}.ui-sidebar__badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 var(--spacing-1-5);border-radius:var(--radius-md);background:var(--color-bg);border:1px solid var(--sidebar-border-accented);color:var(--color-text);font-size:10px;font-weight:var(--font-medium, 500);line-height:1;flex-shrink:0;margin-left:auto}.ui-sidebar__chevron{display:flex;align-items:center;flex-shrink:0;margin-left:auto;color:var(--color-text-subtle);transition:transform var(--transition-fast)}.ui-sidebar__chevron svg{width:20px;height:20px}.ui-sidebar__chevron--open{transform:rotate(180deg)}.ui-sidebar__children{display:flex;flex-direction:column;padding-left:var(--spacing-5);margin-top:var(--spacing-2);overflow:hidden}.ui-sidebar__child-wrap{display:flex;align-items:center;padding:0 var(--spacing-1-5);border-left:1px solid var(--color-border);width:100%}.ui-sidebar__child-wrap--active{border-color:var(--color-primary-500)}.ui-sidebar__child{display:flex;align-items:center;gap:var(--spacing-1-5);flex:1 0 0;width:100%;padding:var(--spacing-1-5) var(--spacing-2-5);border:none;border-radius:var(--radius-md);background:transparent;color:var(--color-text-muted);font-family:var(--font-sans);font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);text-align:left;text-decoration:none;cursor:pointer;transition:background-color var(--transition-colors),color var(--transition-colors);white-space:nowrap;overflow:hidden;min-width:0}.ui-sidebar__child:hover:not(.ui-sidebar__child--disabled):not(.ui-sidebar__child--active){background:var(--color-bg-subtle);color:var(--color-text)}.ui-sidebar__child:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar__child--active{color:var(--color-primary-500);background:color-mix(in srgb,var(--color-primary-500) 6%,transparent)}.ui-sidebar__child--disabled{opacity:.45;cursor:not-allowed;pointer-events:none}lucide-icon.ui-sidebar__child-icon{display:flex;align-items:center;flex-shrink:0;width:16px;height:16px;opacity:.6}lucide-icon.ui-sidebar__child-icon svg{width:100%;height:100%}.ui-sidebar__child-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-sidebar__footer{flex-shrink:0;padding:var(--spacing-2) var(--spacing-4);border-top:1px solid var(--color-border);z-index:1}.ui-sidebar--collapsed .ui-sidebar__footer{padding:var(--spacing-2)}.ui-sidebar__user{display:flex;align-items:center;gap:var(--spacing-1-5);width:100%;padding:var(--spacing-1-5) var(--spacing-2-5);border:none;border-radius:var(--radius-md);background:transparent;color:var(--color-text);font-family:var(--font-sans);font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);cursor:pointer;text-align:left;white-space:nowrap;overflow:hidden;transition:background-color var(--transition-colors)}.ui-sidebar__user:hover{background:var(--color-bg-subtle)}.ui-sidebar__user:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar--collapsed .ui-sidebar__user{justify-content:center;padding:var(--spacing-1-5)}.ui-sidebar__avatar{width:20px;height:20px;border-radius:var(--radius-full);object-fit:cover;flex-shrink:0}.ui-sidebar--collapsed .ui-sidebar__avatar{width:24px;height:24px}.ui-sidebar__avatar-fallback{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--radius-full);background:var(--color-primary-500);color:#fff;font-size:10px;font-weight:var(--font-semibold, 600);flex-shrink:0}.ui-sidebar--collapsed .ui-sidebar__avatar-fallback{width:24px;height:24px;font-size:11px}.ui-sidebar__user-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__user-name{display:none}[data-theme=dark] .ui-sidebar{background:var(--color-neutral-950);border-color:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__header{border-color:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__toggle{border-color:var(--color-neutral-700);color:var(--color-neutral-400)}[data-theme=dark] .ui-sidebar__toggle:hover{background:var(--color-neutral-800);color:var(--color-neutral-100);border-color:var(--color-neutral-600)}[data-theme=dark] .ui-sidebar__search{background:var(--color-neutral-900);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-sidebar__search:hover{background:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__kbd{background:var(--color-neutral-800);border-color:var(--color-neutral-600);color:var(--color-neutral-300)}[data-theme=dark] .ui-sidebar__item:hover:not(.ui-sidebar__item--disabled):not(.ui-sidebar__item--active){background:var(--color-neutral-800);color:var(--color-neutral-100)}[data-theme=dark] .ui-sidebar__item--active{background:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__badge{background:var(--color-neutral-800);border-color:var(--color-neutral-700);color:var(--color-neutral-200)}[data-theme=dark] .ui-sidebar__child-wrap{border-color:var(--color-neutral-700)}[data-theme=dark] .ui-sidebar__child-wrap--active{border-color:var(--color-primary-500)}[data-theme=dark] .ui-sidebar__child:hover:not(.ui-sidebar__child--disabled){background:var(--color-neutral-800);color:var(--color-neutral-100)}[data-theme=dark] .ui-sidebar__footer{border-color:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__user:hover{background:var(--color-neutral-800)}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1$2.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }], animations: [
1086
+ trigger('expand', [
1087
+ transition(':enter', [
1088
+ style({ height: '0', opacity: 0, overflow: 'hidden' }),
1089
+ animate('180ms ease', style({ height: '*', opacity: 1, overflow: 'hidden' })),
1090
+ ]),
1091
+ transition(':leave', [
1092
+ style({ overflow: 'hidden' }),
1093
+ animate('150ms ease', style({ height: '0', opacity: 0 })),
1094
+ ]),
1095
+ ]),
1096
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1097
+ }
1098
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: SidebarComponent, decorators: [{
1099
+ type: Component,
1100
+ args: [{ selector: 'ui-sidebar', standalone: true, imports: [RouterLink, RouterLinkActive, LucideAngularModule], providers: [
1101
+ { provide: LUCIDE_ICONS, multi: true, useValue: new LucideIconProvider(SIDEBAR_ICONS) },
1102
+ ], changeDetection: ChangeDetectionStrategy.OnPush, animations: [
1103
+ trigger('expand', [
1104
+ transition(':enter', [
1105
+ style({ height: '0', opacity: 0, overflow: 'hidden' }),
1106
+ animate('180ms ease', style({ height: '*', opacity: 1, overflow: 'hidden' })),
1107
+ ]),
1108
+ transition(':leave', [
1109
+ style({ overflow: 'hidden' }),
1110
+ animate('150ms ease', style({ height: '0', opacity: 0 })),
1111
+ ]),
1112
+ ]),
1113
+ ], template: `
1114
+ <aside
1115
+ class="ui-sidebar"
1116
+ [class.ui-sidebar--collapsed]="collapsed()"
1117
+ [class.ui-sidebar--collapsible]="collapsible()"
1118
+ [attr.aria-label]="'Sidebar navigation'"
1119
+ >
1120
+
1121
+ <!-- ── Header ─────────────────────────────────────────────── -->
1122
+ <div class="ui-sidebar__header">
1123
+ <div class="ui-sidebar__logo">
1124
+ @if (logoSrc()) {
1125
+ <img [src]="logoSrc()" [alt]="logoAlt()" class="ui-sidebar__logo-img" />
1126
+ } @else {
1127
+ <span class="ui-sidebar__logo-text">{{ logoAlt() }}</span>
1128
+ }
1129
+ </div>
1130
+
1131
+ @if (collapsible()) {
1132
+ <!-- Figma: toggle uses i-lucide-chevrons-up-down, consistent in expanded & collapsed states -->
1133
+ <button
1134
+ type="button"
1135
+ class="ui-sidebar__toggle"
1136
+ [attr.aria-label]="collapsed() ? 'Expand sidebar' : 'Collapse sidebar'"
1137
+ (click)="toggleCollapse()"
1138
+ >
1139
+ <lucide-icon name="chevrons-up-down" [size]="16" aria-hidden="true" />
1140
+ </button>
1141
+ }
1142
+ </div>
1143
+
1144
+ <!-- ── Body ───────────────────────────────────────────────── -->
1145
+ <div class="ui-sidebar__body">
1146
+
1147
+ <!-- Top section: search + primary nav groups -->
1148
+ <div class="ui-sidebar__top">
1149
+
1150
+ <!-- Search button -->
1151
+ @if (showSearch()) {
1152
+ <button
1153
+ type="button"
1154
+ class="ui-sidebar__search"
1155
+ [attr.aria-label]="searchPlaceholder()"
1156
+ (click)="searchClick.emit()"
1157
+ >
1158
+ <lucide-icon name="search" [size]="20" aria-hidden="true" class="ui-sidebar__search-icon" />
1159
+ <span class="ui-sidebar__search-label">{{ searchPlaceholder() }}</span>
1160
+ <span class="ui-sidebar__search-kbd" aria-hidden="true">
1161
+ <kbd class="ui-sidebar__kbd">⌘</kbd>
1162
+ <kbd class="ui-sidebar__kbd">K</kbd>
1163
+ </span>
1164
+ </button>
1165
+ }
1166
+
1167
+ <!-- Primary nav groups -->
1168
+ @for (group of navGroups(); track $index) {
1169
+ <nav class="ui-sidebar__group" [attr.aria-label]="group.label ?? 'Navigation'">
1170
+ @if (group.label && !collapsed()) {
1171
+ <p class="ui-sidebar__group-label">{{ group.label }}</p>
1172
+ }
1173
+ @for (item of group.items; track item.id) {
1174
+ <div class="ui-sidebar__nav-item-wrap">
1175
+
1176
+ @if (item.children?.length) {
1177
+ <!-- ── Collapsible parent item ── -->
1178
+ <button
1179
+ type="button"
1180
+ class="ui-sidebar__item"
1181
+ [class.ui-sidebar__item--active]="isParentActive(item)"
1182
+ [class.ui-sidebar__item--disabled]="item.disabled"
1183
+ [attr.aria-expanded]="isItemOpen(item.id)"
1184
+ [disabled]="item.disabled ?? null"
1185
+ (click)="toggleItem(item.id)"
1186
+ >
1187
+ @if (item.icon) {
1188
+ <lucide-icon [name]="item.icon" [size]="20" aria-hidden="true" class="ui-sidebar__item-icon" />
1189
+ }
1190
+ <span class="ui-sidebar__item-label">{{ item.label }}</span>
1191
+ @if (item.badge != null && !collapsed()) {
1192
+ <span class="ui-sidebar__badge" [attr.aria-label]="item.badge + ' notifications'">
1193
+ {{ item.badge }}
1194
+ </span>
1195
+ }
1196
+ @if (!collapsed()) {
1197
+ <span class="ui-sidebar__chevron"
1198
+ [class.ui-sidebar__chevron--open]="isItemOpen(item.id)"
1199
+ aria-hidden="true">
1200
+ <lucide-icon name="chevron-down" [size]="20" />
1201
+ </span>
1202
+ }
1203
+ </button>
1204
+
1205
+ <!-- Sub-items (only in expanded mode) -->
1206
+ @if (isItemOpen(item.id) && !collapsed()) {
1207
+ <div class="ui-sidebar__children" [@expand]>
1208
+ @for (child of item.children; track child.id) {
1209
+ <!-- Figma: NavigationMenuItem child has border-l + px-[6px] on outer wrapper -->
1210
+ <div class="ui-sidebar__child-wrap"
1211
+ [class.ui-sidebar__child-wrap--active]="childRla.isActive">
1212
+ <button
1213
+ type="button"
1214
+ #childRla="routerLinkActive"
1215
+ routerLinkActive
1216
+ [routerLink]="!child.external ? (child.href ?? null) : null"
1217
+ [routerLinkActiveOptions]="{ exact: true }"
1218
+ class="ui-sidebar__child"
1219
+ [class.ui-sidebar__child--active]="child.external ? !!child.active : childRla.isActive"
1220
+ [class.ui-sidebar__child--disabled]="child.disabled"
1221
+ [disabled]="child.disabled ?? null"
1222
+ (click)="navigate(child)"
1223
+ >
1224
+ @if (child.icon) {
1225
+ <lucide-icon [name]="child.icon" [size]="16" aria-hidden="true" class="ui-sidebar__child-icon" />
1226
+ }
1227
+ <span class="ui-sidebar__child-label">{{ child.label }}</span>
1228
+ </button>
1229
+ </div>
1230
+ }
1231
+ </div>
1232
+ }
1233
+
1234
+ } @else {
1235
+ <!-- ── Simple item ── -->
1236
+ <button
1237
+ type="button"
1238
+ #navRla="routerLinkActive"
1239
+ routerLinkActive
1240
+ [routerLink]="!item.external ? (item.href ?? null) : null"
1241
+ [routerLinkActiveOptions]="{ exact: false }"
1242
+ class="ui-sidebar__item"
1243
+ [class.ui-sidebar__item--active]="item.external ? !!item.active : navRla.isActive"
1244
+ [class.ui-sidebar__item--disabled]="item.disabled"
1245
+ [disabled]="item.disabled ?? null"
1246
+ (click)="navigate(item)"
1247
+ >
1248
+ @if (item.icon) {
1249
+ <lucide-icon [name]="item.icon" [size]="20" aria-hidden="true" class="ui-sidebar__item-icon" />
1250
+ }
1251
+ <span class="ui-sidebar__item-label">
1252
+ {{ item.label }}
1253
+ @if (item.external) {
1254
+ <lucide-icon name="arrow-up-right" [size]="12" aria-hidden="true" class="ui-sidebar__external" />
1255
+ }
1256
+ </span>
1257
+ @if (item.badge != null && !collapsed()) {
1258
+ <span class="ui-sidebar__badge" [attr.aria-label]="item.badge + ' notifications'">
1259
+ {{ item.badge }}
1260
+ </span>
1261
+ }
1262
+ </button>
1263
+ }
1264
+
1265
+ </div>
1266
+ }
1267
+ </nav>
1268
+ }
1269
+ </div>
1270
+
1271
+ <!-- Bottom section: secondary / footer nav groups -->
1272
+ @if (footerGroups().length) {
1273
+ <div class="ui-sidebar__bottom">
1274
+ @for (group of footerGroups(); track $index) {
1275
+ <nav class="ui-sidebar__group" [attr.aria-label]="group.label ?? 'Footer navigation'">
1276
+ @for (item of group.items; track item.id) {
1277
+ <button
1278
+ type="button"
1279
+ #footerRla="routerLinkActive"
1280
+ routerLinkActive
1281
+ [routerLink]="!item.external ? (item.href ?? null) : null"
1282
+ [routerLinkActiveOptions]="{ exact: false }"
1283
+ class="ui-sidebar__item"
1284
+ [class.ui-sidebar__item--active]="item.external ? !!item.active : footerRla.isActive"
1285
+ [class.ui-sidebar__item--disabled]="item.disabled"
1286
+ [disabled]="item.disabled ?? null"
1287
+ (click)="navigate(item)"
1288
+ >
1289
+ @if (item.icon) {
1290
+ <lucide-icon [name]="item.icon" [size]="20" aria-hidden="true" class="ui-sidebar__item-icon" />
1291
+ }
1292
+ <span class="ui-sidebar__item-label">
1293
+ {{ item.label }}
1294
+ @if (item.external) {
1295
+ <lucide-icon name="arrow-up-right" [size]="12" aria-hidden="true" class="ui-sidebar__external" />
1296
+ }
1297
+ </span>
1298
+ </button>
1299
+ }
1300
+ </nav>
1301
+ }
1302
+ </div>
1303
+ }
1304
+
1305
+ </div>
1306
+
1307
+ <!-- ── Footer ─────────────────────────────────────────────── -->
1308
+ @if (user()) {
1309
+ <div class="ui-sidebar__footer">
1310
+ <button
1311
+ type="button"
1312
+ class="ui-sidebar__user"
1313
+ [attr.aria-label]="'Account: ' + user()!.name"
1314
+ (click)="userClick.emit(user()!)"
1315
+ >
1316
+ @if (user()!.avatar) {
1317
+ <img
1318
+ class="ui-sidebar__avatar"
1319
+ [src]="user()!.avatar"
1320
+ [alt]="user()!.name"
1321
+ />
1322
+ } @else {
1323
+ <span class="ui-sidebar__avatar-fallback" aria-hidden="true">
1324
+ {{ user()!.name.charAt(0).toUpperCase() }}
1325
+ </span>
1326
+ }
1327
+ <span class="ui-sidebar__user-name">{{ user()!.name }}</span>
1328
+ </button>
1329
+ </div>
1330
+ }
1331
+
1332
+ </aside>
1333
+ `, styles: [".ui-sidebar{--sidebar-border-accented: #cad5e2;position:relative;display:flex;flex-direction:column;width:254px;height:100%;min-height:0;background:var(--color-bg);border-right:1px solid var(--color-border);overflow:hidden;transition:width var(--transition-slow)}.ui-sidebar--collapsed{width:64px}.ui-sidebar__header{position:relative;display:flex;align-items:center;justify-content:space-between;flex-shrink:0;height:64px;padding:0 var(--spacing-4);border-bottom:1px solid var(--color-border);z-index:3}.ui-sidebar--collapsed .ui-sidebar__header{justify-content:center;padding:0 var(--spacing-2)}.ui-sidebar__logo{display:flex;align-items:center;overflow:hidden;white-space:nowrap;min-width:0}.ui-sidebar__logo-img{display:block;height:20px;width:auto;max-width:130px;object-fit:contain;flex-shrink:0;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__logo-img{max-width:32px;height:32px;object-fit:cover;border-radius:var(--radius-md)}.ui-sidebar__logo-text{font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);color:var(--color-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__logo-text{opacity:0;width:0}.ui-sidebar__toggle{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:28px;height:28px;border:1px solid var(--color-border);border-radius:var(--radius-md);background:transparent;color:var(--color-text-subtle);cursor:pointer;transition:background-color var(--transition-colors),color var(--transition-colors),border-color var(--transition-colors);padding:0}.ui-sidebar__toggle:hover{background:var(--color-bg-subtle);color:var(--color-text);border-color:var(--color-border-accent, var(--color-border))}.ui-sidebar__toggle:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar--collapsed .ui-sidebar__toggle{width:32px;height:32px}.ui-sidebar__toggle lucide-icon{display:flex}.ui-sidebar__body{display:flex;flex-direction:column;flex:1 0 0;justify-content:space-between;overflow-y:auto;overflow-x:hidden;min-height:0;padding:var(--spacing-2) var(--spacing-4) var(--spacing-4-5, 18px);scrollbar-width:thin;scrollbar-color:var(--color-border) transparent;z-index:2}.ui-sidebar--collapsed .ui-sidebar__body{padding:var(--spacing-2)}.ui-sidebar__body::-webkit-scrollbar{width:4px}.ui-sidebar__body::-webkit-scrollbar-track{background:transparent}.ui-sidebar__body::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:2px}.ui-sidebar__top{display:flex;flex-direction:column;gap:var(--spacing-4)}.ui-sidebar__bottom{display:flex;flex-direction:column;margin-top:var(--spacing-4)}.ui-sidebar__search{display:flex;align-items:center;gap:var(--spacing-1-5);width:100%;height:32px;padding:0 var(--spacing-2-5);border:1px solid var(--sidebar-border-accented);border-radius:var(--radius-md);background:var(--color-bg);color:var(--color-text);font-family:var(--font-sans);font-size:var(--text-sm, 14px);cursor:pointer;transition:background-color var(--transition-colors),border-color var(--transition-colors);text-align:left;flex-shrink:0}.ui-sidebar__search:hover{background:var(--color-bg-subtle);border-color:var(--sidebar-border-accented);color:var(--color-text)}.ui-sidebar__search:focus-visible{outline:none;border-color:var(--color-primary-500);box-shadow:0 0 0 1px var(--color-primary-500)}.ui-sidebar--collapsed .ui-sidebar__search{width:100%;height:36px;padding:0;border:1px solid var(--sidebar-border-accented);justify-content:center;border-radius:var(--radius-md)}lucide-icon.ui-sidebar__search-icon{display:flex;align-items:center;flex-shrink:0;width:20px;height:20px}lucide-icon.ui-sidebar__search-icon svg{width:100%;height:100%}.ui-sidebar__search-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:opacity var(--transition-fast),width var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__search-label{display:none}.ui-sidebar__search-kbd{display:flex;align-items:center;gap:2px;flex-shrink:0;margin-left:auto}.ui-sidebar--collapsed .ui-sidebar__search-kbd{display:none}.ui-sidebar__kbd{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0 var(--spacing-1);border:1px solid var(--sidebar-border-accented);border-radius:var(--radius-sm, 4px);background:var(--color-bg);font-size:10px;font-family:var(--font-mono, monospace);color:var(--color-text);line-height:1}.ui-sidebar__group{display:flex;flex-direction:column}.ui-sidebar__group-label{padding:var(--spacing-1) var(--spacing-2-5);font-size:var(--text-xs, 11px);font-weight:var(--font-medium, 500);color:var(--color-text-subtle);text-transform:uppercase;letter-spacing:.06em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:var(--spacing-1)}.ui-sidebar__nav-item-wrap{display:flex;flex-direction:column;padding-right:6px}.ui-sidebar__nav-item-wrap:has(.ui-sidebar__item--active){padding-right:0}.ui-sidebar--collapsed .ui-sidebar__nav-item-wrap{padding-right:0}.ui-sidebar__item{display:flex;align-items:center;gap:var(--spacing-1-5);width:100%;padding:var(--spacing-1-5) var(--spacing-2-5);border-radius:var(--radius-md);background:transparent;border:none;color:var(--color-text-muted);font-family:var(--font-sans);font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);text-decoration:none;cursor:pointer;white-space:nowrap;overflow:hidden;text-align:left;transition:background-color var(--transition-colors),color var(--transition-colors);min-height:32px}.ui-sidebar__item:hover:not(.ui-sidebar__item--disabled):not(.ui-sidebar__item--active){background:var(--color-bg-subtle);color:var(--color-text)}.ui-sidebar__item:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar__item--active{background:var(--color-bg-muted);color:var(--color-primary-500);font-weight:var(--font-semibold, 600)}.ui-sidebar__item--active:hover{background:color-mix(in srgb,var(--color-primary-500) 8%,var(--color-bg))}.ui-sidebar__item--active .ui-sidebar__item-icon svg{stroke:var(--color-primary-500)}.ui-sidebar__item--disabled{opacity:.45;cursor:not-allowed;pointer-events:none}.ui-sidebar--collapsed .ui-sidebar__item{justify-content:center;padding:var(--spacing-1-5);min-height:36px}lucide-icon.ui-sidebar__item-icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:20px;height:20px}lucide-icon.ui-sidebar__item-icon svg{width:100%;height:100%;flex-shrink:0}.ui-sidebar__item--active lucide-icon.ui-sidebar__item-icon svg{stroke:var(--color-primary-500)}.ui-sidebar__item-label{display:flex;align-items:center;gap:var(--spacing-1);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__item-label{display:none}lucide-icon.ui-sidebar__external{display:inline-flex;align-items:center;width:12px;height:12px;flex-shrink:0;opacity:.5}lucide-icon.ui-sidebar__external svg{width:100%;height:100%}.ui-sidebar__badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 var(--spacing-1-5);border-radius:var(--radius-md);background:var(--color-bg);border:1px solid var(--sidebar-border-accented);color:var(--color-text);font-size:10px;font-weight:var(--font-medium, 500);line-height:1;flex-shrink:0;margin-left:auto}.ui-sidebar__chevron{display:flex;align-items:center;flex-shrink:0;margin-left:auto;color:var(--color-text-subtle);transition:transform var(--transition-fast)}.ui-sidebar__chevron svg{width:20px;height:20px}.ui-sidebar__chevron--open{transform:rotate(180deg)}.ui-sidebar__children{display:flex;flex-direction:column;padding-left:var(--spacing-5);margin-top:var(--spacing-2);overflow:hidden}.ui-sidebar__child-wrap{display:flex;align-items:center;padding:0 var(--spacing-1-5);border-left:1px solid var(--color-border);width:100%}.ui-sidebar__child-wrap--active{border-color:var(--color-primary-500)}.ui-sidebar__child{display:flex;align-items:center;gap:var(--spacing-1-5);flex:1 0 0;width:100%;padding:var(--spacing-1-5) var(--spacing-2-5);border:none;border-radius:var(--radius-md);background:transparent;color:var(--color-text-muted);font-family:var(--font-sans);font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);text-align:left;text-decoration:none;cursor:pointer;transition:background-color var(--transition-colors),color var(--transition-colors);white-space:nowrap;overflow:hidden;min-width:0}.ui-sidebar__child:hover:not(.ui-sidebar__child--disabled):not(.ui-sidebar__child--active){background:var(--color-bg-subtle);color:var(--color-text)}.ui-sidebar__child:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar__child--active{color:var(--color-primary-500);background:color-mix(in srgb,var(--color-primary-500) 6%,transparent)}.ui-sidebar__child--disabled{opacity:.45;cursor:not-allowed;pointer-events:none}lucide-icon.ui-sidebar__child-icon{display:flex;align-items:center;flex-shrink:0;width:16px;height:16px;opacity:.6}lucide-icon.ui-sidebar__child-icon svg{width:100%;height:100%}.ui-sidebar__child-label{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-sidebar__footer{flex-shrink:0;padding:var(--spacing-2) var(--spacing-4);border-top:1px solid var(--color-border);z-index:1}.ui-sidebar--collapsed .ui-sidebar__footer{padding:var(--spacing-2)}.ui-sidebar__user{display:flex;align-items:center;gap:var(--spacing-1-5);width:100%;padding:var(--spacing-1-5) var(--spacing-2-5);border:none;border-radius:var(--radius-md);background:transparent;color:var(--color-text);font-family:var(--font-sans);font-size:var(--text-sm, 14px);font-weight:var(--font-medium, 500);cursor:pointer;text-align:left;white-space:nowrap;overflow:hidden;transition:background-color var(--transition-colors)}.ui-sidebar__user:hover{background:var(--color-bg-subtle)}.ui-sidebar__user:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.ui-sidebar--collapsed .ui-sidebar__user{justify-content:center;padding:var(--spacing-1-5)}.ui-sidebar__avatar{width:20px;height:20px;border-radius:var(--radius-full);object-fit:cover;flex-shrink:0}.ui-sidebar--collapsed .ui-sidebar__avatar{width:24px;height:24px}.ui-sidebar__avatar-fallback{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:var(--radius-full);background:var(--color-primary-500);color:#fff;font-size:10px;font-weight:var(--font-semibold, 600);flex-shrink:0}.ui-sidebar--collapsed .ui-sidebar__avatar-fallback{width:24px;height:24px;font-size:11px}.ui-sidebar__user-name{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;transition:opacity var(--transition-fast)}.ui-sidebar--collapsed .ui-sidebar__user-name{display:none}[data-theme=dark] .ui-sidebar{background:var(--color-neutral-950);border-color:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__header{border-color:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__toggle{border-color:var(--color-neutral-700);color:var(--color-neutral-400)}[data-theme=dark] .ui-sidebar__toggle:hover{background:var(--color-neutral-800);color:var(--color-neutral-100);border-color:var(--color-neutral-600)}[data-theme=dark] .ui-sidebar__search{background:var(--color-neutral-900);border-color:var(--color-neutral-700)}[data-theme=dark] .ui-sidebar__search:hover{background:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__kbd{background:var(--color-neutral-800);border-color:var(--color-neutral-600);color:var(--color-neutral-300)}[data-theme=dark] .ui-sidebar__item:hover:not(.ui-sidebar__item--disabled):not(.ui-sidebar__item--active){background:var(--color-neutral-800);color:var(--color-neutral-100)}[data-theme=dark] .ui-sidebar__item--active{background:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__badge{background:var(--color-neutral-800);border-color:var(--color-neutral-700);color:var(--color-neutral-200)}[data-theme=dark] .ui-sidebar__child-wrap{border-color:var(--color-neutral-700)}[data-theme=dark] .ui-sidebar__child-wrap--active{border-color:var(--color-primary-500)}[data-theme=dark] .ui-sidebar__child:hover:not(.ui-sidebar__child--disabled){background:var(--color-neutral-800);color:var(--color-neutral-100)}[data-theme=dark] .ui-sidebar__footer{border-color:var(--color-neutral-800)}[data-theme=dark] .ui-sidebar__user:hover{background:var(--color-neutral-800)}\n"] }]
1334
+ }], ctorParameters: () => [] });
1335
+
1336
+ // ============================================================
1337
+ // ORGANISMS — Nuxt UI v3 Design Kit → Angular 19 + NX
1338
+ // Complex components composed of atoms + molecules
1339
+ // ============================================================
1340
+
1341
+ /**
1342
+ * Generated bundle index. Do not edit.
1343
+ */
1344
+
1345
+ export { AccordionComponent, CardComponent, DropdownMenuComponent, ModalComponent, NavigationMenuComponent, SidebarComponent, TableComponent, UiTableCellDirective };
1346
+ //# sourceMappingURL=atomng-ui-organisms.mjs.map