@fayz-ai/ui 0.9.0 → 0.10.1
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 +2 -2
- package/dist/analytics/AnalyticsCard.d.ts +10 -0
- package/dist/analytics/AnalyticsCard.d.ts.map +1 -0
- package/dist/analytics/AnalyticsControls.d.ts +18 -0
- package/dist/analytics/AnalyticsControls.d.ts.map +1 -0
- package/dist/analytics/AnalyticsGrid.d.ts +16 -0
- package/dist/analytics/AnalyticsGrid.d.ts.map +1 -0
- package/dist/analytics/context.d.ts +58 -0
- package/dist/analytics/context.d.ts.map +1 -0
- package/dist/analytics/derive.d.ts +81 -0
- package/dist/analytics/derive.d.ts.map +1 -0
- package/dist/analytics/index.d.ts +13 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/range.d.ts +22 -0
- package/dist/analytics/range.d.ts.map +1 -0
- package/dist/{chunk-PVIB724L.js → chunk-22EVFMS3.js} +5 -3
- package/dist/chunk-22EVFMS3.js.map +1 -0
- package/dist/{chunk-G6OKZ7WL.js → chunk-6V5MGYXH.js} +13 -9
- package/dist/chunk-6V5MGYXH.js.map +1 -0
- package/dist/{chunk-KV3MHB6N.js → chunk-H63TOSQ7.js} +196 -53
- package/dist/chunk-H63TOSQ7.js.map +1 -0
- package/dist/{chunk-OUPJDGKE.js → chunk-I6CPKAOD.js} +134 -37
- package/dist/chunk-I6CPKAOD.js.map +1 -0
- package/dist/{chunk-YRVE4FOD.js → chunk-OKZ6WQB3.js} +3 -3
- package/dist/chunk-OKZ6WQB3.js.map +1 -0
- package/dist/{chunk-S5KNM4D2.js → chunk-SEIY2F5F.js} +235 -107
- package/dist/chunk-SEIY2F5F.js.map +1 -0
- package/dist/{chunk-75EFDLST.js → chunk-VAKWUUVC.js} +157 -6
- package/dist/chunk-VAKWUUVC.js.map +1 -0
- package/dist/dashboard/OnboardingWidget.d.ts +2 -14
- package/dist/dashboard/OnboardingWidget.d.ts.map +1 -1
- package/dist/dashboard/SidebarOnboarding.d.ts +28 -0
- package/dist/dashboard/SidebarOnboarding.d.ts.map +1 -0
- package/dist/dashboard/index.d.ts +2 -0
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +4 -4
- package/dist/dashboard/types.d.ts +18 -0
- package/dist/dashboard/types.d.ts.map +1 -1
- package/dist/dashboard/useOnboardingProgress.d.ts +28 -0
- package/dist/dashboard/useOnboardingProgress.d.ts.map +1 -0
- package/dist/icons.js +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +960 -14
- package/dist/index.js.map +1 -1
- package/dist/layout/AppShell.d.ts +14 -1
- package/dist/layout/AppShell.d.ts.map +1 -1
- package/dist/layout/ModulePage.d.ts +11 -2
- package/dist/layout/ModulePage.d.ts.map +1 -1
- package/dist/layout/Sidebar.d.ts +8 -1
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/index.js +4 -4
- package/dist/lib/cn.d.ts.map +1 -0
- package/dist/preset.d.ts +3 -0
- package/dist/preset.d.ts.map +1 -0
- package/dist/primitives/data-table.d.ts +19 -4
- package/dist/primitives/data-table.d.ts.map +1 -1
- package/dist/primitives/date-picker.d.ts +4 -2
- package/dist/primitives/date-picker.d.ts.map +1 -1
- package/dist/primitives/filter-chip.d.ts +26 -0
- package/dist/primitives/filter-chip.d.ts.map +1 -0
- package/dist/primitives/header-tabs.d.ts +32 -0
- package/dist/primitives/header-tabs.d.ts.map +1 -0
- package/dist/primitives/hint.d.ts +25 -0
- package/dist/primitives/hint.d.ts.map +1 -0
- package/dist/primitives/index.d.ts +7 -0
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +4 -4
- package/dist/primitives/list-view.d.ts +14 -1
- package/dist/primitives/list-view.d.ts.map +1 -1
- package/dist/primitives/page-header.d.ts +23 -0
- package/dist/primitives/page-header.d.ts.map +1 -0
- package/dist/primitives/stat-tiles.d.ts +30 -0
- package/dist/primitives/stat-tiles.d.ts.map +1 -0
- package/dist/primitives/switch.d.ts +11 -0
- package/dist/primitives/switch.d.ts.map +1 -0
- package/dist/stores/index.d.ts +1 -0
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/page-header.store.d.ts +69 -0
- package/dist/stores/page-header.store.d.ts.map +1 -0
- package/package.json +6 -15
- package/dist/chunk-75EFDLST.js.map +0 -1
- package/dist/chunk-G6OKZ7WL.js.map +0 -1
- package/dist/chunk-KV3MHB6N.js.map +0 -1
- package/dist/chunk-OUPJDGKE.js.map +0 -1
- package/dist/chunk-PVIB724L.js.map +0 -1
- package/dist/chunk-S5KNM4D2.js.map +0 -1
- package/dist/chunk-YRVE4FOD.js.map +0 -1
- package/dist/utils/cn.d.ts.map +0 -1
- package/src/dashboard/ChartWidget.tsx +0 -50
- package/src/dashboard/ChartWidgetInner.tsx +0 -83
- package/src/dashboard/DashboardCanvas.tsx +0 -210
- package/src/dashboard/DashboardCustomizeMenu.tsx +0 -53
- package/src/dashboard/DashboardGrid.tsx +0 -35
- package/src/dashboard/DashboardRange.tsx +0 -62
- package/src/dashboard/GoldCard.tsx +0 -38
- package/src/dashboard/KpiCard.tsx +0 -238
- package/src/dashboard/OnboardingWidget.tsx +0 -140
- package/src/dashboard/TableWidget.tsx +0 -51
- package/src/dashboard/define.ts +0 -53
- package/src/dashboard/icon.ts +0 -13
- package/src/dashboard/index.ts +0 -38
- package/src/dashboard/layout.ts +0 -50
- package/src/dashboard/preferences.ts +0 -71
- package/src/dashboard/types.ts +0 -41
- package/src/icons.ts +0 -66
- package/src/index.ts +0 -238
- package/src/layout/AppShell.tsx +0 -987
- package/src/layout/ContentSplit.tsx +0 -153
- package/src/layout/ModulePage.tsx +0 -466
- package/src/layout/PageTransition.tsx +0 -57
- package/src/layout/SaveBar.tsx +0 -247
- package/src/layout/Sidebar.tsx +0 -535
- package/src/layout/Topbar.tsx +0 -462
- package/src/layout/index.ts +0 -39
- package/src/layout/useCrossModuleBack.ts +0 -30
- package/src/primitives/Avatar.tsx +0 -48
- package/src/primitives/SearchCombobox.tsx +0 -216
- package/src/primitives/badge.tsx +0 -68
- package/src/primitives/breadcrumb.tsx +0 -43
- package/src/primitives/button.tsx +0 -60
- package/src/primitives/card.tsx +0 -79
- package/src/primitives/checkbox.tsx +0 -53
- package/src/primitives/confirm-dialog.tsx +0 -125
- package/src/primitives/currency-input.tsx +0 -121
- package/src/primitives/data-table.tsx +0 -160
- package/src/primitives/date-picker.tsx +0 -225
- package/src/primitives/dropdown.tsx +0 -196
- package/src/primitives/index.ts +0 -87
- package/src/primitives/input.tsx +0 -50
- package/src/primitives/list-view.tsx +0 -252
- package/src/primitives/markdown-editor.tsx +0 -75
- package/src/primitives/markdown.tsx +0 -169
- package/src/primitives/modal.tsx +0 -156
- package/src/primitives/phone-link.tsx +0 -138
- package/src/primitives/popover.tsx +0 -30
- package/src/primitives/search-select.tsx +0 -314
- package/src/primitives/segmented-control.tsx +0 -66
- package/src/primitives/select.tsx +0 -157
- package/src/primitives/separator.tsx +0 -29
- package/src/primitives/sheet.tsx +0 -181
- package/src/primitives/skeleton.tsx +0 -46
- package/src/primitives/tabs.tsx +0 -53
- package/src/primitives/time-picker.tsx +0 -148
- package/src/primitives/toast.tsx +0 -46
- package/src/primitives/tooltip.tsx +0 -28
- package/src/stores/index.ts +0 -10
- package/src/stores/layout.store.ts +0 -31
- package/src/stores/theme.store.ts +0 -457
- package/src/tailwind.ts +0 -43
- package/src/theme/index.ts +0 -94
- package/src/theme/preset.ts +0 -209
- package/src/theme/presets.ts +0 -106
- package/src/utils/cn.ts +0 -6
- /package/dist/{utils → lib}/cn.d.ts +0 -0
- /package/{src → dist}/styles.css +0 -0
package/src/primitives/sheet.tsx
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import * as React from 'react'
|
|
2
|
-
import * as DialogPrimitive from '@radix-ui/react-dialog'
|
|
3
|
-
import { X } from 'lucide-react'
|
|
4
|
-
|
|
5
|
-
import { cn } from '../utils/cn'
|
|
6
|
-
|
|
7
|
-
// ---------------------------------------------------------------------------
|
|
8
|
-
// Inject sheet animations once (module-level side effect)
|
|
9
|
-
// ---------------------------------------------------------------------------
|
|
10
|
-
|
|
11
|
-
const STYLE_ID = 'saas-sheet-styles'
|
|
12
|
-
if (typeof document !== 'undefined' && !document.getElementById(STYLE_ID)) {
|
|
13
|
-
const style = document.createElement('style')
|
|
14
|
-
style.id = STYLE_ID
|
|
15
|
-
style.textContent = `
|
|
16
|
-
@keyframes saas-sheet-fade-in { from { opacity: 0 } to { opacity: 1 } }
|
|
17
|
-
@keyframes saas-sheet-fade-out { from { opacity: 1 } to { opacity: 0 } }
|
|
18
|
-
@keyframes saas-sheet-slide-in { from { transform: translateX(100%) } to { transform: translateX(0) } }
|
|
19
|
-
@keyframes saas-sheet-slide-out { from { transform: translateX(0) } to { transform: translateX(100%) } }
|
|
20
|
-
.saas-sheet-overlay[data-state="open"] { animation: saas-sheet-fade-in 200ms ease-out }
|
|
21
|
-
.saas-sheet-overlay[data-state="closed"] { animation: saas-sheet-fade-out 150ms ease-in }
|
|
22
|
-
.saas-sheet-content[data-state="open"] { animation: saas-sheet-slide-in 280ms cubic-bezier(0.16, 1, 0.3, 1) }
|
|
23
|
-
.saas-sheet-content[data-state="closed"] { animation: saas-sheet-slide-out 200ms ease-in }
|
|
24
|
-
`
|
|
25
|
-
document.head.appendChild(style)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
// Root, Trigger, Close — re-exported from Radix
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
|
-
|
|
32
|
-
const Sheet = DialogPrimitive.Root
|
|
33
|
-
const SheetTrigger = DialogPrimitive.Trigger
|
|
34
|
-
const SheetClose = DialogPrimitive.Close
|
|
35
|
-
const SheetPortal = DialogPrimitive.Portal
|
|
36
|
-
|
|
37
|
-
// ---------------------------------------------------------------------------
|
|
38
|
-
// Overlay
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
|
-
|
|
41
|
-
const SheetOverlay = React.forwardRef<
|
|
42
|
-
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
|
43
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
|
44
|
-
>(({ className, ...props }, ref) => (
|
|
45
|
-
<DialogPrimitive.Overlay
|
|
46
|
-
ref={ref}
|
|
47
|
-
className={cn(
|
|
48
|
-
'saas-sheet-overlay fixed inset-0 z-50 bg-black/40 backdrop-blur-[2px]',
|
|
49
|
-
className
|
|
50
|
-
)}
|
|
51
|
-
{...props}
|
|
52
|
-
/>
|
|
53
|
-
))
|
|
54
|
-
SheetOverlay.displayName = 'SheetOverlay'
|
|
55
|
-
|
|
56
|
-
// ---------------------------------------------------------------------------
|
|
57
|
-
// Content — slides in from the right
|
|
58
|
-
// ---------------------------------------------------------------------------
|
|
59
|
-
|
|
60
|
-
const SheetContent = React.forwardRef<
|
|
61
|
-
React.ElementRef<typeof DialogPrimitive.Content>,
|
|
62
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
|
|
63
|
-
/** Width class override — defaults to max-w-md */
|
|
64
|
-
width?: string
|
|
65
|
-
/** Hide the built-in close button */
|
|
66
|
-
hideClose?: boolean
|
|
67
|
-
/** Overlay style: "blur" (default), "dim" (no blur), "none" (transparent) */
|
|
68
|
-
overlay?: 'blur' | 'dim' | 'none'
|
|
69
|
-
}
|
|
70
|
-
>(({ className, children, width, hideClose, overlay = 'blur', ...props }, ref) => (
|
|
71
|
-
<SheetPortal>
|
|
72
|
-
<SheetOverlay className={overlay === 'none' ? 'bg-transparent backdrop-blur-0' : overlay === 'dim' ? 'backdrop-blur-0' : undefined} />
|
|
73
|
-
<DialogPrimitive.Content
|
|
74
|
-
ref={ref}
|
|
75
|
-
className={cn(
|
|
76
|
-
'fayz-glass-surface saas-sheet-content fixed inset-y-0 right-0 z-50 flex flex-col border-l bg-card shadow-2xl outline-none',
|
|
77
|
-
'w-full',
|
|
78
|
-
width ?? 'max-w-md',
|
|
79
|
-
className
|
|
80
|
-
)}
|
|
81
|
-
{...props}
|
|
82
|
-
>
|
|
83
|
-
{children}
|
|
84
|
-
{!hideClose && (
|
|
85
|
-
<DialogPrimitive.Close className="absolute right-4 top-4 z-10 flex h-7 w-7 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring">
|
|
86
|
-
<X className="h-4 w-4" />
|
|
87
|
-
<span className="sr-only">Close</span>
|
|
88
|
-
</DialogPrimitive.Close>
|
|
89
|
-
)}
|
|
90
|
-
</DialogPrimitive.Content>
|
|
91
|
-
</SheetPortal>
|
|
92
|
-
))
|
|
93
|
-
SheetContent.displayName = 'SheetContent'
|
|
94
|
-
|
|
95
|
-
// ---------------------------------------------------------------------------
|
|
96
|
-
// Header — top section with title + description
|
|
97
|
-
// ---------------------------------------------------------------------------
|
|
98
|
-
|
|
99
|
-
function SheetHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
|
100
|
-
return (
|
|
101
|
-
<div
|
|
102
|
-
className={cn('flex flex-col gap-1 px-5 py-4 border-b shrink-0', className)}
|
|
103
|
-
{...props}
|
|
104
|
-
/>
|
|
105
|
-
)
|
|
106
|
-
}
|
|
107
|
-
SheetHeader.displayName = 'SheetHeader'
|
|
108
|
-
|
|
109
|
-
// ---------------------------------------------------------------------------
|
|
110
|
-
// Footer — bottom section for actions
|
|
111
|
-
// ---------------------------------------------------------------------------
|
|
112
|
-
|
|
113
|
-
function SheetFooter({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
|
114
|
-
return (
|
|
115
|
-
<div
|
|
116
|
-
className={cn('flex items-center gap-2 px-5 py-3 border-t shrink-0', className)}
|
|
117
|
-
{...props}
|
|
118
|
-
/>
|
|
119
|
-
)
|
|
120
|
-
}
|
|
121
|
-
SheetFooter.displayName = 'SheetFooter'
|
|
122
|
-
|
|
123
|
-
// ---------------------------------------------------------------------------
|
|
124
|
-
// Title
|
|
125
|
-
// ---------------------------------------------------------------------------
|
|
126
|
-
|
|
127
|
-
const SheetTitle = React.forwardRef<
|
|
128
|
-
React.ElementRef<typeof DialogPrimitive.Title>,
|
|
129
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
|
130
|
-
>(({ className, ...props }, ref) => (
|
|
131
|
-
<DialogPrimitive.Title
|
|
132
|
-
ref={ref}
|
|
133
|
-
className={cn('text-sm font-semibold leading-none tracking-tight', className)}
|
|
134
|
-
{...props}
|
|
135
|
-
/>
|
|
136
|
-
))
|
|
137
|
-
SheetTitle.displayName = 'SheetTitle'
|
|
138
|
-
|
|
139
|
-
// ---------------------------------------------------------------------------
|
|
140
|
-
// Description
|
|
141
|
-
// ---------------------------------------------------------------------------
|
|
142
|
-
|
|
143
|
-
const SheetDescription = React.forwardRef<
|
|
144
|
-
React.ElementRef<typeof DialogPrimitive.Description>,
|
|
145
|
-
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
|
146
|
-
>(({ className, ...props }, ref) => (
|
|
147
|
-
<DialogPrimitive.Description
|
|
148
|
-
ref={ref}
|
|
149
|
-
className={cn('text-xs text-muted-foreground', className)}
|
|
150
|
-
{...props}
|
|
151
|
-
/>
|
|
152
|
-
))
|
|
153
|
-
SheetDescription.displayName = 'SheetDescription'
|
|
154
|
-
|
|
155
|
-
// ---------------------------------------------------------------------------
|
|
156
|
-
// Body — scrollable content area
|
|
157
|
-
// ---------------------------------------------------------------------------
|
|
158
|
-
|
|
159
|
-
function SheetBody({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
|
160
|
-
return (
|
|
161
|
-
<div
|
|
162
|
-
className={cn('flex-1 overflow-y-auto px-5 py-5', className)}
|
|
163
|
-
{...props}
|
|
164
|
-
/>
|
|
165
|
-
)
|
|
166
|
-
}
|
|
167
|
-
SheetBody.displayName = 'SheetBody'
|
|
168
|
-
|
|
169
|
-
export {
|
|
170
|
-
Sheet,
|
|
171
|
-
SheetPortal,
|
|
172
|
-
SheetOverlay,
|
|
173
|
-
SheetTrigger,
|
|
174
|
-
SheetClose,
|
|
175
|
-
SheetContent,
|
|
176
|
-
SheetHeader,
|
|
177
|
-
SheetBody,
|
|
178
|
-
SheetFooter,
|
|
179
|
-
SheetTitle,
|
|
180
|
-
SheetDescription,
|
|
181
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { cn } from '../utils/cn'
|
|
2
|
-
|
|
3
|
-
function Skeleton({
|
|
4
|
-
className,
|
|
5
|
-
...props
|
|
6
|
-
}: React.HTMLAttributes<HTMLDivElement>) {
|
|
7
|
-
return (
|
|
8
|
-
<div
|
|
9
|
-
className={cn('animate-pulse rounded-md bg-muted', className)}
|
|
10
|
-
{...props}
|
|
11
|
-
/>
|
|
12
|
-
)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Skeleton loader that mimics a table with rows and columns.
|
|
17
|
-
* Drop-in replacement for "Loading..." text in list views.
|
|
18
|
-
*/
|
|
19
|
-
function TableSkeleton({ columns = 4, rows = 2 }: { columns?: number; rows?: number }) {
|
|
20
|
-
return (
|
|
21
|
-
<div className="rounded-lg border overflow-hidden">
|
|
22
|
-
<div className="border-b bg-muted/30 flex gap-4 px-4 py-2.5">
|
|
23
|
-
{Array.from({ length: columns }).map((_, i) => (
|
|
24
|
-
<Skeleton key={i} className="h-3 flex-1 rounded bg-muted-foreground/10" />
|
|
25
|
-
))}
|
|
26
|
-
</div>
|
|
27
|
-
<div className="divide-y">
|
|
28
|
-
{Array.from({ length: rows }).map((_, r) => (
|
|
29
|
-
<div key={r} className="flex items-center gap-4 px-4 py-3.5">
|
|
30
|
-
{Array.from({ length: columns }).map((_, c) => (
|
|
31
|
-
<Skeleton
|
|
32
|
-
key={c}
|
|
33
|
-
className={cn(
|
|
34
|
-
'h-3 rounded',
|
|
35
|
-
c === 0 ? 'flex-[2]' : 'flex-1',
|
|
36
|
-
)}
|
|
37
|
-
/>
|
|
38
|
-
))}
|
|
39
|
-
</div>
|
|
40
|
-
))}
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export { Skeleton, TableSkeleton }
|
package/src/primitives/tabs.tsx
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import * as React from 'react'
|
|
2
|
-
import * as TabsPrimitive from '@radix-ui/react-tabs'
|
|
3
|
-
|
|
4
|
-
import { cn } from '../utils/cn'
|
|
5
|
-
|
|
6
|
-
const Tabs = TabsPrimitive.Root
|
|
7
|
-
|
|
8
|
-
const TabsList = React.forwardRef<
|
|
9
|
-
React.ElementRef<typeof TabsPrimitive.List>,
|
|
10
|
-
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
|
11
|
-
>(({ className, ...props }, ref) => (
|
|
12
|
-
<TabsPrimitive.List
|
|
13
|
-
ref={ref}
|
|
14
|
-
className={cn(
|
|
15
|
-
'inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground',
|
|
16
|
-
className
|
|
17
|
-
)}
|
|
18
|
-
{...props}
|
|
19
|
-
/>
|
|
20
|
-
))
|
|
21
|
-
TabsList.displayName = TabsPrimitive.List.displayName
|
|
22
|
-
|
|
23
|
-
const TabsTrigger = React.forwardRef<
|
|
24
|
-
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
|
25
|
-
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
|
26
|
-
>(({ className, ...props }, ref) => (
|
|
27
|
-
<TabsPrimitive.Trigger
|
|
28
|
-
ref={ref}
|
|
29
|
-
className={cn(
|
|
30
|
-
'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm',
|
|
31
|
-
className
|
|
32
|
-
)}
|
|
33
|
-
{...props}
|
|
34
|
-
/>
|
|
35
|
-
))
|
|
36
|
-
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
|
|
37
|
-
|
|
38
|
-
const TabsContent = React.forwardRef<
|
|
39
|
-
React.ElementRef<typeof TabsPrimitive.Content>,
|
|
40
|
-
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
|
41
|
-
>(({ className, ...props }, ref) => (
|
|
42
|
-
<TabsPrimitive.Content
|
|
43
|
-
ref={ref}
|
|
44
|
-
className={cn(
|
|
45
|
-
'mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
|
|
46
|
-
className
|
|
47
|
-
)}
|
|
48
|
-
{...props}
|
|
49
|
-
/>
|
|
50
|
-
))
|
|
51
|
-
TabsContent.displayName = TabsPrimitive.Content.displayName
|
|
52
|
-
|
|
53
|
-
export { Tabs, TabsList, TabsTrigger, TabsContent }
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef, useMemo } from 'react'
|
|
2
|
-
import { createPortal } from 'react-dom'
|
|
3
|
-
import { Clock } from 'lucide-react'
|
|
4
|
-
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
// TimePicker — dropdown time slot selector, Google Calendar style
|
|
7
|
-
// ---------------------------------------------------------------------------
|
|
8
|
-
|
|
9
|
-
function formatTime12(h: number, m: number) {
|
|
10
|
-
const period = h >= 12 ? 'pm' : 'am'
|
|
11
|
-
const h12 = h % 12 || 12
|
|
12
|
-
return `${h12}:${String(m).padStart(2, '0')}${period}`
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function formatTime24(h: number, m: number) {
|
|
16
|
-
return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
interface TimePickerProps {
|
|
20
|
-
/** Value as HH:MM (24h) */
|
|
21
|
-
value: string
|
|
22
|
-
onChange: (value: string) => void
|
|
23
|
-
/** Interval in minutes between slots (default: 15) */
|
|
24
|
-
interval?: number
|
|
25
|
-
/** Min time as HH:MM (default: '00:00') */
|
|
26
|
-
min?: string
|
|
27
|
-
/** Max time as HH:MM (default: '23:45') */
|
|
28
|
-
max?: string
|
|
29
|
-
/** Use 12h format for display (default: false) */
|
|
30
|
-
use12h?: boolean
|
|
31
|
-
/** Read-only mode */
|
|
32
|
-
readOnly?: boolean
|
|
33
|
-
className?: string
|
|
34
|
-
/** Open the dropdown immediately on mount */
|
|
35
|
-
defaultOpen?: boolean
|
|
36
|
-
/** Called when the dropdown opens or closes */
|
|
37
|
-
onOpenChange?: (open: boolean) => void
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function TimePicker({ value, onChange, interval = 15, min = '00:00', max = '23:45', use12h = false, readOnly, className, defaultOpen, onOpenChange }: TimePickerProps) {
|
|
41
|
-
const [open, setOpen] = useState(defaultOpen ?? false)
|
|
42
|
-
const ref = useRef<HTMLDivElement>(null)
|
|
43
|
-
const triggerRef = useRef<HTMLButtonElement>(null)
|
|
44
|
-
const listRef = useRef<HTMLDivElement>(null)
|
|
45
|
-
const [pos, setPos] = useState<{ top: number; left: number; width: number }>({ top: 0, left: 0, width: 0 })
|
|
46
|
-
|
|
47
|
-
// Position the portal dropdown
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
if (!open || !triggerRef.current) return
|
|
50
|
-
const rect = triggerRef.current.getBoundingClientRect()
|
|
51
|
-
setPos({ top: rect.bottom + 4, left: rect.left, width: Math.max(rect.width, 120) })
|
|
52
|
-
}, [open])
|
|
53
|
-
|
|
54
|
-
useEffect(() => {
|
|
55
|
-
if (!open) return
|
|
56
|
-
const handler = (e: MouseEvent) => {
|
|
57
|
-
const target = e.target as Node
|
|
58
|
-
if (ref.current?.contains(target)) return
|
|
59
|
-
if (listRef.current?.contains(target)) return
|
|
60
|
-
setOpen(false)
|
|
61
|
-
onOpenChange?.(false)
|
|
62
|
-
}
|
|
63
|
-
document.addEventListener('mousedown', handler)
|
|
64
|
-
return () => document.removeEventListener('mousedown', handler)
|
|
65
|
-
}, [open])
|
|
66
|
-
|
|
67
|
-
// Scroll to selected time when opening
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
if (!open || !listRef.current || !value) return
|
|
70
|
-
const el = listRef.current.querySelector('[data-selected="true"]')
|
|
71
|
-
if (el) el.scrollIntoView({ block: 'center' })
|
|
72
|
-
}, [open, value])
|
|
73
|
-
|
|
74
|
-
const slots = useMemo(() => {
|
|
75
|
-
const [minH, minM] = min.split(':').map(Number)
|
|
76
|
-
const [maxH, maxM] = max.split(':').map(Number)
|
|
77
|
-
const minTotal = minH * 60 + minM
|
|
78
|
-
const maxTotal = maxH * 60 + maxM
|
|
79
|
-
const result: { value: string; label: string }[] = []
|
|
80
|
-
|
|
81
|
-
for (let t = minTotal; t <= maxTotal; t += interval) {
|
|
82
|
-
const h = Math.floor(t / 60)
|
|
83
|
-
const m = t % 60
|
|
84
|
-
result.push({
|
|
85
|
-
value: formatTime24(h, m),
|
|
86
|
-
label: use12h ? formatTime12(h, m) : formatTime24(h, m),
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
return result
|
|
90
|
-
}, [interval, min, max, use12h])
|
|
91
|
-
|
|
92
|
-
const displayValue = useMemo(() => {
|
|
93
|
-
if (!value) return ''
|
|
94
|
-
const [h, m] = value.split(':').map(Number)
|
|
95
|
-
return use12h ? formatTime12(h, m) : formatTime24(h, m)
|
|
96
|
-
}, [value, use12h])
|
|
97
|
-
|
|
98
|
-
function handleKeyDown(e: React.KeyboardEvent) {
|
|
99
|
-
if (readOnly) return
|
|
100
|
-
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
|
101
|
-
e.preventDefault()
|
|
102
|
-
const idx = slots.findIndex((s) => s.value === value)
|
|
103
|
-
const next = e.key === 'ArrowDown'
|
|
104
|
-
? Math.min(idx + 1, slots.length - 1)
|
|
105
|
-
: Math.max(idx - 1, 0)
|
|
106
|
-
if (slots[next]) onChange(slots[next].value)
|
|
107
|
-
} else if (e.key === 'Enter' || e.key === 'Escape') {
|
|
108
|
-
setOpen(false)
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return (
|
|
113
|
-
<div ref={ref} className={`relative ${className ?? ''}`}>
|
|
114
|
-
{/* Trigger */}
|
|
115
|
-
<button ref={triggerRef} type="button"
|
|
116
|
-
onClick={() => !readOnly && setOpen((p) => !p)}
|
|
117
|
-
onKeyDown={handleKeyDown}
|
|
118
|
-
disabled={readOnly}
|
|
119
|
-
className={`flex items-center gap-2 rounded-lg border px-3 py-2 text-sm w-full text-left transition-colors ${
|
|
120
|
-
readOnly ? 'bg-muted/40 text-muted-foreground cursor-default' : 'bg-background hover:bg-muted/30'
|
|
121
|
-
}`}>
|
|
122
|
-
<Clock className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
|
123
|
-
<span>{displayValue || '--:--'}</span>
|
|
124
|
-
</button>
|
|
125
|
-
|
|
126
|
-
{/* Dropdown — portal to escape overflow containers */}
|
|
127
|
-
{open && !readOnly && createPortal(
|
|
128
|
-
<div ref={listRef} data-modal-passthrough
|
|
129
|
-
style={{ position: 'fixed', top: pos.top, left: pos.left, width: pos.width, zIndex: 9999, pointerEvents: 'auto' }}
|
|
130
|
-
className="fayz-glass-surface min-w-[120px] max-h-48 overflow-y-auto rounded-xl border bg-popover shadow-xl py-1">
|
|
131
|
-
{slots.map((slot) => {
|
|
132
|
-
const selected = slot.value === value
|
|
133
|
-
return (
|
|
134
|
-
<button key={slot.value} type="button" data-selected={selected}
|
|
135
|
-
onClick={() => { onChange(slot.value); setOpen(false) }}
|
|
136
|
-
className={`block w-full px-3 py-1.5 text-sm text-left transition-colors ${
|
|
137
|
-
selected ? 'bg-primary/10 text-primary font-medium' : 'hover:bg-muted/50'
|
|
138
|
-
}`}>
|
|
139
|
-
{slot.label}
|
|
140
|
-
</button>
|
|
141
|
-
)
|
|
142
|
-
})}
|
|
143
|
-
</div>,
|
|
144
|
-
document.body,
|
|
145
|
-
)}
|
|
146
|
-
</div>
|
|
147
|
-
)
|
|
148
|
-
}
|
package/src/primitives/toast.tsx
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import * as React from 'react'
|
|
2
|
-
import { Toaster, toast } from 'sonner'
|
|
3
|
-
import { useSaveBarVisible } from '../layout/SaveBar'
|
|
4
|
-
|
|
5
|
-
interface ToastProviderProps {
|
|
6
|
-
position?:
|
|
7
|
-
| 'top-left'
|
|
8
|
-
| 'top-center'
|
|
9
|
-
| 'top-right'
|
|
10
|
-
| 'bottom-left'
|
|
11
|
-
| 'bottom-center'
|
|
12
|
-
| 'bottom-right'
|
|
13
|
-
theme?: 'light' | 'dark' | 'system'
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function ToastProvider({
|
|
17
|
-
position = 'bottom-center',
|
|
18
|
-
theme = 'system',
|
|
19
|
-
}: ToastProviderProps) {
|
|
20
|
-
// Stack toasts ABOVE the floating SaveBar (instead of overlapping it) by
|
|
21
|
-
// lifting the bottom offset while the bar is on screen.
|
|
22
|
-
const saveBarVisible = useSaveBarVisible()
|
|
23
|
-
const bottomOffset = position.startsWith('bottom') && saveBarVisible ? 84 : 24
|
|
24
|
-
return (
|
|
25
|
-
<Toaster
|
|
26
|
-
position={position}
|
|
27
|
-
theme={theme}
|
|
28
|
-
offset={bottomOffset}
|
|
29
|
-
closeButton
|
|
30
|
-
richColors
|
|
31
|
-
toastOptions={{
|
|
32
|
-
classNames: {
|
|
33
|
-
// Format harmonized with the SaveBar island: soft ring + xl shadow,
|
|
34
|
-
// generous rounded-2xl radius (full-pill looks wrong on multi-line
|
|
35
|
-
// toasts). Colors stay semantic (richColors).
|
|
36
|
-
toast: 'group !gap-3 !rounded-3xl !border !px-4 !py-3 !shadow-xl !ring-1 !ring-black/5',
|
|
37
|
-
title: '!text-sm !font-semibold',
|
|
38
|
-
description: '!text-xs !mt-0.5',
|
|
39
|
-
closeButton: '!opacity-0 group-hover:!opacity-60 hover:!opacity-100 !transition-opacity',
|
|
40
|
-
},
|
|
41
|
-
}}
|
|
42
|
-
/>
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export { ToastProvider, toast }
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import * as React from 'react'
|
|
2
|
-
import * as TooltipPrimitive from '@radix-ui/react-tooltip'
|
|
3
|
-
|
|
4
|
-
import { cn } from '../utils/cn'
|
|
5
|
-
|
|
6
|
-
const TooltipProvider = TooltipPrimitive.Provider
|
|
7
|
-
|
|
8
|
-
const Tooltip = TooltipPrimitive.Root
|
|
9
|
-
|
|
10
|
-
const TooltipTrigger = TooltipPrimitive.Trigger
|
|
11
|
-
|
|
12
|
-
const TooltipContent = React.forwardRef<
|
|
13
|
-
React.ElementRef<typeof TooltipPrimitive.Content>,
|
|
14
|
-
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
|
15
|
-
>(({ className, sideOffset = 4, ...props }, ref) => (
|
|
16
|
-
<TooltipPrimitive.Content
|
|
17
|
-
ref={ref}
|
|
18
|
-
sideOffset={sideOffset}
|
|
19
|
-
className={cn(
|
|
20
|
-
'fayz-glass-surface z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
21
|
-
className
|
|
22
|
-
)}
|
|
23
|
-
{...props}
|
|
24
|
-
/>
|
|
25
|
-
))
|
|
26
|
-
TooltipContent.displayName = TooltipPrimitive.Content.displayName
|
|
27
|
-
|
|
28
|
-
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
|
package/src/stores/index.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { create } from 'zustand'
|
|
2
|
-
|
|
3
|
-
interface LayoutState {
|
|
4
|
-
sidebarOpen: boolean
|
|
5
|
-
sidebarCollapsed: boolean
|
|
6
|
-
mobileDrawerOpen: boolean
|
|
7
|
-
commandPaletteOpen: boolean
|
|
8
|
-
toggleSidebar: () => void
|
|
9
|
-
setSidebarCollapsed: (collapsed: boolean) => void
|
|
10
|
-
toggleMobileDrawer: () => void
|
|
11
|
-
setCommandPaletteOpen: (open: boolean) => void
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const useLayoutStore = create<LayoutState>((set) => ({
|
|
15
|
-
sidebarOpen: true,
|
|
16
|
-
sidebarCollapsed: false,
|
|
17
|
-
mobileDrawerOpen: false,
|
|
18
|
-
commandPaletteOpen: false,
|
|
19
|
-
|
|
20
|
-
toggleSidebar: () =>
|
|
21
|
-
set((state) => ({ sidebarOpen: !state.sidebarOpen })),
|
|
22
|
-
|
|
23
|
-
setSidebarCollapsed: (collapsed) =>
|
|
24
|
-
set({ sidebarCollapsed: collapsed }),
|
|
25
|
-
|
|
26
|
-
toggleMobileDrawer: () =>
|
|
27
|
-
set((state) => ({ mobileDrawerOpen: !state.mobileDrawerOpen })),
|
|
28
|
-
|
|
29
|
-
setCommandPaletteOpen: (open) =>
|
|
30
|
-
set({ commandPaletteOpen: open }),
|
|
31
|
-
}))
|