@stacksjs/components 0.2.35 → 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,51 +0,0 @@
1
- <script server>
2
- export const value = $props.value
3
- export const disabled = $props.disabled || false
4
- export const className = $props.className || ''
5
- export const as = $props.as || 'div'
6
- export const currentValue = $props.currentValue
7
- export const onChange = $props.onChange
8
-
9
- export let active = false
10
- export const checked = currentValue === value
11
-
12
- const baseClasses = 'relative flex cursor-pointer rounded-lg px-5 py-4 shadow-md focus:outline-none transition-all'
13
- const stateClasses = checked
14
- ? 'bg-blue-900 bg-opacity-75 text-white dark:bg-blue-800'
15
- : 'bg-white dark:bg-neutral-800'
16
- const activeClasses = active
17
- ? 'ring-2 ring-white ring-opacity-60 ring-offset-2 ring-offset-blue-300 dark:ring-offset-blue-700'
18
- : ''
19
- const disabledClasses = disabled
20
- ? 'opacity-50 cursor-not-allowed'
21
- : ''
22
-
23
- const optionClasses = `${baseClasses} ${stateClasses} ${activeClasses} ${disabledClasses} ${className}`.trim()
24
-
25
- export function handleClick() {
26
- if (disabled) return
27
- onChange?.(value)
28
- }
29
-
30
- export function handleFocus() {
31
- if (!disabled) active = true
32
- }
33
-
34
- export function handleBlur() {
35
- active = false
36
- }
37
- </script>
38
-
39
- <component
40
- :is="{{ as }}"
41
- class="{{ optionClasses }}"
42
- role="radio"
43
- aria-checked="{{ checked ? 'true' : 'false' }}"
44
- @if(disabled)aria-disabled="true"@endif
45
- tabindex="{{ disabled ? '-1' : '0' }}"
46
- @click="handleClick"
47
- @focus="handleFocus"
48
- @blur="handleBlur"
49
- >
50
- <slot :active="active" :checked="checked" :disabled="disabled" />
51
- </component>
@@ -1,63 +0,0 @@
1
- <script server>
2
- export const value = $props.value || ''
3
- export const onChange = $props.onChange || (() => {})
4
- export const onSearch = $props.onSearch || (() => {})
5
- export const placeholder = $props.placeholder || 'Search...'
6
- export const disabled = $props.disabled || false
7
- export const size = $props.size || 'md'
8
- export const error = $props.error || false
9
- export const label = $props.label || ''
10
- export const helperText = $props.helperText || ''
11
- export const loading = $props.loading || false
12
- export const className = $props.className || ''
13
-
14
- // Search icon SVG
15
- const searchIcon = '<svg fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /></svg>'
16
-
17
- // Loading spinner SVG
18
- const spinnerIcon = '<svg class="animate-spin" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>'
19
-
20
- export const rightIcon = loading ? spinnerIcon : undefined
21
- </script>
22
-
23
- @component('TextInput', {
24
- value,
25
- onChange,
26
- placeholder,
27
- disabled,
28
- size,
29
- error,
30
- label,
31
- helperText,
32
- leftIcon: searchIcon,
33
- rightIcon,
34
- clearable: !loading,
35
- className,
36
- inputClassName: 'pr-20'
37
- })
38
- @endcomponent
39
-
40
- <script>
41
- // Debounce search to avoid excessive calls
42
- let searchTimeout = null
43
-
44
- function handleSearchInput(newValue) {
45
- if (onChange) {
46
- onChange(newValue)
47
- }
48
-
49
- // Debounce the onSearch callback
50
- if (searchTimeout) {
51
- clearTimeout(searchTimeout)
52
- }
53
-
54
- searchTimeout = setTimeout(() => {
55
- if (onSearch) {
56
- onSearch(newValue)
57
- }
58
- }, 300) // 300ms debounce
59
- }
60
-
61
- // Expose enhanced onChange handler
62
- export const enhancedOnChange = handleSearchInput
63
- </script>
@@ -1,288 +0,0 @@
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
- export const sections = $props.sections || []
27
- export const collapsed = $props.collapsed ?? false
28
- export const collapsible = $props.collapsible ?? true
29
- export const width = $props.width || 240
30
- 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'
33
- export const bordered = $props.bordered ?? true
34
- 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
-
54
- // Variant styles - macOS Tahoe inspired
55
- // Native macOS sidebars use vibrancy where desktop background shines through
56
- const variantStyles = {
57
- tahoe: {
58
- // Translucent with warm tint overlay - desktop shows through
59
- bg: 'bg-white/70 dark:bg-black/50',
60
- border: 'border-black/5 dark:border-white/10',
61
- backdrop: 'backdrop-blur-2xl backdrop-saturate-180',
62
- // Warm tint is applied via pseudo-element in template
63
- tint: true
64
- },
65
- vibrancy: {
66
- bg: 'bg-white/50 dark:bg-black/40',
67
- border: 'border-white/20 dark:border-white/10',
68
- backdrop: 'backdrop-blur-3xl backdrop-saturate-200',
69
- tint: false
70
- },
71
- solid: {
72
- bg: 'bg-stone-100 dark:bg-neutral-900',
73
- border: 'border-stone-200 dark:border-neutral-800',
74
- backdrop: '',
75
- tint: false
76
- },
77
- transparent: {
78
- bg: 'bg-transparent',
79
- border: 'border-transparent',
80
- backdrop: '',
81
- tint: false
82
- }
83
- }
84
-
85
- // Get current variant style
86
- function getVariantStyle() {
87
- return variantStyles[variant] || variantStyles.tahoe
88
- }
89
-
90
- // Calculate sidebar width
91
- function getSidebarWidth() {
92
- if (collapsed && !isHovered) {
93
- return `${minWidth}px`
94
- }
95
- return `${width}px`
96
- }
97
-
98
- // Check if showing expanded content
99
- function showExpanded() {
100
- return !collapsed || isHovered
101
- }
102
-
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
- }
130
-
131
- // Handle collapse toggle
132
- function handleCollapseToggle() {
133
- if (onCollapse) {
134
- onCollapse(!collapsed)
135
- }
136
- }
137
-
138
- // Handle mouse enter/leave for hover expand
139
- function handleMouseEnter() {
140
- if (collapsed && collapsible) {
141
- isHovered = true
142
- }
143
- }
144
-
145
- function handleMouseLeave() {
146
- isHovered = false
147
- }
148
-
149
- // Handle section toggle
150
- function handleSectionToggle(sectionId) {
151
- if (onSectionToggle) {
152
- onSectionToggle(sectionId)
153
- }
154
- }
155
-
156
- // Handle item click
157
- function handleItemClick(item, event) {
158
- if (onItemClick) {
159
- onItemClick(item, event)
160
- }
161
- }
162
-
163
- // Build container classes
164
- const style = getVariantStyle()
165
-
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}`
171
- }
172
-
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(' ')
183
-
184
- // Initialize native sidebar on mount
185
- if (typeof window !== 'undefined') {
186
- initNativeSidebar()
187
- }
188
- </script>
189
-
190
- <!-- Only render web sidebar when NOT running in Craft native sidebar mode -->
191
- @if(!hasNativeSidebar)
192
- <aside
193
- class="{{ containerClasses }} sidebar-container"
194
- style="width: {{ getSidebarWidth() }}"
195
- @mouseenter="handleMouseEnter"
196
- @mouseleave="handleMouseLeave"
197
- role="navigation"
198
- aria-label="Sidebar navigation"
199
- >
200
- <!-- Warm tint overlay for macOS Tahoe effect - desktop shows through -->
201
- @if(style.tint)
202
- <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
- @endif
204
-
205
- <!-- Header slot -->
206
- @if($slots.header)
207
- <div class="flex-shrink-0 relative z-10">
208
- <slot name="header" />
209
- </div>
210
- @endif
211
-
212
- <!-- Main content area with sections -->
213
- <div class="flex-1 overflow-y-auto overflow-x-hidden relative z-10">
214
- @if(sections.length > 0)
215
- <nav class="px-3 py-2 space-y-1">
216
- @foreach(sections as section)
217
- <SidebarSection
218
- :id="section.id"
219
- :label="section.label"
220
- :icon="section.icon"
221
- :items="section.items"
222
- :expanded="section.expanded !== false"
223
- :collapsible="section.collapsible !== false"
224
- :showLabel="showExpanded()"
225
- @toggle="handleSectionToggle(section.id)"
226
- @itemClick="handleItemClick"
227
- />
228
- @endforeach
229
- </nav>
230
- @else
231
- <!-- Default slot for custom content -->
232
- <div class="px-3 py-2">
233
- <slot />
234
- </div>
235
- @endif
236
- </div>
237
-
238
- <!-- Footer slot -->
239
- @if($slots.footer)
240
- <div class="flex-shrink-0 relative z-10">
241
- <slot name="footer" />
242
- </div>
243
- @endif
244
-
245
- <!-- Collapse toggle button -->
246
- @if(collapsible && showExpanded())
247
- <button
248
- 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' }}"
252
- >
253
- <div class="{{ collapsed ? 'i-hugeicons-sidebar-right' : 'i-hugeicons-sidebar-left' }} w-5 h-5"></div>
254
- </button>
255
- @endif
256
- </aside>
257
- @endif
258
-
259
- <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 */
279
- @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
- }
287
- }
288
- </style>
@@ -1,95 +0,0 @@
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
- export const showSettings = $props.showSettings ?? true
17
- export const showThemeToggle = $props.showThemeToggle ?? true
18
- export const settingsHref = $props.settingsHref || '/settings'
19
- export const settingsLabel = $props.settingsLabel || 'Settings'
20
- export const collapsed = $props.collapsed ?? false
21
- export const onThemeToggle = $props.onThemeToggle
22
-
23
- // Quick action items
24
- export const actions = $props.actions || []
25
-
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
- }
34
- }
35
- </script>
36
-
37
- <div class="border-t border-black/5 dark:border-white/10 p-3 space-y-2">
38
- <!-- Custom actions slot -->
39
- <slot />
40
-
41
- <!-- Quick actions row -->
42
- @if(!collapsed && actions.length > 0)
43
- <div class="flex items-center gap-2">
44
- @foreach(actions as action)
45
- @if(action.href)
46
- <a
47
- 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"
49
- >
50
- @if(action.icon)
51
- <div class="{{ action.icon }} w-4 h-4"></div>
52
- @endif
53
- <span>{{ action.label }}</span>
54
- </a>
55
- @else
56
- <button
57
- 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"
60
- >
61
- @if(action.icon)
62
- <div class="{{ action.icon }} w-4 h-4"></div>
63
- @endif
64
- <span>{{ action.label }}</span>
65
- </button>
66
- @endif
67
- @endforeach
68
-
69
- @if(showThemeToggle)
70
- <button
71
- 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"
74
- aria-label="Toggle dark mode"
75
- >
76
- <div class="i-hugeicons-moon-02 w-4 h-4 dark:hidden"></div>
77
- <div class="i-hugeicons-sun-02 w-4 h-4 hidden dark:block"></div>
78
- </button>
79
- @endif
80
- </div>
81
- @endif
82
-
83
- <!-- Settings link -->
84
- @if(showSettings)
85
- <a
86
- 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"
88
- >
89
- <div class="i-hugeicons-settings-02 w-5 h-5 text-black/50 dark:text-white/50"></div>
90
- @if(!collapsed)
91
- <span>{{ settingsLabel }}</span>
92
- @endif
93
- </a>
94
- @endif
95
- </div>
@@ -1,100 +0,0 @@
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
- export const title = $props.title || ''
17
- export const subtitle = $props.subtitle || ''
18
- export const logo = $props.logo || ''
19
- export const logoIcon = $props.logoIcon || ''
20
- export const showSearch = $props.showSearch ?? false
21
- export const searchPlaceholder = $props.searchPlaceholder || 'Search...'
22
- export const searchValue = $props.searchValue || ''
23
- export const collapsed = $props.collapsed ?? false
24
- export const onSearch = $props.onSearch
25
-
26
- // Handle search input
27
- function handleSearchInput(event) {
28
- if (onSearch) {
29
- onSearch(event.target.value)
30
- }
31
- }
32
- </script>
33
-
34
- <div class="flex-shrink-0">
35
- <!-- Title bar area -->
36
- <div class="h-13 flex items-center justify-between px-4 border-b border-black/5 dark:border-white/10">
37
- @if(!collapsed)
38
- <div class="flex items-center gap-3 min-w-0">
39
- <!-- Logo -->
40
- @if(logo)
41
- <img src="{{ logo }}" alt="{{ title }}" class="w-8 h-8 rounded-lg object-cover" />
42
- @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">
44
- <div class="{{ logoIcon }} w-5 h-5 text-white"></div>
45
- </div>
46
- @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">
48
- {{ title.charAt(0) }}
49
- </div>
50
- @endif
51
-
52
- <!-- Title & Subtitle -->
53
- <div class="min-w-0">
54
- @if(title)
55
- <div class="text-sm font-semibold text-black/90 dark:text-white truncate">
56
- {{ title }}
57
- </div>
58
- @endif
59
- @if(subtitle)
60
- <div class="text-xs text-black/50 dark:text-white/50 truncate">
61
- {{ subtitle }}
62
- </div>
63
- @endif
64
- </div>
65
- </div>
66
- @else
67
- <!-- Collapsed state - just logo -->
68
- @if(logo)
69
- <img src="{{ logo }}" alt="{{ title }}" class="w-8 h-8 rounded-lg object-cover mx-auto" />
70
- @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">
72
- <div class="{{ logoIcon }} w-5 h-5 text-white"></div>
73
- </div>
74
- @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">
76
- {{ title.charAt(0) }}
77
- </div>
78
- @endif
79
- @endif
80
-
81
- <!-- Slot for custom header actions -->
82
- <slot name="actions" />
83
- </div>
84
-
85
- <!-- Search (only when expanded) -->
86
- @if(showSearch && !collapsed)
87
- <div class="px-3 py-3">
88
- <div class="relative">
89
- <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
- <input
91
- type="text"
92
- placeholder="{{ searchPlaceholder }}"
93
- 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"
96
- />
97
- </div>
98
- </div>
99
- @endif
100
- </div>