@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
@@ -1,219 +1,189 @@
1
1
  <script server>
2
- /**
3
- * Sidebar Component - macOS Native Style
4
- *
5
- * A native-feeling sidebar component that integrates with Craft for true native rendering
6
- * when running in a Craft desktop environment, with beautiful macOS Tahoe-style fallback
7
- * for web environments.
8
- *
9
- * @example
10
- * <Sidebar
11
- * :sections="sections"
12
- * :collapsed="false"
13
- * :width="240"
14
- * variant="tahoe"
15
- * >
16
- * <template #header>
17
- * <SidebarHeader title="My App" />
18
- * </template>
19
- * <template #footer>
20
- * <SidebarFooter />
21
- * </template>
22
- * </Sidebar>
23
- */
24
-
25
- // Props
26
2
  export const sections = $props.sections || []
27
3
  export const collapsed = $props.collapsed ?? false
28
4
  export const collapsible = $props.collapsible ?? true
29
5
  export const width = $props.width || 240
30
6
  export const minWidth = $props.minWidth || 64
31
- export const variant = $props.variant || 'tahoe' // 'tahoe' | 'vibrancy' | 'solid' | 'transparent'
32
- export const position = $props.position || 'left' // 'left' | 'right'
7
+ export const variant = $props.variant || 'tahoe'
8
+ export const position = $props.position || 'left'
9
+ export const placement = $props.placement || 'fixed'
33
10
  export const bordered = $props.bordered ?? true
34
11
  export const className = $props.className || ''
35
- export const onCollapse = $props.onCollapse
36
- export const onSectionToggle = $props.onSectionToggle
37
- export const onItemClick = $props.onItemClick
38
-
39
- // Internal state
40
- let isHovered = false
41
- let nativeSidebarId = null
42
-
43
- // Check if running in Craft environment with native sidebar enabled
44
- // When Craft uses --native-sidebar, it sets these flags and we should NOT render the web sidebar
45
- const hasNativeSidebar = typeof window !== 'undefined' && (
46
- window.__craftNativeSidebar === true ||
47
- window.craft?.hasNativeSidebar?.() ||
48
- (window.webkit?.messageHandlers?.craft && document.body?.dataset?.nativeSidebar === 'true')
49
- )
50
-
51
- // Check if running in Craft environment (may not have native sidebar)
52
- const isCraft = typeof window !== 'undefined' && window.craft?.isCraft?.()
53
12
 
54
- // Variant styles - macOS Tahoe inspired
55
- // Native macOS sidebars use vibrancy where desktop background shines through
56
13
  const variantStyles = {
57
14
  tahoe: {
58
- // Translucent with warm tint overlay - desktop shows through
59
15
  bg: 'bg-white/70 dark:bg-black/50',
60
16
  border: 'border-black/5 dark:border-white/10',
61
17
  backdrop: 'backdrop-blur-2xl backdrop-saturate-180',
62
- // Warm tint is applied via pseudo-element in template
63
- tint: true
18
+ tint: true,
64
19
  },
65
20
  vibrancy: {
66
21
  bg: 'bg-white/50 dark:bg-black/40',
67
22
  border: 'border-white/20 dark:border-white/10',
68
23
  backdrop: 'backdrop-blur-3xl backdrop-saturate-200',
69
- tint: false
24
+ tint: false,
70
25
  },
71
26
  solid: {
72
27
  bg: 'bg-stone-100 dark:bg-neutral-900',
73
28
  border: 'border-stone-200 dark:border-neutral-800',
74
29
  backdrop: '',
75
- tint: false
30
+ tint: false,
76
31
  },
77
32
  transparent: {
78
33
  bg: 'bg-transparent',
79
34
  border: 'border-transparent',
80
35
  backdrop: '',
81
- tint: false
82
- }
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
+ },
83
55
  }
84
56
 
85
- // Get current variant style
86
- function getVariantStyle() {
87
- return variantStyles[variant] || variantStyles.tahoe
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',
88
67
  }
89
68
 
90
- // Calculate sidebar width
91
- function getSidebarWidth() {
92
- if (collapsed && !isHovered) {
93
- return `${minWidth}px`
94
- }
95
- return `${width}px`
96
- }
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(' ')
97
79
 
98
- // Check if showing expanded content
99
- function showExpanded() {
100
- return !collapsed || isHovered
101
- }
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>
102
84
 
103
- // Initialize Craft native sidebar if available
104
- async function initNativeSidebar() {
105
- if (isCraft && window.craft?.components?.createSidebar) {
106
- try {
107
- const config = {
108
- position,
109
- width,
110
- minWidth,
111
- collapsible,
112
- sections: sections.map(section => ({
113
- id: section.id,
114
- label: section.label,
115
- items: section.items?.map(item => ({
116
- id: item.id,
117
- label: item.label,
118
- icon: item.icon,
119
- href: item.href,
120
- badge: item.badge
121
- }))
122
- }))
123
- }
124
- nativeSidebarId = await window.craft.components.createSidebar(config)
125
- } catch (err) {
126
- console.warn('[Sidebar] Failed to create native sidebar, using web fallback:', err)
127
- }
128
- }
129
- }
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 }}
130
94
 
131
- // Handle collapse toggle
132
- function handleCollapseToggle() {
133
- if (onCollapse) {
134
- onCollapse(!collapsed)
135
- }
136
- }
95
+ const collapsed = state(collapsedProp)
96
+ const isHovered = state(false)
97
+ const hasNativeSidebar = state(false)
137
98
 
138
- // Handle mouse enter/leave for hover expand
139
- function handleMouseEnter() {
140
- if (collapsed && collapsible) {
141
- isHovered = true
142
- }
143
- }
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')
144
106
 
145
- function handleMouseLeave() {
146
- isHovered = false
107
+ function onMouseEnter() {
108
+ if (collapsed() && collapsibleProp) isHovered.set(true)
147
109
  }
148
110
 
149
- // Handle section toggle
150
- function handleSectionToggle(sectionId) {
151
- if (onSectionToggle) {
152
- onSectionToggle(sectionId)
153
- }
111
+ function onMouseLeave() {
112
+ isHovered.set(false)
154
113
  }
155
114
 
156
- // Handle item click
157
- function handleItemClick(item, event) {
158
- if (onItemClick) {
159
- onItemClick(item, event)
160
- }
115
+ function toggleCollapse() {
116
+ collapsed.set(!collapsed())
117
+ emit('collapse', collapsed())
161
118
  }
162
119
 
163
- // Build container classes
164
- const style = getVariantStyle()
120
+ function onSectionToggle(sectionId) {
121
+ emit('sectionToggle', sectionId)
122
+ }
165
123
 
166
- // Build border classes properly for Tailwind
167
- function getBorderClasses() {
168
- if (!bordered) return ''
169
- const borderSide = position === 'left' ? 'border-r' : 'border-l'
170
- return `${borderSide} ${style.border}`
124
+ function onItemClick(event) {
125
+ emit('itemClick', event.detail)
171
126
  }
172
127
 
173
- const containerClasses = [
174
- 'fixed inset-y-0 z-50 flex flex-col',
175
- 'transition-all duration-300 ease-out',
176
- 'overflow-hidden', // Contain the tint overlay
177
- style.bg,
178
- style.backdrop,
179
- getBorderClasses(),
180
- position === 'left' ? 'left-0' : 'right-0',
181
- className
182
- ].filter(Boolean).join(' ')
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
+ })
183
157
 
184
- // Initialize native sidebar on mount
185
- if (typeof window !== 'undefined') {
186
- initNativeSidebar()
187
- }
158
+ defineExpose({ collapsed, toggle: toggleCollapse })
188
159
  </script>
189
160
 
190
- <!-- Only render web sidebar when NOT running in Craft native sidebar mode -->
191
- @if(!hasNativeSidebar)
192
161
  <aside
162
+ :show="!hasNativeSidebar()"
193
163
  class="{{ containerClasses }} sidebar-container"
194
- style="width: {{ getSidebarWidth() }}"
195
- @mouseenter="handleMouseEnter"
196
- @mouseleave="handleMouseLeave"
164
+ :style="`width: ${sidebarWidth()}`"
165
+ @mouseenter="onMouseEnter()"
166
+ @mouseleave="onMouseLeave()"
197
167
  role="navigation"
198
168
  aria-label="Sidebar navigation"
199
169
  >
200
- <!-- Warm tint overlay for macOS Tahoe effect - desktop shows through -->
201
- @if(style.tint)
170
+ @if(variantTint)
202
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>
203
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
204
176
 
205
- <!-- Header slot -->
206
177
  @if($slots.header)
207
178
  <div class="flex-shrink-0 relative z-10">
208
179
  <slot name="header" />
209
180
  </div>
210
181
  @endif
211
182
 
212
- <!-- Main content area with sections -->
213
183
  <div class="flex-1 overflow-y-auto overflow-x-hidden relative z-10">
214
184
  @if(sections.length > 0)
215
- <nav class="px-3 py-2 space-y-1">
216
- @foreach(sections as section)
185
+ <nav class="{{ navClasses }}">
186
+ @foreach(section in sections)
217
187
  <SidebarSection
218
188
  :id="section.id"
219
189
  :label="section.label"
@@ -222,67 +192,45 @@ if (typeof window !== 'undefined') {
222
192
  :expanded="section.expanded !== false"
223
193
  :collapsible="section.collapsible !== false"
224
194
  :showLabel="showExpanded()"
225
- @toggle="handleSectionToggle(section.id)"
226
- @itemClick="handleItemClick"
195
+ :variant="variant"
196
+ @toggle="onSectionToggle(section.id)"
197
+ @itemClick="onItemClick($event)"
227
198
  />
228
199
  @endforeach
229
200
  </nav>
230
201
  @else
231
- <!-- Default slot for custom content -->
232
- <div class="px-3 py-2">
202
+ <div class="{{ slotClasses }}">
233
203
  <slot />
234
204
  </div>
235
205
  @endif
236
206
  </div>
237
207
 
238
- <!-- Footer slot -->
239
208
  @if($slots.footer)
240
209
  <div class="flex-shrink-0 relative z-10">
241
210
  <slot name="footer" />
242
211
  </div>
243
212
  @endif
244
213
 
245
- <!-- Collapse toggle button -->
246
- @if(collapsible && showExpanded())
214
+ @if(collapsible)
247
215
  <button
216
+ :show="showExpanded()"
248
217
  type="button"
249
- class="absolute top-4 {{ position === 'left' ? 'right-2' : 'left-2' }} 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"
250
- @click="handleCollapseToggle"
251
- aria-label="{{ collapsed ? 'Expand sidebar' : 'Collapse sidebar' }}"
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()"
252
221
  >
253
- <div class="{{ collapsed ? 'i-hugeicons-sidebar-right' : 'i-hugeicons-sidebar-left' }} w-5 h-5"></div>
222
+ <div :class="`${collapseIconClass()} w-5 h-5`"></div>
254
223
  </button>
255
224
  @endif
256
225
  </aside>
257
- @endif
258
226
 
259
227
  <style scoped>
260
- /* Smooth scrollbar styling for macOS feel */
261
- .overflow-y-auto::-webkit-scrollbar {
262
- width: 6px;
263
- }
264
-
265
- .overflow-y-auto::-webkit-scrollbar-track {
266
- background: transparent;
267
- }
268
-
269
- .overflow-y-auto::-webkit-scrollbar-thumb {
270
- background-color: rgba(0, 0, 0, 0.15);
271
- border-radius: 3px;
272
- }
273
-
274
- .overflow-y-auto::-webkit-scrollbar-thumb:hover {
275
- background-color: rgba(0, 0, 0, 0.25);
276
- }
277
-
278
- /* Dark mode scrollbar */
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); }
279
232
  @media (prefers-color-scheme: dark) {
280
- .overflow-y-auto::-webkit-scrollbar-thumb {
281
- background-color: rgba(255, 255, 255, 0.15);
282
- }
283
-
284
- .overflow-y-auto::-webkit-scrollbar-thumb:hover {
285
- background-color: rgba(255, 255, 255, 0.25);
286
- }
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); }
287
235
  }
288
236
  </style>
@@ -1,40 +1,54 @@
1
1
  <script server>
2
- /**
3
- * SidebarFooter Component
4
- *
5
- * A footer component for the sidebar with quick actions and settings.
6
- *
7
- * @example
8
- * <SidebarFooter
9
- * :showSettings="true"
10
- * :showThemeToggle="true"
11
- * settingsHref="/settings"
12
- * />
13
- */
14
-
15
- // Props
16
2
  export const showSettings = $props.showSettings ?? true
17
3
  export const showThemeToggle = $props.showThemeToggle ?? true
18
4
  export const settingsHref = $props.settingsHref || '/settings'
19
5
  export const settingsLabel = $props.settingsLabel || 'Settings'
20
6
  export const collapsed = $props.collapsed ?? false
21
- export const onThemeToggle = $props.onThemeToggle
22
-
23
- // Quick action items
24
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
+ }
25
45
 
26
- // Handle theme toggle
27
- function handleThemeToggle() {
28
- if (onThemeToggle) {
29
- onThemeToggle()
30
- } else {
31
- // Default theme toggle behavior
32
- document.documentElement.classList.toggle('dark')
33
- }
46
+ function onActionClick(index) {
47
+ emit('actionClick', index)
34
48
  }
35
49
  </script>
36
50
 
37
- <div class="border-t border-black/5 dark:border-white/10 p-3 space-y-2">
51
+ <div class="{{ footerClasses }}">
38
52
  <!-- Custom actions slot -->
39
53
  <slot />
40
54
 
@@ -45,21 +59,21 @@ function handleThemeToggle() {
45
59
  @if(action.href)
46
60
  <a
47
61
  href="{{ action.href }}"
48
- class="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"
62
+ class="{{ actionClasses }}"
49
63
  >
50
64
  @if(action.icon)
51
- <div class="{{ action.icon }} w-4 h-4"></div>
65
+ <div class="{{ action.icon }} {{ footerIconClasses }}"></div>
52
66
  @endif
53
67
  <span>{{ action.label }}</span>
54
68
  </a>
55
69
  @else
56
70
  <button
57
71
  type="button"
58
- class="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"
59
- @click="action.onClick"
72
+ class="{{ actionClasses }}"
73
+ @click="onActionClick({{ $loop.index }})"
60
74
  >
61
75
  @if(action.icon)
62
- <div class="{{ action.icon }} w-4 h-4"></div>
76
+ <div class="{{ action.icon }} {{ footerIconClasses }}"></div>
63
77
  @endif
64
78
  <span>{{ action.label }}</span>
65
79
  </button>
@@ -69,8 +83,8 @@ function handleThemeToggle() {
69
83
  @if(showThemeToggle)
70
84
  <button
71
85
  type="button"
72
- class="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"
73
- @click="handleThemeToggle"
86
+ class="{{ themeButtonClasses }}"
87
+ @click="onThemeToggle()"
74
88
  aria-label="Toggle dark mode"
75
89
  >
76
90
  <div class="i-hugeicons-moon-02 w-4 h-4 dark:hidden"></div>
@@ -84,9 +98,9 @@ function handleThemeToggle() {
84
98
  @if(showSettings)
85
99
  <a
86
100
  href="{{ settingsHref }}"
87
- class="flex items-center gap-3 px-3 py-2 rounded-lg text-sm transition-colors duration-150 text-black/70 dark:text-white/70 hover:bg-black/5 dark:hover:bg-white/10"
101
+ class="{{ actionClasses }}"
88
102
  >
89
- <div class="i-hugeicons-settings-02 w-5 h-5 text-black/50 dark:text-white/50"></div>
103
+ <div class="{{ settingsIconClasses }}"></div>
90
104
  @if(!collapsed)
91
105
  <span>{{ settingsLabel }}</span>
92
106
  @endif