@shellui/core 0.0.4
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.
- package/README.md +17 -0
- package/dist/ContentView-CZG-ro_B.js +146 -0
- package/dist/ContentView-CZG-ro_B.js.map +1 -0
- package/dist/CookiePreferencesView-MhO9FO-4.js +213 -0
- package/dist/CookiePreferencesView-MhO9FO-4.js.map +1 -0
- package/dist/DefaultLayout-Dbb3uJED.js +394 -0
- package/dist/DefaultLayout-Dbb3uJED.js.map +1 -0
- package/dist/FullscreenLayout-1SgPHWw-.js +30 -0
- package/dist/FullscreenLayout-1SgPHWw-.js.map +1 -0
- package/dist/HomeView-DYU-O_Il.js +21 -0
- package/dist/HomeView-DYU-O_Il.js.map +1 -0
- package/dist/NotFoundView-CeYjJNg0.js +52 -0
- package/dist/NotFoundView-CeYjJNg0.js.map +1 -0
- package/dist/OverlayShell-pzbqQW25.js +642 -0
- package/dist/OverlayShell-pzbqQW25.js.map +1 -0
- package/dist/SettingsView-Bndrta44.js +2207 -0
- package/dist/SettingsView-Bndrta44.js.map +1 -0
- package/dist/ViewRoute-ChSPabOy.js +32 -0
- package/dist/ViewRoute-ChSPabOy.js.map +1 -0
- package/dist/WindowsLayout-CXGNPKoY.js +633 -0
- package/dist/WindowsLayout-CXGNPKoY.js.map +1 -0
- package/dist/app.d.ts +3 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/components/ContentView.d.ts +10 -0
- package/dist/components/ContentView.d.ts.map +1 -0
- package/dist/components/HomeView.d.ts +2 -0
- package/dist/components/HomeView.d.ts.map +1 -0
- package/dist/components/LoadingOverlay.d.ts +2 -0
- package/dist/components/LoadingOverlay.d.ts.map +1 -0
- package/dist/components/NotFoundView.d.ts +2 -0
- package/dist/components/NotFoundView.d.ts.map +1 -0
- package/dist/components/RouteErrorBoundary.d.ts +2 -0
- package/dist/components/RouteErrorBoundary.d.ts.map +1 -0
- package/dist/components/ViewRoute.d.ts +7 -0
- package/dist/components/ViewRoute.d.ts.map +1 -0
- package/dist/components/ui/alert-dialog.d.ts +32 -0
- package/dist/components/ui/alert-dialog.d.ts.map +1 -0
- package/dist/components/ui/breadcrumb.d.ts +20 -0
- package/dist/components/ui/breadcrumb.d.ts.map +1 -0
- package/dist/components/ui/button-group.d.ts +7 -0
- package/dist/components/ui/button-group.d.ts.map +1 -0
- package/dist/components/ui/button.d.ts +12 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/dialog.d.ts +24 -0
- package/dist/components/ui/dialog.d.ts.map +1 -0
- package/dist/components/ui/drawer.d.ts +38 -0
- package/dist/components/ui/drawer.d.ts.map +1 -0
- package/dist/components/ui/select.d.ts +5 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/sidebar.d.ts +46 -0
- package/dist/components/ui/sidebar.d.ts.map +1 -0
- package/dist/components/ui/sonner.d.ts +6 -0
- package/dist/components/ui/sonner.d.ts.map +1 -0
- package/dist/components/ui/switch.d.ts +8 -0
- package/dist/components/ui/switch.d.ts.map +1 -0
- package/dist/constants/urls.d.ts +6 -0
- package/dist/constants/urls.d.ts.map +1 -0
- package/dist/constants/urls.js +8 -0
- package/dist/constants/urls.js.map +1 -0
- package/dist/features/alertDialog/DialogContext.d.ts +12 -0
- package/dist/features/alertDialog/DialogContext.d.ts.map +1 -0
- package/dist/features/config/ConfigProvider.d.ts +15 -0
- package/dist/features/config/ConfigProvider.d.ts.map +1 -0
- package/dist/features/config/types.d.ts +177 -0
- package/dist/features/config/types.d.ts.map +1 -0
- package/dist/features/config/useConfig.d.ts +8 -0
- package/dist/features/config/useConfig.d.ts.map +1 -0
- package/dist/features/cookieConsent/CookieConsentModal.d.ts +6 -0
- package/dist/features/cookieConsent/CookieConsentModal.d.ts.map +1 -0
- package/dist/features/cookieConsent/CookiePreferencesView.d.ts +2 -0
- package/dist/features/cookieConsent/CookiePreferencesView.d.ts.map +1 -0
- package/dist/features/cookieConsent/cookieConsent.d.ts +22 -0
- package/dist/features/cookieConsent/cookieConsent.d.ts.map +1 -0
- package/dist/features/cookieConsent/useCookieConsent.d.ts +15 -0
- package/dist/features/cookieConsent/useCookieConsent.d.ts.map +1 -0
- package/dist/features/drawer/DrawerContext.d.ts +24 -0
- package/dist/features/drawer/DrawerContext.d.ts.map +1 -0
- package/dist/features/layouts/AppLayout.d.ts +12 -0
- package/dist/features/layouts/AppLayout.d.ts.map +1 -0
- package/dist/features/layouts/DefaultLayout.d.ts +10 -0
- package/dist/features/layouts/DefaultLayout.d.ts.map +1 -0
- package/dist/features/layouts/FullscreenLayout.d.ts +9 -0
- package/dist/features/layouts/FullscreenLayout.d.ts.map +1 -0
- package/dist/features/layouts/LayoutProviders.d.ts +9 -0
- package/dist/features/layouts/LayoutProviders.d.ts.map +1 -0
- package/dist/features/layouts/OverlayShell.d.ts +10 -0
- package/dist/features/layouts/OverlayShell.d.ts.map +1 -0
- package/dist/features/layouts/WindowsLayout.d.ts +24 -0
- package/dist/features/layouts/WindowsLayout.d.ts.map +1 -0
- package/dist/features/layouts/utils.d.ts +16 -0
- package/dist/features/layouts/utils.d.ts.map +1 -0
- package/dist/features/modal/ModalContext.d.ts +20 -0
- package/dist/features/modal/ModalContext.d.ts.map +1 -0
- package/dist/features/sentry/initSentry.d.ts +14 -0
- package/dist/features/sentry/initSentry.d.ts.map +1 -0
- package/dist/features/settings/SettingsContext.d.ts +10 -0
- package/dist/features/settings/SettingsContext.d.ts.map +1 -0
- package/dist/features/settings/SettingsIcons.d.ts +22 -0
- package/dist/features/settings/SettingsIcons.d.ts.map +1 -0
- package/dist/features/settings/SettingsProvider.d.ts +5 -0
- package/dist/features/settings/SettingsProvider.d.ts.map +1 -0
- package/dist/features/settings/SettingsRoutes.d.ts +7 -0
- package/dist/features/settings/SettingsRoutes.d.ts.map +1 -0
- package/dist/features/settings/SettingsView.d.ts +2 -0
- package/dist/features/settings/SettingsView.d.ts.map +1 -0
- package/dist/features/settings/components/Advanced.d.ts +2 -0
- package/dist/features/settings/components/Advanced.d.ts.map +1 -0
- package/dist/features/settings/components/Appearance.d.ts +2 -0
- package/dist/features/settings/components/Appearance.d.ts.map +1 -0
- package/dist/features/settings/components/DataPrivacy.d.ts +2 -0
- package/dist/features/settings/components/DataPrivacy.d.ts.map +1 -0
- package/dist/features/settings/components/Develop.d.ts +2 -0
- package/dist/features/settings/components/Develop.d.ts.map +1 -0
- package/dist/features/settings/components/LanguageAndRegion.d.ts +2 -0
- package/dist/features/settings/components/LanguageAndRegion.d.ts.map +1 -0
- package/dist/features/settings/components/ServiceWorker.d.ts +2 -0
- package/dist/features/settings/components/ServiceWorker.d.ts.map +1 -0
- package/dist/features/settings/components/UpdateApp.d.ts +2 -0
- package/dist/features/settings/components/UpdateApp.d.ts.map +1 -0
- package/dist/features/settings/components/develop/DialogTestButtons.d.ts +2 -0
- package/dist/features/settings/components/develop/DialogTestButtons.d.ts.map +1 -0
- package/dist/features/settings/components/develop/DrawerTestButtons.d.ts +2 -0
- package/dist/features/settings/components/develop/DrawerTestButtons.d.ts.map +1 -0
- package/dist/features/settings/components/develop/ModalTestButtons.d.ts +2 -0
- package/dist/features/settings/components/develop/ModalTestButtons.d.ts.map +1 -0
- package/dist/features/settings/components/develop/ToastTestButtons.d.ts +2 -0
- package/dist/features/settings/components/develop/ToastTestButtons.d.ts.map +1 -0
- package/dist/features/settings/hooks/useSettings.d.ts +2 -0
- package/dist/features/settings/hooks/useSettings.d.ts.map +1 -0
- package/dist/features/sonner/SonnerContext.d.ts +29 -0
- package/dist/features/sonner/SonnerContext.d.ts.map +1 -0
- package/dist/features/theme/ThemeProvider.d.ts +11 -0
- package/dist/features/theme/ThemeProvider.d.ts.map +1 -0
- package/dist/features/theme/themes.d.ts +114 -0
- package/dist/features/theme/themes.d.ts.map +1 -0
- package/dist/features/theme/useTheme.d.ts +10 -0
- package/dist/features/theme/useTheme.d.ts.map +1 -0
- package/dist/i18n/I18nProvider.d.ts +9 -0
- package/dist/i18n/I18nProvider.d.ts.map +1 -0
- package/dist/i18n/config.d.ts +23 -0
- package/dist/i18n/config.d.ts.map +1 -0
- package/dist/i18n/translations/en/common.json.d.ts +19 -0
- package/dist/i18n/translations/en/cookieConsent.json.d.ts +53 -0
- package/dist/i18n/translations/en/settings.json.d.ts +358 -0
- package/dist/i18n/translations/fr/common.json.d.ts +19 -0
- package/dist/i18n/translations/fr/cookieConsent.json.d.ts +53 -0
- package/dist/i18n/translations/fr/settings.json.d.ts +358 -0
- package/dist/index-lmRk5L6z.js +2160 -0
- package/dist/index-lmRk5L6z.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/z-index.d.ts +29 -0
- package/dist/lib/z-index.d.ts.map +1 -0
- package/dist/router/router.d.ts +3 -0
- package/dist/router/router.d.ts.map +1 -0
- package/dist/router/routes.d.ts +4 -0
- package/dist/router/routes.d.ts.map +1 -0
- package/dist/sidebar-ClIeZ2zb.js +303 -0
- package/dist/sidebar-ClIeZ2zb.js.map +1 -0
- package/dist/style.css +1 -0
- package/dist/switch-8SzUJz7Q.js +44 -0
- package/dist/switch-8SzUJz7Q.js.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +93 -0
- package/postcss.config.js +6 -0
- package/src/app.tsx +119 -0
- package/src/components/ContentView.tsx +258 -0
- package/src/components/HomeView.tsx +19 -0
- package/src/components/LoadingOverlay.tsx +12 -0
- package/src/components/NotFoundView.tsx +84 -0
- package/src/components/RouteErrorBoundary.tsx +95 -0
- package/src/components/ViewRoute.tsx +47 -0
- package/src/components/ui/alert-dialog.tsx +181 -0
- package/src/components/ui/breadcrumb.tsx +155 -0
- package/src/components/ui/button-group.tsx +52 -0
- package/src/components/ui/button.tsx +51 -0
- package/src/components/ui/dialog.tsx +160 -0
- package/src/components/ui/drawer.tsx +200 -0
- package/src/components/ui/select.tsx +24 -0
- package/src/components/ui/sidebar.tsx +406 -0
- package/src/components/ui/sonner.tsx +36 -0
- package/src/components/ui/switch.tsx +45 -0
- package/src/constants/urls.ts +4 -0
- package/src/features/alertDialog/DialogContext.tsx +468 -0
- package/src/features/config/ConfigProvider.ts +96 -0
- package/src/features/config/types.ts +195 -0
- package/src/features/config/useConfig.ts +15 -0
- package/src/features/cookieConsent/CookieConsentModal.tsx +122 -0
- package/src/features/cookieConsent/CookiePreferencesView.tsx +328 -0
- package/src/features/cookieConsent/cookieConsent.ts +84 -0
- package/src/features/cookieConsent/useCookieConsent.ts +39 -0
- package/src/features/drawer/DrawerContext.tsx +116 -0
- package/src/features/layouts/AppLayout.tsx +63 -0
- package/src/features/layouts/DefaultLayout.tsx +625 -0
- package/src/features/layouts/FullscreenLayout.tsx +55 -0
- package/src/features/layouts/LayoutProviders.tsx +20 -0
- package/src/features/layouts/OverlayShell.tsx +171 -0
- package/src/features/layouts/WindowsLayout.tsx +860 -0
- package/src/features/layouts/utils.ts +99 -0
- package/src/features/modal/ModalContext.tsx +112 -0
- package/src/features/sentry/initSentry.ts +72 -0
- package/src/features/settings/SettingsContext.tsx +19 -0
- package/src/features/settings/SettingsIcons.tsx +452 -0
- package/src/features/settings/SettingsProvider.tsx +341 -0
- package/src/features/settings/SettingsRoutes.tsx +66 -0
- package/src/features/settings/SettingsView.tsx +327 -0
- package/src/features/settings/components/Advanced.tsx +128 -0
- package/src/features/settings/components/Appearance.tsx +306 -0
- package/src/features/settings/components/DataPrivacy.tsx +142 -0
- package/src/features/settings/components/Develop.tsx +174 -0
- package/src/features/settings/components/LanguageAndRegion.tsx +329 -0
- package/src/features/settings/components/ServiceWorker.tsx +363 -0
- package/src/features/settings/components/UpdateApp.tsx +206 -0
- package/src/features/settings/components/develop/DialogTestButtons.tsx +137 -0
- package/src/features/settings/components/develop/DrawerTestButtons.tsx +67 -0
- package/src/features/settings/components/develop/ModalTestButtons.tsx +30 -0
- package/src/features/settings/components/develop/ToastTestButtons.tsx +179 -0
- package/src/features/settings/hooks/useSettings.tsx +10 -0
- package/src/features/sonner/SonnerContext.tsx +286 -0
- package/src/features/theme/ThemeProvider.tsx +16 -0
- package/src/features/theme/themes.ts +561 -0
- package/src/features/theme/useTheme.tsx +71 -0
- package/src/i18n/I18nProvider.tsx +32 -0
- package/src/i18n/config.ts +107 -0
- package/src/i18n/translations/en/common.json +16 -0
- package/src/i18n/translations/en/cookieConsent.json +50 -0
- package/src/i18n/translations/en/settings.json +355 -0
- package/src/i18n/translations/fr/common.json +16 -0
- package/src/i18n/translations/fr/cookieConsent.json +50 -0
- package/src/i18n/translations/fr/settings.json +355 -0
- package/src/index.css +412 -0
- package/src/index.html +100 -0
- package/src/index.ts +31 -0
- package/src/lib/utils.ts +6 -0
- package/src/lib/z-index.ts +29 -0
- package/src/main.tsx +26 -0
- package/src/router/router.tsx +8 -0
- package/src/router/routes.tsx +115 -0
- package/src/service-worker/register.ts +1199 -0
- package/src/service-worker/sw-dev.ts +87 -0
- package/src/service-worker/sw.ts +105 -0
- package/tailwind.config.js +60 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
forwardRef,
|
|
5
|
+
type ComponentProps,
|
|
6
|
+
type ComponentPropsWithoutRef,
|
|
7
|
+
type ComponentRef,
|
|
8
|
+
type ReactNode,
|
|
9
|
+
type CSSProperties,
|
|
10
|
+
type HTMLAttributes,
|
|
11
|
+
} from 'react';
|
|
12
|
+
import { Drawer as VaulDrawer } from 'vaul';
|
|
13
|
+
import { cn } from '@/lib/utils';
|
|
14
|
+
import { Z_INDEX } from '@/lib/z-index';
|
|
15
|
+
|
|
16
|
+
export type DrawerDirection = 'top' | 'bottom' | 'left' | 'right';
|
|
17
|
+
|
|
18
|
+
const Drawer = ({
|
|
19
|
+
open,
|
|
20
|
+
onOpenChange,
|
|
21
|
+
direction = 'right',
|
|
22
|
+
...props
|
|
23
|
+
}: ComponentProps<typeof VaulDrawer.Root> & {
|
|
24
|
+
direction?: DrawerDirection;
|
|
25
|
+
}) => (
|
|
26
|
+
<VaulDrawer.Root
|
|
27
|
+
open={open}
|
|
28
|
+
onOpenChange={onOpenChange}
|
|
29
|
+
direction={direction}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
Drawer.displayName = 'Drawer';
|
|
34
|
+
|
|
35
|
+
const DrawerTrigger = VaulDrawer.Trigger;
|
|
36
|
+
DrawerTrigger.displayName = 'DrawerTrigger';
|
|
37
|
+
|
|
38
|
+
const DrawerPortal = VaulDrawer.Portal;
|
|
39
|
+
(DrawerPortal as unknown as { displayName: string }).displayName = 'DrawerPortal';
|
|
40
|
+
|
|
41
|
+
const DrawerOverlay = forwardRef<
|
|
42
|
+
ComponentRef<typeof VaulDrawer.Overlay>,
|
|
43
|
+
ComponentPropsWithoutRef<typeof VaulDrawer.Overlay>
|
|
44
|
+
>(({ className, ...props }, ref) => (
|
|
45
|
+
<VaulDrawer.Overlay
|
|
46
|
+
ref={ref}
|
|
47
|
+
data-drawer-overlay
|
|
48
|
+
className={cn('fixed inset-0 bg-[hsl(var(--background)/0.8)] backdrop-blur-[1px]', className)}
|
|
49
|
+
style={{ zIndex: Z_INDEX.DRAWER_OVERLAY }}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
));
|
|
53
|
+
DrawerOverlay.displayName = VaulDrawer.Overlay.displayName;
|
|
54
|
+
|
|
55
|
+
/** Base layout classes per direction — max dimension is applied via style so size prop can override. */
|
|
56
|
+
const drawerContentByDirection: Record<DrawerDirection, string> = {
|
|
57
|
+
bottom: 'fixed inset-x-0 bottom-0 mt-24 flex h-auto flex-col border border-border bg-background',
|
|
58
|
+
top: 'fixed inset-x-0 top-0 mb-24 flex h-auto flex-col border border-border bg-background',
|
|
59
|
+
left: 'fixed inset-y-0 left-0 mr-24 flex h-full w-auto flex-col border border-border bg-background',
|
|
60
|
+
right:
|
|
61
|
+
'fixed inset-y-0 right-0 ml-24 flex h-full w-auto flex-col border border-border bg-background',
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
interface DrawerContentProps extends Omit<
|
|
65
|
+
ComponentPropsWithoutRef<typeof VaulDrawer.Content>,
|
|
66
|
+
'direction'
|
|
67
|
+
> {
|
|
68
|
+
direction?: DrawerDirection;
|
|
69
|
+
/** CSS length: height for top/bottom (e.g. "80vh", "400px"), width for left/right (e.g. "50vw", "320px") */
|
|
70
|
+
size?: string | null;
|
|
71
|
+
className?: string;
|
|
72
|
+
children?: ReactNode;
|
|
73
|
+
style?: CSSProperties;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const DrawerContent = forwardRef<ComponentRef<typeof VaulDrawer.Content>, DrawerContentProps>(
|
|
77
|
+
({ className, direction = 'right', size, children, style, ...props }, ref) => {
|
|
78
|
+
const pos: DrawerDirection = direction;
|
|
79
|
+
const isVertical = pos === 'top' || pos === 'bottom';
|
|
80
|
+
// Set dimension via inline style; use both width/height and max so Vaul/defaults don't override.
|
|
81
|
+
const effectiveSize = size?.trim() || (isVertical ? '80vh' : '80vw');
|
|
82
|
+
const sizeStyle = isVertical
|
|
83
|
+
? { height: effectiveSize, maxHeight: effectiveSize }
|
|
84
|
+
: { width: effectiveSize, maxWidth: effectiveSize };
|
|
85
|
+
return (
|
|
86
|
+
<DrawerPortal>
|
|
87
|
+
<DrawerOverlay />
|
|
88
|
+
<VaulDrawer.Content
|
|
89
|
+
ref={ref}
|
|
90
|
+
data-drawer-content
|
|
91
|
+
className={cn('outline-none', drawerContentByDirection[pos], className)}
|
|
92
|
+
style={{
|
|
93
|
+
backgroundColor: 'hsl(var(--background))',
|
|
94
|
+
zIndex: Z_INDEX.DRAWER_CONTENT,
|
|
95
|
+
...sizeStyle,
|
|
96
|
+
...style,
|
|
97
|
+
}}
|
|
98
|
+
{...props}
|
|
99
|
+
>
|
|
100
|
+
{children}
|
|
101
|
+
<VaulDrawer.Close
|
|
102
|
+
className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground cursor-pointer"
|
|
103
|
+
aria-label="Close"
|
|
104
|
+
>
|
|
105
|
+
<svg
|
|
106
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
107
|
+
width="24"
|
|
108
|
+
height="24"
|
|
109
|
+
viewBox="0 0 24 24"
|
|
110
|
+
fill="none"
|
|
111
|
+
stroke="currentColor"
|
|
112
|
+
strokeWidth="2"
|
|
113
|
+
strokeLinecap="round"
|
|
114
|
+
strokeLinejoin="round"
|
|
115
|
+
className="h-4 w-4"
|
|
116
|
+
>
|
|
117
|
+
<path d="M18 6 6 18" />
|
|
118
|
+
<path d="m6 6 12 12" />
|
|
119
|
+
</svg>
|
|
120
|
+
<span className="sr-only">Close</span>
|
|
121
|
+
</VaulDrawer.Close>
|
|
122
|
+
</VaulDrawer.Content>
|
|
123
|
+
</DrawerPortal>
|
|
124
|
+
);
|
|
125
|
+
},
|
|
126
|
+
);
|
|
127
|
+
DrawerContent.displayName = 'DrawerContent';
|
|
128
|
+
|
|
129
|
+
const DrawerClose = VaulDrawer.Close;
|
|
130
|
+
DrawerClose.displayName = 'DrawerClose';
|
|
131
|
+
|
|
132
|
+
const DrawerHeader = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (
|
|
133
|
+
<div
|
|
134
|
+
data-drawer-header
|
|
135
|
+
className={cn(
|
|
136
|
+
'flex flex-col space-y-2 border-b border-border/60 px-6 pt-5 pb-4 text-left',
|
|
137
|
+
className,
|
|
138
|
+
)}
|
|
139
|
+
{...props}
|
|
140
|
+
/>
|
|
141
|
+
);
|
|
142
|
+
DrawerHeader.displayName = 'DrawerHeader';
|
|
143
|
+
|
|
144
|
+
const DrawerFooter = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (
|
|
145
|
+
<div
|
|
146
|
+
className={cn(
|
|
147
|
+
'mt-auto flex flex-col-reverse gap-2 border-t border-border px-6 py-4 sm:flex-row sm:justify-end',
|
|
148
|
+
className,
|
|
149
|
+
)}
|
|
150
|
+
{...props}
|
|
151
|
+
/>
|
|
152
|
+
);
|
|
153
|
+
DrawerFooter.displayName = 'DrawerFooter';
|
|
154
|
+
|
|
155
|
+
const DrawerTitle = forwardRef<
|
|
156
|
+
ComponentRef<typeof VaulDrawer.Title>,
|
|
157
|
+
ComponentPropsWithoutRef<typeof VaulDrawer.Title>
|
|
158
|
+
>(({ className, ...props }, ref) => (
|
|
159
|
+
<VaulDrawer.Title
|
|
160
|
+
ref={ref}
|
|
161
|
+
className={cn('text-lg font-semibold leading-none tracking-tight', className)}
|
|
162
|
+
{...props}
|
|
163
|
+
/>
|
|
164
|
+
));
|
|
165
|
+
DrawerTitle.displayName = VaulDrawer.Title.displayName;
|
|
166
|
+
|
|
167
|
+
const DrawerDescription = forwardRef<
|
|
168
|
+
ComponentRef<typeof VaulDrawer.Description>,
|
|
169
|
+
ComponentPropsWithoutRef<typeof VaulDrawer.Description>
|
|
170
|
+
>(({ className, ...props }, ref) => (
|
|
171
|
+
<VaulDrawer.Description
|
|
172
|
+
ref={ref}
|
|
173
|
+
className={cn('text-sm text-muted-foreground', className)}
|
|
174
|
+
{...props}
|
|
175
|
+
/>
|
|
176
|
+
));
|
|
177
|
+
DrawerDescription.displayName = VaulDrawer.Description.displayName;
|
|
178
|
+
|
|
179
|
+
const DrawerHandle = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (
|
|
180
|
+
<div
|
|
181
|
+
data-drawer-handle
|
|
182
|
+
className={cn('mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted', className)}
|
|
183
|
+
{...props}
|
|
184
|
+
/>
|
|
185
|
+
);
|
|
186
|
+
DrawerHandle.displayName = 'DrawerHandle';
|
|
187
|
+
|
|
188
|
+
export {
|
|
189
|
+
Drawer,
|
|
190
|
+
DrawerTrigger,
|
|
191
|
+
DrawerPortal,
|
|
192
|
+
DrawerOverlay,
|
|
193
|
+
DrawerContent,
|
|
194
|
+
DrawerClose,
|
|
195
|
+
DrawerHeader,
|
|
196
|
+
DrawerFooter,
|
|
197
|
+
DrawerTitle,
|
|
198
|
+
DrawerDescription,
|
|
199
|
+
DrawerHandle,
|
|
200
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { forwardRef, type SelectHTMLAttributes } from 'react';
|
|
2
|
+
import { cn } from '@/lib/utils';
|
|
3
|
+
|
|
4
|
+
export type SelectProps = SelectHTMLAttributes<HTMLSelectElement>;
|
|
5
|
+
|
|
6
|
+
const Select = forwardRef<HTMLSelectElement, SelectProps>(
|
|
7
|
+
({ className, children, ...props }, ref) => {
|
|
8
|
+
return (
|
|
9
|
+
<select
|
|
10
|
+
className={cn(
|
|
11
|
+
'select-field flex h-10 w-full rounded-md border border-input bg-background pl-3 pr-10 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50',
|
|
12
|
+
className,
|
|
13
|
+
)}
|
|
14
|
+
ref={ref}
|
|
15
|
+
{...props}
|
|
16
|
+
>
|
|
17
|
+
{children}
|
|
18
|
+
</select>
|
|
19
|
+
);
|
|
20
|
+
},
|
|
21
|
+
);
|
|
22
|
+
Select.displayName = 'Select';
|
|
23
|
+
|
|
24
|
+
export { Select };
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
useState,
|
|
5
|
+
useCallback,
|
|
6
|
+
forwardRef,
|
|
7
|
+
type ReactNode,
|
|
8
|
+
type HTMLAttributes,
|
|
9
|
+
type ButtonHTMLAttributes,
|
|
10
|
+
type AnchorHTMLAttributes,
|
|
11
|
+
} from 'react';
|
|
12
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
13
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
14
|
+
import { cn } from '@/lib/utils';
|
|
15
|
+
import { Z_INDEX } from '@/lib/z-index';
|
|
16
|
+
|
|
17
|
+
type SidebarContextValue = {
|
|
18
|
+
isCollapsed: boolean;
|
|
19
|
+
toggle: () => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const SidebarContext = createContext<SidebarContextValue | undefined>(undefined);
|
|
23
|
+
|
|
24
|
+
const useSidebar = () => {
|
|
25
|
+
const context = useContext(SidebarContext);
|
|
26
|
+
if (!context) {
|
|
27
|
+
throw new Error('useSidebar must be used within a SidebarProvider');
|
|
28
|
+
}
|
|
29
|
+
return context;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const SidebarProvider = ({ children }: { children: ReactNode }) => {
|
|
33
|
+
const [isCollapsed, setIsCollapsed] = useState(false);
|
|
34
|
+
|
|
35
|
+
const toggle = useCallback(() => {
|
|
36
|
+
setIsCollapsed((prev) => !prev);
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<SidebarContext.Provider value={{ isCollapsed, toggle }}>{children}</SidebarContext.Provider>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const Sidebar = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
45
|
+
({ className, ...props }, ref) => {
|
|
46
|
+
const { isCollapsed } = useSidebar();
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div
|
|
50
|
+
ref={ref}
|
|
51
|
+
data-sidebar="sidebar"
|
|
52
|
+
data-collapsed={isCollapsed}
|
|
53
|
+
className={cn(
|
|
54
|
+
'flex h-full flex-col gap-2 border-r bg-sidebar-background p-2 text-sidebar-foreground transition-all duration-300 ease-in-out overflow-hidden',
|
|
55
|
+
isCollapsed ? 'w-0 border-r-0 p-0' : 'w-64',
|
|
56
|
+
className,
|
|
57
|
+
)}
|
|
58
|
+
{...props}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
Sidebar.displayName = 'Sidebar';
|
|
64
|
+
|
|
65
|
+
const SidebarTrigger = forwardRef<HTMLButtonElement, ButtonHTMLAttributes<HTMLButtonElement>>(
|
|
66
|
+
({ className, ...props }, ref) => {
|
|
67
|
+
const { toggle, isCollapsed } = useSidebar();
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<button
|
|
71
|
+
ref={ref}
|
|
72
|
+
onClick={toggle}
|
|
73
|
+
className={cn(
|
|
74
|
+
'relative flex items-center justify-center rounded-md p-2 text-foreground transition-colors hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring shadow-lg backdrop-blur-md cursor-pointer bg-background/95 border border-border',
|
|
75
|
+
className,
|
|
76
|
+
)}
|
|
77
|
+
aria-label={isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
|
|
78
|
+
style={{ zIndex: Z_INDEX.SIDEBAR_TRIGGER }}
|
|
79
|
+
{...props}
|
|
80
|
+
>
|
|
81
|
+
<img
|
|
82
|
+
src={isCollapsed ? '/icons/panel-left.svg' : '/icons/panel-left-closed.svg'}
|
|
83
|
+
alt=""
|
|
84
|
+
className="h-5 w-5 transition-transform duration-300"
|
|
85
|
+
/>
|
|
86
|
+
</button>
|
|
87
|
+
);
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
SidebarTrigger.displayName = 'SidebarTrigger';
|
|
91
|
+
|
|
92
|
+
const SidebarHeader = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
93
|
+
({ className, ...props }, ref) => {
|
|
94
|
+
return (
|
|
95
|
+
<div
|
|
96
|
+
ref={ref}
|
|
97
|
+
className={cn('flex flex-col gap-2 p-2', className)}
|
|
98
|
+
{...props}
|
|
99
|
+
/>
|
|
100
|
+
);
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
SidebarHeader.displayName = 'SidebarHeader';
|
|
104
|
+
|
|
105
|
+
const SidebarContent = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
106
|
+
({ className, ...props }, ref) => {
|
|
107
|
+
return (
|
|
108
|
+
<div
|
|
109
|
+
ref={ref}
|
|
110
|
+
className={cn('flex flex-1 flex-col gap-2 overflow-auto', className)}
|
|
111
|
+
{...props}
|
|
112
|
+
/>
|
|
113
|
+
);
|
|
114
|
+
},
|
|
115
|
+
);
|
|
116
|
+
SidebarContent.displayName = 'SidebarContent';
|
|
117
|
+
|
|
118
|
+
const SidebarFooter = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
119
|
+
({ className, ...props }, ref) => {
|
|
120
|
+
return (
|
|
121
|
+
<div
|
|
122
|
+
ref={ref}
|
|
123
|
+
className={cn('flex flex-col gap-2 p-2', className)}
|
|
124
|
+
{...props}
|
|
125
|
+
/>
|
|
126
|
+
);
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
SidebarFooter.displayName = 'SidebarFooter';
|
|
130
|
+
|
|
131
|
+
const SidebarGroup = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
132
|
+
({ className, ...props }, ref) => {
|
|
133
|
+
return (
|
|
134
|
+
<div
|
|
135
|
+
ref={ref}
|
|
136
|
+
className={cn('group/sidebar-group', className)}
|
|
137
|
+
{...props}
|
|
138
|
+
/>
|
|
139
|
+
);
|
|
140
|
+
},
|
|
141
|
+
);
|
|
142
|
+
SidebarGroup.displayName = 'SidebarGroup';
|
|
143
|
+
|
|
144
|
+
const SidebarGroupLabel = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
145
|
+
({ className, ...props }, ref) => {
|
|
146
|
+
return (
|
|
147
|
+
<div
|
|
148
|
+
ref={ref}
|
|
149
|
+
className={cn(
|
|
150
|
+
'flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opa] ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
|
|
151
|
+
className,
|
|
152
|
+
)}
|
|
153
|
+
style={{ fontFamily: 'var(--heading-font-family, inherit)' }}
|
|
154
|
+
{...props}
|
|
155
|
+
/>
|
|
156
|
+
);
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
SidebarGroupLabel.displayName = 'SidebarGroupLabel';
|
|
160
|
+
|
|
161
|
+
const SidebarGroupAction = forwardRef<
|
|
162
|
+
HTMLButtonElement,
|
|
163
|
+
ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
164
|
+
asChild?: boolean;
|
|
165
|
+
}
|
|
166
|
+
>(({ className, asChild = false, ...props }, ref) => {
|
|
167
|
+
const Comp = asChild ? Slot : 'button';
|
|
168
|
+
return (
|
|
169
|
+
<Comp
|
|
170
|
+
ref={ref}
|
|
171
|
+
className={cn(
|
|
172
|
+
'absolute right-2 top-1/2 -translate-y-1/2 rounded-md p-1.5 text-sidebar-foreground outline-none ring-sidebar-ring transition-opacity hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:opacity-100 focus-visible:ring-2 group-hover/sidebar-group:opacity-100 peer-data-[size=sm]/sidebar-group-action:opacity-0 [&>svg]:size-4 [&>svg]:shrink-0',
|
|
173
|
+
className,
|
|
174
|
+
)}
|
|
175
|
+
{...props}
|
|
176
|
+
/>
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
SidebarGroupAction.displayName = 'SidebarGroupAction';
|
|
180
|
+
|
|
181
|
+
const SidebarGroupContent = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
182
|
+
({ className, ...props }, ref) => {
|
|
183
|
+
return (
|
|
184
|
+
<div
|
|
185
|
+
ref={ref}
|
|
186
|
+
className={cn('w-full text-sm', className)}
|
|
187
|
+
{...props}
|
|
188
|
+
/>
|
|
189
|
+
);
|
|
190
|
+
},
|
|
191
|
+
);
|
|
192
|
+
SidebarGroupContent.displayName = 'SidebarGroupContent';
|
|
193
|
+
|
|
194
|
+
const sidebarMenuButtonVariants = cva(
|
|
195
|
+
'flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:bg-sidebar-accent focus-visible:text-sidebar-accent-foreground focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground',
|
|
196
|
+
{
|
|
197
|
+
variants: {
|
|
198
|
+
variant: {
|
|
199
|
+
default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
|
|
200
|
+
outline:
|
|
201
|
+
'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-ring))]',
|
|
202
|
+
},
|
|
203
|
+
size: {
|
|
204
|
+
default: 'h-8 text-sm',
|
|
205
|
+
sm: 'h-7 text-xs',
|
|
206
|
+
lg: 'h-12 text-base',
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
defaultVariants: {
|
|
210
|
+
variant: 'default',
|
|
211
|
+
size: 'default',
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
const SidebarMenuButton = forwardRef<
|
|
217
|
+
HTMLButtonElement,
|
|
218
|
+
ButtonHTMLAttributes<HTMLButtonElement> &
|
|
219
|
+
VariantProps<typeof sidebarMenuButtonVariants> & {
|
|
220
|
+
asChild?: boolean;
|
|
221
|
+
isActive?: boolean;
|
|
222
|
+
}
|
|
223
|
+
>(({ className, variant, size, asChild = false, isActive, children, ...props }, ref) => {
|
|
224
|
+
const { isCollapsed } = useSidebar();
|
|
225
|
+
const Comp = asChild ? Slot : 'button';
|
|
226
|
+
|
|
227
|
+
return (
|
|
228
|
+
<Comp
|
|
229
|
+
ref={ref}
|
|
230
|
+
data-active={isActive}
|
|
231
|
+
data-collapsed={isCollapsed}
|
|
232
|
+
className={cn(
|
|
233
|
+
sidebarMenuButtonVariants({ variant, size }),
|
|
234
|
+
isCollapsed && 'justify-center',
|
|
235
|
+
className,
|
|
236
|
+
)}
|
|
237
|
+
{...props}
|
|
238
|
+
>
|
|
239
|
+
{children}
|
|
240
|
+
</Comp>
|
|
241
|
+
);
|
|
242
|
+
});
|
|
243
|
+
SidebarMenuButton.displayName = 'SidebarMenuButton';
|
|
244
|
+
|
|
245
|
+
const SidebarMenu = forwardRef<HTMLUListElement, HTMLAttributes<HTMLUListElement>>(
|
|
246
|
+
({ className, ...props }, ref) => {
|
|
247
|
+
return (
|
|
248
|
+
<ul
|
|
249
|
+
ref={ref}
|
|
250
|
+
className={cn('flex w-full min-w-0 flex-col gap-1', className)}
|
|
251
|
+
{...props}
|
|
252
|
+
/>
|
|
253
|
+
);
|
|
254
|
+
},
|
|
255
|
+
);
|
|
256
|
+
SidebarMenu.displayName = 'SidebarMenu';
|
|
257
|
+
|
|
258
|
+
const SidebarMenuItem = forwardRef<HTMLLIElement, HTMLAttributes<HTMLLIElement>>(
|
|
259
|
+
({ className, ...props }, ref) => {
|
|
260
|
+
return (
|
|
261
|
+
<li
|
|
262
|
+
ref={ref}
|
|
263
|
+
className={cn('group/menu-item relative', className)}
|
|
264
|
+
{...props}
|
|
265
|
+
/>
|
|
266
|
+
);
|
|
267
|
+
},
|
|
268
|
+
);
|
|
269
|
+
SidebarMenuItem.displayName = 'SidebarMenuItem';
|
|
270
|
+
|
|
271
|
+
const SidebarMenuAction = forwardRef<
|
|
272
|
+
HTMLButtonElement,
|
|
273
|
+
ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
274
|
+
asChild?: boolean;
|
|
275
|
+
}
|
|
276
|
+
>(({ className, asChild = false, ...props }, ref) => {
|
|
277
|
+
const Comp = asChild ? Slot : 'button';
|
|
278
|
+
return (
|
|
279
|
+
<Comp
|
|
280
|
+
ref={ref}
|
|
281
|
+
className={cn(
|
|
282
|
+
'absolute right-2 top-1/2 flex -translate-y-1/2 items-center justify-center rounded-md p-1 text-sidebar-foreground opacity-0 transition-opacity group-hover/menu-item:opacity-100 group-focus/menu-item:opacity-100 [&:has(~:hover)]:opacity-100 [&:has(~:focus)]:opacity-100',
|
|
283
|
+
className,
|
|
284
|
+
)}
|
|
285
|
+
{...props}
|
|
286
|
+
/>
|
|
287
|
+
);
|
|
288
|
+
});
|
|
289
|
+
SidebarMenuAction.displayName = 'SidebarMenuAction';
|
|
290
|
+
|
|
291
|
+
const SidebarMenuBadge = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
292
|
+
({ className, ...props }, ref) => {
|
|
293
|
+
return (
|
|
294
|
+
<div
|
|
295
|
+
ref={ref}
|
|
296
|
+
className={cn(
|
|
297
|
+
'absolute right-2 top-1/2 flex -translate-y-1/2 items-center justify-center rounded-md px-1.5 py-0.5 text-xs font-medium tabular-nums text-sidebar-foreground',
|
|
298
|
+
className,
|
|
299
|
+
)}
|
|
300
|
+
{...props}
|
|
301
|
+
/>
|
|
302
|
+
);
|
|
303
|
+
},
|
|
304
|
+
);
|
|
305
|
+
SidebarMenuBadge.displayName = 'SidebarMenuBadge';
|
|
306
|
+
|
|
307
|
+
const SidebarMenuSkeleton = forwardRef<
|
|
308
|
+
HTMLDivElement,
|
|
309
|
+
HTMLAttributes<HTMLDivElement> & {
|
|
310
|
+
showIcon?: boolean;
|
|
311
|
+
}
|
|
312
|
+
>(({ className, showIcon = false, ...props }, ref) => {
|
|
313
|
+
return (
|
|
314
|
+
<div
|
|
315
|
+
ref={ref}
|
|
316
|
+
className={cn('flex items-center gap-2 px-2 py-1.5', className)}
|
|
317
|
+
{...props}
|
|
318
|
+
>
|
|
319
|
+
{showIcon && <div className="flex h-4 w-4 rounded-md bg-sidebar-primary/10" />}
|
|
320
|
+
<div className="flex flex-1 flex-col gap-1.5">
|
|
321
|
+
<div className="h-2.5 w-16 rounded-md bg-sidebar-primary/10" />
|
|
322
|
+
<div className="h-2.5 w-24 rounded-md bg-sidebar-primary/10" />
|
|
323
|
+
</div>
|
|
324
|
+
</div>
|
|
325
|
+
);
|
|
326
|
+
});
|
|
327
|
+
SidebarMenuSkeleton.displayName = 'SidebarMenuSkeleton';
|
|
328
|
+
|
|
329
|
+
const SidebarMenuSub = forwardRef<HTMLUListElement, HTMLAttributes<HTMLUListElement>>(
|
|
330
|
+
({ className, ...props }, ref) => {
|
|
331
|
+
return (
|
|
332
|
+
<ul
|
|
333
|
+
ref={ref}
|
|
334
|
+
className={cn(
|
|
335
|
+
'ml-4 mt-1 flex min-w-0 flex-col gap-0.5 border-l border-sidebar-border pl-2.5',
|
|
336
|
+
className,
|
|
337
|
+
)}
|
|
338
|
+
{...props}
|
|
339
|
+
/>
|
|
340
|
+
);
|
|
341
|
+
},
|
|
342
|
+
);
|
|
343
|
+
SidebarMenuSub.displayName = 'SidebarMenuSub';
|
|
344
|
+
|
|
345
|
+
const SidebarMenuSubButton = forwardRef<
|
|
346
|
+
HTMLAnchorElement,
|
|
347
|
+
AnchorHTMLAttributes<HTMLAnchorElement> & {
|
|
348
|
+
asChild?: boolean;
|
|
349
|
+
size?: 'sm' | 'md' | 'lg';
|
|
350
|
+
isActive?: boolean;
|
|
351
|
+
}
|
|
352
|
+
>(({ className, asChild = false, size = 'md', isActive, ...props }, ref) => {
|
|
353
|
+
const Comp = asChild ? Slot : 'a';
|
|
354
|
+
return (
|
|
355
|
+
<Comp
|
|
356
|
+
ref={ref}
|
|
357
|
+
data-size={size}
|
|
358
|
+
data-active={isActive}
|
|
359
|
+
className={cn(
|
|
360
|
+
'flex min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md p-2 text-sidebar-foreground outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
|
|
361
|
+
size === 'sm' && 'text-xs',
|
|
362
|
+
size === 'md' && 'text-sm',
|
|
363
|
+
size === 'lg' && 'text-base',
|
|
364
|
+
className,
|
|
365
|
+
)}
|
|
366
|
+
{...props}
|
|
367
|
+
/>
|
|
368
|
+
);
|
|
369
|
+
});
|
|
370
|
+
SidebarMenuSubButton.displayName = 'SidebarMenuSubButton';
|
|
371
|
+
|
|
372
|
+
const SidebarMenuSubItem = forwardRef<HTMLLIElement, HTMLAttributes<HTMLLIElement>>(
|
|
373
|
+
({ className, ...props }, ref) => {
|
|
374
|
+
return (
|
|
375
|
+
<li
|
|
376
|
+
ref={ref}
|
|
377
|
+
className={cn('group/menu-sub-item relative', className)}
|
|
378
|
+
{...props}
|
|
379
|
+
/>
|
|
380
|
+
);
|
|
381
|
+
},
|
|
382
|
+
);
|
|
383
|
+
SidebarMenuSubItem.displayName = 'SidebarMenuSubItem';
|
|
384
|
+
|
|
385
|
+
export {
|
|
386
|
+
Sidebar,
|
|
387
|
+
SidebarProvider,
|
|
388
|
+
SidebarTrigger,
|
|
389
|
+
SidebarHeader,
|
|
390
|
+
SidebarContent,
|
|
391
|
+
SidebarFooter,
|
|
392
|
+
SidebarGroup,
|
|
393
|
+
SidebarGroupLabel,
|
|
394
|
+
SidebarGroupAction,
|
|
395
|
+
SidebarGroupContent,
|
|
396
|
+
SidebarMenu,
|
|
397
|
+
SidebarMenuButton,
|
|
398
|
+
SidebarMenuItem,
|
|
399
|
+
SidebarMenuAction,
|
|
400
|
+
SidebarMenuBadge,
|
|
401
|
+
SidebarMenuSkeleton,
|
|
402
|
+
SidebarMenuSub,
|
|
403
|
+
SidebarMenuSubButton,
|
|
404
|
+
SidebarMenuSubItem,
|
|
405
|
+
useSidebar,
|
|
406
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ComponentProps } from 'react';
|
|
2
|
+
import { useSettings } from '@/features/settings/hooks/useSettings';
|
|
3
|
+
import { Toaster as Sonner } from 'sonner';
|
|
4
|
+
import { Z_INDEX } from '@/lib/z-index';
|
|
5
|
+
|
|
6
|
+
type ToasterProps = ComponentProps<typeof Sonner>;
|
|
7
|
+
|
|
8
|
+
const Toaster = ({ ...props }: ToasterProps) => {
|
|
9
|
+
const { settings } = useSettings();
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<Sonner
|
|
13
|
+
position="top-center"
|
|
14
|
+
theme={settings.appearance.theme as 'light' | 'dark' | 'system'}
|
|
15
|
+
className="toaster group"
|
|
16
|
+
style={{
|
|
17
|
+
zIndex: Z_INDEX.TOAST,
|
|
18
|
+
// Re-enable pointer events so toasts stay clickable when a Radix modal is open
|
|
19
|
+
// (Radix sets body.style.pointerEvents = 'none' and only the dialog content gets 'auto')
|
|
20
|
+
pointerEvents: 'auto',
|
|
21
|
+
}}
|
|
22
|
+
toastOptions={{
|
|
23
|
+
classNames: {
|
|
24
|
+
toast:
|
|
25
|
+
'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
|
|
26
|
+
description: 'group-[.toast]:text-muted-foreground',
|
|
27
|
+
actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
|
|
28
|
+
cancelButton: 'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground',
|
|
29
|
+
},
|
|
30
|
+
}}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export { Toaster };
|