@customafk/lunas-ui 0.0.24 → 0.0.26

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 (210) hide show
  1. package/README.md +22 -11
  2. package/dist/{button-DLZoEj48.d.ts → button-BmBtMriU.d.ts} +5 -5
  3. package/dist/{button-BajtMcjb.d.cts → button-tCnJHt8O.d.cts} +5 -5
  4. package/dist/{command-DvCEx-HX.d.cts → command-Dr2XmKV6.d.cts} +12 -12
  5. package/dist/{command-80QuD-XX.d.ts → command-Dvq-HZwH.d.ts} +12 -12
  6. package/dist/data-display/country.d.ts +1 -1
  7. package/dist/data-display/empty.d.cts +2 -2
  8. package/dist/data-display/empty.d.ts +2 -2
  9. package/dist/data-display/role-badge.d.ts +1 -1
  10. package/dist/data-display/statistic.d.cts +2 -2
  11. package/dist/data-display/statistic.d.ts +2 -2
  12. package/dist/{dialog-xylwF4m7.d.cts → dialog-C-DYoapJ.d.ts} +12 -12
  13. package/dist/{dialog-BInoLe-Q.d.ts → dialog-CA0E_tNX.d.cts} +12 -12
  14. package/dist/dialogs/detail-dialog/component/sidebar.cjs +1 -1
  15. package/dist/dialogs/detail-dialog/component/sidebar.d.cts +30 -30
  16. package/dist/dialogs/detail-dialog/component/sidebar.d.ts +30 -30
  17. package/dist/dialogs/detail-dialog/component/sidebar.js +1 -1
  18. package/dist/dialogs/detail-dialog/index.cjs +1 -1
  19. package/dist/dialogs/detail-dialog/index.js +1 -1
  20. package/dist/dialogs/form-dialog.d.cts +2 -2
  21. package/dist/dialogs/form-dialog.d.ts +2 -2
  22. package/dist/forms/combobox-field.d.cts +2 -2
  23. package/dist/forms/combobox-field.d.ts +2 -2
  24. package/dist/forms/date-field.d.cts +2 -2
  25. package/dist/forms/date-field.d.ts +2 -2
  26. package/dist/forms/form-wrapper.d.cts +2 -2
  27. package/dist/forms/form-wrapper.d.ts +2 -2
  28. package/dist/forms/multi-select-field.d.cts +2 -2
  29. package/dist/forms/multi-select-field.d.ts +2 -2
  30. package/dist/forms/number-field.d.cts +2 -2
  31. package/dist/forms/number-field.d.ts +2 -2
  32. package/dist/forms/password-field.d.cts +2 -2
  33. package/dist/forms/password-field.d.ts +2 -2
  34. package/dist/forms/select-field.d.cts +2 -2
  35. package/dist/forms/select-field.d.ts +2 -2
  36. package/dist/forms/switch-field.d.cts +2 -2
  37. package/dist/forms/switch-field.d.ts +2 -2
  38. package/dist/forms/text-field.d.cts +2 -2
  39. package/dist/forms/text-field.d.ts +2 -2
  40. package/dist/forms/textarea-field.d.cts +2 -2
  41. package/dist/forms/textarea-field.d.ts +2 -2
  42. package/dist/{input-Lfbw3nE_.d.cts → input-BsXm0_Iq.d.cts} +3 -3
  43. package/dist/{input-BEvwsdQj.d.ts → input-CjNcnHb_.d.ts} +3 -3
  44. package/dist/layouts/app-layout/index.cjs +2 -0
  45. package/dist/layouts/app-layout/index.cjs.map +1 -0
  46. package/dist/layouts/app-layout/index.d.cts +34 -0
  47. package/dist/layouts/app-layout/index.d.ts +34 -0
  48. package/dist/layouts/app-layout/index.js +2 -0
  49. package/dist/layouts/app-layout/index.js.map +1 -0
  50. package/dist/layouts/flex.d.cts +4 -4
  51. package/dist/layouts/flex.d.ts +4 -4
  52. package/dist/layouts/main/index.cjs +1 -1
  53. package/dist/layouts/main/index.cjs.map +1 -1
  54. package/dist/layouts/main/index.d.ts +4 -4
  55. package/dist/layouts/main/index.js +1 -1
  56. package/dist/layouts/main/index.js.map +1 -1
  57. package/dist/{separator-CGHXMKzf.d.ts → separator-5FdzRGaJ.d.ts} +3 -3
  58. package/dist/{separator-SKNlThFJ.d.cts → separator-DpxrpK_H.d.cts} +3 -3
  59. package/dist/{sidebar-BR_UWLC5.js → sidebar-BDDG3PeD.js} +1 -1
  60. package/dist/{sidebar-BR_UWLC5.js.map → sidebar-BDDG3PeD.js.map} +1 -1
  61. package/dist/{sidebar-C2FH-tzm.cjs → sidebar-BbcOcECD.cjs} +1 -1
  62. package/dist/{sidebar-C2FH-tzm.cjs.map → sidebar-BbcOcECD.cjs.map} +1 -1
  63. package/dist/sidebar-CospqUDX.js +2 -0
  64. package/dist/sidebar-CospqUDX.js.map +1 -0
  65. package/dist/sidebar-DWuOHlvn.cjs +2 -0
  66. package/dist/sidebar-DWuOHlvn.cjs.map +1 -0
  67. package/dist/table/index.d.cts +2 -2
  68. package/dist/table/index.d.ts +2 -2
  69. package/dist/{toggle-CHJ2edke.js → toggle-A6eGkFij.js} +1 -1
  70. package/dist/{toggle-CHJ2edke.js.map → toggle-A6eGkFij.js.map} +1 -1
  71. package/dist/{toggle-DO8QbhLS.cjs → toggle-B7nXBZ9r.cjs} +1 -1
  72. package/dist/{toggle-DO8QbhLS.cjs.map → toggle-B7nXBZ9r.cjs.map} +1 -1
  73. package/dist/{toggle-9SGewcSc.d.cts → toggle-Cx9H5u3p.d.cts} +3 -3
  74. package/dist/{toggle-DxWgPH7j.d.ts → toggle-DH9IssyE.d.ts} +5 -5
  75. package/dist/{tooltip-CbLQ7JEO.d.cts → tooltip-BAtWdJyX.d.cts} +6 -6
  76. package/dist/{tooltip-DtXKnGdV.d.ts → tooltip-Djh_dcy5.d.ts} +6 -6
  77. package/dist/{types-0rxiMXBn.d.ts → types-oumb6uSW.d.ts} +1 -1
  78. package/dist/typography/paragraph.d.cts +2 -2
  79. package/dist/typography/paragraph.d.ts +2 -2
  80. package/dist/typography/title.d.cts +2 -2
  81. package/dist/typography/title.d.ts +2 -2
  82. package/dist/ui/alert-dialog.d.cts +12 -12
  83. package/dist/ui/alert-dialog.d.ts +12 -12
  84. package/dist/ui/alert.d.cts +6 -6
  85. package/dist/ui/alert.d.ts +4 -4
  86. package/dist/ui/aspect-ratio.d.cts +2 -2
  87. package/dist/ui/aspect-ratio.d.ts +2 -2
  88. package/dist/ui/avatar.d.cts +4 -4
  89. package/dist/ui/avatar.d.ts +4 -4
  90. package/dist/ui/badge.d.cts +4 -4
  91. package/dist/ui/badge.d.ts +2 -2
  92. package/dist/ui/breadcrumb.d.cts +8 -8
  93. package/dist/ui/breadcrumb.d.ts +8 -8
  94. package/dist/ui/button.d.cts +1 -1
  95. package/dist/ui/button.d.ts +1 -1
  96. package/dist/ui/calendar.d.cts +4 -4
  97. package/dist/ui/calendar.d.ts +4 -4
  98. package/dist/ui/card.d.cts +8 -8
  99. package/dist/ui/card.d.ts +8 -8
  100. package/dist/ui/carousel.d.cts +7 -7
  101. package/dist/ui/carousel.d.ts +7 -7
  102. package/dist/ui/collapsible.d.cts +4 -4
  103. package/dist/ui/collapsible.d.ts +4 -4
  104. package/dist/ui/command.d.cts +2 -2
  105. package/dist/ui/command.d.ts +2 -2
  106. package/dist/ui/context-menu.d.cts +16 -16
  107. package/dist/ui/context-menu.d.ts +16 -16
  108. package/dist/ui/dialog.d.cts +1 -1
  109. package/dist/ui/dialog.d.ts +1 -1
  110. package/dist/ui/dropdown-menu.d.cts +16 -16
  111. package/dist/ui/dropdown-menu.d.ts +16 -16
  112. package/dist/ui/file-uploader.d.cts +2 -2
  113. package/dist/ui/file-uploader.d.ts +2 -2
  114. package/dist/ui/form.d.cts +7 -7
  115. package/dist/ui/form.d.ts +7 -7
  116. package/dist/ui/hover-card.d.cts +4 -4
  117. package/dist/ui/hover-card.d.ts +4 -4
  118. package/dist/ui/input-otp.d.cts +5 -5
  119. package/dist/ui/input-otp.d.ts +5 -5
  120. package/dist/ui/input.d.cts +1 -1
  121. package/dist/ui/input.d.ts +1 -1
  122. package/dist/ui/inputs/search-input.d.cts +3 -3
  123. package/dist/ui/inputs/search-input.d.ts +3 -3
  124. package/dist/ui/label.d.cts +2 -2
  125. package/dist/ui/label.d.ts +2 -2
  126. package/dist/ui/menubar.d.cts +17 -17
  127. package/dist/ui/menubar.d.ts +17 -17
  128. package/dist/ui/multi-select.d.cts +2 -2
  129. package/dist/ui/multi-select.d.ts +2 -2
  130. package/dist/ui/navigation-menu.d.cts +11 -11
  131. package/dist/ui/navigation-menu.d.ts +11 -11
  132. package/dist/ui/pagination.d.cts +9 -9
  133. package/dist/ui/pagination.d.ts +9 -9
  134. package/dist/ui/popover.d.cts +5 -5
  135. package/dist/ui/popover.d.ts +5 -5
  136. package/dist/ui/progress.d.cts +2 -2
  137. package/dist/ui/progress.d.ts +2 -2
  138. package/dist/ui/radio-group.d.cts +3 -3
  139. package/dist/ui/radio-group.d.ts +3 -3
  140. package/dist/ui/resizable.d.cts +4 -4
  141. package/dist/ui/resizable.d.ts +4 -4
  142. package/dist/ui/scroll-area.d.cts +3 -3
  143. package/dist/ui/scroll-area.d.ts +3 -3
  144. package/dist/ui/select.d.cts +11 -11
  145. package/dist/ui/select.d.ts +11 -11
  146. package/dist/ui/separator.d.cts +1 -1
  147. package/dist/ui/separator.d.ts +1 -1
  148. package/dist/ui/sheet.d.cts +9 -9
  149. package/dist/ui/sheet.d.ts +9 -9
  150. package/dist/ui/sidebar.cjs +1 -1
  151. package/dist/ui/sidebar.d.cts +28 -28
  152. package/dist/ui/sidebar.d.ts +30 -30
  153. package/dist/ui/sidebar.js +1 -1
  154. package/dist/ui/skeleton.d.cts +2 -2
  155. package/dist/ui/skeleton.d.ts +2 -2
  156. package/dist/ui/slider.d.cts +2 -2
  157. package/dist/ui/slider.d.ts +2 -2
  158. package/dist/ui/sonner.d.cts +2 -2
  159. package/dist/ui/sonner.d.ts +2 -2
  160. package/dist/ui/switch.d.cts +2 -2
  161. package/dist/ui/switch.d.ts +2 -2
  162. package/dist/ui/table.d.cts +9 -9
  163. package/dist/ui/table.d.ts +9 -9
  164. package/dist/ui/tabs.d.cts +5 -5
  165. package/dist/ui/tabs.d.ts +5 -5
  166. package/dist/ui/textarea.d.cts +2 -2
  167. package/dist/ui/textarea.d.ts +2 -2
  168. package/dist/ui/toggle-group.cjs +1 -1
  169. package/dist/ui/toggle-group.d.cts +4 -4
  170. package/dist/ui/toggle-group.d.ts +4 -4
  171. package/dist/ui/toggle-group.js +1 -1
  172. package/dist/ui/toggle.cjs +1 -1
  173. package/dist/ui/toggle.d.cts +1 -1
  174. package/dist/ui/toggle.d.ts +1 -1
  175. package/dist/ui/toggle.js +1 -1
  176. package/dist/ui/tooltip.d.cts +1 -1
  177. package/dist/ui/tooltip.d.ts +1 -1
  178. package/dist/use-mobile-CNVZwItd.js +2 -0
  179. package/dist/use-mobile-CNVZwItd.js.map +1 -0
  180. package/dist/use-mobile-DD7ESbjU.cjs +2 -0
  181. package/dist/use-mobile-DD7ESbjU.cjs.map +1 -0
  182. package/package.json +5 -5
  183. package/packages/components/layouts/app-layout/index.tsx +74 -0
  184. package/packages/components/layouts/app-layout/sidebar.tsx +663 -0
  185. package/packages/index.css +5 -4
  186. package/packages/stories/layouts/app-layout.stories.tsx +49 -0
  187. package/dist/sidebar-BKNai9nJ.cjs +0 -2
  188. package/dist/sidebar-BKNai9nJ.cjs.map +0 -1
  189. package/dist/sidebar-DphZ29-4.js +0 -2
  190. package/dist/sidebar-DphZ29-4.js.map +0 -1
  191. package/dist/styles/base.cjs +0 -0
  192. package/dist/styles/base.css +0 -32
  193. package/dist/styles/base.css.map +0 -1
  194. package/dist/styles/base.js +0 -1
  195. package/dist/styles/loader.cjs +0 -0
  196. package/dist/styles/loader.css +0 -116
  197. package/dist/styles/loader.css.map +0 -1
  198. package/dist/styles/loader.js +0 -1
  199. package/dist/styles/theme.cjs +0 -0
  200. package/dist/styles/theme.css +0 -106
  201. package/dist/styles/theme.css.map +0 -1
  202. package/dist/styles/theme.js +0 -1
  203. package/dist/styles/typography.cjs +0 -0
  204. package/dist/styles/typography.css +0 -9
  205. package/dist/styles/typography.css.map +0 -1
  206. package/dist/styles/typography.js +0 -1
  207. package/packages/components/styles/base.css +0 -29
  208. package/packages/components/styles/loader.css +0 -113
  209. package/packages/components/styles/theme.css +0 -103
  210. package/packages/components/styles/typography.css +0 -6
@@ -0,0 +1,663 @@
1
+ import React from 'react'
2
+ import { Slot as SlotPrimitive } from 'radix-ui'
3
+ import { cva, type VariantProps } from 'class-variance-authority'
4
+ import { MenuIcon } from 'lucide-react'
5
+
6
+ import { Button } from '@/components/ui/button'
7
+ import { Separator } from '@/components/ui/separator'
8
+ import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@/components/ui/sheet'
9
+ import { Skeleton } from '@/components/ui/skeleton'
10
+ import { TooltipProvider } from '@/components/ui/tooltip'
11
+ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
12
+
13
+ import { useIsMobile } from '@/hooks/use-mobile'
14
+ import { cn } from '@/lib/utils'
15
+
16
+ const SIDEBAR_COOKIE_NAME = 'sidebar_state'
17
+ const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
18
+ const SIDEBAR_WIDTH = '16rem'
19
+ const SIDEBAR_WIDTH_MOBILE = '18rem'
20
+ const SIDEBAR_WIDTH_ICON = '3rem'
21
+ const SIDEBAR_KEYBOARD_SHORTCUT = 'b'
22
+
23
+ type SidebarContextProps = {
24
+ state: 'expanded' | 'collapsed'
25
+ open: boolean
26
+ setOpen: (open: boolean) => void
27
+ openMobile: boolean
28
+ setOpenMobile: (open: boolean) => void
29
+ isMobile: boolean
30
+ toggleSidebar: () => void
31
+ }
32
+
33
+ const SidebarContext = React.createContext<SidebarContextProps | null>(null)
34
+
35
+ function useSidebar() {
36
+ const context = React.useContext(SidebarContext)
37
+ if (!context) {
38
+ throw new Error('useSidebar must be used within a SidebarProvider.')
39
+ }
40
+
41
+ return context
42
+ }
43
+
44
+ function SidebarProvider({
45
+ defaultOpen = true,
46
+ open: openProp,
47
+ onOpenChange: setOpenProp,
48
+ className,
49
+ style,
50
+ children,
51
+ ...props
52
+ }: React.ComponentProps<'div'> & {
53
+ defaultOpen?: boolean
54
+ open?: boolean
55
+ onOpenChange?: (open: boolean) => void
56
+ }) {
57
+ const isMobile = useIsMobile()
58
+ const [openMobile, setOpenMobile] = React.useState(false)
59
+
60
+ // This is the internal state of the sidebar.
61
+ // We use openProp and setOpenProp for control from outside the component.
62
+ const [_open, _setOpen] = React.useState(defaultOpen)
63
+ const open = openProp ?? _open
64
+ const setOpen = React.useCallback(
65
+ (value: boolean | ((value: boolean) => boolean)) => {
66
+ const openState = typeof value === 'function' ? value(open) : value
67
+ if (setOpenProp) {
68
+ setOpenProp(openState)
69
+ } else {
70
+ _setOpen(openState)
71
+ }
72
+
73
+ // This sets the cookie to keep the sidebar state.
74
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
75
+ },
76
+ [setOpenProp, open],
77
+ )
78
+
79
+ // Helper to toggle the sidebar.
80
+ const toggleSidebar = React.useCallback(() => {
81
+ return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
82
+ }, [isMobile, setOpen, setOpenMobile])
83
+
84
+ // Adds a keyboard shortcut to toggle the sidebar.
85
+ React.useEffect(() => {
86
+ const handleKeyDown = (event: KeyboardEvent) => {
87
+ if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
88
+ event.preventDefault()
89
+ toggleSidebar()
90
+ }
91
+ }
92
+
93
+ window.addEventListener('keydown', handleKeyDown)
94
+ return () => window.removeEventListener('keydown', handleKeyDown)
95
+ }, [toggleSidebar])
96
+
97
+ // We add a state so that we can do data-state="expanded" or "collapsed".
98
+ // This makes it easier to style the sidebar with Tailwind classes.
99
+ const state = open ? 'expanded' : 'collapsed'
100
+
101
+ const contextValue = React.useMemo<SidebarContextProps>(
102
+ () => ({
103
+ state,
104
+ isMobile,
105
+
106
+ toggleSidebar,
107
+
108
+ open,
109
+ setOpen,
110
+
111
+ openMobile,
112
+ setOpenMobile,
113
+ }),
114
+ [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],
115
+ )
116
+
117
+ return (
118
+ <SidebarContext.Provider value={contextValue}>
119
+ <TooltipProvider delayDuration={0}>
120
+ <div
121
+ data-slot="sidebar-wrapper"
122
+ style={
123
+ {
124
+ '--sidebar-width': SIDEBAR_WIDTH,
125
+ '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,
126
+ ...style,
127
+ } as React.CSSProperties
128
+ }
129
+ className={cn('group/sidebar-wrapper', 'has-data-[variant=inset]:bg-sidebar', 'flex h-svh w-full', className)}
130
+ {...props}
131
+ >
132
+ {children}
133
+ </div>
134
+ </TooltipProvider>
135
+ </SidebarContext.Provider>
136
+ )
137
+ }
138
+
139
+ function Sidebar({
140
+ side = 'left',
141
+ variant = 'sidebar',
142
+ collapsible = 'offcanvas',
143
+ className,
144
+ children,
145
+ ...props
146
+ }: React.ComponentProps<'div'> & {
147
+ side?: 'left' | 'right'
148
+ variant?: 'sidebar' | 'floating' | 'inset'
149
+ collapsible?: 'offcanvas' | 'icon' | 'none'
150
+ }) {
151
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
152
+
153
+ if (collapsible === 'none') {
154
+ return (
155
+ <aside data-slot="sidebar" className={cn('bg-sidebar', 'text-sidebar-foreground', 'flex h-full w-(--sidebar-width) flex-col', className)} {...props}>
156
+ {children}
157
+ </aside>
158
+ )
159
+ }
160
+
161
+ if (isMobile) {
162
+ return (
163
+ <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
164
+ <SheetContent
165
+ data-sidebar="sidebar"
166
+ data-slot="sidebar"
167
+ data-mobile="true"
168
+ className="bg-sidebar text-sidebar-foreground w-(--sidebar-width) p-0 [&>button]:hidden"
169
+ style={
170
+ {
171
+ '--sidebar-width': SIDEBAR_WIDTH_MOBILE,
172
+ } as React.CSSProperties
173
+ }
174
+ side={side}
175
+ >
176
+ <SheetHeader className="sr-only">
177
+ <SheetTitle>Sidebar</SheetTitle>
178
+ <SheetDescription>Displays the mobile sidebar.</SheetDescription>
179
+ </SheetHeader>
180
+ <div className="flex h-full w-full flex-col">{children}</div>
181
+ </SheetContent>
182
+ </Sheet>
183
+ )
184
+ }
185
+
186
+ return (
187
+ <aside
188
+ className="group peer text-sidebar-foreground bg-card hidden md:block"
189
+ data-state={state}
190
+ data-collapsible={state === 'collapsed' ? collapsible : ''}
191
+ data-variant={variant}
192
+ data-side={side}
193
+ data-slot="sidebar"
194
+ >
195
+ {/* This is what handles the sidebar gap on desktop */}
196
+ <div
197
+ data-slot="sidebar-gap"
198
+ className={cn(
199
+ 'relative',
200
+ 'bg-transparent',
201
+ 'transition-[width] duration-200 ease-linear',
202
+ 'h-14 w-(--sidebar-width)',
203
+ 'group-data-[collapsible=offcanvas]:w-0',
204
+ 'group-data-[side=right]:rotate-180',
205
+ variant === 'floating' || variant === 'inset'
206
+ ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]'
207
+ : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',
208
+ )}
209
+ />
210
+ <div
211
+ data-slot="sidebar-container"
212
+ className={cn(
213
+ 'hidden md:flex',
214
+ 'shadow-nav fixed inset-y-0 top-14 z-10',
215
+ 'h-[calc(100svh-3.5rem)] w-(--sidebar-width)',
216
+ 'transition-[left,right,width] duration-200 ease-linear',
217
+ side === 'left' && 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]',
218
+ side === 'right' && 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
219
+ // Adjust the padding for floating and inset variants.
220
+ variant === 'floating' || variant === 'inset'
221
+ ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]'
222
+ : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l',
223
+ className,
224
+ )}
225
+ {...props}
226
+ >
227
+ <div
228
+ data-sidebar="sidebar"
229
+ data-slot="sidebar-inner"
230
+ className={cn(
231
+ 'flex size-full flex-col',
232
+ 'group-data-[variant=floating]:rounded-lg',
233
+ 'group-data-[variant=floating]:border',
234
+ 'group-data-[variant=floating]:border-sidebar-border',
235
+ 'group-data-[variant=floating]:shadow-sm',
236
+ )}
237
+ >
238
+ {children}
239
+ </div>
240
+ </div>
241
+ </aside>
242
+ )
243
+ }
244
+
245
+ function SidebarTrigger({ className, onClick, ...props }: React.ComponentProps<typeof Button>) {
246
+ const { toggleSidebar } = useSidebar()
247
+
248
+ return (
249
+ <Button
250
+ data-sidebar="trigger"
251
+ data-slot="sidebar-trigger"
252
+ variant="ghost"
253
+ color="muted"
254
+ size="icon"
255
+ className={cn('size-10 rounded-full', className)}
256
+ onClick={(event) => {
257
+ onClick?.(event)
258
+ toggleSidebar()
259
+ }}
260
+ {...props}
261
+ >
262
+ <MenuIcon className="!size-6" />
263
+ <span className="sr-only">Toggle Sidebar</span>
264
+ </Button>
265
+ )
266
+ }
267
+
268
+ function SidebarRail({ className, ...props }: React.ComponentProps<'button'>) {
269
+ const { toggleSidebar } = useSidebar()
270
+
271
+ return (
272
+ <button
273
+ data-sidebar="rail"
274
+ data-slot="sidebar-rail"
275
+ aria-label="Toggle Sidebar"
276
+ tabIndex={-1}
277
+ onClick={toggleSidebar}
278
+ title="Toggle Sidebar"
279
+ className={cn(
280
+ 'absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear sm:flex',
281
+ 'after:absolute after:inset-y-0 after:left-1/2 after:w-[2px]',
282
+ 'group-data-[side=left]:-right-4',
283
+ 'group-data-[side=right]:left-0',
284
+ 'in-data-[side=left]:cursor-w-resize',
285
+ 'in-data-[side=right]:cursor-e-resize',
286
+ 'hover:after:bg-sidebar-border',
287
+ 'hover:group-data-[collapsible=offcanvas]:bg-sidebar',
288
+ 'group-data-[collapsible=offcanvas]:translate-x-0',
289
+ 'group-data-[collapsible=offcanvas]:after:left-full',
290
+ '[[data-side=left][data-state=collapsed]_&]:cursor-e-resize',
291
+ '[[data-side=right][data-state=collapsed]_&]:cursor-w-resize',
292
+ '[[data-side=left][data-collapsible=offcanvas]_&]:-right-2',
293
+ '[[data-side=right][data-collapsible=offcanvas]_&]:-left-2',
294
+ className,
295
+ )}
296
+ {...props}
297
+ />
298
+ )
299
+ }
300
+
301
+ function SidebarInset({ className, children, ...props }: React.ComponentProps<'main'>) {
302
+ return (
303
+ <main data-slot="sidebar-inset" className={cn('w-full', 'relative', 'flex flex-1 flex-col', className)} {...props}>
304
+ <div className="h-14 w-full" />
305
+ <div className={cn('flex-1 inset-shadow-sm')}>{children}</div>
306
+ </main>
307
+ )
308
+ }
309
+
310
+ function SidebarHeader({ className, ...props }: React.ComponentProps<'div'>) {
311
+ return <div data-slot="sidebar-header" data-sidebar="header" className={cn('flex flex-col gap-2 p-2', className)} {...props} />
312
+ }
313
+
314
+ function SidebarFooter({ className, ...props }: React.ComponentProps<'div'>) {
315
+ return <div data-slot="sidebar-footer" data-sidebar="footer" className={cn('flex flex-col gap-2 p-2', className)} {...props} />
316
+ }
317
+
318
+ function SidebarSeparator({ className, ...props }: React.ComponentProps<typeof Separator>) {
319
+ return <Separator data-slot="sidebar-separator" data-sidebar="separator" className={cn('bg-sidebar-border mx-2 w-auto', className)} {...props} />
320
+ }
321
+
322
+ function SidebarContent({ className, ...props }: React.ComponentProps<'div'>) {
323
+ return (
324
+ <div
325
+ data-slot="sidebar-content"
326
+ data-sidebar="content"
327
+ className={cn('flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden', className)}
328
+ {...props}
329
+ />
330
+ )
331
+ }
332
+
333
+ function SidebarGroup({ className, ...props }: React.ComponentProps<'div'>) {
334
+ return <div data-slot="sidebar-group" data-sidebar="group" className={cn('relative flex w-full min-w-0 flex-col p-2', className)} {...props} />
335
+ }
336
+
337
+ function SidebarGroupLabel({ className, asChild = false, ...props }: React.ComponentProps<'div'> & { asChild?: boolean }) {
338
+ const Comp = asChild ? SlotPrimitive.Slot : 'div'
339
+
340
+ return (
341
+ <Comp
342
+ data-slot="sidebar-group-label"
343
+ data-sidebar="group-label"
344
+ className={cn(
345
+ 'flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2',
346
+ 'text-sidebar-foreground/70',
347
+ 'ring-sidebar-ring',
348
+ '[&>svg]:size-4',
349
+ '[&>svg]:shrink-0',
350
+ 'group-data-[collapsible=icon]:-mt-8',
351
+ 'group-data-[collapsible=icon]:opacity-0',
352
+ className,
353
+ )}
354
+ {...props}
355
+ />
356
+ )
357
+ }
358
+
359
+ function SidebarGroupAction({ className, asChild = false, ...props }: React.ComponentProps<'button'> & { asChild?: boolean }) {
360
+ const Comp = asChild ? SlotPrimitive.Slot : 'button'
361
+
362
+ return (
363
+ <Comp
364
+ data-slot="sidebar-group-action"
365
+ data-sidebar="group-action"
366
+ className={cn(
367
+ 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform',
368
+ 'focus-visible:ring-2',
369
+ '[&>svg]:size-4',
370
+ '[&>svg]:shrink-0',
371
+ // Increases the hit area of the button on mobile.
372
+ 'after:absolute after:-inset-2 md:after:hidden',
373
+ 'group-data-[collapsible=icon]:hidden',
374
+ className,
375
+ )}
376
+ {...props}
377
+ />
378
+ )
379
+ }
380
+
381
+ function SidebarGroupContent({ className, ...props }: React.ComponentProps<'div'>) {
382
+ return <div data-slot="sidebar-group-content" data-sidebar="group-content" className={cn('w-full text-sm', className)} {...props} />
383
+ }
384
+
385
+ function SidebarMenu({ className, ...props }: React.ComponentProps<'ul'>) {
386
+ return <ul data-slot="sidebar-menu" data-sidebar="menu" className={cn('flex w-full min-w-0 flex-col gap-1', className)} {...props} />
387
+ }
388
+
389
+ function SidebarMenuItem({ className, ...props }: React.ComponentProps<'li'>) {
390
+ return <li data-slot="sidebar-menu-item" data-sidebar="menu-item" className={cn('group/menu-item relative', className)} {...props} />
391
+ }
392
+
393
+ const sidebarMenuButtonVariants = cva(
394
+ [
395
+ 'peer/menu-button',
396
+ 'cursor-pointer',
397
+ 'flex w-full items-center gap-2',
398
+ 'overflow-hidden rounded-md p-2 text-left text-sm outline-hidden',
399
+ 'ring-sidebar-ring transition-[width,height,padding]',
400
+ 'focus-visible:ring-2',
401
+ 'hover:bg-sidebar-accent',
402
+ 'hover:text-sidebar-accent-foreground',
403
+ 'active:bg-sidebar-accent',
404
+ 'active:text-sidebar-accent-foreground',
405
+ 'disabled:pointer-events-none',
406
+ 'disabled:opacity-50',
407
+ 'group-has-data-[sidebar=menu-action]/menu-item:pr-8',
408
+ 'aria-disabled:pointer-events-none',
409
+ 'aria-disabled:opacity-50',
410
+ 'data-[active=true]:bg-sidebar-accent',
411
+ 'data-[active=true]:font-medium',
412
+ 'data-[active=true]:text-sidebar-accent-foreground',
413
+ 'data-[state=open]:hover:bg-sidebar-accent',
414
+ 'data-[state=open]:hover:text-sidebar-accent-foreground',
415
+ 'group-data-[collapsible=icon]:size-8!',
416
+ 'group-data-[collapsible=icon]:p-2!',
417
+ '[&>span:last-child]:truncate',
418
+ '[&>svg]:size-4',
419
+ '[&>svg]:shrink-0',
420
+ ],
421
+ {
422
+ variants: {
423
+ variant: {
424
+ default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
425
+ outline:
426
+ 'bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]',
427
+ },
428
+ size: {
429
+ default: 'h-8 text-sm',
430
+ sm: 'h-7 text-xs',
431
+ lg: 'h-12 text-sm group-data-[collapsible=icon]:p-0!',
432
+ },
433
+ },
434
+ defaultVariants: {
435
+ variant: 'default',
436
+ size: 'default',
437
+ },
438
+ },
439
+ )
440
+
441
+ function SidebarMenuButton({
442
+ asChild = false,
443
+ isActive = false,
444
+ variant = 'default',
445
+ size = 'default',
446
+ tooltip,
447
+ className,
448
+ ...props
449
+ }: React.ComponentProps<'button'> & {
450
+ asChild?: boolean
451
+ isActive?: boolean
452
+ tooltip?: string | React.ComponentProps<typeof TooltipContent>
453
+ } & VariantProps<typeof sidebarMenuButtonVariants>) {
454
+ const Comp = asChild ? SlotPrimitive.Slot : 'button'
455
+ const { isMobile, state } = useSidebar()
456
+
457
+ const button = (
458
+ <Comp
459
+ data-slot="sidebar-menu-button"
460
+ data-sidebar="menu-button"
461
+ data-size={size}
462
+ data-active={isActive}
463
+ className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
464
+ {...props}
465
+ />
466
+ )
467
+
468
+ if (!tooltip) {
469
+ return button
470
+ }
471
+
472
+ if (typeof tooltip === 'string') {
473
+ tooltip = {
474
+ children: tooltip,
475
+ }
476
+ }
477
+
478
+ return (
479
+ <Tooltip>
480
+ <TooltipTrigger asChild>{button}</TooltipTrigger>
481
+ <TooltipContent side="right" align="center" hidden={state !== 'collapsed' || isMobile} {...tooltip} />
482
+ </Tooltip>
483
+ )
484
+ }
485
+
486
+ function SidebarMenuAction({
487
+ className,
488
+ asChild = false,
489
+ showOnHover = false,
490
+ ...props
491
+ }: React.ComponentProps<'button'> & {
492
+ asChild?: boolean
493
+ showOnHover?: boolean
494
+ }) {
495
+ const Comp = asChild ? SlotPrimitive.Slot : 'button'
496
+
497
+ return (
498
+ <Comp
499
+ data-slot="sidebar-menu-action"
500
+ data-sidebar="menu-action"
501
+ className={cn(
502
+ 'text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform',
503
+ 'focus-visible:ring-2',
504
+ '[&>svg]:size-4',
505
+ '[&>svg]:shrink-0',
506
+ // Increases the hit area of the button on mobile.
507
+ 'after:absolute after:-inset-2 md:after:hidden',
508
+ 'peer-data-[size=sm]/menu-button:top-1',
509
+ 'peer-data-[size=default]/menu-button:top-1.5',
510
+ 'peer-data-[size=lg]/menu-button:top-2.5',
511
+ 'group-data-[collapsible=icon]:hidden',
512
+ showOnHover && 'peer-data-[active=true]/menu-button:text-sidebar-accent-foreground',
513
+ showOnHover && 'group-focus-within/menu-item:opacity-100',
514
+ showOnHover && 'group-hover/menu-item:opacity-100',
515
+ showOnHover && 'data-[state=open]:opacity-100 md:opacity-0',
516
+ className,
517
+ )}
518
+ {...props}
519
+ />
520
+ )
521
+ }
522
+
523
+ function SidebarMenuBadge({ className, ...props }: React.ComponentProps<'div'>) {
524
+ return (
525
+ <div
526
+ data-slot="sidebar-menu-badge"
527
+ data-sidebar="menu-badge"
528
+ className={cn(
529
+ 'text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums select-none',
530
+ 'peer-hover/menu-button:text-sidebar-accent-foreground',
531
+ 'peer-data-[active=true]/menu-button:text-sidebar-accent-foreground',
532
+ 'peer-data-[size=sm]/menu-button:top-1',
533
+ 'peer-data-[size=default]/menu-button:top-1.5',
534
+ 'peer-data-[size=lg]/menu-button:top-2.5',
535
+ 'group-data-[collapsible=icon]:hidden',
536
+ className,
537
+ )}
538
+ {...props}
539
+ />
540
+ )
541
+ }
542
+
543
+ function SidebarMenuSkeleton({
544
+ className,
545
+ showIcon = false,
546
+ ...props
547
+ }: React.ComponentProps<'div'> & {
548
+ showIcon?: boolean
549
+ }) {
550
+ // Random width between 50 to 90%.
551
+ const width = React.useMemo(() => {
552
+ return `${Math.floor(Math.random() * 40) + 50}%`
553
+ }, [])
554
+
555
+ return (
556
+ <div data-slot="sidebar-menu-skeleton" data-sidebar="menu-skeleton" className={cn('flex h-8 items-center gap-2 rounded-md px-2', className)} {...props}>
557
+ {showIcon && <Skeleton className="size-4 rounded-md" data-sidebar="menu-skeleton-icon" />}
558
+ <Skeleton
559
+ className="h-4 max-w-(--skeleton-width) flex-1"
560
+ data-sidebar="menu-skeleton-text"
561
+ style={
562
+ {
563
+ '--skeleton-width': width,
564
+ } as React.CSSProperties
565
+ }
566
+ />
567
+ </div>
568
+ )
569
+ }
570
+
571
+ function SidebarMenuSub({ className, ...props }: React.ComponentProps<'ul'>) {
572
+ return (
573
+ <ul
574
+ data-slot="sidebar-menu-sub"
575
+ data-sidebar="menu-sub"
576
+ className={cn(
577
+ 'border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5',
578
+ 'group-data-[collapsible=icon]:hidden',
579
+ className,
580
+ )}
581
+ {...props}
582
+ />
583
+ )
584
+ }
585
+
586
+ function SidebarMenuSubItem({ className, ...props }: React.ComponentProps<'li'>) {
587
+ return <li data-slot="sidebar-menu-sub-item" data-sidebar="menu-sub-item" className={cn('group/menu-sub-item relative', className)} {...props} />
588
+ }
589
+
590
+ function SidebarMenuSubButton({
591
+ asChild = false,
592
+ size = 'md',
593
+ isActive = false,
594
+ className,
595
+ ...props
596
+ }: React.ComponentProps<'a'> & {
597
+ asChild?: boolean
598
+ size?: 'sm' | 'md'
599
+ isActive?: boolean
600
+ }) {
601
+ const Comp = asChild ? SlotPrimitive.Slot : 'a'
602
+
603
+ return (
604
+ <Comp
605
+ data-slot="sidebar-menu-sub-button"
606
+ data-sidebar="menu-sub-button"
607
+ data-size={size}
608
+ data-active={isActive}
609
+ className={cn(
610
+ 'text-sidebar-foreground',
611
+ 'ring-sidebar-ring',
612
+ 'flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden',
613
+ 'focus-visible:ring-2',
614
+ 'hover:bg-sidebar-accent',
615
+ 'hover:text-sidebar-accent-foreground',
616
+ 'active:bg-sidebar-accent',
617
+ 'active:text-sidebar-accent-foreground',
618
+ 'disabled:pointer-events-none',
619
+ 'disabled:opacity-50',
620
+ 'aria-disabled:pointer-events-none',
621
+ 'aria-disabled:opacity-50',
622
+ '[&>svg]:size-4',
623
+ '[&>svg]:shrink-0',
624
+ '[&>svg]:text-sidebar-accent-foreground',
625
+ '[&>span:last-child]:truncate',
626
+ 'data-[active=true]:bg-sidebar-accent',
627
+ 'data-[active=true]:text-sidebar-accent-foreground',
628
+ size === 'sm' && 'text-xs',
629
+ size === 'md' && 'text-sm',
630
+ 'group-data-[collapsible=icon]:hidden',
631
+ className,
632
+ )}
633
+ {...props}
634
+ />
635
+ )
636
+ }
637
+
638
+ export {
639
+ Sidebar,
640
+ SidebarContent,
641
+ SidebarFooter,
642
+ SidebarGroup,
643
+ SidebarGroupAction,
644
+ SidebarGroupContent,
645
+ SidebarGroupLabel,
646
+ SidebarHeader,
647
+ SidebarInset,
648
+ SidebarMenu,
649
+ SidebarMenuAction,
650
+ SidebarMenuBadge,
651
+ SidebarMenuButton,
652
+ SidebarMenuItem,
653
+ SidebarMenuSkeleton,
654
+ SidebarMenuSub,
655
+ SidebarMenuSubButton,
656
+ SidebarMenuSubItem,
657
+ SidebarProvider,
658
+ SidebarRail,
659
+ SidebarSeparator,
660
+ SidebarTrigger,
661
+ // eslint-disable-next-line react-refresh/only-export-components
662
+ useSidebar,
663
+ }
@@ -4,10 +4,10 @@
4
4
  @import 'tailwindcss';
5
5
  @import 'tw-animate-css';
6
6
 
7
- @import './components/styles/base.css';
8
- @import './components/styles/theme.css';
9
- @import './components/styles/loader.css';
10
- @import './components/styles/typography.css';
7
+ @import '../styles/base.css';
8
+ @import '../styles/theme.css';
9
+ @import '../styles/loader.css';
10
+ @import '../styles/typography.css';
11
11
 
12
12
  :root {
13
13
  --header-height: 3.5rem;
@@ -120,6 +120,7 @@
120
120
  /* Effects */
121
121
  --shadow-btn: var(--shadow-btn);
122
122
  --shadow-input: var(--shadow-input);
123
+ --shadow-nav: var(--shadow-nav);
123
124
  --shadow-card: var(--shadow-card);
124
125
  --shadow-dropdown: var(--shadow-dropdown);
125
126
  --shadow-dialog: var(--shadow-dialog);