@olwiba/ui 0.2.6 → 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 +145 -2
- package/dist/index.js +238 -133
- package/dist/index.js.map +1 -1
- package/package.json +1 -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
|
};
|
|
@@ -531,7 +534,7 @@ function DefaultForm({
|
|
|
531
534
|
const isForgotPassword = mode === "forgot-password";
|
|
532
535
|
const isResetPassword = mode === "reset-password";
|
|
533
536
|
const isVerify = mode === "verify";
|
|
534
|
-
const [code, setCode] =
|
|
537
|
+
const [code, setCode] = React35.useState("");
|
|
535
538
|
const hasPrefill = !!(defaultEmail || defaultPassword);
|
|
536
539
|
const prefillStyle = (active) => active ? { animation: "auth-prefill 1.6s ease-out 0.35s 1 both" } : void 0;
|
|
537
540
|
const copy = authCopy[mode];
|
|
@@ -691,10 +694,10 @@ function DataTable({
|
|
|
691
694
|
emptyMessage = "No results.",
|
|
692
695
|
className
|
|
693
696
|
}) {
|
|
694
|
-
const [sorting, setSorting] =
|
|
695
|
-
const [rowSelection, setRowSelection] =
|
|
696
|
-
const [globalFilter, setGlobalFilter] =
|
|
697
|
-
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(
|
|
698
701
|
() => selectable ? [selectColumn, ...columns] : columns,
|
|
699
702
|
[selectable, columns]
|
|
700
703
|
);
|
|
@@ -716,7 +719,7 @@ function DataTable({
|
|
|
716
719
|
initialState: pageSize > 0 ? { pagination: { pageSize } } : void 0,
|
|
717
720
|
enableRowSelection: selectable
|
|
718
721
|
});
|
|
719
|
-
|
|
722
|
+
React35.useEffect(() => {
|
|
720
723
|
if (!onSelectionChange) return;
|
|
721
724
|
onSelectionChange(table.getSelectedRowModel().rows.map((r) => r.original));
|
|
722
725
|
}, [rowSelection]);
|
|
@@ -796,8 +799,8 @@ function DataTable({
|
|
|
796
799
|
] });
|
|
797
800
|
}
|
|
798
801
|
function InviteDialog({ roles, onInvite, onClose }) {
|
|
799
|
-
const [email, setEmail] =
|
|
800
|
-
const [role, setRole] =
|
|
802
|
+
const [email, setEmail] = React35.useState("");
|
|
803
|
+
const [role, setRole] = React35.useState(roles[roles.length - 1] ?? roles[0]);
|
|
801
804
|
return /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsxs(
|
|
802
805
|
"form",
|
|
803
806
|
{
|
|
@@ -841,8 +844,8 @@ function TeamMembersPanel({
|
|
|
841
844
|
title = "Team members",
|
|
842
845
|
description = "Manage who has access to this workspace."
|
|
843
846
|
}) {
|
|
844
|
-
const [inviteOpen, setInviteOpen] =
|
|
845
|
-
const columns =
|
|
847
|
+
const [inviteOpen, setInviteOpen] = React35.useState(false);
|
|
848
|
+
const columns = React35.useMemo(() => [
|
|
846
849
|
{
|
|
847
850
|
accessorKey: "name",
|
|
848
851
|
header: "Name",
|
|
@@ -911,7 +914,7 @@ function BillingPanel({
|
|
|
911
914
|
onUpdatePaymentMethod,
|
|
912
915
|
className
|
|
913
916
|
}) {
|
|
914
|
-
const invoiceColumns =
|
|
917
|
+
const invoiceColumns = React35.useMemo(() => [
|
|
915
918
|
{ accessorKey: "date", header: "Date", enableSorting: false },
|
|
916
919
|
{ accessorKey: "amount", header: "Amount", enableSorting: false },
|
|
917
920
|
{
|
|
@@ -990,9 +993,9 @@ function OnboardingWizard({
|
|
|
990
993
|
completeLabel = "Finish",
|
|
991
994
|
className
|
|
992
995
|
}) {
|
|
993
|
-
const [internalStep, setInternalStep] =
|
|
994
|
-
const [error, setError] =
|
|
995
|
-
const [pending, setPending] =
|
|
996
|
+
const [internalStep, setInternalStep] = React35.useState(0);
|
|
997
|
+
const [error, setError] = React35.useState(null);
|
|
998
|
+
const [pending, setPending] = React35.useState(false);
|
|
996
999
|
const index = stepProp ?? internalStep;
|
|
997
1000
|
const current = steps[index];
|
|
998
1001
|
const isLast = index === steps.length - 1;
|
|
@@ -1322,10 +1325,10 @@ function UpdateBanner({
|
|
|
1322
1325
|
buttonLabel = "Refresh now",
|
|
1323
1326
|
className
|
|
1324
1327
|
}) {
|
|
1325
|
-
const [show, setShow] =
|
|
1326
|
-
const [entered, setEntered] =
|
|
1327
|
-
const [refreshing, setRefreshing] =
|
|
1328
|
-
|
|
1328
|
+
const [show, setShow] = React35.useState(forceShow);
|
|
1329
|
+
const [entered, setEntered] = React35.useState(false);
|
|
1330
|
+
const [refreshing, setRefreshing] = React35.useState(false);
|
|
1331
|
+
React35.useEffect(() => {
|
|
1329
1332
|
if (forceShow) {
|
|
1330
1333
|
setShow(true);
|
|
1331
1334
|
return;
|
|
@@ -1348,7 +1351,7 @@ function UpdateBanner({
|
|
|
1348
1351
|
clearInterval(id);
|
|
1349
1352
|
};
|
|
1350
1353
|
}, [currentVersion, fetchVersion, forceShow, intervalMs]);
|
|
1351
|
-
|
|
1354
|
+
React35.useEffect(() => {
|
|
1352
1355
|
if (!show) {
|
|
1353
1356
|
setEntered(false);
|
|
1354
1357
|
return;
|
|
@@ -1421,9 +1424,9 @@ function FadeIn({
|
|
|
1421
1424
|
style,
|
|
1422
1425
|
...props
|
|
1423
1426
|
}) {
|
|
1424
|
-
const ref =
|
|
1425
|
-
const [visible, setVisible] =
|
|
1426
|
-
|
|
1427
|
+
const ref = React35.useRef(null);
|
|
1428
|
+
const [visible, setVisible] = React35.useState(false);
|
|
1429
|
+
React35.useEffect(() => {
|
|
1427
1430
|
const el = ref.current;
|
|
1428
1431
|
if (!el) return;
|
|
1429
1432
|
const observer = new IntersectionObserver(
|
|
@@ -1618,16 +1621,16 @@ function Carousel({
|
|
|
1618
1621
|
className
|
|
1619
1622
|
}) {
|
|
1620
1623
|
const mode = useUIVariant();
|
|
1621
|
-
const trackRef =
|
|
1622
|
-
const [canPrev, setCanPrev] =
|
|
1623
|
-
const [canNext, setCanNext] =
|
|
1624
|
-
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(() => {
|
|
1625
1628
|
const track = trackRef.current;
|
|
1626
1629
|
if (!track) return;
|
|
1627
1630
|
setCanPrev(track.scrollLeft > 8);
|
|
1628
1631
|
setCanNext(track.scrollLeft < track.scrollWidth - track.clientWidth - 8);
|
|
1629
1632
|
}, []);
|
|
1630
|
-
|
|
1633
|
+
React35.useEffect(() => {
|
|
1631
1634
|
const track = trackRef.current;
|
|
1632
1635
|
if (!track) return;
|
|
1633
1636
|
updateScrollState();
|
|
@@ -1684,7 +1687,7 @@ function Carousel({
|
|
|
1684
1687
|
role: "region",
|
|
1685
1688
|
"aria-label": ariaLabel,
|
|
1686
1689
|
className: "flex snap-x snap-mandatory gap-6 overflow-x-auto pb-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
1687
|
-
children:
|
|
1690
|
+
children: React35.Children.map(
|
|
1688
1691
|
children,
|
|
1689
1692
|
(child) => child == null ? null : /* @__PURE__ */ jsx("div", { "data-carousel-item": true, className: cn$1("shrink-0 snap-start", itemClassName), children: child })
|
|
1690
1693
|
)
|
|
@@ -1709,9 +1712,9 @@ function StaggerChildren({
|
|
|
1709
1712
|
className,
|
|
1710
1713
|
...props
|
|
1711
1714
|
}) {
|
|
1712
|
-
const ref =
|
|
1713
|
-
const [visible, setVisible] =
|
|
1714
|
-
|
|
1715
|
+
const ref = React35.useRef(null);
|
|
1716
|
+
const [visible, setVisible] = React35.useState(false);
|
|
1717
|
+
React35.useEffect(() => {
|
|
1715
1718
|
const el = ref.current;
|
|
1716
1719
|
if (!el) return;
|
|
1717
1720
|
const observer = new IntersectionObserver(
|
|
@@ -1729,7 +1732,7 @@ function StaggerChildren({
|
|
|
1729
1732
|
return () => observer.disconnect();
|
|
1730
1733
|
}, [once]);
|
|
1731
1734
|
const [tx, ty] = translateMap2[direction];
|
|
1732
|
-
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(
|
|
1733
1736
|
"div",
|
|
1734
1737
|
{
|
|
1735
1738
|
className: "h-full",
|
|
@@ -1871,7 +1874,7 @@ function StepsSection({
|
|
|
1871
1874
|
/* @__PURE__ */ jsx("div", { className: "mt-12", children: resolvedGroups.map((group, groupIndex) => {
|
|
1872
1875
|
const startNumber = nextNumber;
|
|
1873
1876
|
nextNumber += group.steps.length;
|
|
1874
|
-
return /* @__PURE__ */ jsxs(
|
|
1877
|
+
return /* @__PURE__ */ jsxs(React35.Fragment, { children: [
|
|
1875
1878
|
/* @__PURE__ */ jsx("div", { className: cn$1(groupIndex > 0 && "mt-10"), children: /* @__PURE__ */ jsx(TimelineGroup, { steps: group.steps, startNumber, fadeIn: groupIndex > 0 }) }),
|
|
1876
1879
|
group.after && /* @__PURE__ */ jsx("div", { className: "mt-16", children: group.after })
|
|
1877
1880
|
] }, groupIndex);
|
|
@@ -2041,9 +2044,9 @@ function FeatureMarqueeSection({
|
|
|
2041
2044
|
] });
|
|
2042
2045
|
}
|
|
2043
2046
|
function useIntersectionObserver(options) {
|
|
2044
|
-
const ref =
|
|
2045
|
-
const [isIntersecting, setIsIntersecting] =
|
|
2046
|
-
|
|
2047
|
+
const ref = React35.useRef(null);
|
|
2048
|
+
const [isIntersecting, setIsIntersecting] = React35.useState(false);
|
|
2049
|
+
React35.useEffect(() => {
|
|
2047
2050
|
const el = ref.current;
|
|
2048
2051
|
if (!el) return;
|
|
2049
2052
|
const observer = new IntersectionObserver(([entry]) => {
|
|
@@ -2065,8 +2068,8 @@ function ShowcaseCta({
|
|
|
2065
2068
|
sectionClasses
|
|
2066
2069
|
}) {
|
|
2067
2070
|
const [ref, intersecting] = useIntersectionObserver({ threshold: 0.15 });
|
|
2068
|
-
const [visible, setVisible] =
|
|
2069
|
-
|
|
2071
|
+
const [visible, setVisible] = React35.useState(false);
|
|
2072
|
+
React35.useEffect(() => {
|
|
2070
2073
|
if (intersecting) setVisible(true);
|
|
2071
2074
|
}, [intersecting]);
|
|
2072
2075
|
return /* @__PURE__ */ jsxs(
|
|
@@ -2243,8 +2246,8 @@ function CountdownTimer({
|
|
|
2243
2246
|
className,
|
|
2244
2247
|
compact = false
|
|
2245
2248
|
}) {
|
|
2246
|
-
const [timeLeft, setTimeLeft] =
|
|
2247
|
-
|
|
2249
|
+
const [timeLeft, setTimeLeft] = React35.useState(() => getTimeLeft(deadline));
|
|
2250
|
+
React35.useEffect(() => {
|
|
2248
2251
|
setTimeLeft(getTimeLeft(deadline));
|
|
2249
2252
|
const id = setInterval(() => setTimeLeft(getTimeLeft(deadline)), 1e3);
|
|
2250
2253
|
return () => clearInterval(id);
|
|
@@ -2270,7 +2273,7 @@ function CountdownTimer({
|
|
|
2270
2273
|
];
|
|
2271
2274
|
return /* @__PURE__ */ jsxs("div", { className: cn$1("flex items-center justify-center gap-2 text-sm", className), children: [
|
|
2272
2275
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
|
|
2273
|
-
/* @__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: [
|
|
2274
2277
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
2275
2278
|
String(value).padStart(2, "0"),
|
|
2276
2279
|
/* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: unit })
|
|
@@ -2295,7 +2298,7 @@ function PricingSection({
|
|
|
2295
2298
|
highlightedBadgeLabel = "Founding member",
|
|
2296
2299
|
renderPlanFooter
|
|
2297
2300
|
}) {
|
|
2298
|
-
const [annual, setAnnual] =
|
|
2301
|
+
const [annual, setAnnual] = React35.useState(false);
|
|
2299
2302
|
const isOneTime = mode === "one-time";
|
|
2300
2303
|
const uiMode = useUIVariant();
|
|
2301
2304
|
const sectionClasses = cn$1(
|
|
@@ -2564,10 +2567,10 @@ function CountUp({
|
|
|
2564
2567
|
className,
|
|
2565
2568
|
...props
|
|
2566
2569
|
}) {
|
|
2567
|
-
const ref =
|
|
2568
|
-
const [value, setValue] =
|
|
2569
|
-
const hasStarted =
|
|
2570
|
-
|
|
2570
|
+
const ref = React35.useRef(null);
|
|
2571
|
+
const [value, setValue] = React35.useState(from);
|
|
2572
|
+
const hasStarted = React35.useRef(false);
|
|
2573
|
+
React35.useEffect(() => {
|
|
2571
2574
|
const el = ref.current;
|
|
2572
2575
|
if (!el) return;
|
|
2573
2576
|
const observer = new IntersectionObserver(
|
|
@@ -2660,8 +2663,8 @@ function NewsletterSection({
|
|
|
2660
2663
|
successDescription = defaults.successDescription,
|
|
2661
2664
|
onSubscribe
|
|
2662
2665
|
} = {}) {
|
|
2663
|
-
const [email, setEmail] =
|
|
2664
|
-
const [submitted, setSubmitted] =
|
|
2666
|
+
const [email, setEmail] = React35.useState("");
|
|
2667
|
+
const [submitted, setSubmitted] = React35.useState(false);
|
|
2665
2668
|
const mode = useUIVariant();
|
|
2666
2669
|
const sectionClasses = cn$1(
|
|
2667
2670
|
"overflow-hidden bg-card",
|
|
@@ -2752,7 +2755,7 @@ function ContactSection({
|
|
|
2752
2755
|
sendAnotherLabel = defaults2.sendAnotherLabel,
|
|
2753
2756
|
onSubmit
|
|
2754
2757
|
} = {}) {
|
|
2755
|
-
const [submitted, setSubmitted] =
|
|
2758
|
+
const [submitted, setSubmitted] = React35.useState(false);
|
|
2756
2759
|
const mode = useUIVariant();
|
|
2757
2760
|
const sectionClasses = cn$1(
|
|
2758
2761
|
"overflow-hidden bg-card",
|
|
@@ -3050,9 +3053,10 @@ function Navbar({
|
|
|
3050
3053
|
controls,
|
|
3051
3054
|
renderLink = defaultRenderLink7
|
|
3052
3055
|
}) {
|
|
3053
|
-
const [open, setOpen] =
|
|
3056
|
+
const [open, setOpen] = React35.useState(false);
|
|
3054
3057
|
const brandHref = brand.href ?? "/";
|
|
3055
3058
|
const hasRightContent = controls?.length || cta?.primary || cta?.secondary;
|
|
3059
|
+
const closeMobileMenu = React35.useCallback(() => setOpen(false), []);
|
|
3056
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: [
|
|
3057
3061
|
renderLink({
|
|
3058
3062
|
href: brandHref,
|
|
@@ -3067,7 +3071,7 @@ function Navbar({
|
|
|
3067
3071
|
children: link.label
|
|
3068
3072
|
}) }, link.label)) }),
|
|
3069
3073
|
hasRightContent && /* @__PURE__ */ jsxs("div", { className: "hidden items-center justify-end gap-2 md:flex", children: [
|
|
3070
|
-
controls?.map((control, i) => /* @__PURE__ */ jsx(
|
|
3074
|
+
controls?.map((control, i) => /* @__PURE__ */ jsx(React35.Fragment, { children: control }, i)),
|
|
3071
3075
|
(cta?.secondary || cta?.primary) && controls?.length ? /* @__PURE__ */ jsx("div", { className: "mx-1 h-4 w-px bg-border" }) : null,
|
|
3072
3076
|
cta?.secondary && renderLink({
|
|
3073
3077
|
href: cta.secondary.href,
|
|
@@ -3084,29 +3088,29 @@ function Navbar({
|
|
|
3084
3088
|
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Open menu" })
|
|
3085
3089
|
] }) }),
|
|
3086
3090
|
/* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "w-72", children: [
|
|
3087
|
-
/* @__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({
|
|
3088
3092
|
href: brandHref,
|
|
3089
3093
|
children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 font-semibold", children: [
|
|
3090
3094
|
brand.logo,
|
|
3091
3095
|
/* @__PURE__ */ jsx("span", { children: brand.name })
|
|
3092
3096
|
] })
|
|
3093
3097
|
}) }) }),
|
|
3094
|
-
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,
|
|
3095
3099
|
/* @__PURE__ */ jsx(Separator, {}),
|
|
3096
|
-
/* @__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({
|
|
3097
3101
|
href: link.href,
|
|
3098
3102
|
className: "block rounded-md px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
|
|
3099
3103
|
children: link.label
|
|
3100
3104
|
}) }, link.label)) }),
|
|
3101
3105
|
/* @__PURE__ */ jsxs("div", { className: "mt-6 flex flex-col gap-2", children: [
|
|
3102
|
-
cta?.secondary && renderLink({
|
|
3106
|
+
cta?.secondary && /* @__PURE__ */ jsx("span", { onClickCapture: closeMobileMenu, children: renderLink({
|
|
3103
3107
|
href: cta.secondary.href,
|
|
3104
3108
|
children: /* @__PURE__ */ jsx(Button$1, { variant: "outline", className: "w-full", children: cta.secondary.label })
|
|
3105
|
-
}),
|
|
3106
|
-
cta?.primary && renderLink({
|
|
3109
|
+
}) }),
|
|
3110
|
+
cta?.primary && /* @__PURE__ */ jsx("span", { onClickCapture: closeMobileMenu, children: renderLink({
|
|
3107
3111
|
href: cta.primary.href,
|
|
3108
3112
|
children: /* @__PURE__ */ jsx(Button$1, { className: "w-full", children: cta.primary.label })
|
|
3109
|
-
})
|
|
3113
|
+
}) })
|
|
3110
3114
|
] })
|
|
3111
3115
|
] })
|
|
3112
3116
|
] })
|
|
@@ -3240,7 +3244,7 @@ function LogoStrip({
|
|
|
3240
3244
|
] });
|
|
3241
3245
|
}
|
|
3242
3246
|
function GridUnderlay({ variant, size = 24, className, ...props }) {
|
|
3243
|
-
const id =
|
|
3247
|
+
const id = React35.useId();
|
|
3244
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: [
|
|
3245
3249
|
/* @__PURE__ */ jsx("line", { x1: size / 2, y1: 0, x2: size / 2, y2: size, stroke: "currentColor", strokeWidth: 0.5 }),
|
|
3246
3250
|
/* @__PURE__ */ jsx("line", { x1: 0, y1: size / 2, x2: size, y2: size / 2, stroke: "currentColor", strokeWidth: 0.5 })
|
|
@@ -3268,9 +3272,9 @@ function GlowUnderlay({
|
|
|
3268
3272
|
style,
|
|
3269
3273
|
...props
|
|
3270
3274
|
}) {
|
|
3271
|
-
const [pos, setPos] =
|
|
3272
|
-
const containerRef =
|
|
3273
|
-
|
|
3275
|
+
const [pos, setPos] = React35.useState({ x: "50%", y: "50%" });
|
|
3276
|
+
const containerRef = React35.useRef(null);
|
|
3277
|
+
React35.useEffect(() => {
|
|
3274
3278
|
if (!followCursor) return;
|
|
3275
3279
|
const handleMouseMove = (e) => {
|
|
3276
3280
|
const el = containerRef.current;
|
|
@@ -3409,8 +3413,8 @@ function PageTransition({
|
|
|
3409
3413
|
style,
|
|
3410
3414
|
...props
|
|
3411
3415
|
}) {
|
|
3412
|
-
const [mounted, setMounted] =
|
|
3413
|
-
|
|
3416
|
+
const [mounted, setMounted] = React35.useState(false);
|
|
3417
|
+
React35.useEffect(() => {
|
|
3414
3418
|
const id = requestAnimationFrame(() => setMounted(true));
|
|
3415
3419
|
return () => cancelAnimationFrame(id);
|
|
3416
3420
|
}, []);
|
|
@@ -3485,7 +3489,7 @@ function Sortable({
|
|
|
3485
3489
|
if (oldIndex === -1 || newIndex === -1) return;
|
|
3486
3490
|
onReorder(arrayMove(items, oldIndex, newIndex));
|
|
3487
3491
|
};
|
|
3488
|
-
const childArray =
|
|
3492
|
+
const childArray = React35.Children.toArray(children);
|
|
3489
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(
|
|
3490
3494
|
(child, i) => items[i] === void 0 ? null : /* @__PURE__ */ jsx(SortableItem, { id: items[i], disabled, className: itemClassName, children: child }, items[i])
|
|
3491
3495
|
) }) }) });
|
|
@@ -3497,8 +3501,8 @@ function Spotlight({
|
|
|
3497
3501
|
triggerClassName,
|
|
3498
3502
|
shortcut = "\u2318K"
|
|
3499
3503
|
}) {
|
|
3500
|
-
const [open, setOpen] =
|
|
3501
|
-
|
|
3504
|
+
const [open, setOpen] = React35.useState(false);
|
|
3505
|
+
React35.useEffect(() => {
|
|
3502
3506
|
const down = (e) => {
|
|
3503
3507
|
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
|
3504
3508
|
e.preventDefault();
|
|
@@ -3528,7 +3532,7 @@ function Spotlight({
|
|
|
3528
3532
|
/* @__PURE__ */ jsx(CommandInput, { placeholder }),
|
|
3529
3533
|
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
3530
3534
|
/* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
|
|
3531
|
-
groups.map((group, i) => /* @__PURE__ */ jsxs(
|
|
3535
|
+
groups.map((group, i) => /* @__PURE__ */ jsxs(React35.Fragment, { children: [
|
|
3532
3536
|
i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
3533
3537
|
/* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
3534
3538
|
CommandItem,
|
|
@@ -3553,8 +3557,8 @@ function Spotlight({
|
|
|
3553
3557
|
var BASE = 40;
|
|
3554
3558
|
var MAGNIFY_RADIUS = 80;
|
|
3555
3559
|
function Dock({ items, iconSize = BASE, magnification = 1.7, className, ...props }) {
|
|
3556
|
-
const [mouseX, setMouseX] =
|
|
3557
|
-
const containerRef =
|
|
3560
|
+
const [mouseX, setMouseX] = React35.useState(null);
|
|
3561
|
+
const containerRef = React35.useRef(null);
|
|
3558
3562
|
function getScale(index) {
|
|
3559
3563
|
if (mouseX === null || !containerRef.current) return 1;
|
|
3560
3564
|
const container = containerRef.current;
|
|
@@ -3653,7 +3657,7 @@ function ConfirmDialog({ isOpen, options, handleConfirm, handleCancel, destructi
|
|
|
3653
3657
|
] }) });
|
|
3654
3658
|
}
|
|
3655
3659
|
function RegisterHotkeys({ hotkeys }) {
|
|
3656
|
-
|
|
3660
|
+
React35.useEffect(() => {
|
|
3657
3661
|
const handleKeyDown = (event) => {
|
|
3658
3662
|
for (const hotkey of hotkeys) {
|
|
3659
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;
|
|
@@ -3670,10 +3674,10 @@ function RegisterHotkeys({ hotkeys }) {
|
|
|
3670
3674
|
return null;
|
|
3671
3675
|
}
|
|
3672
3676
|
function useControlledOpen(defaultOpen = false) {
|
|
3673
|
-
const [isOpen, setIsOpen] =
|
|
3674
|
-
const open =
|
|
3675
|
-
const close =
|
|
3676
|
-
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), []);
|
|
3677
3681
|
return { isOpen, open, close, toggle, setIsOpen };
|
|
3678
3682
|
}
|
|
3679
3683
|
function CommandMenu({
|
|
@@ -3686,7 +3690,7 @@ function CommandMenu({
|
|
|
3686
3690
|
}) {
|
|
3687
3691
|
const internal = useControlledOpen(false);
|
|
3688
3692
|
const isOpen = openProp ?? internal.isOpen;
|
|
3689
|
-
const setOpen =
|
|
3693
|
+
const setOpen = React35.useCallback(
|
|
3690
3694
|
(next) => {
|
|
3691
3695
|
if (openProp === void 0) internal.setIsOpen(next);
|
|
3692
3696
|
onOpenChange?.(next);
|
|
@@ -3711,7 +3715,7 @@ function CommandMenu({
|
|
|
3711
3715
|
/* @__PURE__ */ jsx(CommandInput, { placeholder }),
|
|
3712
3716
|
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
3713
3717
|
/* @__PURE__ */ jsx(CommandEmpty, { children: emptyMessage }),
|
|
3714
|
-
groups.map((group, i) => /* @__PURE__ */ jsxs(
|
|
3718
|
+
groups.map((group, i) => /* @__PURE__ */ jsxs(React35.Fragment, { children: [
|
|
3715
3719
|
i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
3716
3720
|
/* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
3717
3721
|
CommandItem,
|
|
@@ -3731,6 +3735,43 @@ function CommandMenu({
|
|
|
3731
3735
|
] })
|
|
3732
3736
|
] });
|
|
3733
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
|
+
}
|
|
3734
3775
|
var TOKEN_COLORS = ["var(--chart-1)", "var(--chart-2)", "var(--chart-3)", "var(--chart-4)", "var(--chart-5)"];
|
|
3735
3776
|
var seriesColor = (s, i) => s.color ?? TOKEN_COLORS[i % TOKEN_COLORS.length];
|
|
3736
3777
|
function ChartTooltip({
|
|
@@ -3903,20 +3944,20 @@ function FileUpload({
|
|
|
3903
3944
|
hint,
|
|
3904
3945
|
className
|
|
3905
3946
|
}) {
|
|
3906
|
-
const [internalFiles, setInternalFiles] =
|
|
3907
|
-
const [isDragging, setIsDragging] =
|
|
3908
|
-
const [validationError, setValidationError] =
|
|
3909
|
-
const inputRef =
|
|
3910
|
-
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);
|
|
3911
3952
|
const files = filesProp ?? internalFiles;
|
|
3912
|
-
const setFiles =
|
|
3953
|
+
const setFiles = React35.useCallback(
|
|
3913
3954
|
(next) => {
|
|
3914
3955
|
if (!filesProp) setInternalFiles(next);
|
|
3915
3956
|
onFilesChange?.(next);
|
|
3916
3957
|
},
|
|
3917
3958
|
[filesProp, onFilesChange]
|
|
3918
3959
|
);
|
|
3919
|
-
const acceptList =
|
|
3960
|
+
const acceptList = React35.useMemo(
|
|
3920
3961
|
() => accept?.split(",").map((a) => a.trim().toLowerCase()).filter(Boolean) ?? [],
|
|
3921
3962
|
[accept]
|
|
3922
3963
|
);
|
|
@@ -4296,6 +4337,63 @@ function ImageCard({
|
|
|
4296
4337
|
}
|
|
4297
4338
|
);
|
|
4298
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
|
+
}
|
|
4299
4397
|
var DASH_ON = "5px";
|
|
4300
4398
|
var DASH_OFF = "4px";
|
|
4301
4399
|
function FlowConnector({
|
|
@@ -4583,7 +4681,7 @@ function PageHeader({
|
|
|
4583
4681
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1 pb-6", className), children: [
|
|
4584
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) => {
|
|
4585
4683
|
const isLast = i === breadcrumbs.length - 1;
|
|
4586
|
-
return /* @__PURE__ */ jsxs(
|
|
4684
|
+
return /* @__PURE__ */ jsxs(React35.Fragment, { children: [
|
|
4587
4685
|
i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0" }),
|
|
4588
4686
|
isLast || !crumb.href ? /* @__PURE__ */ jsx("span", { className: cn(isLast && "text-foreground font-medium"), children: crumb.label }) : renderLink({
|
|
4589
4687
|
href: crumb.href,
|
|
@@ -4619,7 +4717,7 @@ function PageHeader({
|
|
|
4619
4717
|
] });
|
|
4620
4718
|
}
|
|
4621
4719
|
function Suspensed({ children, fallback }) {
|
|
4622
|
-
return /* @__PURE__ */ jsx(
|
|
4720
|
+
return /* @__PURE__ */ jsx(React35.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
|
|
4623
4721
|
}
|
|
4624
4722
|
function getInitialTheme() {
|
|
4625
4723
|
if (typeof document === "undefined") return "dark";
|
|
@@ -4627,7 +4725,7 @@ function getInitialTheme() {
|
|
|
4627
4725
|
return stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
|
|
4628
4726
|
}
|
|
4629
4727
|
function ThemeSwitchMinimal() {
|
|
4630
|
-
const [theme, setThemeState] =
|
|
4728
|
+
const [theme, setThemeState] = React35.useState(getInitialTheme);
|
|
4631
4729
|
const toggle = () => {
|
|
4632
4730
|
const next = theme === "dark" ? "light" : "dark";
|
|
4633
4731
|
setThemeState(next);
|
|
@@ -4753,9 +4851,9 @@ function getInitialColorName() {
|
|
|
4753
4851
|
return localStorage.getItem(STORAGE_KEY) ?? "emerald";
|
|
4754
4852
|
}
|
|
4755
4853
|
function BrandColorSwitchMinimal() {
|
|
4756
|
-
const [active, setActive] =
|
|
4757
|
-
const [open, setOpen] =
|
|
4758
|
-
|
|
4854
|
+
const [active, setActive] = React35.useState(getInitialColorName);
|
|
4855
|
+
const [open, setOpen] = React35.useState(false);
|
|
4856
|
+
React35.useEffect(() => {
|
|
4759
4857
|
const saved = localStorage.getItem(STORAGE_KEY) ?? "emerald";
|
|
4760
4858
|
const color = BRAND_COLORS.find((c) => c.name === saved);
|
|
4761
4859
|
if (color) applyColor(color);
|
|
@@ -4816,7 +4914,7 @@ function BrandColorSwitchMinimal() {
|
|
|
4816
4914
|
] });
|
|
4817
4915
|
}
|
|
4818
4916
|
function ThemeColorUpdater({ colorTheme }) {
|
|
4819
|
-
|
|
4917
|
+
React35.useEffect(() => {
|
|
4820
4918
|
if (colorTheme) {
|
|
4821
4919
|
document.documentElement.setAttribute("data-theme", colorTheme);
|
|
4822
4920
|
} else {
|
|
@@ -4826,7 +4924,7 @@ function ThemeColorUpdater({ colorTheme }) {
|
|
|
4826
4924
|
return null;
|
|
4827
4925
|
}
|
|
4828
4926
|
function VersionBanner({ version, message, className, onDismiss }) {
|
|
4829
|
-
const [dismissed, setDismissed] =
|
|
4927
|
+
const [dismissed, setDismissed] = React35.useState(false);
|
|
4830
4928
|
if (dismissed) return null;
|
|
4831
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: [
|
|
4832
4930
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -5083,29 +5181,29 @@ function useMounted() {
|
|
|
5083
5181
|
return mounted;
|
|
5084
5182
|
}
|
|
5085
5183
|
function useConfirm() {
|
|
5086
|
-
const [isOpen, setIsOpen] =
|
|
5087
|
-
const [options, setOptions] =
|
|
5088
|
-
const resolveRef =
|
|
5089
|
-
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 = {}) => {
|
|
5090
5188
|
setOptions(opts);
|
|
5091
5189
|
setIsOpen(true);
|
|
5092
5190
|
return new Promise((resolve) => {
|
|
5093
5191
|
resolveRef.current = resolve;
|
|
5094
5192
|
});
|
|
5095
5193
|
}, []);
|
|
5096
|
-
const handleConfirm =
|
|
5194
|
+
const handleConfirm = React35.useCallback(() => {
|
|
5097
5195
|
resolveRef.current?.(true);
|
|
5098
5196
|
setIsOpen(false);
|
|
5099
5197
|
}, []);
|
|
5100
|
-
const handleCancel =
|
|
5198
|
+
const handleCancel = React35.useCallback(() => {
|
|
5101
5199
|
resolveRef.current?.(false);
|
|
5102
5200
|
setIsOpen(false);
|
|
5103
5201
|
}, []);
|
|
5104
5202
|
return { confirm, isOpen, options, handleConfirm, handleCancel };
|
|
5105
5203
|
}
|
|
5106
5204
|
function useScrolledPast(threshold) {
|
|
5107
|
-
const [scrolledPast, setScrolledPast] =
|
|
5108
|
-
|
|
5205
|
+
const [scrolledPast, setScrolledPast] = React35.useState(false);
|
|
5206
|
+
React35.useEffect(() => {
|
|
5109
5207
|
const handleScroll = () => {
|
|
5110
5208
|
setScrolledPast(window.scrollY > threshold);
|
|
5111
5209
|
};
|
|
@@ -5116,28 +5214,28 @@ function useScrolledPast(threshold) {
|
|
|
5116
5214
|
return scrolledPast;
|
|
5117
5215
|
}
|
|
5118
5216
|
function useCopyToClipboard() {
|
|
5119
|
-
const [copied, setCopied] =
|
|
5120
|
-
const timeoutRef =
|
|
5121
|
-
const copy =
|
|
5217
|
+
const [copied, setCopied] = React35.useState(false);
|
|
5218
|
+
const timeoutRef = React35.useRef(void 0);
|
|
5219
|
+
const copy = React35.useCallback((text) => {
|
|
5122
5220
|
navigator.clipboard.writeText(text).then(() => {
|
|
5123
5221
|
setCopied(true);
|
|
5124
5222
|
clearTimeout(timeoutRef.current);
|
|
5125
5223
|
timeoutRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
5126
5224
|
});
|
|
5127
5225
|
}, []);
|
|
5128
|
-
|
|
5226
|
+
React35.useEffect(() => () => clearTimeout(timeoutRef.current), []);
|
|
5129
5227
|
return [copied, copy];
|
|
5130
5228
|
}
|
|
5131
5229
|
function useDebounce(value, delay) {
|
|
5132
|
-
const [debounced, setDebounced] =
|
|
5133
|
-
|
|
5230
|
+
const [debounced, setDebounced] = React35.useState(value);
|
|
5231
|
+
React35.useEffect(() => {
|
|
5134
5232
|
const timer = setTimeout(() => setDebounced(value), delay);
|
|
5135
5233
|
return () => clearTimeout(timer);
|
|
5136
5234
|
}, [value, delay]);
|
|
5137
5235
|
return debounced;
|
|
5138
5236
|
}
|
|
5139
5237
|
function useLocalStorage(key, initialValue) {
|
|
5140
|
-
const [storedValue, setStoredValue] =
|
|
5238
|
+
const [storedValue, setStoredValue] = React35.useState(() => {
|
|
5141
5239
|
if (typeof window === "undefined") return initialValue;
|
|
5142
5240
|
try {
|
|
5143
5241
|
const item = window.localStorage.getItem(key);
|
|
@@ -5146,7 +5244,7 @@ function useLocalStorage(key, initialValue) {
|
|
|
5146
5244
|
return initialValue;
|
|
5147
5245
|
}
|
|
5148
5246
|
});
|
|
5149
|
-
const setValue =
|
|
5247
|
+
const setValue = React35.useCallback(
|
|
5150
5248
|
(value) => {
|
|
5151
5249
|
try {
|
|
5152
5250
|
setStoredValue(value);
|
|
@@ -5160,12 +5258,19 @@ function useLocalStorage(key, initialValue) {
|
|
|
5160
5258
|
);
|
|
5161
5259
|
return [storedValue, setValue];
|
|
5162
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
|
+
}
|
|
5163
5268
|
function useMediaQuery(query) {
|
|
5164
|
-
const [matches, setMatches] =
|
|
5269
|
+
const [matches, setMatches] = React35.useState(() => {
|
|
5165
5270
|
if (typeof window === "undefined") return false;
|
|
5166
5271
|
return window.matchMedia(query).matches;
|
|
5167
5272
|
});
|
|
5168
|
-
|
|
5273
|
+
React35.useEffect(() => {
|
|
5169
5274
|
if (typeof window === "undefined") return;
|
|
5170
5275
|
const mql = window.matchMedia(query);
|
|
5171
5276
|
setMatches(mql.matches);
|
|
@@ -5176,18 +5281,18 @@ function useMediaQuery(query) {
|
|
|
5176
5281
|
return matches;
|
|
5177
5282
|
}
|
|
5178
5283
|
function usePagination(total, pageSize) {
|
|
5179
|
-
const [page, setPage] =
|
|
5284
|
+
const [page, setPage] = React35.useState(1);
|
|
5180
5285
|
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
5181
5286
|
const offset = (page - 1) * pageSize;
|
|
5182
|
-
const goTo =
|
|
5287
|
+
const goTo = React35.useCallback(
|
|
5183
5288
|
(p) => setPage(Math.min(Math.max(1, p), totalPages)),
|
|
5184
5289
|
[totalPages]
|
|
5185
5290
|
);
|
|
5186
|
-
const next =
|
|
5187
|
-
const prev =
|
|
5291
|
+
const next = React35.useCallback(() => goTo(page + 1), [page, goTo]);
|
|
5292
|
+
const prev = React35.useCallback(() => goTo(page - 1), [page, goTo]);
|
|
5188
5293
|
return { page, pageSize, totalPages, offset, hasPrev: page > 1, hasNext: page < totalPages, goTo, next, prev };
|
|
5189
5294
|
}
|
|
5190
5295
|
|
|
5191
|
-
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 };
|
|
5192
5297
|
//# sourceMappingURL=index.js.map
|
|
5193
5298
|
//# sourceMappingURL=index.js.map
|