@olwiba/ui 0.2.6 → 0.2.8
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 +180 -3
- package/dist/index.js +297 -139
- 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/src/marketing/PricingSection.tsx +172 -29
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 })
|
|
@@ -2279,6 +2282,32 @@ function CountdownTimer({
|
|
|
2279
2282
|
] }, unit)) })
|
|
2280
2283
|
] });
|
|
2281
2284
|
}
|
|
2285
|
+
function computeSaveBadges(plans, cadences, defaultKey) {
|
|
2286
|
+
const annualised = (key) => {
|
|
2287
|
+
const cadence = cadences.find((c) => c.key === key);
|
|
2288
|
+
if (!cadence?.periodsPerYear) return null;
|
|
2289
|
+
const totals = plans.filter((plan) => plan.priceDisplay === void 0 && plan.prices?.[key] !== void 0).map((plan) => plan.prices[key] * cadence.periodsPerYear);
|
|
2290
|
+
return totals.length > 0 ? totals.reduce((sum, n) => sum + n, 0) : null;
|
|
2291
|
+
};
|
|
2292
|
+
const baseline = annualised(defaultKey);
|
|
2293
|
+
if (!baseline) return {};
|
|
2294
|
+
const badges = {};
|
|
2295
|
+
for (const cadence of cadences) {
|
|
2296
|
+
if (cadence.key === defaultKey) continue;
|
|
2297
|
+
const total = annualised(cadence.key);
|
|
2298
|
+
if (!total || total >= baseline) continue;
|
|
2299
|
+
const percent = Math.round((baseline - total) / baseline * 100);
|
|
2300
|
+
if (percent > 0) badges[cadence.key] = `Save ${percent}%`;
|
|
2301
|
+
}
|
|
2302
|
+
return badges;
|
|
2303
|
+
}
|
|
2304
|
+
function gridClassesFor(count) {
|
|
2305
|
+
if (count <= 1) return "mx-auto max-w-sm";
|
|
2306
|
+
if (count === 2) return "mx-auto max-w-3xl sm:grid-cols-2";
|
|
2307
|
+
if (count === 3) return "mx-auto max-w-5xl lg:grid-cols-3";
|
|
2308
|
+
if (count === 4) return "mx-auto max-w-6xl sm:grid-cols-2 lg:grid-cols-4";
|
|
2309
|
+
return "mx-auto max-w-5xl sm:grid-cols-2 lg:grid-cols-3";
|
|
2310
|
+
}
|
|
2282
2311
|
var defaultRenderLink6 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
2283
2312
|
function PricingSection({
|
|
2284
2313
|
title = "Simple, transparent pricing",
|
|
@@ -2293,10 +2322,21 @@ function PricingSection({
|
|
|
2293
2322
|
foundingDeadline,
|
|
2294
2323
|
currency = "$",
|
|
2295
2324
|
highlightedBadgeLabel = "Founding member",
|
|
2296
|
-
renderPlanFooter
|
|
2325
|
+
renderPlanFooter,
|
|
2326
|
+
cadences,
|
|
2327
|
+
defaultCadence
|
|
2297
2328
|
}) {
|
|
2298
|
-
const [annual, setAnnual] =
|
|
2329
|
+
const [annual, setAnnual] = React35.useState(false);
|
|
2299
2330
|
const isOneTime = mode === "one-time";
|
|
2331
|
+
const useCadences = !!cadences?.length;
|
|
2332
|
+
const initialCadence = (defaultCadence && cadences?.some((c) => c.key === defaultCadence) ? defaultCadence : null) ?? cadences?.[0]?.key ?? "";
|
|
2333
|
+
const [activeCadence, setActiveCadence] = React35.useState(initialCadence);
|
|
2334
|
+
const cadence = cadences?.find((c) => c.key === activeCadence);
|
|
2335
|
+
const saveBadges = React35.useMemo(
|
|
2336
|
+
() => useCadences ? computeSaveBadges(plans, cadences, initialCadence) : {},
|
|
2337
|
+
[useCadences, plans, cadences, initialCadence]
|
|
2338
|
+
);
|
|
2339
|
+
const showToggle = useCadences ? cadences.length > 1 : !isOneTime;
|
|
2300
2340
|
const uiMode = useUIVariant();
|
|
2301
2341
|
const sectionClasses = cn$1(
|
|
2302
2342
|
"overflow-hidden bg-card",
|
|
@@ -2309,7 +2349,23 @@ function PricingSection({
|
|
|
2309
2349
|
badge && (typeof badge === "string" ? /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-4", children: badge }) : /* @__PURE__ */ jsx("div", { className: "mb-4", children: badge })),
|
|
2310
2350
|
/* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: title }),
|
|
2311
2351
|
description && /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-xl text-pretty text-muted-foreground", children: description }),
|
|
2312
|
-
|
|
2352
|
+
showToggle && /* @__PURE__ */ jsx("div", { className: "mt-6 inline-flex items-center gap-3 rounded-full border bg-muted p-1", children: useCadences ? cadences.map((entry) => /* @__PURE__ */ jsxs(
|
|
2353
|
+
Button$1,
|
|
2354
|
+
{
|
|
2355
|
+
variant: "ghost",
|
|
2356
|
+
size: "sm",
|
|
2357
|
+
onClick: () => setActiveCadence(entry.key),
|
|
2358
|
+
className: cn$1(
|
|
2359
|
+
"flex items-center gap-2 rounded-full px-4 py-1.5 text-sm font-medium transition-colors",
|
|
2360
|
+
entry.key === activeCadence ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
|
|
2361
|
+
),
|
|
2362
|
+
children: [
|
|
2363
|
+
entry.label,
|
|
2364
|
+
saveBadges[entry.key] && /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "text-xs", children: saveBadges[entry.key] })
|
|
2365
|
+
]
|
|
2366
|
+
},
|
|
2367
|
+
entry.key
|
|
2368
|
+
)) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2313
2369
|
/* @__PURE__ */ jsx(
|
|
2314
2370
|
Button$1,
|
|
2315
2371
|
{
|
|
@@ -2339,12 +2395,12 @@ function PricingSection({
|
|
|
2339
2395
|
]
|
|
2340
2396
|
}
|
|
2341
2397
|
)
|
|
2342
|
-
] })
|
|
2398
|
+
] }) })
|
|
2343
2399
|
] }),
|
|
2344
|
-
/* @__PURE__ */ jsx(StaggerChildren, { className: "mt-10 grid gap-4
|
|
2345
|
-
const rawPrice = isOneTime ? plan.monthly : annual ? plan.annual : plan.monthly;
|
|
2400
|
+
/* @__PURE__ */ jsx(StaggerChildren, { className: cn$1("mt-10 grid gap-4", gridClassesFor(plans.length)), children: plans.map((plan) => {
|
|
2401
|
+
const rawPrice = useCadences ? plan.prices?.[activeCadence] ?? plan.monthly : isOneTime ? plan.monthly : annual ? plan.annual : plan.monthly;
|
|
2346
2402
|
const price = plan.priceDisplay ?? `${currency}${rawPrice}`;
|
|
2347
|
-
const period = plan.periodDisplay ?? (isOneTime ? "one-time" : rawPrice > 0 ? "/mo" : "");
|
|
2403
|
+
const period = useCadences ? cadence?.suffix ?? plan.periodDisplay ?? "" : plan.periodDisplay ?? (isOneTime ? "one-time" : rawPrice > 0 ? "/mo" : "");
|
|
2348
2404
|
const badge2 = plan.highlighted && foundingDeadline ? /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded-full border bg-secondary px-2.5 py-0.5 text-xs font-semibold text-secondary-foreground", children: /* @__PURE__ */ jsx(CountdownTimer, { deadline: foundingDeadline, compact: true }) }) : plan.highlighted && highlightedBadgeLabel ? highlightedBadgeLabel : void 0;
|
|
2349
2405
|
return /* @__PURE__ */ jsx(
|
|
2350
2406
|
PricingCard,
|
|
@@ -2564,10 +2620,10 @@ function CountUp({
|
|
|
2564
2620
|
className,
|
|
2565
2621
|
...props
|
|
2566
2622
|
}) {
|
|
2567
|
-
const ref =
|
|
2568
|
-
const [value, setValue] =
|
|
2569
|
-
const hasStarted =
|
|
2570
|
-
|
|
2623
|
+
const ref = React35.useRef(null);
|
|
2624
|
+
const [value, setValue] = React35.useState(from);
|
|
2625
|
+
const hasStarted = React35.useRef(false);
|
|
2626
|
+
React35.useEffect(() => {
|
|
2571
2627
|
const el = ref.current;
|
|
2572
2628
|
if (!el) return;
|
|
2573
2629
|
const observer = new IntersectionObserver(
|
|
@@ -2660,8 +2716,8 @@ function NewsletterSection({
|
|
|
2660
2716
|
successDescription = defaults.successDescription,
|
|
2661
2717
|
onSubscribe
|
|
2662
2718
|
} = {}) {
|
|
2663
|
-
const [email, setEmail] =
|
|
2664
|
-
const [submitted, setSubmitted] =
|
|
2719
|
+
const [email, setEmail] = React35.useState("");
|
|
2720
|
+
const [submitted, setSubmitted] = React35.useState(false);
|
|
2665
2721
|
const mode = useUIVariant();
|
|
2666
2722
|
const sectionClasses = cn$1(
|
|
2667
2723
|
"overflow-hidden bg-card",
|
|
@@ -2752,7 +2808,7 @@ function ContactSection({
|
|
|
2752
2808
|
sendAnotherLabel = defaults2.sendAnotherLabel,
|
|
2753
2809
|
onSubmit
|
|
2754
2810
|
} = {}) {
|
|
2755
|
-
const [submitted, setSubmitted] =
|
|
2811
|
+
const [submitted, setSubmitted] = React35.useState(false);
|
|
2756
2812
|
const mode = useUIVariant();
|
|
2757
2813
|
const sectionClasses = cn$1(
|
|
2758
2814
|
"overflow-hidden bg-card",
|
|
@@ -3050,9 +3106,10 @@ function Navbar({
|
|
|
3050
3106
|
controls,
|
|
3051
3107
|
renderLink = defaultRenderLink7
|
|
3052
3108
|
}) {
|
|
3053
|
-
const [open, setOpen] =
|
|
3109
|
+
const [open, setOpen] = React35.useState(false);
|
|
3054
3110
|
const brandHref = brand.href ?? "/";
|
|
3055
3111
|
const hasRightContent = controls?.length || cta?.primary || cta?.secondary;
|
|
3112
|
+
const closeMobileMenu = React35.useCallback(() => setOpen(false), []);
|
|
3056
3113
|
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
3114
|
renderLink({
|
|
3058
3115
|
href: brandHref,
|
|
@@ -3067,7 +3124,7 @@ function Navbar({
|
|
|
3067
3124
|
children: link.label
|
|
3068
3125
|
}) }, link.label)) }),
|
|
3069
3126
|
hasRightContent && /* @__PURE__ */ jsxs("div", { className: "hidden items-center justify-end gap-2 md:flex", children: [
|
|
3070
|
-
controls?.map((control, i) => /* @__PURE__ */ jsx(
|
|
3127
|
+
controls?.map((control, i) => /* @__PURE__ */ jsx(React35.Fragment, { children: control }, i)),
|
|
3071
3128
|
(cta?.secondary || cta?.primary) && controls?.length ? /* @__PURE__ */ jsx("div", { className: "mx-1 h-4 w-px bg-border" }) : null,
|
|
3072
3129
|
cta?.secondary && renderLink({
|
|
3073
3130
|
href: cta.secondary.href,
|
|
@@ -3084,29 +3141,29 @@ function Navbar({
|
|
|
3084
3141
|
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Open menu" })
|
|
3085
3142
|
] }) }),
|
|
3086
3143
|
/* @__PURE__ */ jsxs(SheetContent, { side: "left", className: "w-72", children: [
|
|
3087
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center pb-4", children: /* @__PURE__ */ jsx("span", {
|
|
3144
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center pb-4", children: /* @__PURE__ */ jsx("span", { onClickCapture: closeMobileMenu, className: "cursor-pointer", children: renderLink({
|
|
3088
3145
|
href: brandHref,
|
|
3089
3146
|
children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 font-semibold", children: [
|
|
3090
3147
|
brand.logo,
|
|
3091
3148
|
/* @__PURE__ */ jsx("span", { children: brand.name })
|
|
3092
3149
|
] })
|
|
3093
3150
|
}) }) }),
|
|
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(
|
|
3151
|
+
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
3152
|
/* @__PURE__ */ jsx(Separator, {}),
|
|
3096
|
-
/* @__PURE__ */ jsx("nav", { className: "mt-4 flex flex-col gap-1", children: navLinks.map((link) => /* @__PURE__ */ jsx("span", {
|
|
3153
|
+
/* @__PURE__ */ jsx("nav", { className: "mt-4 flex flex-col gap-1", children: navLinks.map((link) => /* @__PURE__ */ jsx("span", { onClickCapture: closeMobileMenu, children: renderLink({
|
|
3097
3154
|
href: link.href,
|
|
3098
3155
|
className: "block rounded-md px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
|
|
3099
3156
|
children: link.label
|
|
3100
3157
|
}) }, link.label)) }),
|
|
3101
3158
|
/* @__PURE__ */ jsxs("div", { className: "mt-6 flex flex-col gap-2", children: [
|
|
3102
|
-
cta?.secondary && renderLink({
|
|
3159
|
+
cta?.secondary && /* @__PURE__ */ jsx("span", { onClickCapture: closeMobileMenu, children: renderLink({
|
|
3103
3160
|
href: cta.secondary.href,
|
|
3104
3161
|
children: /* @__PURE__ */ jsx(Button$1, { variant: "outline", className: "w-full", children: cta.secondary.label })
|
|
3105
|
-
}),
|
|
3106
|
-
cta?.primary && renderLink({
|
|
3162
|
+
}) }),
|
|
3163
|
+
cta?.primary && /* @__PURE__ */ jsx("span", { onClickCapture: closeMobileMenu, children: renderLink({
|
|
3107
3164
|
href: cta.primary.href,
|
|
3108
3165
|
children: /* @__PURE__ */ jsx(Button$1, { className: "w-full", children: cta.primary.label })
|
|
3109
|
-
})
|
|
3166
|
+
}) })
|
|
3110
3167
|
] })
|
|
3111
3168
|
] })
|
|
3112
3169
|
] })
|
|
@@ -3240,7 +3297,7 @@ function LogoStrip({
|
|
|
3240
3297
|
] });
|
|
3241
3298
|
}
|
|
3242
3299
|
function GridUnderlay({ variant, size = 24, className, ...props }) {
|
|
3243
|
-
const id =
|
|
3300
|
+
const id = React35.useId();
|
|
3244
3301
|
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
3302
|
/* @__PURE__ */ jsx("line", { x1: size / 2, y1: 0, x2: size / 2, y2: size, stroke: "currentColor", strokeWidth: 0.5 }),
|
|
3246
3303
|
/* @__PURE__ */ jsx("line", { x1: 0, y1: size / 2, x2: size, y2: size / 2, stroke: "currentColor", strokeWidth: 0.5 })
|
|
@@ -3268,9 +3325,9 @@ function GlowUnderlay({
|
|
|
3268
3325
|
style,
|
|
3269
3326
|
...props
|
|
3270
3327
|
}) {
|
|
3271
|
-
const [pos, setPos] =
|
|
3272
|
-
const containerRef =
|
|
3273
|
-
|
|
3328
|
+
const [pos, setPos] = React35.useState({ x: "50%", y: "50%" });
|
|
3329
|
+
const containerRef = React35.useRef(null);
|
|
3330
|
+
React35.useEffect(() => {
|
|
3274
3331
|
if (!followCursor) return;
|
|
3275
3332
|
const handleMouseMove = (e) => {
|
|
3276
3333
|
const el = containerRef.current;
|
|
@@ -3409,8 +3466,8 @@ function PageTransition({
|
|
|
3409
3466
|
style,
|
|
3410
3467
|
...props
|
|
3411
3468
|
}) {
|
|
3412
|
-
const [mounted, setMounted] =
|
|
3413
|
-
|
|
3469
|
+
const [mounted, setMounted] = React35.useState(false);
|
|
3470
|
+
React35.useEffect(() => {
|
|
3414
3471
|
const id = requestAnimationFrame(() => setMounted(true));
|
|
3415
3472
|
return () => cancelAnimationFrame(id);
|
|
3416
3473
|
}, []);
|
|
@@ -3485,7 +3542,7 @@ function Sortable({
|
|
|
3485
3542
|
if (oldIndex === -1 || newIndex === -1) return;
|
|
3486
3543
|
onReorder(arrayMove(items, oldIndex, newIndex));
|
|
3487
3544
|
};
|
|
3488
|
-
const childArray =
|
|
3545
|
+
const childArray = React35.Children.toArray(children);
|
|
3489
3546
|
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
3547
|
(child, i) => items[i] === void 0 ? null : /* @__PURE__ */ jsx(SortableItem, { id: items[i], disabled, className: itemClassName, children: child }, items[i])
|
|
3491
3548
|
) }) }) });
|
|
@@ -3497,8 +3554,8 @@ function Spotlight({
|
|
|
3497
3554
|
triggerClassName,
|
|
3498
3555
|
shortcut = "\u2318K"
|
|
3499
3556
|
}) {
|
|
3500
|
-
const [open, setOpen] =
|
|
3501
|
-
|
|
3557
|
+
const [open, setOpen] = React35.useState(false);
|
|
3558
|
+
React35.useEffect(() => {
|
|
3502
3559
|
const down = (e) => {
|
|
3503
3560
|
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
|
3504
3561
|
e.preventDefault();
|
|
@@ -3528,7 +3585,7 @@ function Spotlight({
|
|
|
3528
3585
|
/* @__PURE__ */ jsx(CommandInput, { placeholder }),
|
|
3529
3586
|
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
3530
3587
|
/* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
|
|
3531
|
-
groups.map((group, i) => /* @__PURE__ */ jsxs(
|
|
3588
|
+
groups.map((group, i) => /* @__PURE__ */ jsxs(React35.Fragment, { children: [
|
|
3532
3589
|
i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
3533
3590
|
/* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
3534
3591
|
CommandItem,
|
|
@@ -3553,8 +3610,8 @@ function Spotlight({
|
|
|
3553
3610
|
var BASE = 40;
|
|
3554
3611
|
var MAGNIFY_RADIUS = 80;
|
|
3555
3612
|
function Dock({ items, iconSize = BASE, magnification = 1.7, className, ...props }) {
|
|
3556
|
-
const [mouseX, setMouseX] =
|
|
3557
|
-
const containerRef =
|
|
3613
|
+
const [mouseX, setMouseX] = React35.useState(null);
|
|
3614
|
+
const containerRef = React35.useRef(null);
|
|
3558
3615
|
function getScale(index) {
|
|
3559
3616
|
if (mouseX === null || !containerRef.current) return 1;
|
|
3560
3617
|
const container = containerRef.current;
|
|
@@ -3653,7 +3710,7 @@ function ConfirmDialog({ isOpen, options, handleConfirm, handleCancel, destructi
|
|
|
3653
3710
|
] }) });
|
|
3654
3711
|
}
|
|
3655
3712
|
function RegisterHotkeys({ hotkeys }) {
|
|
3656
|
-
|
|
3713
|
+
React35.useEffect(() => {
|
|
3657
3714
|
const handleKeyDown = (event) => {
|
|
3658
3715
|
for (const hotkey of hotkeys) {
|
|
3659
3716
|
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 +3727,10 @@ function RegisterHotkeys({ hotkeys }) {
|
|
|
3670
3727
|
return null;
|
|
3671
3728
|
}
|
|
3672
3729
|
function useControlledOpen(defaultOpen = false) {
|
|
3673
|
-
const [isOpen, setIsOpen] =
|
|
3674
|
-
const open =
|
|
3675
|
-
const close =
|
|
3676
|
-
const toggle =
|
|
3730
|
+
const [isOpen, setIsOpen] = React35.useState(defaultOpen);
|
|
3731
|
+
const open = React35.useCallback(() => setIsOpen(true), []);
|
|
3732
|
+
const close = React35.useCallback(() => setIsOpen(false), []);
|
|
3733
|
+
const toggle = React35.useCallback(() => setIsOpen((prev) => !prev), []);
|
|
3677
3734
|
return { isOpen, open, close, toggle, setIsOpen };
|
|
3678
3735
|
}
|
|
3679
3736
|
function CommandMenu({
|
|
@@ -3686,7 +3743,7 @@ function CommandMenu({
|
|
|
3686
3743
|
}) {
|
|
3687
3744
|
const internal = useControlledOpen(false);
|
|
3688
3745
|
const isOpen = openProp ?? internal.isOpen;
|
|
3689
|
-
const setOpen =
|
|
3746
|
+
const setOpen = React35.useCallback(
|
|
3690
3747
|
(next) => {
|
|
3691
3748
|
if (openProp === void 0) internal.setIsOpen(next);
|
|
3692
3749
|
onOpenChange?.(next);
|
|
@@ -3711,7 +3768,7 @@ function CommandMenu({
|
|
|
3711
3768
|
/* @__PURE__ */ jsx(CommandInput, { placeholder }),
|
|
3712
3769
|
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
3713
3770
|
/* @__PURE__ */ jsx(CommandEmpty, { children: emptyMessage }),
|
|
3714
|
-
groups.map((group, i) => /* @__PURE__ */ jsxs(
|
|
3771
|
+
groups.map((group, i) => /* @__PURE__ */ jsxs(React35.Fragment, { children: [
|
|
3715
3772
|
i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
3716
3773
|
/* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
3717
3774
|
CommandItem,
|
|
@@ -3731,6 +3788,43 @@ function CommandMenu({
|
|
|
3731
3788
|
] })
|
|
3732
3789
|
] });
|
|
3733
3790
|
}
|
|
3791
|
+
function DataView({
|
|
3792
|
+
items,
|
|
3793
|
+
getRowId,
|
|
3794
|
+
renderCard,
|
|
3795
|
+
columns,
|
|
3796
|
+
view,
|
|
3797
|
+
ready = true,
|
|
3798
|
+
gridColumns = 3,
|
|
3799
|
+
gap = "sm",
|
|
3800
|
+
empty,
|
|
3801
|
+
placeholder = null,
|
|
3802
|
+
searchKey,
|
|
3803
|
+
searchPlaceholder,
|
|
3804
|
+
pageSize = 25,
|
|
3805
|
+
emptyMessage,
|
|
3806
|
+
onRowClick,
|
|
3807
|
+
className
|
|
3808
|
+
}) {
|
|
3809
|
+
if (!ready) return /* @__PURE__ */ jsx(Fragment, { children: placeholder });
|
|
3810
|
+
if (items.length === 0 && empty) return /* @__PURE__ */ jsx(Fragment, { children: empty });
|
|
3811
|
+
if (view === "list") {
|
|
3812
|
+
return /* @__PURE__ */ jsx(
|
|
3813
|
+
DataTable,
|
|
3814
|
+
{
|
|
3815
|
+
columns,
|
|
3816
|
+
data: items,
|
|
3817
|
+
searchKey,
|
|
3818
|
+
searchPlaceholder,
|
|
3819
|
+
pageSize,
|
|
3820
|
+
emptyMessage,
|
|
3821
|
+
onRowClick,
|
|
3822
|
+
className
|
|
3823
|
+
}
|
|
3824
|
+
);
|
|
3825
|
+
}
|
|
3826
|
+
return /* @__PURE__ */ jsx(AppGrid, { columns: gridColumns, gap, className: cn$1(className), children: items.map((item) => /* @__PURE__ */ jsx(React35.Fragment, { children: renderCard(item) }, getRowId(item))) });
|
|
3827
|
+
}
|
|
3734
3828
|
var TOKEN_COLORS = ["var(--chart-1)", "var(--chart-2)", "var(--chart-3)", "var(--chart-4)", "var(--chart-5)"];
|
|
3735
3829
|
var seriesColor = (s, i) => s.color ?? TOKEN_COLORS[i % TOKEN_COLORS.length];
|
|
3736
3830
|
function ChartTooltip({
|
|
@@ -3903,20 +3997,20 @@ function FileUpload({
|
|
|
3903
3997
|
hint,
|
|
3904
3998
|
className
|
|
3905
3999
|
}) {
|
|
3906
|
-
const [internalFiles, setInternalFiles] =
|
|
3907
|
-
const [isDragging, setIsDragging] =
|
|
3908
|
-
const [validationError, setValidationError] =
|
|
3909
|
-
const inputRef =
|
|
3910
|
-
const dragDepth =
|
|
4000
|
+
const [internalFiles, setInternalFiles] = React35.useState(defaultFiles ?? []);
|
|
4001
|
+
const [isDragging, setIsDragging] = React35.useState(false);
|
|
4002
|
+
const [validationError, setValidationError] = React35.useState(null);
|
|
4003
|
+
const inputRef = React35.useRef(null);
|
|
4004
|
+
const dragDepth = React35.useRef(0);
|
|
3911
4005
|
const files = filesProp ?? internalFiles;
|
|
3912
|
-
const setFiles =
|
|
4006
|
+
const setFiles = React35.useCallback(
|
|
3913
4007
|
(next) => {
|
|
3914
4008
|
if (!filesProp) setInternalFiles(next);
|
|
3915
4009
|
onFilesChange?.(next);
|
|
3916
4010
|
},
|
|
3917
4011
|
[filesProp, onFilesChange]
|
|
3918
4012
|
);
|
|
3919
|
-
const acceptList =
|
|
4013
|
+
const acceptList = React35.useMemo(
|
|
3920
4014
|
() => accept?.split(",").map((a) => a.trim().toLowerCase()).filter(Boolean) ?? [],
|
|
3921
4015
|
[accept]
|
|
3922
4016
|
);
|
|
@@ -4296,6 +4390,63 @@ function ImageCard({
|
|
|
4296
4390
|
}
|
|
4297
4391
|
);
|
|
4298
4392
|
}
|
|
4393
|
+
var bannerAspectClass = {
|
|
4394
|
+
wide: "aspect-[3/1]",
|
|
4395
|
+
video: "aspect-video",
|
|
4396
|
+
square: "aspect-square"
|
|
4397
|
+
};
|
|
4398
|
+
function MediaCard({
|
|
4399
|
+
banner,
|
|
4400
|
+
bannerAspect = "wide",
|
|
4401
|
+
footer,
|
|
4402
|
+
children,
|
|
4403
|
+
className,
|
|
4404
|
+
...props
|
|
4405
|
+
}) {
|
|
4406
|
+
return /* @__PURE__ */ jsxs(
|
|
4407
|
+
Card$1,
|
|
4408
|
+
{
|
|
4409
|
+
className: cn$1("flex h-full w-full flex-col overflow-hidden", banner && "pt-0", className),
|
|
4410
|
+
...props,
|
|
4411
|
+
children: [
|
|
4412
|
+
banner && /* @__PURE__ */ jsx("div", { className: cn$1("w-full shrink-0 overflow-hidden", bannerAspectClass[bannerAspect]), children: banner }),
|
|
4413
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-3 p-4", children: [
|
|
4414
|
+
children,
|
|
4415
|
+
footer && /* @__PURE__ */ jsx("div", { className: "mt-auto pt-1", children: footer })
|
|
4416
|
+
] })
|
|
4417
|
+
]
|
|
4418
|
+
}
|
|
4419
|
+
);
|
|
4420
|
+
}
|
|
4421
|
+
function ViewToggle({ view, onChange, labels, className, ...props }) {
|
|
4422
|
+
const options = [
|
|
4423
|
+
{ mode: "cards", label: labels?.cards ?? "Card view", Icon: LayoutGrid },
|
|
4424
|
+
{ mode: "list", label: labels?.list ?? "List view", Icon: List }
|
|
4425
|
+
];
|
|
4426
|
+
return /* @__PURE__ */ jsx(
|
|
4427
|
+
"div",
|
|
4428
|
+
{
|
|
4429
|
+
className: cn$1("inline-flex items-center rounded-md border p-0.5", className),
|
|
4430
|
+
role: "group",
|
|
4431
|
+
"aria-label": "View mode",
|
|
4432
|
+
...props,
|
|
4433
|
+
children: options.map(({ mode, label, Icon }) => /* @__PURE__ */ jsx(
|
|
4434
|
+
Button$1,
|
|
4435
|
+
{
|
|
4436
|
+
type: "button",
|
|
4437
|
+
size: "sm",
|
|
4438
|
+
variant: view === mode ? "secondary" : "ghost",
|
|
4439
|
+
className: "h-7 px-2",
|
|
4440
|
+
"aria-label": label,
|
|
4441
|
+
"aria-pressed": view === mode,
|
|
4442
|
+
onClick: () => onChange(mode),
|
|
4443
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "size-4" })
|
|
4444
|
+
},
|
|
4445
|
+
mode
|
|
4446
|
+
))
|
|
4447
|
+
}
|
|
4448
|
+
);
|
|
4449
|
+
}
|
|
4299
4450
|
var DASH_ON = "5px";
|
|
4300
4451
|
var DASH_OFF = "4px";
|
|
4301
4452
|
function FlowConnector({
|
|
@@ -4583,7 +4734,7 @@ function PageHeader({
|
|
|
4583
4734
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1 pb-6", className), children: [
|
|
4584
4735
|
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
4736
|
const isLast = i === breadcrumbs.length - 1;
|
|
4586
|
-
return /* @__PURE__ */ jsxs(
|
|
4737
|
+
return /* @__PURE__ */ jsxs(React35.Fragment, { children: [
|
|
4587
4738
|
i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0" }),
|
|
4588
4739
|
isLast || !crumb.href ? /* @__PURE__ */ jsx("span", { className: cn(isLast && "text-foreground font-medium"), children: crumb.label }) : renderLink({
|
|
4589
4740
|
href: crumb.href,
|
|
@@ -4619,7 +4770,7 @@ function PageHeader({
|
|
|
4619
4770
|
] });
|
|
4620
4771
|
}
|
|
4621
4772
|
function Suspensed({ children, fallback }) {
|
|
4622
|
-
return /* @__PURE__ */ jsx(
|
|
4773
|
+
return /* @__PURE__ */ jsx(React35.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
|
|
4623
4774
|
}
|
|
4624
4775
|
function getInitialTheme() {
|
|
4625
4776
|
if (typeof document === "undefined") return "dark";
|
|
@@ -4627,7 +4778,7 @@ function getInitialTheme() {
|
|
|
4627
4778
|
return stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
|
|
4628
4779
|
}
|
|
4629
4780
|
function ThemeSwitchMinimal() {
|
|
4630
|
-
const [theme, setThemeState] =
|
|
4781
|
+
const [theme, setThemeState] = React35.useState(getInitialTheme);
|
|
4631
4782
|
const toggle = () => {
|
|
4632
4783
|
const next = theme === "dark" ? "light" : "dark";
|
|
4633
4784
|
setThemeState(next);
|
|
@@ -4753,9 +4904,9 @@ function getInitialColorName() {
|
|
|
4753
4904
|
return localStorage.getItem(STORAGE_KEY) ?? "emerald";
|
|
4754
4905
|
}
|
|
4755
4906
|
function BrandColorSwitchMinimal() {
|
|
4756
|
-
const [active, setActive] =
|
|
4757
|
-
const [open, setOpen] =
|
|
4758
|
-
|
|
4907
|
+
const [active, setActive] = React35.useState(getInitialColorName);
|
|
4908
|
+
const [open, setOpen] = React35.useState(false);
|
|
4909
|
+
React35.useEffect(() => {
|
|
4759
4910
|
const saved = localStorage.getItem(STORAGE_KEY) ?? "emerald";
|
|
4760
4911
|
const color = BRAND_COLORS.find((c) => c.name === saved);
|
|
4761
4912
|
if (color) applyColor(color);
|
|
@@ -4816,7 +4967,7 @@ function BrandColorSwitchMinimal() {
|
|
|
4816
4967
|
] });
|
|
4817
4968
|
}
|
|
4818
4969
|
function ThemeColorUpdater({ colorTheme }) {
|
|
4819
|
-
|
|
4970
|
+
React35.useEffect(() => {
|
|
4820
4971
|
if (colorTheme) {
|
|
4821
4972
|
document.documentElement.setAttribute("data-theme", colorTheme);
|
|
4822
4973
|
} else {
|
|
@@ -4826,7 +4977,7 @@ function ThemeColorUpdater({ colorTheme }) {
|
|
|
4826
4977
|
return null;
|
|
4827
4978
|
}
|
|
4828
4979
|
function VersionBanner({ version, message, className, onDismiss }) {
|
|
4829
|
-
const [dismissed, setDismissed] =
|
|
4980
|
+
const [dismissed, setDismissed] = React35.useState(false);
|
|
4830
4981
|
if (dismissed) return null;
|
|
4831
4982
|
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
4983
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -5083,29 +5234,29 @@ function useMounted() {
|
|
|
5083
5234
|
return mounted;
|
|
5084
5235
|
}
|
|
5085
5236
|
function useConfirm() {
|
|
5086
|
-
const [isOpen, setIsOpen] =
|
|
5087
|
-
const [options, setOptions] =
|
|
5088
|
-
const resolveRef =
|
|
5089
|
-
const confirm =
|
|
5237
|
+
const [isOpen, setIsOpen] = React35.useState(false);
|
|
5238
|
+
const [options, setOptions] = React35.useState({});
|
|
5239
|
+
const resolveRef = React35.useRef(null);
|
|
5240
|
+
const confirm = React35.useCallback((opts = {}) => {
|
|
5090
5241
|
setOptions(opts);
|
|
5091
5242
|
setIsOpen(true);
|
|
5092
5243
|
return new Promise((resolve) => {
|
|
5093
5244
|
resolveRef.current = resolve;
|
|
5094
5245
|
});
|
|
5095
5246
|
}, []);
|
|
5096
|
-
const handleConfirm =
|
|
5247
|
+
const handleConfirm = React35.useCallback(() => {
|
|
5097
5248
|
resolveRef.current?.(true);
|
|
5098
5249
|
setIsOpen(false);
|
|
5099
5250
|
}, []);
|
|
5100
|
-
const handleCancel =
|
|
5251
|
+
const handleCancel = React35.useCallback(() => {
|
|
5101
5252
|
resolveRef.current?.(false);
|
|
5102
5253
|
setIsOpen(false);
|
|
5103
5254
|
}, []);
|
|
5104
5255
|
return { confirm, isOpen, options, handleConfirm, handleCancel };
|
|
5105
5256
|
}
|
|
5106
5257
|
function useScrolledPast(threshold) {
|
|
5107
|
-
const [scrolledPast, setScrolledPast] =
|
|
5108
|
-
|
|
5258
|
+
const [scrolledPast, setScrolledPast] = React35.useState(false);
|
|
5259
|
+
React35.useEffect(() => {
|
|
5109
5260
|
const handleScroll = () => {
|
|
5110
5261
|
setScrolledPast(window.scrollY > threshold);
|
|
5111
5262
|
};
|
|
@@ -5116,28 +5267,28 @@ function useScrolledPast(threshold) {
|
|
|
5116
5267
|
return scrolledPast;
|
|
5117
5268
|
}
|
|
5118
5269
|
function useCopyToClipboard() {
|
|
5119
|
-
const [copied, setCopied] =
|
|
5120
|
-
const timeoutRef =
|
|
5121
|
-
const copy =
|
|
5270
|
+
const [copied, setCopied] = React35.useState(false);
|
|
5271
|
+
const timeoutRef = React35.useRef(void 0);
|
|
5272
|
+
const copy = React35.useCallback((text) => {
|
|
5122
5273
|
navigator.clipboard.writeText(text).then(() => {
|
|
5123
5274
|
setCopied(true);
|
|
5124
5275
|
clearTimeout(timeoutRef.current);
|
|
5125
5276
|
timeoutRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
5126
5277
|
});
|
|
5127
5278
|
}, []);
|
|
5128
|
-
|
|
5279
|
+
React35.useEffect(() => () => clearTimeout(timeoutRef.current), []);
|
|
5129
5280
|
return [copied, copy];
|
|
5130
5281
|
}
|
|
5131
5282
|
function useDebounce(value, delay) {
|
|
5132
|
-
const [debounced, setDebounced] =
|
|
5133
|
-
|
|
5283
|
+
const [debounced, setDebounced] = React35.useState(value);
|
|
5284
|
+
React35.useEffect(() => {
|
|
5134
5285
|
const timer = setTimeout(() => setDebounced(value), delay);
|
|
5135
5286
|
return () => clearTimeout(timer);
|
|
5136
5287
|
}, [value, delay]);
|
|
5137
5288
|
return debounced;
|
|
5138
5289
|
}
|
|
5139
5290
|
function useLocalStorage(key, initialValue) {
|
|
5140
|
-
const [storedValue, setStoredValue] =
|
|
5291
|
+
const [storedValue, setStoredValue] = React35.useState(() => {
|
|
5141
5292
|
if (typeof window === "undefined") return initialValue;
|
|
5142
5293
|
try {
|
|
5143
5294
|
const item = window.localStorage.getItem(key);
|
|
@@ -5146,7 +5297,7 @@ function useLocalStorage(key, initialValue) {
|
|
|
5146
5297
|
return initialValue;
|
|
5147
5298
|
}
|
|
5148
5299
|
});
|
|
5149
|
-
const setValue =
|
|
5300
|
+
const setValue = React35.useCallback(
|
|
5150
5301
|
(value) => {
|
|
5151
5302
|
try {
|
|
5152
5303
|
setStoredValue(value);
|
|
@@ -5160,12 +5311,19 @@ function useLocalStorage(key, initialValue) {
|
|
|
5160
5311
|
);
|
|
5161
5312
|
return [storedValue, setValue];
|
|
5162
5313
|
}
|
|
5314
|
+
|
|
5315
|
+
// src/hooks/use-view-mode.ts
|
|
5316
|
+
function useViewMode(key = "view-mode", fallback = "cards") {
|
|
5317
|
+
const [stored, setStored] = useLocalStorage(key, fallback);
|
|
5318
|
+
const mounted = useMounted();
|
|
5319
|
+
return { view: mounted ? stored : fallback, setView: setStored, ready: mounted };
|
|
5320
|
+
}
|
|
5163
5321
|
function useMediaQuery(query) {
|
|
5164
|
-
const [matches, setMatches] =
|
|
5322
|
+
const [matches, setMatches] = React35.useState(() => {
|
|
5165
5323
|
if (typeof window === "undefined") return false;
|
|
5166
5324
|
return window.matchMedia(query).matches;
|
|
5167
5325
|
});
|
|
5168
|
-
|
|
5326
|
+
React35.useEffect(() => {
|
|
5169
5327
|
if (typeof window === "undefined") return;
|
|
5170
5328
|
const mql = window.matchMedia(query);
|
|
5171
5329
|
setMatches(mql.matches);
|
|
@@ -5176,18 +5334,18 @@ function useMediaQuery(query) {
|
|
|
5176
5334
|
return matches;
|
|
5177
5335
|
}
|
|
5178
5336
|
function usePagination(total, pageSize) {
|
|
5179
|
-
const [page, setPage] =
|
|
5337
|
+
const [page, setPage] = React35.useState(1);
|
|
5180
5338
|
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
5181
5339
|
const offset = (page - 1) * pageSize;
|
|
5182
|
-
const goTo =
|
|
5340
|
+
const goTo = React35.useCallback(
|
|
5183
5341
|
(p) => setPage(Math.min(Math.max(1, p), totalPages)),
|
|
5184
5342
|
[totalPages]
|
|
5185
5343
|
);
|
|
5186
|
-
const next =
|
|
5187
|
-
const prev =
|
|
5344
|
+
const next = React35.useCallback(() => goTo(page + 1), [page, goTo]);
|
|
5345
|
+
const prev = React35.useCallback(() => goTo(page - 1), [page, goTo]);
|
|
5188
5346
|
return { page, pageSize, totalPages, offset, hasPrev: page > 1, hasNext: page < totalPages, goTo, next, prev };
|
|
5189
5347
|
}
|
|
5190
5348
|
|
|
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 };
|
|
5349
|
+
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
5350
|
//# sourceMappingURL=index.js.map
|
|
5193
5351
|
//# sourceMappingURL=index.js.map
|