@stacksjs/components 0.2.27 → 0.2.53

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 (237) hide show
  1. package/dist/Accordion-19x8q4rj.stx +88 -0
  2. package/dist/{Audio-vdmg1258.stx → Audio-hjywk3qc.stx} +4 -4
  3. package/dist/{Avatar-365cvrh4.stx → Avatar-h3jmwcq0.stx} +23 -34
  4. package/dist/{Badge-8m3qete4.stx → Badge-k8dy3d53.stx} +11 -19
  5. package/dist/{Button-3tt4vsqt.stx → Button-1vknasy3.stx} +18 -33
  6. package/dist/Calendar-reny0et7.stx +189 -0
  7. package/dist/{Card-6wdbexqr.stx → Card-c1g1fd1w.stx} +27 -33
  8. package/dist/{Checkbox-p3q3e3nf.stx → Checkbox-zgdmy3p5.stx} +36 -44
  9. package/dist/{Checkout-e4037tyy.stx → Checkout-agt0ngpw.stx} +8 -16
  10. package/dist/Combobox-fdkr6cdq.stx +96 -0
  11. package/dist/{ComboboxButton-8gxwkhdx.stx → ComboboxButton-g76stp1e.stx} +14 -2
  12. package/dist/{ComboboxInput-mk99z65n.stx → ComboboxInput-z1293bbh.stx} +12 -5
  13. package/dist/ComboboxOption-hmxt3gte.stx +49 -0
  14. package/dist/{ListboxOptions-8kqvfp7z.stx → ComboboxOptions-sq5360ae.stx} +2 -2
  15. package/dist/CommandPalette-36mxf05w.stx +81 -0
  16. package/dist/CommandPaletteItem-mvk6q7a2.stx +27 -0
  17. package/dist/Dialog-hczpexs4.stx +37 -0
  18. package/dist/{Drawer-p7m351bn.stx → Drawer-xhevp5cw.stx} +29 -49
  19. package/dist/Dropdown-vvhemtc0.stx +82 -0
  20. package/dist/{DropdownButton-9w8zkfwj.stx → DropdownButton-wcz67dxy.stx} +12 -6
  21. package/dist/DropdownItem-c7rz08e5.stx +35 -0
  22. package/dist/{DropdownItems-aygjpxkx.stx → DropdownItems-1sxnd5qn.stx} +2 -2
  23. package/dist/EmailInput-vak3kkmk.stx +30 -0
  24. package/dist/Form-mas630hy.stx +95 -0
  25. package/dist/{Image-jhkm6w1f.stx → Image-yhxcvgzs.stx} +68 -100
  26. package/dist/Listbox-q49tnr90.stx +101 -0
  27. package/dist/{ListboxButton-spwx7513.stx → ListboxButton-keb8gm0q.stx} +12 -1
  28. package/dist/ListboxOption-e0dtv1gc.stx +49 -0
  29. package/dist/{ComboboxOptions-6b5ywc5x.stx → ListboxOptions-ejkatcfg.stx} +7 -3
  30. package/dist/{Login-rx9gyqhx.stx → Login-gepemsth.stx} +17 -19
  31. package/dist/Navigator-rk2a5wvk.stx +113 -0
  32. package/dist/Notification-tb9b525s.stx +78 -0
  33. package/dist/{NumberInput-nzpkx1ry.stx → NumberInput-drnvtqej.stx} +40 -53
  34. package/dist/{Pagination-h61eq390.stx → Pagination-n3d31cns.stx} +73 -108
  35. package/dist/PasswordInput-n02x6053.stx +142 -0
  36. package/dist/{PaymentMethods-j42jsk5x.stx → PaymentMethods-x4vrx9yb.stx} +21 -30
  37. package/dist/Popover-et2q44m7.stx +60 -0
  38. package/dist/{PopoverButton-fnaqc77g.stx → PopoverButton-mffzc9pr.stx} +12 -6
  39. package/dist/{PopoverPanel-y0vtf5w9.stx → PopoverPanel-054yh38h.stx} +6 -6
  40. package/dist/{Portal-s2q37yp0.stx → Portal-1vf14s4x.stx} +20 -37
  41. package/dist/{Progress-vmdkm06p.stx → Progress-yxcntr4x.stx} +36 -48
  42. package/dist/{Radio-04bs3d21.stx → Radio-cgjv2hb2.stx} +29 -34
  43. package/dist/RadioGroup-qxmnm3xm.stx +60 -0
  44. package/dist/RadioGroupOption-s1d6r221.stx +58 -0
  45. package/dist/SearchInput-pdx7agn0.stx +44 -0
  46. package/dist/{Select-g4mmvfv8.stx → Select-28y0pg83.stx} +23 -31
  47. package/dist/Sidebar-73vc78as.stx +236 -0
  48. package/dist/SidebarFooter-zsfsgcxb.stx +109 -0
  49. package/dist/SidebarHeader-7v174a9c.stx +122 -0
  50. package/dist/SidebarItem-3y3e8g2t.stx +92 -0
  51. package/dist/SidebarSection-z5ey6awe.stx +113 -0
  52. package/dist/{Signup-c4dyv6f3.stx → Signup-hxm5hwkr.stx} +26 -28
  53. package/dist/{StepperStep-en4r00zv.stx → StepperStep-wxgembat.stx} +9 -5
  54. package/dist/{SubscriptionCheckout-gawjzf3q.stx → SubscriptionCheckout-zy2ycrmw.stx} +99 -129
  55. package/dist/Switch-r5t5w04w.stx +70 -0
  56. package/dist/{TableHeader-ydys9rzz.stx → TableHeader-0eyzbqpz.stx} +10 -3
  57. package/dist/Tabs-bzvvn4ke.stx +126 -0
  58. package/dist/Teleport-tsx4bt4n.stx +65 -0
  59. package/dist/{TextInput-k2kfkgy1.stx → TextInput-kf084763.stx} +42 -59
  60. package/dist/{Textarea-szad57dz.stx → Textarea-xg4rr2xz.stx} +42 -54
  61. package/dist/{Tooltip-em7t551n.stx → Tooltip-m0tqd72e.stx} +34 -40
  62. package/dist/Transition-7smenaz8.stx +102 -0
  63. package/dist/{TwoFactorChallenge-an9yvxvq.stx → TwoFactorChallenge-y5m3nk79.stx} +49 -63
  64. package/dist/{Video-crxva65p.stx → Video-84j4pv6h.stx} +4 -4
  65. package/dist/VirtualList-fa7v5a3h.stx +67 -0
  66. package/dist/VirtualTable-f9crbfjr.stx +103 -0
  67. package/dist/components/CodeBlock.stx +1 -6
  68. package/dist/index.js +13 -13
  69. package/dist/ui/accordion/Accordion.stx +1 -3
  70. package/dist/ui/auth/Login.stx +0 -1
  71. package/dist/ui/auth/Signup.stx +0 -1
  72. package/dist/ui/auth/TwoFactorChallenge.stx +1 -3
  73. package/dist/ui/avatar/Avatar.stx +0 -2
  74. package/dist/ui/badge/Badge.stx +0 -1
  75. package/dist/ui/button/Button.stx +1 -2
  76. package/dist/ui/calendar/Calendar.stx +12 -2
  77. package/dist/ui/card/Card.stx +0 -2
  78. package/dist/ui/checkbox/Checkbox.stx +2 -2
  79. package/dist/ui/combobox/Combobox.stx +2 -1
  80. package/dist/ui/combobox/ComboboxButton.stx +1 -0
  81. package/dist/ui/combobox/ComboboxInput.stx +1 -4
  82. package/dist/ui/combobox/ComboboxOption.stx +2 -9
  83. package/dist/ui/combobox/ComboboxOptions.stx +1 -1
  84. package/dist/ui/command-palette/CommandPalette.stx +3 -6
  85. package/dist/ui/command-palette/CommandPaletteItem.stx +2 -7
  86. package/dist/ui/dialog/Dialog.stx +1 -3
  87. package/dist/ui/drawer/Drawer.stx +1 -3
  88. package/dist/ui/dropdown/Dropdown.stx +2 -5
  89. package/dist/ui/dropdown/DropdownButton.stx +1 -3
  90. package/dist/ui/dropdown/DropdownItem.stx +2 -7
  91. package/dist/ui/dropdown/DropdownItems.stx +1 -1
  92. package/dist/ui/form/Form.stx +0 -5
  93. package/dist/ui/image/Image.stx +1 -6
  94. package/dist/ui/input/EmailInput.stx +1 -1
  95. package/dist/ui/input/NumberInput.stx +0 -1
  96. package/dist/ui/input/PasswordInput.stx +1 -4
  97. package/dist/ui/input/SearchInput.stx +2 -2
  98. package/dist/ui/input/TextInput.stx +1 -2
  99. package/dist/ui/listbox/Listbox.stx +2 -1
  100. package/dist/ui/listbox/ListboxButton.stx +1 -0
  101. package/dist/ui/listbox/ListboxOption.stx +2 -9
  102. package/dist/ui/listbox/ListboxOptions.stx +1 -1
  103. package/dist/ui/navigator/Navigator.stx +4 -4
  104. package/dist/ui/notification/Notification.stx +1 -5
  105. package/dist/ui/pagination/Pagination.stx +1 -2
  106. package/dist/ui/payment/Checkout.stx +0 -4
  107. package/dist/ui/payment/PaymentMethods.stx +15 -2
  108. package/dist/ui/payment/SubscriptionCheckout.stx +3 -184
  109. package/dist/ui/popover/Popover.stx +2 -5
  110. package/dist/ui/popover/PopoverButton.stx +1 -3
  111. package/dist/ui/popover/PopoverPanel.stx +1 -1
  112. package/dist/ui/portal/Portal.stx +1 -0
  113. package/dist/ui/progress/Progress.stx +6 -1
  114. package/dist/ui/radio/Radio.stx +1 -1
  115. package/dist/ui/radio-group/RadioGroup.stx +2 -1
  116. package/dist/ui/radio-group/RadioGroupOption.stx +2 -9
  117. package/dist/ui/select/Select.stx +1 -1
  118. package/dist/ui/sidebar/Sidebar.stx +9 -26
  119. package/dist/ui/sidebar/SidebarFooter.stx +6 -21
  120. package/dist/ui/sidebar/SidebarHeader.stx +7 -18
  121. package/dist/ui/sidebar/SidebarItem.stx +4 -20
  122. package/dist/ui/sidebar/SidebarSection.stx +5 -18
  123. package/dist/ui/sidebar/index.d.ts +13 -1
  124. package/dist/ui/stepper/StepperStep.stx +1 -5
  125. package/dist/ui/switch/Switch.stx +4 -10
  126. package/dist/ui/table/TableHeader.stx +1 -1
  127. package/dist/ui/tabs/Tabs.stx +0 -1
  128. package/dist/ui/teleport/Teleport.stx +1 -0
  129. package/dist/ui/textarea/Textarea.stx +1 -1
  130. package/dist/ui/tooltip/Tooltip.stx +1 -2
  131. package/dist/ui/transition/Transition.stx +9 -16
  132. package/dist/ui/virtual-list/VirtualList.stx +2 -4
  133. package/dist/ui/virtual-table/VirtualTable.stx +1 -1
  134. package/package.json +3 -3
  135. package/src/components/CodeBlock.stx +26 -29
  136. package/src/components/Footer.stx +1 -1
  137. package/src/components/Hero.stx +1 -1
  138. package/src/components/Installation.stx +5 -7
  139. package/src/ui/accordion/Accordion.stx +48 -68
  140. package/src/ui/audio/Audio.stx +4 -4
  141. package/src/ui/auth/Login.stx +17 -19
  142. package/src/ui/auth/Signup.stx +26 -28
  143. package/src/ui/auth/TwoFactorChallenge.stx +49 -63
  144. package/src/ui/avatar/Avatar.stx +23 -34
  145. package/src/ui/badge/Badge.stx +11 -19
  146. package/src/ui/button/Button.stx +18 -33
  147. package/src/ui/calendar/Calendar.stx +93 -136
  148. package/src/ui/card/Card.stx +27 -33
  149. package/src/ui/checkbox/Checkbox.stx +36 -44
  150. package/src/ui/combobox/Combobox.stx +87 -4
  151. package/src/ui/combobox/ComboboxButton.stx +14 -2
  152. package/src/ui/combobox/ComboboxInput.stx +12 -5
  153. package/src/ui/combobox/ComboboxOption.stx +29 -32
  154. package/src/ui/combobox/ComboboxOptions.stx +7 -3
  155. package/src/ui/command-palette/CommandPalette.stx +70 -28
  156. package/src/ui/command-palette/CommandPaletteItem.stx +15 -20
  157. package/src/ui/dialog/Dialog.stx +28 -10
  158. package/src/ui/drawer/Drawer.stx +29 -49
  159. package/src/ui/dropdown/Dropdown.stx +69 -11
  160. package/src/ui/dropdown/DropdownButton.stx +12 -6
  161. package/src/ui/dropdown/DropdownItem.stx +18 -26
  162. package/src/ui/dropdown/DropdownItems.stx +2 -2
  163. package/src/ui/form/Form.stx +50 -164
  164. package/src/ui/heatmap/Heatmap.stx +16 -37
  165. package/src/ui/image/Image.stx +68 -100
  166. package/src/ui/input/EmailInput.stx +16 -27
  167. package/src/ui/input/NumberInput.stx +40 -53
  168. package/src/ui/input/PasswordInput.stx +64 -77
  169. package/src/ui/input/SearchInput.stx +27 -46
  170. package/src/ui/input/TextInput.stx +42 -59
  171. package/src/ui/listbox/Listbox.stx +91 -4
  172. package/src/ui/listbox/ListboxButton.stx +12 -1
  173. package/src/ui/listbox/ListboxOption.stx +30 -38
  174. package/src/ui/listbox/ListboxOptions.stx +2 -2
  175. package/src/ui/navigator/Navigator.stx +52 -77
  176. package/src/ui/notification/Notification.stx +46 -39
  177. package/src/ui/pagination/Pagination.stx +73 -108
  178. package/src/ui/payment/Checkout.stx +8 -16
  179. package/src/ui/payment/PaymentMethods.stx +21 -30
  180. package/src/ui/payment/SubscriptionCheckout.stx +99 -129
  181. package/src/ui/popover/Popover.stx +50 -14
  182. package/src/ui/popover/PopoverButton.stx +12 -6
  183. package/src/ui/popover/PopoverPanel.stx +6 -6
  184. package/src/ui/portal/Portal.stx +20 -37
  185. package/src/ui/progress/Progress.stx +36 -48
  186. package/src/ui/radio/Radio.stx +29 -34
  187. package/src/ui/radio-group/RadioGroup.stx +51 -4
  188. package/src/ui/radio-group/RadioGroupOption.stx +37 -30
  189. package/src/ui/select/Select.stx +23 -31
  190. package/src/ui/sidebar/Sidebar.stx +136 -188
  191. package/src/ui/sidebar/SidebarFooter.stx +49 -35
  192. package/src/ui/sidebar/SidebarHeader.stx +52 -30
  193. package/src/ui/sidebar/SidebarItem.stx +52 -78
  194. package/src/ui/sidebar/SidebarSection.stx +56 -51
  195. package/src/ui/sidebar/index.ts +21 -1
  196. package/src/ui/stepper/StepperStep.stx +9 -5
  197. package/src/ui/switch/Switch.stx +38 -42
  198. package/src/ui/table/TableHeader.stx +10 -3
  199. package/src/ui/tabs/Tabs.stx +68 -87
  200. package/src/ui/teleport/Teleport.stx +23 -59
  201. package/src/ui/textarea/Textarea.stx +42 -54
  202. package/src/ui/tooltip/Tooltip.stx +34 -40
  203. package/src/ui/transition/Transition.stx +76 -148
  204. package/src/ui/video/Video.stx +4 -4
  205. package/src/ui/virtual-list/VirtualList.stx +45 -61
  206. package/src/ui/virtual-table/VirtualTable.stx +62 -72
  207. package/dist/Accordion-sbfra0mz.stx +0 -108
  208. package/dist/Calendar-58nnkdh8.stx +0 -232
  209. package/dist/Combobox-th5ebw62.stx +0 -13
  210. package/dist/ComboboxOption-an9zyan6.stx +0 -52
  211. package/dist/CommandPalette-kwmdf2np.stx +0 -39
  212. package/dist/CommandPaletteItem-zx2fbpts.stx +0 -32
  213. package/dist/Dialog-rgmj8q2j.stx +0 -19
  214. package/dist/Dropdown-jz4jy0n3.stx +0 -24
  215. package/dist/DropdownItem-wagdspb8.stx +0 -43
  216. package/dist/EmailInput-ajsp9vw6.stx +0 -41
  217. package/dist/Form-1mdmx9b6.stx +0 -209
  218. package/dist/Listbox-pqqh72g8.stx +0 -14
  219. package/dist/ListboxOption-7nxzaexq.stx +0 -57
  220. package/dist/Navigator-aay8bjab.stx +0 -138
  221. package/dist/Notification-gk33gv7b.stx +0 -71
  222. package/dist/PasswordInput-zv4hm43j.stx +0 -155
  223. package/dist/Popover-469gbt6r.stx +0 -24
  224. package/dist/RadioGroup-bvb1mrhd.stx +0 -13
  225. package/dist/RadioGroupOption-cpdwgnhw.stx +0 -51
  226. package/dist/SearchInput-2521m475.stx +0 -63
  227. package/dist/Sidebar-40ckbzh8.stx +0 -288
  228. package/dist/SidebarFooter-hnth56mg.stx +0 -95
  229. package/dist/SidebarHeader-3wrte2p2.stx +0 -100
  230. package/dist/SidebarItem-zqtvvzpc.stx +0 -118
  231. package/dist/SidebarSection-3etwnbjr.stx +0 -108
  232. package/dist/Switch-036j9vm1.stx +0 -74
  233. package/dist/Tabs-svh721m0.stx +0 -145
  234. package/dist/Teleport-qfch3w0b.stx +0 -101
  235. package/dist/Transition-0hmr6zxb.stx +0 -174
  236. package/dist/VirtualList-cndhjejh.stx +0 -83
  237. package/dist/VirtualTable-ng0b48yp.stx +0 -113
@@ -0,0 +1,236 @@
1
+ <script server>
2
+ export const sections = $props.sections || []
3
+ export const collapsed = $props.collapsed ?? false
4
+ export const collapsible = $props.collapsible ?? true
5
+ export const width = $props.width || 240
6
+ export const minWidth = $props.minWidth || 64
7
+ export const variant = $props.variant || 'tahoe'
8
+ export const position = $props.position || 'left'
9
+ export const placement = $props.placement || 'fixed'
10
+ export const bordered = $props.bordered ?? true
11
+ export const className = $props.className || ''
12
+
13
+ const variantStyles = {
14
+ tahoe: {
15
+ bg: 'bg-white/70 dark:bg-black/50',
16
+ border: 'border-black/5 dark:border-white/10',
17
+ backdrop: 'backdrop-blur-2xl backdrop-saturate-180',
18
+ tint: true,
19
+ },
20
+ vibrancy: {
21
+ bg: 'bg-white/50 dark:bg-black/40',
22
+ border: 'border-white/20 dark:border-white/10',
23
+ backdrop: 'backdrop-blur-3xl backdrop-saturate-200',
24
+ tint: false,
25
+ },
26
+ solid: {
27
+ bg: 'bg-stone-100 dark:bg-neutral-900',
28
+ border: 'border-stone-200 dark:border-neutral-800',
29
+ backdrop: '',
30
+ tint: false,
31
+ },
32
+ transparent: {
33
+ bg: 'bg-transparent',
34
+ border: 'border-transparent',
35
+ backdrop: '',
36
+ tint: false,
37
+ },
38
+ workspace: {
39
+ bg: 'bg-[#f4f4f3] dark:bg-neutral-950',
40
+ border: 'border-transparent',
41
+ backdrop: '',
42
+ tint: false,
43
+ nav: 'px-5 py-5 space-y-1',
44
+ slot: 'px-5 py-5',
45
+ },
46
+ desktop: {
47
+ bg: 'bg-white/42 dark:bg-black/32',
48
+ border: 'border-white/30 dark:border-white/10',
49
+ backdrop: 'backdrop-blur-3xl backdrop-saturate-200',
50
+ tint: false,
51
+ shimmer: true,
52
+ nav: 'px-4 py-4 space-y-1',
53
+ slot: 'px-4 py-4',
54
+ },
55
+ }
56
+
57
+ const style = variantStyles[variant] || variantStyles.tahoe
58
+ export const variantTint = style.tint
59
+ export const variantShimmer = style.shimmer
60
+ const borderSide = position === 'left' ? 'border-r' : 'border-l'
61
+ const borderClasses = bordered ? `${borderSide} ${style.border}` : ''
62
+ const positionClass = position === 'left' ? 'left-0' : 'right-0'
63
+ const placementClasses = {
64
+ fixed: `fixed inset-y-0 z-50 ${positionClass}`,
65
+ sticky: 'sticky top-0 h-screen',
66
+ static: 'relative h-full',
67
+ }
68
+
69
+ export const containerClasses = [
70
+ placementClasses[placement] || placementClasses.fixed,
71
+ 'flex flex-col',
72
+ 'transition-all duration-300 ease-out',
73
+ 'overflow-hidden',
74
+ style.bg,
75
+ style.backdrop,
76
+ borderClasses,
77
+ className,
78
+ ].filter(Boolean).join(' ')
79
+
80
+ export const collapseBtnPosition = position === 'left' ? 'right-2' : 'left-2'
81
+ export const navClasses = style.nav || 'px-3 py-2 space-y-1'
82
+ export const slotClasses = style.slot || 'px-3 py-2'
83
+ </script>
84
+
85
+ <script client>
86
+ const emit = defineEmits()
87
+ const collapsedProp = {{ collapsed }}
88
+ const collapsibleProp = {{ collapsible }}
89
+ const widthProp = {{ width }}
90
+ const minWidthProp = {{ minWidth }}
91
+ const sectionsProp = {{ sections }}
92
+ const positionProp = {{ position }}
93
+ const variantProp = {{ variant }}
94
+
95
+ const collapsed = state(collapsedProp)
96
+ const isHovered = state(false)
97
+ const hasNativeSidebar = state(false)
98
+
99
+ const showExpanded = derived(() => !collapsed() || isHovered())
100
+ const sidebarWidth = derived(() => {
101
+ if (collapsed() && !isHovered()) return `${minWidthProp}px`
102
+ return `${widthProp}px`
103
+ })
104
+ const collapseAriaLabel = derived(() => collapsed() ? 'Expand sidebar' : 'Collapse sidebar')
105
+ const collapseIconClass = derived(() => collapsed() ? 'i-hugeicons-sidebar-right' : 'i-hugeicons-sidebar-left')
106
+
107
+ function onMouseEnter() {
108
+ if (collapsed() && collapsibleProp) isHovered.set(true)
109
+ }
110
+
111
+ function onMouseLeave() {
112
+ isHovered.set(false)
113
+ }
114
+
115
+ function toggleCollapse() {
116
+ collapsed.set(!collapsed())
117
+ emit('collapse', collapsed())
118
+ }
119
+
120
+ function onSectionToggle(sectionId) {
121
+ emit('sectionToggle', sectionId)
122
+ }
123
+
124
+ function onItemClick(event) {
125
+ emit('itemClick', event.detail)
126
+ }
127
+
128
+ onMount(async () => {
129
+ hasNativeSidebar.set(
130
+ window.__craftNativeSidebar === true
131
+ || window.craft?.hasNativeSidebar?.()
132
+ || (window.webkit?.messageHandlers?.craft && document.body?.dataset?.nativeSidebar === 'true'),
133
+ )
134
+ if (window.craft?.isCraft?.() && window.craft?.components?.createSidebar) {
135
+ try {
136
+ await window.craft.components.createSidebar({
137
+ position: positionProp,
138
+ width: widthProp,
139
+ minWidth: minWidthProp,
140
+ collapsible: collapsibleProp,
141
+ variant: variantProp,
142
+ material: variantProp === 'desktop' ? 'sidebar' : undefined,
143
+ backgroundEffect: variantProp === 'desktop' ? 'shimmer' : undefined,
144
+ allowsVibrancy: variantProp === 'desktop' || variantProp === 'vibrancy' || variantProp === 'tahoe',
145
+ sections: sectionsProp.map(s => ({
146
+ id: s.id,
147
+ label: s.label,
148
+ items: s.items?.map(i => ({ id: i.id, label: i.label, icon: i.icon, href: i.href, badge: i.badge })),
149
+ })),
150
+ })
151
+ }
152
+ catch (err) {
153
+ console.warn('[Sidebar] Failed to create native sidebar, using web fallback:', err)
154
+ }
155
+ }
156
+ })
157
+
158
+ defineExpose({ collapsed, toggle: toggleCollapse })
159
+ </script>
160
+
161
+ <aside
162
+ :show="!hasNativeSidebar()"
163
+ class="{{ containerClasses }} sidebar-container"
164
+ :style="`width: ${sidebarWidth()}`"
165
+ @mouseenter="onMouseEnter()"
166
+ @mouseleave="onMouseLeave()"
167
+ role="navigation"
168
+ aria-label="Sidebar navigation"
169
+ >
170
+ @if(variantTint)
171
+ <div class="absolute inset-0 pointer-events-none bg-gradient-to-b from-amber-50/30 via-orange-50/20 to-stone-100/30 dark:from-neutral-800/20 dark:via-neutral-900/10 dark:to-neutral-800/20 mix-blend-overlay"></div>
172
+ @endif
173
+ @if(variantShimmer)
174
+ <div class="absolute inset-0 pointer-events-none bg-[radial-gradient(circle_at_18%_12%,rgba(255,255,255,0.46),transparent_28%),linear-gradient(120deg,rgba(255,255,255,0.22),rgba(255,255,255,0.04)_42%,rgba(255,255,255,0.18))] dark:bg-[radial-gradient(circle_at_18%_12%,rgba(255,255,255,0.12),transparent_30%),linear-gradient(120deg,rgba(255,255,255,0.10),rgba(255,255,255,0.02)_45%,rgba(255,255,255,0.08))]"></div>
175
+ @endif
176
+
177
+ @if($slots.header)
178
+ <div class="flex-shrink-0 relative z-10">
179
+ <slot name="header" />
180
+ </div>
181
+ @endif
182
+
183
+ <div class="flex-1 overflow-y-auto overflow-x-hidden relative z-10">
184
+ @if(sections.length > 0)
185
+ <nav class="{{ navClasses }}">
186
+ @foreach(section in sections)
187
+ <SidebarSection
188
+ :id="section.id"
189
+ :label="section.label"
190
+ :icon="section.icon"
191
+ :items="section.items"
192
+ :expanded="section.expanded !== false"
193
+ :collapsible="section.collapsible !== false"
194
+ :showLabel="showExpanded()"
195
+ :variant="variant"
196
+ @toggle="onSectionToggle(section.id)"
197
+ @itemClick="onItemClick($event)"
198
+ />
199
+ @endforeach
200
+ </nav>
201
+ @else
202
+ <div class="{{ slotClasses }}">
203
+ <slot />
204
+ </div>
205
+ @endif
206
+ </div>
207
+
208
+ @if($slots.footer)
209
+ <div class="flex-shrink-0 relative z-10">
210
+ <slot name="footer" />
211
+ </div>
212
+ @endif
213
+
214
+ @if(collapsible)
215
+ <button
216
+ :show="showExpanded()"
217
+ type="button"
218
+ class="absolute top-4 {{ collapseBtnPosition }} p-1.5 rounded-lg text-stone-400 hover:text-stone-600 hover:bg-black/5 dark:hover:text-neutral-300 dark:hover:bg-white/10 transition-colors z-20"
219
+ @click="toggleCollapse()"
220
+ :aria-label="collapseAriaLabel()"
221
+ >
222
+ <div :class="`${collapseIconClass()} w-5 h-5`"></div>
223
+ </button>
224
+ @endif
225
+ </aside>
226
+
227
+ <style scoped>
228
+ .overflow-y-auto::-webkit-scrollbar { width: 6px; }
229
+ .overflow-y-auto::-webkit-scrollbar-track { background: transparent; }
230
+ .overflow-y-auto::-webkit-scrollbar-thumb { background-color: rgba(0, 0, 0, 0.15); border-radius: 3px; }
231
+ .overflow-y-auto::-webkit-scrollbar-thumb:hover { background-color: rgba(0, 0, 0, 0.25); }
232
+ @media (prefers-color-scheme: dark) {
233
+ .overflow-y-auto::-webkit-scrollbar-thumb { background-color: rgba(255, 255, 255, 0.15); }
234
+ .overflow-y-auto::-webkit-scrollbar-thumb:hover { background-color: rgba(255, 255, 255, 0.25); }
235
+ }
236
+ </style>
@@ -0,0 +1,109 @@
1
+ <script server>
2
+ export const showSettings = $props.showSettings ?? true
3
+ export const showThemeToggle = $props.showThemeToggle ?? true
4
+ export const settingsHref = $props.settingsHref || '/settings'
5
+ export const settingsLabel = $props.settingsLabel || 'Settings'
6
+ export const collapsed = $props.collapsed ?? false
7
+ export const actions = $props.actions || []
8
+ export const variant = $props.variant || 'tahoe'
9
+
10
+ const footerVariants = {
11
+ workspace: {
12
+ container: 'p-5 space-y-2',
13
+ action: 'flex-1 flex items-center gap-3 rounded-[18px] px-4 py-3 text-[17px] text-zinc-700 transition-colors hover:bg-[#ececea] hover:text-zinc-950 dark:text-zinc-300 dark:hover:bg-white/10',
14
+ icon: 'w-5 h-5 text-zinc-500 dark:text-zinc-400',
15
+ },
16
+ desktop: {
17
+ container: 'p-4 space-y-2',
18
+ action: 'flex-1 flex items-center gap-3 rounded-[16px] px-3.5 py-2.5 text-[15px] text-zinc-700 transition-colors hover:bg-white/34 hover:text-zinc-950 dark:text-zinc-300 dark:hover:bg-white/10',
19
+ icon: 'w-5 h-5 text-zinc-500 dark:text-zinc-400',
20
+ },
21
+ default: {
22
+ container: 'border-t border-black/5 dark:border-white/10 p-3 space-y-2',
23
+ action: 'flex-1 flex items-center gap-2 px-3 py-2 rounded-lg text-sm text-black/70 dark:text-white/70 hover:bg-black/5 dark:hover:bg-white/10 transition-colors',
24
+ icon: 'w-4 h-4',
25
+ },
26
+ }
27
+
28
+ const footerStyle = footerVariants[variant] || footerVariants.default
29
+ export const footerClasses = footerStyle.container
30
+ export const actionClasses = footerStyle.action
31
+ export const footerIconClasses = footerStyle.icon
32
+ export const settingsIconClasses = `i-hugeicons-settings-02 ${footerStyle.icon}`
33
+ export const themeButtonClasses = variant === 'workspace' || variant === 'desktop'
34
+ ? 'p-3 rounded-[16px] text-zinc-500 hover:text-zinc-900 hover:bg-white/50 dark:text-zinc-400 dark:hover:text-white dark:hover:bg-white/10 transition-colors'
35
+ : 'p-2 rounded-lg text-black/50 hover:text-black/80 hover:bg-black/5 dark:text-white/50 dark:hover:text-white/80 dark:hover:bg-white/10 transition-colors'
36
+ </script>
37
+
38
+ <script client>
39
+ const emit = defineEmits()
40
+
41
+ function onThemeToggle() {
42
+ document.documentElement.classList.toggle('dark')
43
+ emit('themeToggle')
44
+ }
45
+
46
+ function onActionClick(index) {
47
+ emit('actionClick', index)
48
+ }
49
+ </script>
50
+
51
+ <div class="{{ footerClasses }}">
52
+ <!-- Custom actions slot -->
53
+ <slot />
54
+
55
+ <!-- Quick actions row -->
56
+ @if(!collapsed && actions.length > 0)
57
+ <div class="flex items-center gap-2">
58
+ @foreach(actions as action)
59
+ @if(action.href)
60
+ <a
61
+ href="{{ action.href }}"
62
+ class="{{ actionClasses }}"
63
+ >
64
+ @if(action.icon)
65
+ <div class="{{ action.icon }} {{ footerIconClasses }}"></div>
66
+ @endif
67
+ <span>{{ action.label }}</span>
68
+ </a>
69
+ @else
70
+ <button
71
+ type="button"
72
+ class="{{ actionClasses }}"
73
+ @click="onActionClick({{ $loop.index }})"
74
+ >
75
+ @if(action.icon)
76
+ <div class="{{ action.icon }} {{ footerIconClasses }}"></div>
77
+ @endif
78
+ <span>{{ action.label }}</span>
79
+ </button>
80
+ @endif
81
+ @endforeach
82
+
83
+ @if(showThemeToggle)
84
+ <button
85
+ type="button"
86
+ class="{{ themeButtonClasses }}"
87
+ @click="onThemeToggle()"
88
+ aria-label="Toggle dark mode"
89
+ >
90
+ <div class="i-hugeicons-moon-02 w-4 h-4 dark:hidden"></div>
91
+ <div class="i-hugeicons-sun-02 w-4 h-4 hidden dark:block"></div>
92
+ </button>
93
+ @endif
94
+ </div>
95
+ @endif
96
+
97
+ <!-- Settings link -->
98
+ @if(showSettings)
99
+ <a
100
+ href="{{ settingsHref }}"
101
+ class="{{ actionClasses }}"
102
+ >
103
+ <div class="{{ settingsIconClasses }}"></div>
104
+ @if(!collapsed)
105
+ <span>{{ settingsLabel }}</span>
106
+ @endif
107
+ </a>
108
+ @endif
109
+ </div>
@@ -0,0 +1,122 @@
1
+ <script server>
2
+ export const title = $props.title || ''
3
+ export const subtitle = $props.subtitle || ''
4
+ export const logo = $props.logo || ''
5
+ export const logoIcon = $props.logoIcon || ''
6
+ export const showSearch = $props.showSearch ?? false
7
+ export const searchPlaceholder = $props.searchPlaceholder || 'Search...'
8
+ export const searchValue = $props.searchValue || ''
9
+ export const collapsed = $props.collapsed ?? false
10
+ export const variant = $props.variant || 'tahoe'
11
+
12
+ const headerVariants = {
13
+ workspace: {
14
+ titlebar: 'h-18 flex items-center justify-between px-5',
15
+ logo: 'w-9 h-9 rounded-[12px] bg-black text-white flex items-center justify-center font-semibold text-sm',
16
+ title: 'text-[18px] font-semibold text-zinc-950 dark:text-white truncate',
17
+ subtitle: 'text-sm text-zinc-500 dark:text-zinc-400 truncate',
18
+ searchWrap: 'px-5 pb-4',
19
+ searchInput: 'w-full rounded-[16px] border border-zinc-200/70 bg-white/70 px-10 py-2.5 text-[15px] text-zinc-900 placeholder:text-zinc-400 focus:outline-none focus:ring-2 focus:ring-zinc-300/80 dark:border-white/10 dark:bg-white/10 dark:text-white',
20
+ },
21
+ desktop: {
22
+ titlebar: 'h-16 flex items-center justify-between px-4',
23
+ logo: 'w-9 h-9 rounded-[12px] bg-black/80 text-white flex items-center justify-center font-semibold text-sm shadow-sm dark:bg-white/14',
24
+ title: 'text-[17px] font-semibold text-zinc-950 dark:text-white truncate',
25
+ subtitle: 'text-sm text-zinc-500 dark:text-zinc-400 truncate',
26
+ searchWrap: 'px-4 pb-4',
27
+ searchInput: 'w-full rounded-[16px] border border-white/40 bg-white/45 px-10 py-2.5 text-[15px] text-zinc-900 placeholder:text-zinc-500 shadow-sm focus:outline-none focus:ring-2 focus:ring-white/70 dark:border-white/10 dark:bg-white/10 dark:text-white',
28
+ },
29
+ default: {
30
+ titlebar: 'h-13 flex items-center justify-between px-4 border-b border-black/5 dark:border-white/10',
31
+ logo: 'w-8 h-8 rounded-lg bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center text-white font-bold text-sm',
32
+ title: 'text-sm font-semibold text-black/90 dark:text-white truncate',
33
+ subtitle: 'text-xs text-black/50 dark:text-white/50 truncate',
34
+ searchWrap: 'px-3 py-3',
35
+ searchInput: 'w-full pl-9 pr-3 py-2 text-sm bg-black/5 dark:bg-white/10 border border-black/10 dark:border-white/10 rounded-lg text-black/90 dark:text-white placeholder:text-black/40 dark:placeholder:text-white/40 focus:outline-none focus:ring-2 focus:ring-blue-500/30 focus:border-blue-400/50 transition-colors',
36
+ },
37
+ }
38
+
39
+ const headerStyle = headerVariants[variant] || headerVariants.default
40
+ export const titlebarClasses = headerStyle.titlebar
41
+ export const logoClasses = headerStyle.logo
42
+ export const titleClasses = headerStyle.title
43
+ export const subtitleClasses = headerStyle.subtitle
44
+ export const searchWrapClasses = headerStyle.searchWrap
45
+ export const searchInputClasses = headerStyle.searchInput
46
+ </script>
47
+
48
+ <script client>
49
+ const emit = defineEmits()
50
+
51
+ function onSearchInput(event) {
52
+ emit('search', event.target.value)
53
+ }
54
+ </script>
55
+
56
+ <div class="flex-shrink-0">
57
+ <!-- Title bar area -->
58
+ <div class="{{ titlebarClasses }}">
59
+ @if(!collapsed)
60
+ <div class="flex items-center gap-3 min-w-0">
61
+ <!-- Logo -->
62
+ @if(logo)
63
+ <img src="{{ logo }}" alt="{{ title }}" class="w-8 h-8 rounded-lg object-cover" />
64
+ @elseif(logoIcon)
65
+ <div class="{{ logoClasses }}">
66
+ <div class="{{ logoIcon }} w-5 h-5 text-white"></div>
67
+ </div>
68
+ @else
69
+ <div class="{{ logoClasses }}">
70
+ {{ title.charAt(0) }}
71
+ </div>
72
+ @endif
73
+
74
+ <!-- Title & Subtitle -->
75
+ <div class="min-w-0">
76
+ @if(title)
77
+ <div class="{{ titleClasses }}">
78
+ {{ title }}
79
+ </div>
80
+ @endif
81
+ @if(subtitle)
82
+ <div class="{{ subtitleClasses }}">
83
+ {{ subtitle }}
84
+ </div>
85
+ @endif
86
+ </div>
87
+ </div>
88
+ @else
89
+ <!-- Collapsed state - just logo -->
90
+ @if(logo)
91
+ <img src="{{ logo }}" alt="{{ title }}" class="w-8 h-8 rounded-lg object-cover mx-auto" />
92
+ @elseif(logoIcon)
93
+ <div class="{{ logoClasses }} mx-auto">
94
+ <div class="{{ logoIcon }} w-5 h-5 text-white"></div>
95
+ </div>
96
+ @else
97
+ <div class="{{ logoClasses }} mx-auto">
98
+ {{ title.charAt(0) }}
99
+ </div>
100
+ @endif
101
+ @endif
102
+
103
+ <!-- Slot for custom header actions -->
104
+ <slot name="actions" />
105
+ </div>
106
+
107
+ <!-- Search (only when expanded) -->
108
+ @if(showSearch && !collapsed)
109
+ <div class="{{ searchWrapClasses }}">
110
+ <div class="relative">
111
+ <div class="i-hugeicons-search-01 absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-black/40 dark:text-white/40"></div>
112
+ <input
113
+ type="text"
114
+ placeholder="{{ searchPlaceholder }}"
115
+ value="{{ searchValue }}"
116
+ class="{{ searchInputClasses }}"
117
+ @input="onSearchInput($event)"
118
+ />
119
+ </div>
120
+ </div>
121
+ @endif
122
+ </div>
@@ -0,0 +1,92 @@
1
+ <script server>
2
+ export const id = $props.id || ''
3
+ export const label = $props.label || ''
4
+ export const icon = $props.icon || ''
5
+ export const href = $props.href || ''
6
+ export const badge = $props.badge || ''
7
+ export const active = $props.active ?? false
8
+ export const disabled = $props.disabled ?? false
9
+ export const indent = $props.indent ?? false
10
+ export const variant = $props.variant || 'tahoe'
11
+
12
+ const itemVariants = {
13
+ workspace: {
14
+ base: 'flex w-full items-center gap-3 rounded-[18px] px-4 py-3 text-[17px] leading-tight transition-colors duration-150',
15
+ indent: '',
16
+ active: 'bg-[#e7e7e5] text-zinc-950',
17
+ inactive: 'text-zinc-700 hover:bg-[#ececea] hover:text-zinc-950 dark:text-zinc-300 dark:hover:bg-white/10',
18
+ icon: active ? 'text-zinc-900 dark:text-zinc-100' : 'text-zinc-500 dark:text-zinc-500',
19
+ badge: 'ml-auto rounded-full bg-white/70 px-2.5 py-0.5 text-[13px] font-medium text-zinc-500 shadow-sm dark:bg-white/10 dark:text-zinc-400',
20
+ },
21
+ desktop: {
22
+ base: 'flex w-full items-center gap-3 rounded-[16px] px-3.5 py-2.5 text-[15px] leading-tight transition-colors duration-150',
23
+ indent: '',
24
+ active: 'bg-white/55 text-zinc-950 shadow-sm ring-1 ring-white/50 dark:bg-white/12 dark:text-white dark:ring-white/10',
25
+ inactive: 'text-zinc-700 hover:bg-white/34 hover:text-zinc-950 dark:text-zinc-300 dark:hover:bg-white/10',
26
+ icon: active ? 'text-zinc-900 dark:text-white' : 'text-zinc-500 dark:text-zinc-400',
27
+ badge: 'ml-auto rounded-full bg-white/55 px-2.5 py-0.5 text-xs font-medium text-zinc-500 shadow-sm dark:bg-white/10 dark:text-zinc-400',
28
+ },
29
+ default: {
30
+ base: 'flex items-center gap-2.5 px-2.5 py-1.5 rounded-md text-[13px] transition-all duration-150',
31
+ indent: indent ? 'ml-2' : '',
32
+ active: 'bg-blue-500/20 text-blue-600 dark:bg-blue-400/25 dark:text-blue-300 font-medium',
33
+ inactive: 'text-black/80 dark:text-white/80 hover:bg-black/5 dark:hover:bg-white/10',
34
+ icon: active ? 'text-blue-600 dark:text-blue-300' : 'text-black/50 dark:text-white/50',
35
+ badge: 'ml-auto px-2 py-0.5 text-xs font-medium rounded-full bg-black/10 text-black/70 dark:bg-white/15 dark:text-white/70',
36
+ },
37
+ }
38
+
39
+ const itemStyle = itemVariants[variant] || itemVariants.default
40
+ const baseItemList = [itemStyle.base, itemStyle.indent]
41
+ const stateClasses = disabled ? 'opacity-50 cursor-not-allowed' : active ? itemStyle.active : itemStyle.inactive
42
+
43
+ export const itemClasses = [...baseItemList, stateClasses].filter(Boolean).join(' ')
44
+ export const iconClasses = `${icon} w-5 h-5 flex-shrink-0 ${itemStyle.icon}`
45
+ export const badgeClasses = itemStyle.badge
46
+ </script>
47
+
48
+ <script client>
49
+ const emit = defineEmits()
50
+ const isDisabled = {{ disabled }}
51
+ const itemPayload = { id: {{ id }}, label: {{ label }}, href: {{ href }} }
52
+
53
+ function onClick(event) {
54
+ if (isDisabled) {
55
+ event.preventDefault()
56
+ return
57
+ }
58
+ emit('click', { item: itemPayload, event })
59
+ }
60
+ </script>
61
+
62
+ @if(href && !disabled)
63
+ <a
64
+ href="{{ href }}"
65
+ class="{{ itemClasses }}"
66
+ @click="onClick($event)"
67
+ @if(active)aria-current="page"@endif
68
+ >
69
+ @if(icon)
70
+ <div class="{{ iconClasses }}"></div>
71
+ @endif
72
+ <span class="flex-1 truncate">{{ label }}</span>
73
+ @if(badge)
74
+ <span class="{{ badgeClasses }}">{{ badge }}</span>
75
+ @endif
76
+ </a>
77
+ @else
78
+ <button
79
+ type="button"
80
+ class="{{ itemClasses }}"
81
+ @click="onClick($event)"
82
+ @if(disabled)disabled aria-disabled="true"@endif
83
+ >
84
+ @if(icon)
85
+ <div class="{{ iconClasses }}"></div>
86
+ @endif
87
+ <span class="flex-1 truncate text-left">{{ label }}</span>
88
+ @if(badge)
89
+ <span class="{{ badgeClasses }}">{{ badge }}</span>
90
+ @endif
91
+ </button>
92
+ @endif
@@ -0,0 +1,113 @@
1
+ <script server>
2
+ export const id = $props.id || ''
3
+ export const label = $props.label || ''
4
+ export const icon = $props.icon || ''
5
+ export const items = $props.items || []
6
+ export const expanded = $props.expanded ?? true
7
+ export const collapsible = $props.collapsible ?? true
8
+ export const showLabel = $props.showLabel ?? true
9
+ export const variant = $props.variant || 'tahoe'
10
+
11
+ const headerVariants = {
12
+ workspace: {
13
+ base: 'w-full flex items-center gap-2.5 px-4 pb-2 pt-5 rounded-[14px] text-left transition-colors duration-150 text-[13px] font-semibold uppercase tracking-[0.12em] text-zinc-400 dark:text-zinc-500',
14
+ hover: 'hover:text-zinc-600 dark:hover:text-zinc-300 cursor-pointer',
15
+ },
16
+ desktop: {
17
+ base: 'w-full flex items-center gap-2.5 px-3.5 pb-2 pt-4 rounded-[14px] text-left transition-colors duration-150 text-[12px] font-semibold uppercase tracking-[0.10em] text-zinc-500/80 dark:text-zinc-400/80',
18
+ hover: 'hover:bg-white/25 dark:hover:bg-white/10 cursor-pointer',
19
+ },
20
+ default: {
21
+ base: 'w-full flex items-center gap-2.5 px-2.5 py-1.5 rounded-md text-left transition-all duration-150 text-black/60 dark:text-white/60',
22
+ hover: 'hover:bg-black/5 dark:hover:bg-white/10 cursor-pointer',
23
+ },
24
+ }
25
+
26
+ const headerStyle = headerVariants[variant] || headerVariants.default
27
+ const headerClasses = [headerStyle.base, collapsible ? headerStyle.hover : ''].filter(Boolean).join(' ')
28
+ export const headerClassesValue = headerClasses
29
+ export const sectionClasses = variant === 'workspace' || variant === 'desktop' ? 'py-1.5' : 'py-1'
30
+ export const groupClasses = variant === 'workspace' || variant === 'desktop' ? 'space-y-1 overflow-hidden' : 'mt-1 space-y-0.5 overflow-hidden'
31
+ export const labelClasses = variant === 'workspace' || variant === 'desktop'
32
+ ? 'flex-1 truncate'
33
+ : 'flex-1 text-[13px] font-semibold tracking-tight truncate'
34
+ </script>
35
+
36
+ <script client>
37
+ const emit = defineEmits()
38
+ const sectionId = {{ id }}
39
+ const collapsibleProp = {{ collapsible }}
40
+ const isExpanded = state({{ expanded }})
41
+
42
+ function onHeaderClick() {
43
+ if (!collapsibleProp) return
44
+ isExpanded.set(!isExpanded())
45
+ emit('toggle', sectionId)
46
+ }
47
+
48
+ function onItemClick(event) {
49
+ emit('itemClick', event.detail)
50
+ }
51
+
52
+ const arrowClass = derived(() => `i-hugeicons-arrow-right-01 w-3 h-3 transition-transform duration-200 opacity-50 ${isExpanded() ? 'rotate-90' : ''}`)
53
+
54
+ defineExpose({ isExpanded })
55
+ </script>
56
+
57
+ <div class="{{ sectionClasses }}">
58
+ @if(collapsible)
59
+ <button
60
+ type="button"
61
+ class="{{ headerClassesValue }}"
62
+ @click="onHeaderClick()"
63
+ :aria-expanded="isExpanded() ? 'true' : 'false'"
64
+ aria-controls="sidebar-section-{{ id }}"
65
+ >
66
+ @if(icon)
67
+ <div class="{{ icon }} w-4 h-4 flex-shrink-0 opacity-70"></div>
68
+ @endif
69
+ @if(showLabel)
70
+ <span class="{{ labelClasses }}">
71
+ {{ label }}
72
+ </span>
73
+ <div :class="arrowClass()"></div>
74
+ @endif
75
+ </button>
76
+ @else
77
+ <div class="{{ headerClassesValue }}">
78
+ @if(icon)
79
+ <div class="{{ icon }} w-4 h-4 flex-shrink-0 opacity-70"></div>
80
+ @endif
81
+ @if(showLabel)
82
+ <span class="{{ labelClasses }}">
83
+ {{ label }}
84
+ </span>
85
+ @endif
86
+ </div>
87
+ @endif
88
+
89
+ @if(showLabel && items.length > 0)
90
+ <div
91
+ :show="isExpanded()"
92
+ id="sidebar-section-{{ id }}"
93
+ class="{{ groupClasses }}"
94
+ role="group"
95
+ aria-label="{{ label }}"
96
+ >
97
+ @foreach(item in items)
98
+ <SidebarItem
99
+ :id="item.id"
100
+ :label="item.label"
101
+ :icon="item.icon"
102
+ :href="item.href"
103
+ :badge="item.badge"
104
+ :active="item.active"
105
+ :disabled="item.disabled"
106
+ :indent="variant !== 'workspace' && variant !== 'desktop'"
107
+ :variant="variant"
108
+ @click="onItemClick($event)"
109
+ />
110
+ @endforeach
111
+ </div>
112
+ @endif
113
+ </div>