@stacksjs/components 0.2.35 → 0.2.54

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 +5 -5
  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
@@ -1,18 +1,4 @@
1
1
  <script server>
2
- /**
3
- * SidebarHeader Component
4
- *
5
- * A header component for the sidebar with logo, title, and optional search.
6
- *
7
- * @example
8
- * <SidebarHeader
9
- * title="My App"
10
- * subtitle="Professional"
11
- * :showSearch="true"
12
- * />
13
- */
14
-
15
- // Props
16
2
  export const title = $props.title || ''
17
3
  export const subtitle = $props.subtitle || ''
18
4
  export const logo = $props.logo || ''
@@ -21,30 +7,66 @@ export const showSearch = $props.showSearch ?? false
21
7
  export const searchPlaceholder = $props.searchPlaceholder || 'Search...'
22
8
  export const searchValue = $props.searchValue || ''
23
9
  export const collapsed = $props.collapsed ?? false
24
- export const onSearch = $props.onSearch
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()
25
50
 
26
- // Handle search input
27
- function handleSearchInput(event) {
28
- if (onSearch) {
29
- onSearch(event.target.value)
30
- }
51
+ function onSearchInput(event) {
52
+ emit('search', event.target.value)
31
53
  }
32
54
  </script>
33
55
 
34
56
  <div class="flex-shrink-0">
35
57
  <!-- Title bar area -->
36
- <div class="h-13 flex items-center justify-between px-4 border-b border-black/5 dark:border-white/10">
58
+ <div class="{{ titlebarClasses }}">
37
59
  @if(!collapsed)
38
60
  <div class="flex items-center gap-3 min-w-0">
39
61
  <!-- Logo -->
40
62
  @if(logo)
41
63
  <img src="{{ logo }}" alt="{{ title }}" class="w-8 h-8 rounded-lg object-cover" />
42
64
  @elseif(logoIcon)
43
- <div class="w-8 h-8 rounded-lg bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center">
65
+ <div class="{{ logoClasses }}">
44
66
  <div class="{{ logoIcon }} w-5 h-5 text-white"></div>
45
67
  </div>
46
68
  @else
47
- <div class="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">
69
+ <div class="{{ logoClasses }}">
48
70
  {{ title.charAt(0) }}
49
71
  </div>
50
72
  @endif
@@ -52,12 +74,12 @@ function handleSearchInput(event) {
52
74
  <!-- Title & Subtitle -->
53
75
  <div class="min-w-0">
54
76
  @if(title)
55
- <div class="text-sm font-semibold text-black/90 dark:text-white truncate">
77
+ <div class="{{ titleClasses }}">
56
78
  {{ title }}
57
79
  </div>
58
80
  @endif
59
81
  @if(subtitle)
60
- <div class="text-xs text-black/50 dark:text-white/50 truncate">
82
+ <div class="{{ subtitleClasses }}">
61
83
  {{ subtitle }}
62
84
  </div>
63
85
  @endif
@@ -68,11 +90,11 @@ function handleSearchInput(event) {
68
90
  @if(logo)
69
91
  <img src="{{ logo }}" alt="{{ title }}" class="w-8 h-8 rounded-lg object-cover mx-auto" />
70
92
  @elseif(logoIcon)
71
- <div class="w-8 h-8 rounded-lg bg-gradient-to-br from-blue-500 to-blue-600 flex items-center justify-center mx-auto">
93
+ <div class="{{ logoClasses }} mx-auto">
72
94
  <div class="{{ logoIcon }} w-5 h-5 text-white"></div>
73
95
  </div>
74
96
  @else
75
- <div class="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 mx-auto">
97
+ <div class="{{ logoClasses }} mx-auto">
76
98
  {{ title.charAt(0) }}
77
99
  </div>
78
100
  @endif
@@ -84,15 +106,15 @@ function handleSearchInput(event) {
84
106
 
85
107
  <!-- Search (only when expanded) -->
86
108
  @if(showSearch && !collapsed)
87
- <div class="px-3 py-3">
109
+ <div class="{{ searchWrapClasses }}">
88
110
  <div class="relative">
89
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>
90
112
  <input
91
113
  type="text"
92
114
  placeholder="{{ searchPlaceholder }}"
93
115
  value="{{ searchValue }}"
94
- class="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"
95
- @input="handleSearchInput"
116
+ class="{{ searchInputClasses }}"
117
+ @input="onSearchInput($event)"
96
118
  />
97
119
  </div>
98
120
  </div>
@@ -1,21 +1,4 @@
1
1
  <script server>
2
- /**
3
- * SidebarItem Component
4
- *
5
- * An individual navigation item within a sidebar section.
6
- * Supports icons, badges, active states, and keyboard navigation.
7
- *
8
- * @example
9
- * <SidebarItem
10
- * id="home"
11
- * label="Home"
12
- * icon="i-hugeicons-home-02"
13
- * href="/"
14
- * :active="true"
15
- * />
16
- */
17
-
18
- // Props
19
2
  export const id = $props.id || ''
20
3
  export const label = $props.label || ''
21
4
  export const icon = $props.icon || ''
@@ -24,95 +7,86 @@ export const badge = $props.badge || ''
24
7
  export const active = $props.active ?? false
25
8
  export const disabled = $props.disabled ?? false
26
9
  export const indent = $props.indent ?? false
27
- export const onClick = $props.onClick
28
-
29
- // Handle click
30
- function handleClick(event) {
31
- if (disabled) {
32
- event.preventDefault()
33
- return
34
- }
10
+ export const variant = $props.variant || 'tahoe'
35
11
 
36
- if (onClick) {
37
- onClick(event)
38
- }
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
+ },
39
37
  }
40
38
 
41
- // Build item classes - macOS Tahoe style with translucent-friendly colors
42
- function getItemClasses() {
43
- const baseClasses = [
44
- 'flex items-center gap-2.5 px-2.5 py-1.5 rounded-md text-[13px]',
45
- 'transition-all duration-150',
46
- indent ? 'ml-2' : ''
47
- ]
48
-
49
- if (disabled) {
50
- baseClasses.push('opacity-50 cursor-not-allowed')
51
- } else if (active) {
52
- // Active state - subtle blue highlight like macOS
53
- baseClasses.push(
54
- 'bg-blue-500/20 text-blue-600 dark:bg-blue-400/25 dark:text-blue-300 font-medium'
55
- )
56
- } else {
57
- // Default state - works with translucent backgrounds
58
- baseClasses.push(
59
- 'text-black/80 dark:text-white/80',
60
- 'hover:bg-black/5 dark:hover:bg-white/10'
61
- )
62
- }
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
63
42
 
64
- return baseClasses.filter(Boolean).join(' ')
65
- }
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>
66
47
 
67
- // Icon classes
68
- function getIconClasses() {
69
- const baseClasses = 'w-4 h-4 flex-shrink-0'
48
+ <script client>
49
+ const emit = defineEmits()
50
+ const isDisabled = {{ disabled }}
51
+ const itemPayload = { id: {{ id }}, label: {{ label }}, href: {{ href }} }
70
52
 
71
- if (active) {
72
- return `${icon} ${baseClasses} text-blue-600 dark:text-blue-300`
53
+ function onClick(event) {
54
+ if (isDisabled) {
55
+ event.preventDefault()
56
+ return
73
57
  }
74
-
75
- return `${icon} ${baseClasses} text-black/50 dark:text-white/50`
58
+ emit('click', { item: itemPayload, event })
76
59
  }
77
60
  </script>
78
61
 
79
62
  @if(href && !disabled)
80
63
  <a
81
64
  href="{{ href }}"
82
- class="{{ getItemClasses() }}"
83
- @click="handleClick"
84
- @if(active)
85
- aria-current="page"
86
- @endif
65
+ class="{{ itemClasses }}"
66
+ @click="onClick($event)"
67
+ @if(active)aria-current="page"@endif
87
68
  >
88
69
  @if(icon)
89
- <div class="{{ getIconClasses() }}"></div>
70
+ <div class="{{ iconClasses }}"></div>
90
71
  @endif
91
72
  <span class="flex-1 truncate">{{ label }}</span>
92
73
  @if(badge)
93
- <span class="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">
94
- {{ badge }}
95
- </span>
74
+ <span class="{{ badgeClasses }}">{{ badge }}</span>
96
75
  @endif
97
76
  </a>
98
77
  @else
99
78
  <button
100
79
  type="button"
101
- class="{{ getItemClasses() }}"
102
- @click="handleClick"
103
- @if(disabled)
104
- disabled
105
- aria-disabled="true"
106
- @endif
80
+ class="{{ itemClasses }}"
81
+ @click="onClick($event)"
82
+ @if(disabled)disabled aria-disabled="true"@endif
107
83
  >
108
84
  @if(icon)
109
- <div class="{{ getIconClasses() }}"></div>
85
+ <div class="{{ iconClasses }}"></div>
110
86
  @endif
111
87
  <span class="flex-1 truncate text-left">{{ label }}</span>
112
88
  @if(badge)
113
- <span class="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">
114
- {{ badge }}
115
- </span>
89
+ <span class="{{ badgeClasses }}">{{ badge }}</span>
116
90
  @endif
117
91
  </button>
118
92
  @endif
@@ -1,21 +1,4 @@
1
1
  <script server>
2
- /**
3
- * SidebarSection Component
4
- *
5
- * A collapsible section within the sidebar containing navigation items.
6
- * Follows macOS Finder sidebar conventions.
7
- *
8
- * @example
9
- * <SidebarSection
10
- * id="favorites"
11
- * label="Favorites"
12
- * icon="i-hugeicons-star"
13
- * :items="favoriteItems"
14
- * :expanded="true"
15
- * />
16
- */
17
-
18
- // Props
19
2
  export const id = $props.id || ''
20
3
  export const label = $props.label || ''
21
4
  export const icon = $props.icon || ''
@@ -23,74 +6,95 @@ export const items = $props.items || []
23
6
  export const expanded = $props.expanded ?? true
24
7
  export const collapsible = $props.collapsible ?? true
25
8
  export const showLabel = $props.showLabel ?? true
26
- export const onToggle = $props.onToggle
27
- export const onItemClick = $props.onItemClick
9
+ export const variant = $props.variant || 'tahoe'
28
10
 
29
- // Handle section header click
30
- function handleHeaderClick() {
31
- if (collapsible && onToggle) {
32
- onToggle(id)
33
- }
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
+ },
34
24
  }
35
25
 
36
- // Handle item click
37
- function handleItemClick(item, event) {
38
- if (onItemClick) {
39
- onItemClick(item, event)
40
- }
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)
41
46
  }
42
47
 
43
- // Section header classes - macOS Finder style
44
- const headerClasses = [
45
- 'w-full flex items-center gap-2.5 px-2.5 py-1.5 rounded-md text-left',
46
- 'transition-all duration-150',
47
- 'text-black/60 dark:text-white/60',
48
- collapsible ? 'hover:bg-black/5 dark:hover:bg-white/10 cursor-pointer' : ''
49
- ].filter(Boolean).join(' ')
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 })
50
55
  </script>
51
56
 
52
- <div class="py-1">
53
- <!-- Section header -->
57
+ <div class="{{ sectionClasses }}">
54
58
  @if(collapsible)
55
59
  <button
56
60
  type="button"
57
- class="{{ headerClasses }}"
58
- @click="handleHeaderClick"
59
- aria-expanded="{{ expanded }}"
61
+ class="{{ headerClassesValue }}"
62
+ @click="onHeaderClick()"
63
+ :aria-expanded="isExpanded() ? 'true' : 'false'"
60
64
  aria-controls="sidebar-section-{{ id }}"
61
65
  >
62
66
  @if(icon)
63
67
  <div class="{{ icon }} w-4 h-4 flex-shrink-0 opacity-70"></div>
64
68
  @endif
65
69
  @if(showLabel)
66
- <span class="flex-1 text-[13px] font-semibold tracking-tight truncate">
70
+ <span class="{{ labelClasses }}">
67
71
  {{ label }}
68
72
  </span>
69
- <div class="i-hugeicons-arrow-right-01 w-3 h-3 transition-transform duration-200 opacity-50 {{ expanded ? 'rotate-90' : '' }}"></div>
73
+ <div :class="arrowClass()"></div>
70
74
  @endif
71
75
  </button>
72
76
  @else
73
- <div class="{{ headerClasses }}">
77
+ <div class="{{ headerClassesValue }}">
74
78
  @if(icon)
75
79
  <div class="{{ icon }} w-4 h-4 flex-shrink-0 opacity-70"></div>
76
80
  @endif
77
81
  @if(showLabel)
78
- <span class="flex-1 text-[13px] font-semibold tracking-tight truncate">
82
+ <span class="{{ labelClasses }}">
79
83
  {{ label }}
80
84
  </span>
81
85
  @endif
82
86
  </div>
83
87
  @endif
84
88
 
85
- <!-- Section items -->
86
- @if(expanded && showLabel && items.length > 0)
89
+ @if(showLabel && items.length > 0)
87
90
  <div
91
+ :show="isExpanded()"
88
92
  id="sidebar-section-{{ id }}"
89
- class="mt-1 space-y-0.5 overflow-hidden"
93
+ class="{{ groupClasses }}"
90
94
  role="group"
91
95
  aria-label="{{ label }}"
92
96
  >
93
- @foreach(items as item)
97
+ @foreach(item in items)
94
98
  <SidebarItem
95
99
  :id="item.id"
96
100
  :label="item.label"
@@ -99,8 +103,9 @@ const headerClasses = [
99
103
  :badge="item.badge"
100
104
  :active="item.active"
101
105
  :disabled="item.disabled"
102
- :indent="true"
103
- @click="handleItemClick(item, $event)"
106
+ :indent="variant !== 'workspace' && variant !== 'desktop'"
107
+ :variant="variant"
108
+ @click="onItemClick($event)"
104
109
  />
105
110
  @endforeach
106
111
  </div>
@@ -36,7 +36,9 @@ export interface SidebarProps {
36
36
  /** Minimum width when collapsed in pixels */
37
37
  minWidth?: number
38
38
  /** Visual style variant */
39
- variant?: 'tahoe' | 'vibrancy' | 'solid' | 'transparent'
39
+ variant?: SidebarVariant
40
+ /** Layout placement for app shells and native-like sidebars */
41
+ placement?: 'fixed' | 'sticky' | 'static'
40
42
  /** Position of the sidebar */
41
43
  position?: 'left' | 'right'
42
44
  /** Whether to show border */
@@ -59,6 +61,7 @@ export interface SidebarSectionProps {
59
61
  expanded?: boolean
60
62
  collapsible?: boolean
61
63
  showLabel?: boolean
64
+ variant?: SidebarVariant
62
65
  onToggle?: (id: string) => void
63
66
  onItemClick?: (item: SidebarItemData, event: Event) => void
64
67
  }
@@ -72,6 +75,7 @@ export interface SidebarItemProps {
72
75
  active?: boolean
73
76
  disabled?: boolean
74
77
  indent?: boolean
78
+ variant?: SidebarVariant
75
79
  onClick?: (event: Event) => void
76
80
  }
77
81
 
@@ -84,6 +88,7 @@ export interface SidebarHeaderProps {
84
88
  searchPlaceholder?: string
85
89
  searchValue?: string
86
90
  collapsed?: boolean
91
+ variant?: SidebarVariant
87
92
  onSearch?: (value: string) => void
88
93
  }
89
94
 
@@ -93,6 +98,7 @@ export interface SidebarFooterProps {
93
98
  settingsHref?: string
94
99
  settingsLabel?: string
95
100
  collapsed?: boolean
101
+ variant?: SidebarVariant
96
102
  actions?: Array<{
97
103
  label: string
98
104
  icon?: string
@@ -102,6 +108,12 @@ export interface SidebarFooterProps {
102
108
  onThemeToggle?: () => void
103
109
  }
104
110
 
111
+ export type SidebarVariant = 'tahoe' | 'vibrancy' | 'solid' | 'transparent' | 'workspace' | 'desktop'
112
+
113
+ export type SidebarMaterial = 'auto' | 'sidebar' | 'hud' | 'popover' | 'content'
114
+
115
+ export type SidebarBackgroundEffect = 'none' | 'vibrancy' | 'shimmer'
116
+
105
117
  /**
106
118
  * Native Sidebar Configuration
107
119
  *
@@ -109,6 +121,14 @@ export interface SidebarFooterProps {
109
121
  * The sidebar uses NSOutlineView with vibrancy for a true Tahoe-style appearance.
110
122
  */
111
123
  export interface NativeSidebarConfig {
124
+ /** Visual style variant shared with the web fallback */
125
+ variant?: SidebarVariant
126
+ /** Native material used by Craft desktop sidebars */
127
+ material?: SidebarMaterial
128
+ /** Native background treatment */
129
+ backgroundEffect?: SidebarBackgroundEffect
130
+ /** Whether the native sidebar should let the window background show through */
131
+ allowsVibrancy?: boolean
112
132
  /** Header configuration */
113
133
  header?: {
114
134
  title?: string
@@ -5,24 +5,28 @@ export const label = $props.label || ''
5
5
  export const description = $props.description || ''
6
6
  export const className = $props.className || ''
7
7
  export const as = $props.as || 'div'
8
- export const onClick = $props.onClick
9
8
 
10
9
  export const isComplete = stepNumber < currentStep
11
10
  export const isCurrent = stepNumber === currentStep
12
11
  export const isUpcoming = stepNumber > currentStep
13
12
 
14
13
  const baseClasses = 'flex items-center'
15
- const stepClasses = `${baseClasses} ${className}`.trim()
14
+ export const stepClasses = `${baseClasses} ${className}`.trim()
15
+ </script>
16
+
17
+ <script client>
18
+ const emit = defineEmits()
19
+ const stepNumber = {{ stepNumber }}
16
20
 
17
- export function handleClick() {
18
- onClick?.(stepNumber)
21
+ function onClick() {
22
+ emit('click', stepNumber)
19
23
  }
20
24
  </script>
21
25
 
22
26
  <component :is="{{ as }}" class="{{ stepClasses }}">
23
27
  <button
24
28
  type="button"
25
- @click="handleClick"
29
+ @click="onClick()"
26
30
  class="flex items-center gap-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 rounded-lg p-2"
27
31
  >
28
32
  <div class="{{ isComplete ? 'bg-blue-600 dark:bg-blue-500' : isCurrent ? 'bg-blue-600 dark:bg-blue-500 ring-4 ring-blue-200 dark:ring-blue-800' : 'bg-neutral-300 dark:bg-neutral-600' }} w-10 h-10 rounded-full flex items-center justify-center text-white font-semibold transition-all">