@olwiba/ui 0.2.5 → 0.2.7
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/dist/index.d.ts +155 -3
- package/dist/index.js +240 -134
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/app/AppShell.tsx +11 -1
- package/src/app/DataView.tsx +99 -0
- package/src/components/MediaCard.tsx +68 -0
- package/src/components/ViewToggle.tsx +47 -0
- package/src/hooks/use-view-mode.ts +36 -0
- package/src/index.ts +4 -0
- package/src/layout/AppGrid.tsx +26 -7
- package/src/layout/index.ts +1 -1
- package/src/marketing/Navbar.tsx +19 -12
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { cn } from './chunk-AMWLSHD6.js';
|
|
2
2
|
export { MdxContent, cn } from './chunk-AMWLSHD6.js';
|
|
3
|
-
import * as
|
|
3
|
+
import * as React35 from 'react';
|
|
4
4
|
import { useRef, useEffect, useState } from 'react';
|
|
5
5
|
import { Button as Button$1, Card as Card$1, Input as Input$1, Textarea as Textarea$1, Checkbox as Checkbox$1, Switch as Switch$1, useIsMobile, UIVariantProvider, Badge as Badge$1, cn as cn$1, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Avatar, AvatarImage, AvatarFallback, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, Dialog, DialogTrigger, Progress, useUIVariant, Separator, Accordion, AccordionItem, AccordionTrigger, AccordionContent, Label, Sheet, SheetTrigger, SheetContent, StatusIndicator, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandSeparator, CommandGroup, CommandItem, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, ContextMenu as ContextMenu$1, ContextMenuTrigger, ContextMenuContent, AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, CommandShortcut, Popover, PopoverTrigger, PopoverContent, Spinner, SidebarProvider, SidebarInset, CardHeader, CardTitle, CardDescription, CardContent, InputOTP, InputOTPGroup, InputOTPSlot, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose, ContextMenuSeparator, ContextMenuLabel, ContextMenuSub, ContextMenuSubTrigger, ContextMenuSubContent, ContextMenuItem, ContextMenuShortcut, Sidebar, SidebarHeader, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarFooter, SidebarTrigger, useSidebar, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuGroup } from '@olwiba/cn';
|
|
6
6
|
export { CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Enchanted } from '@olwiba/cn';
|
|
7
7
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
-
import { Search, ArrowUp, ArrowDown, ArrowUpDown, ChevronLeft, ChevronRight, MoreHorizontal, UserPlus, Download, CreditCard, Check, Loader2, ArrowLeft, ArrowUpRight, X, Sparkles, RefreshCw, ArrowRight, Minus, Quote, Star, Twitter, Github, Linkedin, Mail, MessageSquare, ChevronDown, Send, Menu, UploadCloud, File, CheckCircle2, AlertCircle, Bell, Inbox, Activity, TrendingUp, TrendingDown, Sun, Moon, Palette, AlertTriangle, Rocket, Info, Layers,
|
|
8
|
+
import { Search, ArrowUp, ArrowDown, ArrowUpDown, ChevronLeft, ChevronRight, MoreHorizontal, UserPlus, Download, CreditCard, Check, Loader2, ArrowLeft, ArrowUpRight, X, Sparkles, RefreshCw, ArrowRight, Minus, Quote, Star, Twitter, Github, Linkedin, Mail, MessageSquare, ChevronDown, Send, Menu, UploadCloud, File, CheckCircle2, AlertCircle, Bell, Inbox, Activity, TrendingUp, TrendingDown, LayoutGrid, List, Sun, Moon, Palette, AlertTriangle, Rocket, Info, Layers, ShieldCheck, Building2, MoreVerticalIcon, CreditCardIcon, BellIcon, LogOutIcon } from 'lucide-react';
|
|
9
9
|
import { useReactTable, getPaginationRowModel, getSortedRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
|
|
10
10
|
import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, closestCenter } from '@dnd-kit/core';
|
|
11
11
|
import { sortableKeyboardCoordinates, SortableContext, rectSortingStrategy, horizontalListSortingStrategy, verticalListSortingStrategy, arrayMove, useSortable } from '@dnd-kit/sortable';
|
|
@@ -13,7 +13,7 @@ import { CSS } from '@dnd-kit/utilities';
|
|
|
13
13
|
import { PieChart, Pie, Cell, BarChart, XAxis, YAxis, Bar, AreaChart, Area, LineChart, Line, ResponsiveContainer, Tooltip as Tooltip$1, CartesianGrid } from 'recharts';
|
|
14
14
|
import { toast } from 'sonner';
|
|
15
15
|
|
|
16
|
-
var OlwibaUIContext =
|
|
16
|
+
var OlwibaUIContext = React35.createContext({
|
|
17
17
|
isMobile: false,
|
|
18
18
|
mode: "default",
|
|
19
19
|
setMode: () => {
|
|
@@ -22,17 +22,17 @@ var OlwibaUIContext = React34.createContext({
|
|
|
22
22
|
function OlwibaUIProvider({ children, isMobile: isMobileProp, mode: initialMode = "default" }) {
|
|
23
23
|
const detectedMobile = useIsMobile();
|
|
24
24
|
const isMobile = isMobileProp ?? detectedMobile;
|
|
25
|
-
const [mode, setMode] =
|
|
25
|
+
const [mode, setMode] = React35.useState(initialMode);
|
|
26
26
|
const variant = mode !== "default" ? mode : void 0;
|
|
27
27
|
return /* @__PURE__ */ jsx(OlwibaUIContext.Provider, { value: { isMobile, mode, setMode }, children: /* @__PURE__ */ jsx(UIVariantProvider, { mode: variant, children }) });
|
|
28
28
|
}
|
|
29
29
|
function useOlwibaUI() {
|
|
30
|
-
return
|
|
30
|
+
return React35.useContext(OlwibaUIContext);
|
|
31
31
|
}
|
|
32
32
|
function useUIMode() {
|
|
33
|
-
return
|
|
33
|
+
return React35.useContext(OlwibaUIContext).mode;
|
|
34
34
|
}
|
|
35
|
-
var Button =
|
|
35
|
+
var Button = React35.forwardRef(
|
|
36
36
|
({ mode, ...props }, ref) => {
|
|
37
37
|
const ctxMode = useUIMode();
|
|
38
38
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
@@ -40,7 +40,7 @@ var Button = React34.forwardRef(
|
|
|
40
40
|
}
|
|
41
41
|
);
|
|
42
42
|
Button.displayName = "Button";
|
|
43
|
-
var Card =
|
|
43
|
+
var Card = React35.forwardRef(
|
|
44
44
|
({ mode, ...props }, ref) => {
|
|
45
45
|
const ctxMode = useUIMode();
|
|
46
46
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
@@ -51,7 +51,7 @@ Card.displayName = "Card";
|
|
|
51
51
|
function Badge(props) {
|
|
52
52
|
return /* @__PURE__ */ jsx(Badge$1, { ...props });
|
|
53
53
|
}
|
|
54
|
-
var Input =
|
|
54
|
+
var Input = React35.forwardRef(
|
|
55
55
|
({ mode, ...props }, ref) => {
|
|
56
56
|
const ctxMode = useUIMode();
|
|
57
57
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
@@ -59,7 +59,7 @@ var Input = React34.forwardRef(
|
|
|
59
59
|
}
|
|
60
60
|
);
|
|
61
61
|
Input.displayName = "Input";
|
|
62
|
-
var Textarea =
|
|
62
|
+
var Textarea = React35.forwardRef(
|
|
63
63
|
({ mode, ...props }, ref) => {
|
|
64
64
|
const ctxMode = useUIMode();
|
|
65
65
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
@@ -67,13 +67,13 @@ var Textarea = React34.forwardRef(
|
|
|
67
67
|
}
|
|
68
68
|
);
|
|
69
69
|
Textarea.displayName = "Textarea";
|
|
70
|
-
var Checkbox =
|
|
70
|
+
var Checkbox = React35.forwardRef(({ mode, ...props }, ref) => {
|
|
71
71
|
const ctxMode = useUIMode();
|
|
72
72
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
73
73
|
return /* @__PURE__ */ jsx(Checkbox$1, { mode: resolvedMode, ...props, ref });
|
|
74
74
|
});
|
|
75
75
|
Checkbox.displayName = "Checkbox";
|
|
76
|
-
var Switch =
|
|
76
|
+
var Switch = React35.forwardRef(({ mode: _mode, ...props }, ref) => {
|
|
77
77
|
return /* @__PURE__ */ jsx(Switch$1, { ...props, ref });
|
|
78
78
|
});
|
|
79
79
|
Switch.displayName = "Switch";
|
|
@@ -212,19 +212,22 @@ function AppContent({
|
|
|
212
212
|
}
|
|
213
213
|
var columnsMap = {
|
|
214
214
|
1: "grid-cols-1",
|
|
215
|
-
2: "grid-cols-1
|
|
216
|
-
3: "grid-cols-1
|
|
217
|
-
4: "grid-cols-1
|
|
215
|
+
2: "grid-cols-1 sm:grid-cols-2",
|
|
216
|
+
3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
|
|
217
|
+
4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
|
|
218
|
+
5: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5",
|
|
219
|
+
6: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6"
|
|
218
220
|
};
|
|
219
221
|
var gapMap3 = {
|
|
222
|
+
none: "gap-0",
|
|
220
223
|
sm: "gap-3",
|
|
221
224
|
md: "gap-4",
|
|
222
225
|
lg: "gap-6"
|
|
223
226
|
};
|
|
224
227
|
var spanMap2 = {
|
|
225
|
-
1: "
|
|
226
|
-
2: "
|
|
227
|
-
3: "
|
|
228
|
+
1: "sm:col-span-1",
|
|
229
|
+
2: "sm:col-span-2",
|
|
230
|
+
3: "lg:col-span-3",
|
|
228
231
|
4: "xl:col-span-4",
|
|
229
232
|
full: "col-span-full"
|
|
230
233
|
};
|
|
@@ -429,6 +432,7 @@ function AppShell({
|
|
|
429
432
|
collapsible = "icon",
|
|
430
433
|
sidebarPosition = "viewport",
|
|
431
434
|
side = "left",
|
|
435
|
+
contentClassName = "p-6",
|
|
432
436
|
children
|
|
433
437
|
} = {}) {
|
|
434
438
|
const isContained = sidebarPosition === "contained";
|
|
@@ -453,7 +457,7 @@ function AppShell({
|
|
|
453
457
|
),
|
|
454
458
|
/* @__PURE__ */ jsxs(SidebarInset, { className: isContained ? void 0 : "overflow-y-auto", children: [
|
|
455
459
|
/* @__PURE__ */ jsx(ShellHeader, { pageTitle, headerStart, headerEnd }),
|
|
456
|
-
children
|
|
460
|
+
/* @__PURE__ */ jsx("div", { className: contentClassName, children })
|
|
457
461
|
] })
|
|
458
462
|
]
|
|
459
463
|
}
|
|
@@ -530,7 +534,7 @@ function DefaultForm({
|
|
|
530
534
|
const isForgotPassword = mode === "forgot-password";
|
|
531
535
|
const isResetPassword = mode === "reset-password";
|
|
532
536
|
const isVerify = mode === "verify";
|
|
533
|
-
const [code, setCode] =
|
|
537
|
+
const [code, setCode] = React35.useState("");
|
|
534
538
|
const hasPrefill = !!(defaultEmail || defaultPassword);
|
|
535
539
|
const prefillStyle = (active) => active ? { animation: "auth-prefill 1.6s ease-out 0.35s 1 both" } : void 0;
|
|
536
540
|
const copy = authCopy[mode];
|
|
@@ -690,10 +694,10 @@ function DataTable({
|
|
|
690
694
|
emptyMessage = "No results.",
|
|
691
695
|
className
|
|
692
696
|
}) {
|
|
693
|
-
const [sorting, setSorting] =
|
|
694
|
-
const [rowSelection, setRowSelection] =
|
|
695
|
-
const [globalFilter, setGlobalFilter] =
|
|
696
|
-
const allColumns =
|
|
697
|
+
const [sorting, setSorting] = React35.useState([]);
|
|
698
|
+
const [rowSelection, setRowSelection] = React35.useState({});
|
|
699
|
+
const [globalFilter, setGlobalFilter] = React35.useState("");
|
|
700
|
+
const allColumns = React35.useMemo(
|
|
697
701
|
() => selectable ? [selectColumn, ...columns] : columns,
|
|
698
702
|
[selectable, columns]
|
|
699
703
|
);
|
|
@@ -715,7 +719,7 @@ function DataTable({
|
|
|
715
719
|
initialState: pageSize > 0 ? { pagination: { pageSize } } : void 0,
|
|
716
720
|
enableRowSelection: selectable
|
|
717
721
|
});
|
|
718
|
-
|
|
722
|
+
React35.useEffect(() => {
|
|
719
723
|
if (!onSelectionChange) return;
|
|
720
724
|
onSelectionChange(table.getSelectedRowModel().rows.map((r) => r.original));
|
|
721
725
|
}, [rowSelection]);
|
|
@@ -795,8 +799,8 @@ function DataTable({
|
|
|
795
799
|
] });
|
|
796
800
|
}
|
|
797
801
|
function InviteDialog({ roles, onInvite, onClose }) {
|
|
798
|
-
const [email, setEmail] =
|
|
799
|
-
const [role, setRole] =
|
|
802
|
+
const [email, setEmail] = React35.useState("");
|
|
803
|
+
const [role, setRole] = React35.useState(roles[roles.length - 1] ?? roles[0]);
|
|
800
804
|
return /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsxs(
|
|
801
805
|
"form",
|
|
802
806
|
{
|
|
@@ -840,8 +844,8 @@ function TeamMembersPanel({
|
|
|
840
844
|
title = "Team members",
|
|
841
845
|
description = "Manage who has access to this workspace."
|
|
842
846
|
}) {
|
|
843
|
-
const [inviteOpen, setInviteOpen] =
|
|
844
|
-
const columns =
|
|
847
|
+
const [inviteOpen, setInviteOpen] = React35.useState(false);
|
|
848
|
+
const columns = React35.useMemo(() => [
|
|
845
849
|
{
|
|
846
850
|
accessorKey: "name",
|
|
847
851
|
header: "Name",
|
|
@@ -910,7 +914,7 @@ function BillingPanel({
|
|
|
910
914
|
onUpdatePaymentMethod,
|
|
911
915
|
className
|
|
912
916
|
}) {
|
|
913
|
-
const invoiceColumns =
|
|
917
|
+
const invoiceColumns = React35.useMemo(() => [
|
|
914
918
|
{ accessorKey: "date", header: "Date", enableSorting: false },
|
|
915
919
|
{ accessorKey: "amount", header: "Amount", enableSorting: false },
|
|
916
920
|
{
|
|
@@ -989,9 +993,9 @@ function OnboardingWizard({
|
|
|
989
993
|
completeLabel = "Finish",
|
|
990
994
|
className
|
|
991
995
|
}) {
|
|
992
|
-
const [internalStep, setInternalStep] =
|
|
993
|
-
const [error, setError] =
|
|
994
|
-
const [pending, setPending] =
|
|
996
|
+
const [internalStep, setInternalStep] = React35.useState(0);
|
|
997
|
+
const [error, setError] = React35.useState(null);
|
|
998
|
+
const [pending, setPending] = React35.useState(false);
|
|
995
999
|
const index = stepProp ?? internalStep;
|
|
996
1000
|
const current = steps[index];
|
|
997
1001
|
const isLast = index === steps.length - 1;
|
|
@@ -1321,10 +1325,10 @@ function UpdateBanner({
|
|
|
1321
1325
|
buttonLabel = "Refresh now",
|
|
1322
1326
|
className
|
|
1323
1327
|
}) {
|
|
1324
|
-
const [show, setShow] =
|
|
1325
|
-
const [entered, setEntered] =
|
|
1326
|
-
const [refreshing, setRefreshing] =
|
|
1327
|
-
|
|
1328
|
+
const [show, setShow] = React35.useState(forceShow);
|
|
1329
|
+
const [entered, setEntered] = React35.useState(false);
|
|
1330
|
+
const [refreshing, setRefreshing] = React35.useState(false);
|
|
1331
|
+
React35.useEffect(() => {
|
|
1328
1332
|
if (forceShow) {
|
|
1329
1333
|
setShow(true);
|
|
1330
1334
|
return;
|
|
@@ -1347,7 +1351,7 @@ function UpdateBanner({
|
|
|
1347
1351
|
clearInterval(id);
|
|
1348
1352
|
};
|
|
1349
1353
|
}, [currentVersion, fetchVersion, forceShow, intervalMs]);
|
|
1350
|
-
|
|
1354
|
+
React35.useEffect(() => {
|
|
1351
1355
|
if (!show) {
|
|
1352
1356
|
setEntered(false);
|
|
1353
1357
|
return;
|
|
@@ -1420,9 +1424,9 @@ function FadeIn({
|
|
|
1420
1424
|
style,
|
|
1421
1425
|
...props
|
|
1422
1426
|
}) {
|
|
1423
|
-
const ref =
|
|
1424
|
-
const [visible, setVisible] =
|
|
1425
|
-
|
|
1427
|
+
const ref = React35.useRef(null);
|
|
1428
|
+
const [visible, setVisible] = React35.useState(false);
|
|
1429
|
+
React35.useEffect(() => {
|
|
1426
1430
|
const el = ref.current;
|
|
1427
1431
|
if (!el) return;
|
|
1428
1432
|
const observer = new IntersectionObserver(
|
|
@@ -1617,16 +1621,16 @@ function Carousel({
|
|
|
1617
1621
|
className
|
|
1618
1622
|
}) {
|
|
1619
1623
|
const mode = useUIVariant();
|
|
1620
|
-
const trackRef =
|
|
1621
|
-
const [canPrev, setCanPrev] =
|
|
1622
|
-
const [canNext, setCanNext] =
|
|
1623
|
-
const updateScrollState =
|
|
1624
|
+
const trackRef = React35.useRef(null);
|
|
1625
|
+
const [canPrev, setCanPrev] = React35.useState(false);
|
|
1626
|
+
const [canNext, setCanNext] = React35.useState(true);
|
|
1627
|
+
const updateScrollState = React35.useCallback(() => {
|
|
1624
1628
|
const track = trackRef.current;
|
|
1625
1629
|
if (!track) return;
|
|
1626
1630
|
setCanPrev(track.scrollLeft > 8);
|
|
1627
1631
|
setCanNext(track.scrollLeft < track.scrollWidth - track.clientWidth - 8);
|
|
1628
1632
|
}, []);
|
|
1629
|
-
|
|
1633
|
+
React35.useEffect(() => {
|
|
1630
1634
|
const track = trackRef.current;
|
|
1631
1635
|
if (!track) return;
|
|
1632
1636
|
updateScrollState();
|
|
@@ -1683,7 +1687,7 @@ function Carousel({
|
|
|
1683
1687
|
role: "region",
|
|
1684
1688
|
"aria-label": ariaLabel,
|
|
1685
1689
|
className: "flex snap-x snap-mandatory gap-6 overflow-x-auto pb-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
1686
|
-
children:
|
|
1690
|
+
children: React35.Children.map(
|
|
1687
1691
|
children,
|
|
1688
1692
|
(child) => child == null ? null : /* @__PURE__ */ jsx("div", { "data-carousel-item": true, className: cn$1("shrink-0 snap-start", itemClassName), children: child })
|
|
1689
1693
|
)
|
|
@@ -1708,9 +1712,9 @@ function StaggerChildren({
|
|
|
1708
1712
|
className,
|
|
1709
1713
|
...props
|
|
1710
1714
|
}) {
|
|
1711
|
-
const ref =
|
|
1712
|
-
const [visible, setVisible] =
|
|
1713
|
-
|
|
1715
|
+
const ref = React35.useRef(null);
|
|
1716
|
+
const [visible, setVisible] = React35.useState(false);
|
|
1717
|
+
React35.useEffect(() => {
|
|
1714
1718
|
const el = ref.current;
|
|
1715
1719
|
if (!el) return;
|
|
1716
1720
|
const observer = new IntersectionObserver(
|
|
@@ -1728,7 +1732,7 @@ function StaggerChildren({
|
|
|
1728
1732
|
return () => observer.disconnect();
|
|
1729
1733
|
}, [once]);
|
|
1730
1734
|
const [tx, ty] = translateMap2[direction];
|
|
1731
|
-
return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children:
|
|
1735
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React35.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
|
|
1732
1736
|
"div",
|
|
1733
1737
|
{
|
|
1734
1738
|
className: "h-full",
|
|
@@ -1870,7 +1874,7 @@ function StepsSection({
|
|
|
1870
1874
|
/* @__PURE__ */ jsx("div", { className: "mt-12", children: resolvedGroups.map((group, groupIndex) => {
|
|
1871
1875
|
const startNumber = nextNumber;
|
|
1872
1876
|
nextNumber += group.steps.length;
|
|
1873
|
-
return /* @__PURE__ */ jsxs(
|
|
1877
|
+
return /* @__PURE__ */ jsxs(React35.Fragment, { children: [
|
|
1874
1878
|
/* @__PURE__ */ jsx("div", { className: cn$1(groupIndex > 0 && "mt-10"), children: /* @__PURE__ */ jsx(TimelineGroup, { steps: group.steps, startNumber, fadeIn: groupIndex > 0 }) }),
|
|
1875
1879
|
group.after && /* @__PURE__ */ jsx("div", { className: "mt-16", children: group.after })
|
|
1876
1880
|
] }, groupIndex);
|
|
@@ -2040,9 +2044,9 @@ function FeatureMarqueeSection({
|
|
|
2040
2044
|
] });
|
|
2041
2045
|
}
|
|
2042
2046
|
function useIntersectionObserver(options) {
|
|
2043
|
-
const ref =
|
|
2044
|
-
const [isIntersecting, setIsIntersecting] =
|
|
2045
|
-
|
|
2047
|
+
const ref = React35.useRef(null);
|
|
2048
|
+
const [isIntersecting, setIsIntersecting] = React35.useState(false);
|
|
2049
|
+
React35.useEffect(() => {
|
|
2046
2050
|
const el = ref.current;
|
|
2047
2051
|
if (!el) return;
|
|
2048
2052
|
const observer = new IntersectionObserver(([entry]) => {
|
|
@@ -2064,8 +2068,8 @@ function ShowcaseCta({
|
|
|
2064
2068
|
sectionClasses
|
|
2065
2069
|
}) {
|
|
2066
2070
|
const [ref, intersecting] = useIntersectionObserver({ threshold: 0.15 });
|
|
2067
|
-
const [visible, setVisible] =
|
|
2068
|
-
|
|
2071
|
+
const [visible, setVisible] = React35.useState(false);
|
|
2072
|
+
React35.useEffect(() => {
|
|
2069
2073
|
if (intersecting) setVisible(true);
|
|
2070
2074
|
}, [intersecting]);
|
|
2071
2075
|
return /* @__PURE__ */ jsxs(
|
|
@@ -2242,8 +2246,8 @@ function CountdownTimer({
|
|
|
2242
2246
|
className,
|
|
2243
2247
|
compact = false
|
|
2244
2248
|
}) {
|
|
2245
|
-
const [timeLeft, setTimeLeft] =
|
|
2246
|
-
|
|
2249
|
+
const [timeLeft, setTimeLeft] = React35.useState(() => getTimeLeft(deadline));
|
|
2250
|
+
React35.useEffect(() => {
|
|
2247
2251
|
setTimeLeft(getTimeLeft(deadline));
|
|
2248
2252
|
const id = setInterval(() => setTimeLeft(getTimeLeft(deadline)), 1e3);
|
|
2249
2253
|
return () => clearInterval(id);
|
|
@@ -2269,7 +2273,7 @@ function CountdownTimer({
|
|
|
2269
2273
|
];
|
|
2270
2274
|
return /* @__PURE__ */ jsxs("div", { className: cn$1("flex items-center justify-center gap-2 text-sm", className), children: [
|
|
2271
2275
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
|
|
2272
|
-
/* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 font-mono font-semibold tabular-nums", children: units.map(({ value, unit }, i) => /* @__PURE__ */ jsxs(
|
|
2276
|
+
/* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 font-mono font-semibold tabular-nums", children: units.map(({ value, unit }, i) => /* @__PURE__ */ jsxs(React35.Fragment, { children: [
|
|
2273
2277
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
2274
2278
|
String(value).padStart(2, "0"),
|
|
2275
2279
|
/* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: unit })
|
|
@@ -2294,7 +2298,7 @@ function PricingSection({
|
|
|
2294
2298
|
highlightedBadgeLabel = "Founding member",
|
|
2295
2299
|
renderPlanFooter
|
|
2296
2300
|
}) {
|
|
2297
|
-
const [annual, setAnnual] =
|
|
2301
|
+
const [annual, setAnnual] = React35.useState(false);
|
|
2298
2302
|
const isOneTime = mode === "one-time";
|
|
2299
2303
|
const uiMode = useUIVariant();
|
|
2300
2304
|
const sectionClasses = cn$1(
|
|
@@ -2563,10 +2567,10 @@ function CountUp({
|
|
|
2563
2567
|
className,
|
|
2564
2568
|
...props
|
|
2565
2569
|
}) {
|
|
2566
|
-
const ref =
|
|
2567
|
-
const [value, setValue] =
|
|
2568
|
-
const hasStarted =
|
|
2569
|
-
|
|
2570
|
+
const ref = React35.useRef(null);
|
|
2571
|
+
const [value, setValue] = React35.useState(from);
|
|
2572
|
+
const hasStarted = React35.useRef(false);
|
|
2573
|
+
React35.useEffect(() => {
|
|
2570
2574
|
const el = ref.current;
|
|
2571
2575
|
if (!el) return;
|
|
2572
2576
|
const observer = new IntersectionObserver(
|
|
@@ -2659,8 +2663,8 @@ function NewsletterSection({
|
|
|
2659
2663
|
successDescription = defaults.successDescription,
|
|
2660
2664
|
onSubscribe
|
|
2661
2665
|
} = {}) {
|
|
2662
|
-
const [email, setEmail] =
|
|
2663
|
-
const [submitted, setSubmitted] =
|
|
2666
|
+
const [email, setEmail] = React35.useState("");
|
|
2667
|
+
const [submitted, setSubmitted] = React35.useState(false);
|
|
2664
2668
|
const mode = useUIVariant();
|
|
2665
2669
|
const sectionClasses = cn$1(
|
|
2666
2670
|
"overflow-hidden bg-card",
|
|
@@ -2751,7 +2755,7 @@ function ContactSection({
|
|
|
2751
2755
|
sendAnotherLabel = defaults2.sendAnotherLabel,
|
|
2752
2756
|
onSubmit
|
|
2753
2757
|
} = {}) {
|
|
2754
|
-
const [submitted, setSubmitted] =
|
|
2758
|
+
const [submitted, setSubmitted] = React35.useState(false);
|
|
2755
2759
|
const mode = useUIVariant();
|
|
2756
2760
|
const sectionClasses = cn$1(
|
|
2757
2761
|
"overflow-hidden bg-card",
|
|
@@ -3049,9 +3053,10 @@ function Navbar({
|
|
|
3049
3053
|
controls,
|
|
3050
3054
|
renderLink = defaultRenderLink7
|
|
3051
3055
|
}) {
|
|
3052
|
-
const [open, setOpen] =
|
|
3056
|
+
const [open, setOpen] = React35.useState(false);
|
|
3053
3057
|
const brandHref = brand.href ?? "/";
|
|
3054
3058
|
const hasRightContent = controls?.length || cta?.primary || cta?.secondary;
|
|
3059
|
+
const closeMobileMenu = React35.useCallback(() => setOpen(false), []);
|
|
3055
3060
|
return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", children: /* @__PURE__ */ jsxs("nav", { className: "grid h-16 grid-cols-[1fr_auto_1fr] items-center px-6", children: [
|
|
3056
3061
|
renderLink({
|
|
3057
3062
|
href: brandHref,
|
|
@@ -3066,7 +3071,7 @@ function Navbar({
|
|
|
3066
3071
|
children: link.label
|
|
3067
3072
|
}) }, link.label)) }),
|
|
3068
3073
|
hasRightContent && /* @__PURE__ */ jsxs("div", { className: "hidden items-center justify-end gap-2 md:flex", children: [
|
|
3069
|
-
controls?.map((control, i) => /* @__PURE__ */ jsx(
|
|
3074
|
+
controls?.map((control, i) => /* @__PURE__ */ jsx(React35.Fragment, { children: control }, i)),
|
|
3070
3075
|
(cta?.secondary || cta?.primary) && controls?.length ? /* @__PURE__ */ jsx("div", { className: "mx-1 h-4 w-px bg-border" }) : null,
|
|
3071
3076
|
cta?.secondary && renderLink({
|
|
3072
3077
|
href: cta.secondary.href,
|
|
@@ -3083,29 +3088,29 @@ function Navbar({
|
|
|
3083
3088
|
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Open menu" })
|
|
3084
3089
|
] }) }),
|
|
3085
3090
|
/* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "w-72", children: [
|
|
3086
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center pb-4", children: /* @__PURE__ */ jsx("span", {
|
|
3091
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center pb-4", children: /* @__PURE__ */ jsx("span", { onClickCapture: closeMobileMenu, className: "cursor-pointer", children: renderLink({
|
|
3087
3092
|
href: brandHref,
|
|
3088
3093
|
children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 font-semibold", children: [
|
|
3089
3094
|
brand.logo,
|
|
3090
3095
|
/* @__PURE__ */ jsx("span", { children: brand.name })
|
|
3091
3096
|
] })
|
|
3092
3097
|
}) }) }),
|
|
3093
|
-
controls?.length ? /* @__PURE__ */ jsx("div", { className: "mb-4 flex w-full items-center justify-between gap-1", children: controls.map((control, i) => /* @__PURE__ */ jsx(
|
|
3098
|
+
controls?.length ? /* @__PURE__ */ jsx("div", { className: "mb-4 flex w-full items-center justify-between gap-1", children: controls.map((control, i) => /* @__PURE__ */ jsx(React35.Fragment, { children: control }, i)) }) : null,
|
|
3094
3099
|
/* @__PURE__ */ jsx(Separator, {}),
|
|
3095
|
-
/* @__PURE__ */ jsx("nav", { className: "mt-4 flex flex-col gap-1", children: navLinks.map((link) => /* @__PURE__ */ jsx("span", {
|
|
3100
|
+
/* @__PURE__ */ jsx("nav", { className: "mt-4 flex flex-col gap-1", children: navLinks.map((link) => /* @__PURE__ */ jsx("span", { onClickCapture: closeMobileMenu, children: renderLink({
|
|
3096
3101
|
href: link.href,
|
|
3097
3102
|
className: "block rounded-md px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
|
|
3098
3103
|
children: link.label
|
|
3099
3104
|
}) }, link.label)) }),
|
|
3100
3105
|
/* @__PURE__ */ jsxs("div", { className: "mt-6 flex flex-col gap-2", children: [
|
|
3101
|
-
cta?.secondary && renderLink({
|
|
3106
|
+
cta?.secondary && /* @__PURE__ */ jsx("span", { onClickCapture: closeMobileMenu, children: renderLink({
|
|
3102
3107
|
href: cta.secondary.href,
|
|
3103
3108
|
children: /* @__PURE__ */ jsx(Button$1, { variant: "outline", className: "w-full", children: cta.secondary.label })
|
|
3104
|
-
}),
|
|
3105
|
-
cta?.primary && renderLink({
|
|
3109
|
+
}) }),
|
|
3110
|
+
cta?.primary && /* @__PURE__ */ jsx("span", { onClickCapture: closeMobileMenu, children: renderLink({
|
|
3106
3111
|
href: cta.primary.href,
|
|
3107
3112
|
children: /* @__PURE__ */ jsx(Button$1, { className: "w-full", children: cta.primary.label })
|
|
3108
|
-
})
|
|
3113
|
+
}) })
|
|
3109
3114
|
] })
|
|
3110
3115
|
] })
|
|
3111
3116
|
] })
|
|
@@ -3239,7 +3244,7 @@ function LogoStrip({
|
|
|
3239
3244
|
] });
|
|
3240
3245
|
}
|
|
3241
3246
|
function GridUnderlay({ variant, size = 24, className, ...props }) {
|
|
3242
|
-
const id =
|
|
3247
|
+
const id = React35.useId();
|
|
3243
3248
|
const pattern = variant === "dots" ? /* @__PURE__ */ jsx("circle", { cx: size / 2, cy: size / 2, r: 1, fill: "currentColor" }) : variant === "lines" ? /* @__PURE__ */ jsx("path", { d: `M ${size} 0 L 0 0 0 ${size}`, fill: "none", stroke: "currentColor", strokeWidth: 0.5 }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3244
3249
|
/* @__PURE__ */ jsx("line", { x1: size / 2, y1: 0, x2: size / 2, y2: size, stroke: "currentColor", strokeWidth: 0.5 }),
|
|
3245
3250
|
/* @__PURE__ */ jsx("line", { x1: 0, y1: size / 2, x2: size, y2: size / 2, stroke: "currentColor", strokeWidth: 0.5 })
|
|
@@ -3267,9 +3272,9 @@ function GlowUnderlay({
|
|
|
3267
3272
|
style,
|
|
3268
3273
|
...props
|
|
3269
3274
|
}) {
|
|
3270
|
-
const [pos, setPos] =
|
|
3271
|
-
const containerRef =
|
|
3272
|
-
|
|
3275
|
+
const [pos, setPos] = React35.useState({ x: "50%", y: "50%" });
|
|
3276
|
+
const containerRef = React35.useRef(null);
|
|
3277
|
+
React35.useEffect(() => {
|
|
3273
3278
|
if (!followCursor) return;
|
|
3274
3279
|
const handleMouseMove = (e) => {
|
|
3275
3280
|
const el = containerRef.current;
|
|
@@ -3408,8 +3413,8 @@ function PageTransition({
|
|
|
3408
3413
|
style,
|
|
3409
3414
|
...props
|
|
3410
3415
|
}) {
|
|
3411
|
-
const [mounted, setMounted] =
|
|
3412
|
-
|
|
3416
|
+
const [mounted, setMounted] = React35.useState(false);
|
|
3417
|
+
React35.useEffect(() => {
|
|
3413
3418
|
const id = requestAnimationFrame(() => setMounted(true));
|
|
3414
3419
|
return () => cancelAnimationFrame(id);
|
|
3415
3420
|
}, []);
|
|
@@ -3484,7 +3489,7 @@ function Sortable({
|
|
|
3484
3489
|
if (oldIndex === -1 || newIndex === -1) return;
|
|
3485
3490
|
onReorder(arrayMove(items, oldIndex, newIndex));
|
|
3486
3491
|
};
|
|
3487
|
-
const childArray =
|
|
3492
|
+
const childArray = React35.Children.toArray(children);
|
|
3488
3493
|
return /* @__PURE__ */ jsx(DndContext, { sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, children: /* @__PURE__ */ jsx(SortableContext, { items, strategy: strategies[direction], children: /* @__PURE__ */ jsx("div", { className: cn$1(containerClasses[direction], className), children: childArray.map(
|
|
3489
3494
|
(child, i) => items[i] === void 0 ? null : /* @__PURE__ */ jsx(SortableItem, { id: items[i], disabled, className: itemClassName, children: child }, items[i])
|
|
3490
3495
|
) }) }) });
|
|
@@ -3496,8 +3501,8 @@ function Spotlight({
|
|
|
3496
3501
|
triggerClassName,
|
|
3497
3502
|
shortcut = "\u2318K"
|
|
3498
3503
|
}) {
|
|
3499
|
-
const [open, setOpen] =
|
|
3500
|
-
|
|
3504
|
+
const [open, setOpen] = React35.useState(false);
|
|
3505
|
+
React35.useEffect(() => {
|
|
3501
3506
|
const down = (e) => {
|
|
3502
3507
|
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
|
3503
3508
|
e.preventDefault();
|
|
@@ -3527,7 +3532,7 @@ function Spotlight({
|
|
|
3527
3532
|
/* @__PURE__ */ jsx(CommandInput, { placeholder }),
|
|
3528
3533
|
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
3529
3534
|
/* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
|
|
3530
|
-
groups.map((group, i) => /* @__PURE__ */ jsxs(
|
|
3535
|
+
groups.map((group, i) => /* @__PURE__ */ jsxs(React35.Fragment, { children: [
|
|
3531
3536
|
i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
3532
3537
|
/* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
3533
3538
|
CommandItem,
|
|
@@ -3552,8 +3557,8 @@ function Spotlight({
|
|
|
3552
3557
|
var BASE = 40;
|
|
3553
3558
|
var MAGNIFY_RADIUS = 80;
|
|
3554
3559
|
function Dock({ items, iconSize = BASE, magnification = 1.7, className, ...props }) {
|
|
3555
|
-
const [mouseX, setMouseX] =
|
|
3556
|
-
const containerRef =
|
|
3560
|
+
const [mouseX, setMouseX] = React35.useState(null);
|
|
3561
|
+
const containerRef = React35.useRef(null);
|
|
3557
3562
|
function getScale(index) {
|
|
3558
3563
|
if (mouseX === null || !containerRef.current) return 1;
|
|
3559
3564
|
const container = containerRef.current;
|
|
@@ -3652,7 +3657,7 @@ function ConfirmDialog({ isOpen, options, handleConfirm, handleCancel, destructi
|
|
|
3652
3657
|
] }) });
|
|
3653
3658
|
}
|
|
3654
3659
|
function RegisterHotkeys({ hotkeys }) {
|
|
3655
|
-
|
|
3660
|
+
React35.useEffect(() => {
|
|
3656
3661
|
const handleKeyDown = (event) => {
|
|
3657
3662
|
for (const hotkey of hotkeys) {
|
|
3658
3663
|
const matches = event.key.toLowerCase() === hotkey.key.toLowerCase() && !!event.ctrlKey === !!hotkey.ctrl && !!event.metaKey === !!hotkey.meta && !!event.shiftKey === !!hotkey.shift && !!event.altKey === !!hotkey.alt;
|
|
@@ -3669,10 +3674,10 @@ function RegisterHotkeys({ hotkeys }) {
|
|
|
3669
3674
|
return null;
|
|
3670
3675
|
}
|
|
3671
3676
|
function useControlledOpen(defaultOpen = false) {
|
|
3672
|
-
const [isOpen, setIsOpen] =
|
|
3673
|
-
const open =
|
|
3674
|
-
const close =
|
|
3675
|
-
const toggle =
|
|
3677
|
+
const [isOpen, setIsOpen] = React35.useState(defaultOpen);
|
|
3678
|
+
const open = React35.useCallback(() => setIsOpen(true), []);
|
|
3679
|
+
const close = React35.useCallback(() => setIsOpen(false), []);
|
|
3680
|
+
const toggle = React35.useCallback(() => setIsOpen((prev) => !prev), []);
|
|
3676
3681
|
return { isOpen, open, close, toggle, setIsOpen };
|
|
3677
3682
|
}
|
|
3678
3683
|
function CommandMenu({
|
|
@@ -3685,7 +3690,7 @@ function CommandMenu({
|
|
|
3685
3690
|
}) {
|
|
3686
3691
|
const internal = useControlledOpen(false);
|
|
3687
3692
|
const isOpen = openProp ?? internal.isOpen;
|
|
3688
|
-
const setOpen =
|
|
3693
|
+
const setOpen = React35.useCallback(
|
|
3689
3694
|
(next) => {
|
|
3690
3695
|
if (openProp === void 0) internal.setIsOpen(next);
|
|
3691
3696
|
onOpenChange?.(next);
|
|
@@ -3710,7 +3715,7 @@ function CommandMenu({
|
|
|
3710
3715
|
/* @__PURE__ */ jsx(CommandInput, { placeholder }),
|
|
3711
3716
|
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
3712
3717
|
/* @__PURE__ */ jsx(CommandEmpty, { children: emptyMessage }),
|
|
3713
|
-
groups.map((group, i) => /* @__PURE__ */ jsxs(
|
|
3718
|
+
groups.map((group, i) => /* @__PURE__ */ jsxs(React35.Fragment, { children: [
|
|
3714
3719
|
i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
3715
3720
|
/* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
3716
3721
|
CommandItem,
|
|
@@ -3730,6 +3735,43 @@ function CommandMenu({
|
|
|
3730
3735
|
] })
|
|
3731
3736
|
] });
|
|
3732
3737
|
}
|
|
3738
|
+
function DataView({
|
|
3739
|
+
items,
|
|
3740
|
+
getRowId,
|
|
3741
|
+
renderCard,
|
|
3742
|
+
columns,
|
|
3743
|
+
view,
|
|
3744
|
+
ready = true,
|
|
3745
|
+
gridColumns = 3,
|
|
3746
|
+
gap = "sm",
|
|
3747
|
+
empty,
|
|
3748
|
+
placeholder = null,
|
|
3749
|
+
searchKey,
|
|
3750
|
+
searchPlaceholder,
|
|
3751
|
+
pageSize = 25,
|
|
3752
|
+
emptyMessage,
|
|
3753
|
+
onRowClick,
|
|
3754
|
+
className
|
|
3755
|
+
}) {
|
|
3756
|
+
if (!ready) return /* @__PURE__ */ jsx(Fragment, { children: placeholder });
|
|
3757
|
+
if (items.length === 0 && empty) return /* @__PURE__ */ jsx(Fragment, { children: empty });
|
|
3758
|
+
if (view === "list") {
|
|
3759
|
+
return /* @__PURE__ */ jsx(
|
|
3760
|
+
DataTable,
|
|
3761
|
+
{
|
|
3762
|
+
columns,
|
|
3763
|
+
data: items,
|
|
3764
|
+
searchKey,
|
|
3765
|
+
searchPlaceholder,
|
|
3766
|
+
pageSize,
|
|
3767
|
+
emptyMessage,
|
|
3768
|
+
onRowClick,
|
|
3769
|
+
className
|
|
3770
|
+
}
|
|
3771
|
+
);
|
|
3772
|
+
}
|
|
3773
|
+
return /* @__PURE__ */ jsx(AppGrid, { columns: gridColumns, gap, className: cn$1(className), children: items.map((item) => /* @__PURE__ */ jsx(React35.Fragment, { children: renderCard(item) }, getRowId(item))) });
|
|
3774
|
+
}
|
|
3733
3775
|
var TOKEN_COLORS = ["var(--chart-1)", "var(--chart-2)", "var(--chart-3)", "var(--chart-4)", "var(--chart-5)"];
|
|
3734
3776
|
var seriesColor = (s, i) => s.color ?? TOKEN_COLORS[i % TOKEN_COLORS.length];
|
|
3735
3777
|
function ChartTooltip({
|
|
@@ -3902,20 +3944,20 @@ function FileUpload({
|
|
|
3902
3944
|
hint,
|
|
3903
3945
|
className
|
|
3904
3946
|
}) {
|
|
3905
|
-
const [internalFiles, setInternalFiles] =
|
|
3906
|
-
const [isDragging, setIsDragging] =
|
|
3907
|
-
const [validationError, setValidationError] =
|
|
3908
|
-
const inputRef =
|
|
3909
|
-
const dragDepth =
|
|
3947
|
+
const [internalFiles, setInternalFiles] = React35.useState(defaultFiles ?? []);
|
|
3948
|
+
const [isDragging, setIsDragging] = React35.useState(false);
|
|
3949
|
+
const [validationError, setValidationError] = React35.useState(null);
|
|
3950
|
+
const inputRef = React35.useRef(null);
|
|
3951
|
+
const dragDepth = React35.useRef(0);
|
|
3910
3952
|
const files = filesProp ?? internalFiles;
|
|
3911
|
-
const setFiles =
|
|
3953
|
+
const setFiles = React35.useCallback(
|
|
3912
3954
|
(next) => {
|
|
3913
3955
|
if (!filesProp) setInternalFiles(next);
|
|
3914
3956
|
onFilesChange?.(next);
|
|
3915
3957
|
},
|
|
3916
3958
|
[filesProp, onFilesChange]
|
|
3917
3959
|
);
|
|
3918
|
-
const acceptList =
|
|
3960
|
+
const acceptList = React35.useMemo(
|
|
3919
3961
|
() => accept?.split(",").map((a) => a.trim().toLowerCase()).filter(Boolean) ?? [],
|
|
3920
3962
|
[accept]
|
|
3921
3963
|
);
|
|
@@ -4295,6 +4337,63 @@ function ImageCard({
|
|
|
4295
4337
|
}
|
|
4296
4338
|
);
|
|
4297
4339
|
}
|
|
4340
|
+
var bannerAspectClass = {
|
|
4341
|
+
wide: "aspect-[3/1]",
|
|
4342
|
+
video: "aspect-video",
|
|
4343
|
+
square: "aspect-square"
|
|
4344
|
+
};
|
|
4345
|
+
function MediaCard({
|
|
4346
|
+
banner,
|
|
4347
|
+
bannerAspect = "wide",
|
|
4348
|
+
footer,
|
|
4349
|
+
children,
|
|
4350
|
+
className,
|
|
4351
|
+
...props
|
|
4352
|
+
}) {
|
|
4353
|
+
return /* @__PURE__ */ jsxs(
|
|
4354
|
+
Card$1,
|
|
4355
|
+
{
|
|
4356
|
+
className: cn$1("flex h-full w-full flex-col overflow-hidden", banner && "pt-0", className),
|
|
4357
|
+
...props,
|
|
4358
|
+
children: [
|
|
4359
|
+
banner && /* @__PURE__ */ jsx("div", { className: cn$1("w-full shrink-0 overflow-hidden", bannerAspectClass[bannerAspect]), children: banner }),
|
|
4360
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-3 p-4", children: [
|
|
4361
|
+
children,
|
|
4362
|
+
footer && /* @__PURE__ */ jsx("div", { className: "mt-auto pt-1", children: footer })
|
|
4363
|
+
] })
|
|
4364
|
+
]
|
|
4365
|
+
}
|
|
4366
|
+
);
|
|
4367
|
+
}
|
|
4368
|
+
function ViewToggle({ view, onChange, labels, className, ...props }) {
|
|
4369
|
+
const options = [
|
|
4370
|
+
{ mode: "cards", label: labels?.cards ?? "Card view", Icon: LayoutGrid },
|
|
4371
|
+
{ mode: "list", label: labels?.list ?? "List view", Icon: List }
|
|
4372
|
+
];
|
|
4373
|
+
return /* @__PURE__ */ jsx(
|
|
4374
|
+
"div",
|
|
4375
|
+
{
|
|
4376
|
+
className: cn$1("inline-flex items-center rounded-md border p-0.5", className),
|
|
4377
|
+
role: "group",
|
|
4378
|
+
"aria-label": "View mode",
|
|
4379
|
+
...props,
|
|
4380
|
+
children: options.map(({ mode, label, Icon }) => /* @__PURE__ */ jsx(
|
|
4381
|
+
Button$1,
|
|
4382
|
+
{
|
|
4383
|
+
type: "button",
|
|
4384
|
+
size: "sm",
|
|
4385
|
+
variant: view === mode ? "secondary" : "ghost",
|
|
4386
|
+
className: "h-7 px-2",
|
|
4387
|
+
"aria-label": label,
|
|
4388
|
+
"aria-pressed": view === mode,
|
|
4389
|
+
onClick: () => onChange(mode),
|
|
4390
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "size-4" })
|
|
4391
|
+
},
|
|
4392
|
+
mode
|
|
4393
|
+
))
|
|
4394
|
+
}
|
|
4395
|
+
);
|
|
4396
|
+
}
|
|
4298
4397
|
var DASH_ON = "5px";
|
|
4299
4398
|
var DASH_OFF = "4px";
|
|
4300
4399
|
function FlowConnector({
|
|
@@ -4582,7 +4681,7 @@ function PageHeader({
|
|
|
4582
4681
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1 pb-6", className), children: [
|
|
4583
4682
|
breadcrumbs && breadcrumbs.length > 0 && /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: "mb-2 flex items-center gap-1 text-sm text-muted-foreground", children: breadcrumbs.map((crumb, i) => {
|
|
4584
4683
|
const isLast = i === breadcrumbs.length - 1;
|
|
4585
|
-
return /* @__PURE__ */ jsxs(
|
|
4684
|
+
return /* @__PURE__ */ jsxs(React35.Fragment, { children: [
|
|
4586
4685
|
i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0" }),
|
|
4587
4686
|
isLast || !crumb.href ? /* @__PURE__ */ jsx("span", { className: cn(isLast && "text-foreground font-medium"), children: crumb.label }) : renderLink({
|
|
4588
4687
|
href: crumb.href,
|
|
@@ -4618,7 +4717,7 @@ function PageHeader({
|
|
|
4618
4717
|
] });
|
|
4619
4718
|
}
|
|
4620
4719
|
function Suspensed({ children, fallback }) {
|
|
4621
|
-
return /* @__PURE__ */ jsx(
|
|
4720
|
+
return /* @__PURE__ */ jsx(React35.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
|
|
4622
4721
|
}
|
|
4623
4722
|
function getInitialTheme() {
|
|
4624
4723
|
if (typeof document === "undefined") return "dark";
|
|
@@ -4626,7 +4725,7 @@ function getInitialTheme() {
|
|
|
4626
4725
|
return stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
|
|
4627
4726
|
}
|
|
4628
4727
|
function ThemeSwitchMinimal() {
|
|
4629
|
-
const [theme, setThemeState] =
|
|
4728
|
+
const [theme, setThemeState] = React35.useState(getInitialTheme);
|
|
4630
4729
|
const toggle = () => {
|
|
4631
4730
|
const next = theme === "dark" ? "light" : "dark";
|
|
4632
4731
|
setThemeState(next);
|
|
@@ -4752,9 +4851,9 @@ function getInitialColorName() {
|
|
|
4752
4851
|
return localStorage.getItem(STORAGE_KEY) ?? "emerald";
|
|
4753
4852
|
}
|
|
4754
4853
|
function BrandColorSwitchMinimal() {
|
|
4755
|
-
const [active, setActive] =
|
|
4756
|
-
const [open, setOpen] =
|
|
4757
|
-
|
|
4854
|
+
const [active, setActive] = React35.useState(getInitialColorName);
|
|
4855
|
+
const [open, setOpen] = React35.useState(false);
|
|
4856
|
+
React35.useEffect(() => {
|
|
4758
4857
|
const saved = localStorage.getItem(STORAGE_KEY) ?? "emerald";
|
|
4759
4858
|
const color = BRAND_COLORS.find((c) => c.name === saved);
|
|
4760
4859
|
if (color) applyColor(color);
|
|
@@ -4815,7 +4914,7 @@ function BrandColorSwitchMinimal() {
|
|
|
4815
4914
|
] });
|
|
4816
4915
|
}
|
|
4817
4916
|
function ThemeColorUpdater({ colorTheme }) {
|
|
4818
|
-
|
|
4917
|
+
React35.useEffect(() => {
|
|
4819
4918
|
if (colorTheme) {
|
|
4820
4919
|
document.documentElement.setAttribute("data-theme", colorTheme);
|
|
4821
4920
|
} else {
|
|
@@ -4825,7 +4924,7 @@ function ThemeColorUpdater({ colorTheme }) {
|
|
|
4825
4924
|
return null;
|
|
4826
4925
|
}
|
|
4827
4926
|
function VersionBanner({ version, message, className, onDismiss }) {
|
|
4828
|
-
const [dismissed, setDismissed] =
|
|
4927
|
+
const [dismissed, setDismissed] = React35.useState(false);
|
|
4829
4928
|
if (dismissed) return null;
|
|
4830
4929
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-4 bg-primary/10 px-4 py-2 text-sm", className), children: [
|
|
4831
4930
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -5082,29 +5181,29 @@ function useMounted() {
|
|
|
5082
5181
|
return mounted;
|
|
5083
5182
|
}
|
|
5084
5183
|
function useConfirm() {
|
|
5085
|
-
const [isOpen, setIsOpen] =
|
|
5086
|
-
const [options, setOptions] =
|
|
5087
|
-
const resolveRef =
|
|
5088
|
-
const confirm =
|
|
5184
|
+
const [isOpen, setIsOpen] = React35.useState(false);
|
|
5185
|
+
const [options, setOptions] = React35.useState({});
|
|
5186
|
+
const resolveRef = React35.useRef(null);
|
|
5187
|
+
const confirm = React35.useCallback((opts = {}) => {
|
|
5089
5188
|
setOptions(opts);
|
|
5090
5189
|
setIsOpen(true);
|
|
5091
5190
|
return new Promise((resolve) => {
|
|
5092
5191
|
resolveRef.current = resolve;
|
|
5093
5192
|
});
|
|
5094
5193
|
}, []);
|
|
5095
|
-
const handleConfirm =
|
|
5194
|
+
const handleConfirm = React35.useCallback(() => {
|
|
5096
5195
|
resolveRef.current?.(true);
|
|
5097
5196
|
setIsOpen(false);
|
|
5098
5197
|
}, []);
|
|
5099
|
-
const handleCancel =
|
|
5198
|
+
const handleCancel = React35.useCallback(() => {
|
|
5100
5199
|
resolveRef.current?.(false);
|
|
5101
5200
|
setIsOpen(false);
|
|
5102
5201
|
}, []);
|
|
5103
5202
|
return { confirm, isOpen, options, handleConfirm, handleCancel };
|
|
5104
5203
|
}
|
|
5105
5204
|
function useScrolledPast(threshold) {
|
|
5106
|
-
const [scrolledPast, setScrolledPast] =
|
|
5107
|
-
|
|
5205
|
+
const [scrolledPast, setScrolledPast] = React35.useState(false);
|
|
5206
|
+
React35.useEffect(() => {
|
|
5108
5207
|
const handleScroll = () => {
|
|
5109
5208
|
setScrolledPast(window.scrollY > threshold);
|
|
5110
5209
|
};
|
|
@@ -5115,28 +5214,28 @@ function useScrolledPast(threshold) {
|
|
|
5115
5214
|
return scrolledPast;
|
|
5116
5215
|
}
|
|
5117
5216
|
function useCopyToClipboard() {
|
|
5118
|
-
const [copied, setCopied] =
|
|
5119
|
-
const timeoutRef =
|
|
5120
|
-
const copy =
|
|
5217
|
+
const [copied, setCopied] = React35.useState(false);
|
|
5218
|
+
const timeoutRef = React35.useRef(void 0);
|
|
5219
|
+
const copy = React35.useCallback((text) => {
|
|
5121
5220
|
navigator.clipboard.writeText(text).then(() => {
|
|
5122
5221
|
setCopied(true);
|
|
5123
5222
|
clearTimeout(timeoutRef.current);
|
|
5124
5223
|
timeoutRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
5125
5224
|
});
|
|
5126
5225
|
}, []);
|
|
5127
|
-
|
|
5226
|
+
React35.useEffect(() => () => clearTimeout(timeoutRef.current), []);
|
|
5128
5227
|
return [copied, copy];
|
|
5129
5228
|
}
|
|
5130
5229
|
function useDebounce(value, delay) {
|
|
5131
|
-
const [debounced, setDebounced] =
|
|
5132
|
-
|
|
5230
|
+
const [debounced, setDebounced] = React35.useState(value);
|
|
5231
|
+
React35.useEffect(() => {
|
|
5133
5232
|
const timer = setTimeout(() => setDebounced(value), delay);
|
|
5134
5233
|
return () => clearTimeout(timer);
|
|
5135
5234
|
}, [value, delay]);
|
|
5136
5235
|
return debounced;
|
|
5137
5236
|
}
|
|
5138
5237
|
function useLocalStorage(key, initialValue) {
|
|
5139
|
-
const [storedValue, setStoredValue] =
|
|
5238
|
+
const [storedValue, setStoredValue] = React35.useState(() => {
|
|
5140
5239
|
if (typeof window === "undefined") return initialValue;
|
|
5141
5240
|
try {
|
|
5142
5241
|
const item = window.localStorage.getItem(key);
|
|
@@ -5145,7 +5244,7 @@ function useLocalStorage(key, initialValue) {
|
|
|
5145
5244
|
return initialValue;
|
|
5146
5245
|
}
|
|
5147
5246
|
});
|
|
5148
|
-
const setValue =
|
|
5247
|
+
const setValue = React35.useCallback(
|
|
5149
5248
|
(value) => {
|
|
5150
5249
|
try {
|
|
5151
5250
|
setStoredValue(value);
|
|
@@ -5159,12 +5258,19 @@ function useLocalStorage(key, initialValue) {
|
|
|
5159
5258
|
);
|
|
5160
5259
|
return [storedValue, setValue];
|
|
5161
5260
|
}
|
|
5261
|
+
|
|
5262
|
+
// src/hooks/use-view-mode.ts
|
|
5263
|
+
function useViewMode(key = "view-mode", fallback = "cards") {
|
|
5264
|
+
const [stored, setStored] = useLocalStorage(key, fallback);
|
|
5265
|
+
const mounted = useMounted();
|
|
5266
|
+
return { view: mounted ? stored : fallback, setView: setStored, ready: mounted };
|
|
5267
|
+
}
|
|
5162
5268
|
function useMediaQuery(query) {
|
|
5163
|
-
const [matches, setMatches] =
|
|
5269
|
+
const [matches, setMatches] = React35.useState(() => {
|
|
5164
5270
|
if (typeof window === "undefined") return false;
|
|
5165
5271
|
return window.matchMedia(query).matches;
|
|
5166
5272
|
});
|
|
5167
|
-
|
|
5273
|
+
React35.useEffect(() => {
|
|
5168
5274
|
if (typeof window === "undefined") return;
|
|
5169
5275
|
const mql = window.matchMedia(query);
|
|
5170
5276
|
setMatches(mql.matches);
|
|
@@ -5175,18 +5281,18 @@ function useMediaQuery(query) {
|
|
|
5175
5281
|
return matches;
|
|
5176
5282
|
}
|
|
5177
5283
|
function usePagination(total, pageSize) {
|
|
5178
|
-
const [page, setPage] =
|
|
5284
|
+
const [page, setPage] = React35.useState(1);
|
|
5179
5285
|
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
5180
5286
|
const offset = (page - 1) * pageSize;
|
|
5181
|
-
const goTo =
|
|
5287
|
+
const goTo = React35.useCallback(
|
|
5182
5288
|
(p) => setPage(Math.min(Math.max(1, p), totalPages)),
|
|
5183
5289
|
[totalPages]
|
|
5184
5290
|
);
|
|
5185
|
-
const next =
|
|
5186
|
-
const prev =
|
|
5291
|
+
const next = React35.useCallback(() => goTo(page + 1), [page, goTo]);
|
|
5292
|
+
const prev = React35.useCallback(() => goTo(page - 1), [page, goTo]);
|
|
5187
5293
|
return { page, pageSize, totalPages, offset, hasPrev: page > 1, hasNext: page < totalPages, goTo, next, prev };
|
|
5188
5294
|
}
|
|
5189
5295
|
|
|
5190
|
-
export { ActivityFeed, AnimatedPill, AppContent, AppGrid, AppGridCell, AppScreen, AppShell, AuthSection, Badge, BillingPanel, BrandColorSwitchMinimal, Button, Card, Carousel, ChangelogCard, ChangelogList, Chart, Checkbox, CommandMenu, ComparisonSection, ConfirmDialog, ContactSection, ContextMenu, CountUp, CountdownTimer, CtaSection, DataTable, DevBanner, Dock, EmptyState, ErrorPage, FadeIn, FaqSection, FeatureCard, FeatureMarqueeSection, FeaturesSection, FileUpload, FlowBracket, FlowConnector, Footer, FullPageSpinner, GlassCard, Grid, GridItem, GroupedFeaturesSection, HeroSection, ImageCard, Input, LogoStrip, ModeSwitchMinimal, Navbar, NewsletterSection, NotificationToast, NotificationsPopover, OlwibaUIProvider, OnboardingWizard, Overlay, PageHeader, PageTransition, PhoneFrame, PostCard, PostList, PricingCard, PricingSection, PublicPageFrame, QualificationSection, RegisterHotkeys, RootErrorFallback, Section, SectionTitle, SettingsSection, Sortable, Spotlight, Stack, StaggerChildren, StatCard, StatsSection, StepsSection, Suspensed, Switch, TeamMembersPanel, TeamSection, TechStackSection, TestimonialCard, TestimonialsSection, Textarea, ThemeColorUpdater, ThemeSwitchMinimal, Underlay, UpdateBanner, UpgradePrompt, VersionBanner, marketingSectionSpacing, notify, useConfirm, useControlledOpen, useCopyToClipboard, useDebounce, useIntersectionObserver, useLocalStorage, useMediaQuery, useMounted, useOlwibaUI, usePagination, useScrolledPast, useUIMode };
|
|
5296
|
+
export { ActivityFeed, AnimatedPill, AppContent, AppGrid, AppGridCell, AppScreen, AppShell, AuthSection, Badge, BillingPanel, BrandColorSwitchMinimal, Button, Card, Carousel, ChangelogCard, ChangelogList, Chart, Checkbox, CommandMenu, ComparisonSection, ConfirmDialog, ContactSection, ContextMenu, CountUp, CountdownTimer, CtaSection, DataTable, DataView, DevBanner, Dock, EmptyState, ErrorPage, FadeIn, FaqSection, FeatureCard, FeatureMarqueeSection, FeaturesSection, FileUpload, FlowBracket, FlowConnector, Footer, FullPageSpinner, GlassCard, Grid, GridItem, GroupedFeaturesSection, HeroSection, ImageCard, Input, LogoStrip, MediaCard, ModeSwitchMinimal, Navbar, NewsletterSection, NotificationToast, NotificationsPopover, OlwibaUIProvider, OnboardingWizard, Overlay, PageHeader, PageTransition, PhoneFrame, PostCard, PostList, PricingCard, PricingSection, PublicPageFrame, QualificationSection, RegisterHotkeys, RootErrorFallback, Section, SectionTitle, SettingsSection, Sortable, Spotlight, Stack, StaggerChildren, StatCard, StatsSection, StepsSection, Suspensed, Switch, TeamMembersPanel, TeamSection, TechStackSection, TestimonialCard, TestimonialsSection, Textarea, ThemeColorUpdater, ThemeSwitchMinimal, Underlay, UpdateBanner, UpgradePrompt, VersionBanner, ViewToggle, marketingSectionSpacing, notify, useConfirm, useControlledOpen, useCopyToClipboard, useDebounce, useIntersectionObserver, useLocalStorage, useMediaQuery, useMounted, useOlwibaUI, usePagination, useScrolledPast, useUIMode, useViewMode };
|
|
5191
5297
|
//# sourceMappingURL=index.js.map
|
|
5192
5298
|
//# sourceMappingURL=index.js.map
|