@olwiba/ui 0.1.15 → 0.2.0
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 +93 -35
- package/dist/index.js +575 -408
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/app/AuthSection.tsx +5 -4
- package/src/app/BillingPanel.tsx +18 -12
- package/src/app/OnboardingWizard.tsx +19 -6
- package/src/app/SettingsSection.tsx +1 -1
- package/src/app/TeamMembersPanel.tsx +47 -37
- package/src/components/ActivityFeed.tsx +82 -0
- package/src/components/CommandMenu.tsx +7 -1
- package/src/components/DataTable.tsx +23 -13
- package/src/components/FileUpload.tsx +24 -5
- package/src/components/NotificationsPopover.tsx +146 -0
- package/src/components/Notify.tsx +4 -2
- package/src/index.ts +5 -2
- package/src/marketing/ContactSection.tsx +13 -2
- package/src/marketing/CtaSection.tsx +93 -9
- package/src/marketing/FeaturesSection.tsx +27 -12
- package/src/marketing/HeroSection.tsx +5 -2
- package/src/marketing/NewsletterSection.tsx +12 -2
- package/src/marketing/TeamSection.tsx +10 -2
- package/src/mechanics/Carousel.tsx +112 -0
- package/src/marketing/CarouselSection.tsx +0 -126
- package/src/marketing/CtaCardSection.tsx +0 -95
package/dist/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { cn } from './chunk-AMWLSHD6.js';
|
|
2
2
|
export { MdxContent, cn } from './chunk-AMWLSHD6.js';
|
|
3
|
-
import * as
|
|
3
|
+
import * as React31 from 'react';
|
|
4
4
|
import { useRef, useEffect, useState } from 'react';
|
|
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,
|
|
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, ArrowLeft, ArrowUpRight, X, ArrowRight, Sparkles,
|
|
8
|
+
import { Search, ArrowUp, ArrowDown, ArrowUpDown, ChevronLeft, ChevronRight, MoreHorizontal, UserPlus, Download, CreditCard, Check, Loader2, ArrowLeft, ArrowUpRight, X, ArrowRight, Sparkles, 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, LayoutGrid, ShieldCheck, Building2, MoreVerticalIcon, CreditCardIcon, BellIcon, LogOutIcon } from 'lucide-react';
|
|
9
9
|
import { useReactTable, getPaginationRowModel, getSortedRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
|
|
10
10
|
import { toast } from 'sonner';
|
|
11
11
|
|
|
12
|
-
var OlwibaUIContext =
|
|
12
|
+
var OlwibaUIContext = React31.createContext({
|
|
13
13
|
isMobile: false,
|
|
14
14
|
mode: "default",
|
|
15
15
|
setMode: () => {
|
|
@@ -18,17 +18,17 @@ var OlwibaUIContext = React30.createContext({
|
|
|
18
18
|
function OlwibaUIProvider({ children, isMobile: isMobileProp, mode: initialMode = "default" }) {
|
|
19
19
|
const detectedMobile = useIsMobile();
|
|
20
20
|
const isMobile = isMobileProp ?? detectedMobile;
|
|
21
|
-
const [mode, setMode] =
|
|
21
|
+
const [mode, setMode] = React31.useState(initialMode);
|
|
22
22
|
const variant = mode !== "default" ? mode : void 0;
|
|
23
23
|
return /* @__PURE__ */ jsx(OlwibaUIContext.Provider, { value: { isMobile, mode, setMode }, children: /* @__PURE__ */ jsx(UIVariantProvider, { mode: variant, children }) });
|
|
24
24
|
}
|
|
25
25
|
function useOlwibaUI() {
|
|
26
|
-
return
|
|
26
|
+
return React31.useContext(OlwibaUIContext);
|
|
27
27
|
}
|
|
28
28
|
function useUIMode() {
|
|
29
|
-
return
|
|
29
|
+
return React31.useContext(OlwibaUIContext).mode;
|
|
30
30
|
}
|
|
31
|
-
var Button =
|
|
31
|
+
var Button = React31.forwardRef(
|
|
32
32
|
({ mode, ...props }, ref) => {
|
|
33
33
|
const ctxMode = useUIMode();
|
|
34
34
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
@@ -36,7 +36,7 @@ var Button = React30.forwardRef(
|
|
|
36
36
|
}
|
|
37
37
|
);
|
|
38
38
|
Button.displayName = "Button";
|
|
39
|
-
var Card =
|
|
39
|
+
var Card = React31.forwardRef(
|
|
40
40
|
({ mode, ...props }, ref) => {
|
|
41
41
|
const ctxMode = useUIMode();
|
|
42
42
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
@@ -47,7 +47,7 @@ Card.displayName = "Card";
|
|
|
47
47
|
function Badge(props) {
|
|
48
48
|
return /* @__PURE__ */ jsx(Badge$1, { ...props });
|
|
49
49
|
}
|
|
50
|
-
var Input =
|
|
50
|
+
var Input = React31.forwardRef(
|
|
51
51
|
({ mode, ...props }, ref) => {
|
|
52
52
|
const ctxMode = useUIMode();
|
|
53
53
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
@@ -55,7 +55,7 @@ var Input = React30.forwardRef(
|
|
|
55
55
|
}
|
|
56
56
|
);
|
|
57
57
|
Input.displayName = "Input";
|
|
58
|
-
var Textarea =
|
|
58
|
+
var Textarea = React31.forwardRef(
|
|
59
59
|
({ mode, ...props }, ref) => {
|
|
60
60
|
const ctxMode = useUIMode();
|
|
61
61
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
@@ -63,13 +63,13 @@ var Textarea = React30.forwardRef(
|
|
|
63
63
|
}
|
|
64
64
|
);
|
|
65
65
|
Textarea.displayName = "Textarea";
|
|
66
|
-
var Checkbox =
|
|
66
|
+
var Checkbox = React31.forwardRef(({ mode, ...props }, ref) => {
|
|
67
67
|
const ctxMode = useUIMode();
|
|
68
68
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
69
69
|
return /* @__PURE__ */ jsx(Checkbox$1, { mode: resolvedMode, ...props, ref });
|
|
70
70
|
});
|
|
71
71
|
Checkbox.displayName = "Checkbox";
|
|
72
|
-
var Switch =
|
|
72
|
+
var Switch = React31.forwardRef(({ mode: _mode, ...props }, ref) => {
|
|
73
73
|
return /* @__PURE__ */ jsx(Switch$1, { ...props, ref });
|
|
74
74
|
});
|
|
75
75
|
Switch.displayName = "Switch";
|
|
@@ -513,7 +513,7 @@ function DefaultForm({
|
|
|
513
513
|
const isForgotPassword = mode === "forgot-password";
|
|
514
514
|
const isResetPassword = mode === "reset-password";
|
|
515
515
|
const isVerify = mode === "verify";
|
|
516
|
-
const [code, setCode] =
|
|
516
|
+
const [code, setCode] = React31.useState("");
|
|
517
517
|
const hasPrefill = !!(defaultEmail || defaultPassword);
|
|
518
518
|
const prefillStyle = (active) => active ? { animation: "auth-prefill 1.6s ease-out 0.35s 1 both" } : void 0;
|
|
519
519
|
const copy = authCopy[mode];
|
|
@@ -586,11 +586,14 @@ function DefaultForm({
|
|
|
586
586
|
/* @__PURE__ */ jsx("input", { type: "hidden", name: "code", value: code }),
|
|
587
587
|
/* @__PURE__ */ jsx("div", { className: "flex justify-center py-2", children: /* @__PURE__ */ jsx(InputOTP, { maxLength: codeLength, value: code, onChange: setCode, containerClassName: "justify-center", children: /* @__PURE__ */ jsx(InputOTPGroup, { children: Array.from({ length: codeLength }).map((_, i) => /* @__PURE__ */ jsx(InputOTPSlot, { index: i }, i)) }) }) })
|
|
588
588
|
] }),
|
|
589
|
-
error && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-destructive", children: error }),
|
|
590
|
-
success && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-primary", children: success }),
|
|
589
|
+
error && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm font-medium text-destructive", children: error }),
|
|
590
|
+
success && /* @__PURE__ */ jsx("p", { role: "status", className: "text-sm font-medium text-primary", children: success }),
|
|
591
591
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
592
|
-
/* @__PURE__ */
|
|
593
|
-
|
|
592
|
+
/* @__PURE__ */ jsxs(Button, { type: "submit", className: "w-full", disabled: loading || isVerify && code.length < codeLength, children: [
|
|
593
|
+
loading && /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin" }),
|
|
594
|
+
loading ? "Please wait\u2026" : copy.submit
|
|
595
|
+
] }),
|
|
596
|
+
onSso && (mode === "signin" || mode === "signup") && /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", className: "w-full", onClick: onSso, disabled: loading, children: "Use SSO" })
|
|
594
597
|
] })
|
|
595
598
|
] }),
|
|
596
599
|
isVerify && onResend && /* @__PURE__ */ jsxs("p", { className: "text-center text-xs text-muted-foreground", children: [
|
|
@@ -670,10 +673,10 @@ function DataTable({
|
|
|
670
673
|
emptyMessage = "No results.",
|
|
671
674
|
className
|
|
672
675
|
}) {
|
|
673
|
-
const [sorting, setSorting] =
|
|
674
|
-
const [rowSelection, setRowSelection] =
|
|
675
|
-
const [globalFilter, setGlobalFilter] =
|
|
676
|
-
const allColumns =
|
|
676
|
+
const [sorting, setSorting] = React31.useState([]);
|
|
677
|
+
const [rowSelection, setRowSelection] = React31.useState({});
|
|
678
|
+
const [globalFilter, setGlobalFilter] = React31.useState("");
|
|
679
|
+
const allColumns = React31.useMemo(
|
|
677
680
|
() => selectable ? [selectColumn, ...columns] : columns,
|
|
678
681
|
[selectable, columns]
|
|
679
682
|
);
|
|
@@ -695,7 +698,7 @@ function DataTable({
|
|
|
695
698
|
initialState: pageSize > 0 ? { pagination: { pageSize } } : void 0,
|
|
696
699
|
enableRowSelection: selectable
|
|
697
700
|
});
|
|
698
|
-
|
|
701
|
+
React31.useEffect(() => {
|
|
699
702
|
if (!onSelectionChange) return;
|
|
700
703
|
onSelectionChange(table.getSelectedRowModel().rows.map((r) => r.original));
|
|
701
704
|
}, [rowSelection]);
|
|
@@ -720,39 +723,48 @@ function DataTable({
|
|
|
720
723
|
/* @__PURE__ */ jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(TableRow, { children: headerGroup.headers.map((header) => {
|
|
721
724
|
const canSort = header.column.getCanSort();
|
|
722
725
|
const sortDir = header.column.getIsSorted();
|
|
723
|
-
return /* @__PURE__ */ jsx(
|
|
724
|
-
|
|
726
|
+
return /* @__PURE__ */ jsx(
|
|
727
|
+
TableHead,
|
|
725
728
|
{
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
729
|
+
"aria-sort": sortDir === "asc" ? "ascending" : sortDir === "desc" ? "descending" : canSort ? "none" : void 0,
|
|
730
|
+
children: header.isPlaceholder ? null : canSort ? /* @__PURE__ */ jsxs(
|
|
731
|
+
"button",
|
|
732
|
+
{
|
|
733
|
+
type: "button",
|
|
734
|
+
className: "flex items-center gap-1.5 font-medium hover:text-foreground",
|
|
735
|
+
onClick: header.column.getToggleSortingHandler(),
|
|
736
|
+
children: [
|
|
737
|
+
flexRender(header.column.columnDef.header, header.getContext()),
|
|
738
|
+
sortDir === "asc" ? /* @__PURE__ */ jsx(ArrowUp, { className: "size-3.5" }) : sortDir === "desc" ? /* @__PURE__ */ jsx(ArrowDown, { className: "size-3.5" }) : /* @__PURE__ */ jsx(ArrowUpDown, { className: "size-3.5 text-muted-foreground/50" })
|
|
739
|
+
]
|
|
740
|
+
}
|
|
741
|
+
) : flexRender(header.column.columnDef.header, header.getContext())
|
|
742
|
+
},
|
|
743
|
+
header.id
|
|
744
|
+
);
|
|
735
745
|
}) }, headerGroup.id)) }),
|
|
736
746
|
/* @__PURE__ */ jsx(TableBody, { children: rows.length ? rows.map((row) => /* @__PURE__ */ jsx(
|
|
737
747
|
TableRow,
|
|
738
748
|
{
|
|
739
749
|
"data-state": row.getIsSelected() ? "selected" : void 0,
|
|
740
750
|
onClick: () => onRowClick?.(row.original),
|
|
741
|
-
|
|
751
|
+
tabIndex: onRowClick ? 0 : void 0,
|
|
752
|
+
onKeyDown: onRowClick ? (e) => {
|
|
753
|
+
if (e.key === "Enter" && e.target === e.currentTarget) onRowClick(row.original);
|
|
754
|
+
} : void 0,
|
|
755
|
+
className: cn$1(onRowClick && "cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"),
|
|
742
756
|
children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(TableCell, { children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id))
|
|
743
757
|
},
|
|
744
758
|
row.id
|
|
745
759
|
)) : /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, { colSpan: allColumns.length, className: "h-24 text-center text-muted-foreground", children: emptyMessage }) }) })
|
|
746
760
|
] }) }),
|
|
747
|
-
pageSize > 0 && table.getPageCount() > 1 && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
761
|
+
(selectable || pageSize > 0 && table.getPageCount() > 1) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
748
762
|
/* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
|
|
749
|
-
selectable && `${table.getFilteredSelectedRowModel().rows.length} of ${table.getFilteredRowModel().rows.length} selected
|
|
750
|
-
"
|
|
751
|
-
table.getState().pagination.pageIndex + 1
|
|
752
|
-
" of ",
|
|
753
|
-
table.getPageCount()
|
|
763
|
+
selectable && `${table.getFilteredSelectedRowModel().rows.length} of ${table.getFilteredRowModel().rows.length} selected`,
|
|
764
|
+
selectable && pageSize > 0 && table.getPageCount() > 1 && " \xB7 ",
|
|
765
|
+
pageSize > 0 && table.getPageCount() > 1 && `Page ${table.getState().pagination.pageIndex + 1} of ${table.getPageCount()}`
|
|
754
766
|
] }),
|
|
755
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
767
|
+
pageSize > 0 && table.getPageCount() > 1 && /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
756
768
|
/* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: () => table.previousPage(), disabled: !table.getCanPreviousPage(), children: [
|
|
757
769
|
/* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" }),
|
|
758
770
|
" Previous"
|
|
@@ -765,32 +777,42 @@ function DataTable({
|
|
|
765
777
|
] })
|
|
766
778
|
] });
|
|
767
779
|
}
|
|
768
|
-
function InviteDialog({ roles, onInvite }) {
|
|
769
|
-
const [email, setEmail] =
|
|
770
|
-
const [role, setRole] =
|
|
771
|
-
return /* @__PURE__ */
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
/* @__PURE__ */
|
|
780
|
+
function InviteDialog({ roles, onInvite, onClose }) {
|
|
781
|
+
const [email, setEmail] = React31.useState("");
|
|
782
|
+
const [role, setRole] = React31.useState(roles[roles.length - 1] ?? roles[0]);
|
|
783
|
+
return /* @__PURE__ */ jsx(DialogContent, { children: /* @__PURE__ */ jsxs(
|
|
784
|
+
"form",
|
|
785
|
+
{
|
|
786
|
+
onSubmit: (e) => {
|
|
787
|
+
e.preventDefault();
|
|
788
|
+
onInvite?.(email, role);
|
|
789
|
+
onClose();
|
|
790
|
+
},
|
|
791
|
+
children: [
|
|
792
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
793
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: "Invite a team member" }),
|
|
794
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: "They\u2019ll get an email invite to join this workspace." })
|
|
795
|
+
] }),
|
|
796
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-4 py-4", children: [
|
|
797
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
798
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "invite-email", children: "Email address" }),
|
|
799
|
+
/* @__PURE__ */ jsx(Input, { id: "invite-email", type: "email", required: true, placeholder: "name@company.com", value: email, onChange: (e) => setEmail(e.target.value) })
|
|
800
|
+
] }),
|
|
801
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
802
|
+
/* @__PURE__ */ jsx(Label, { children: "Role" }),
|
|
803
|
+
/* @__PURE__ */ jsxs(Select, { value: role, onValueChange: setRole, children: [
|
|
804
|
+
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
805
|
+
/* @__PURE__ */ jsx(SelectContent, { children: roles.map((r) => /* @__PURE__ */ jsx(SelectItem, { value: r, children: r }, r)) })
|
|
806
|
+
] })
|
|
807
|
+
] })
|
|
808
|
+
] }),
|
|
809
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
810
|
+
/* @__PURE__ */ jsx(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", children: "Cancel" }) }),
|
|
811
|
+
/* @__PURE__ */ jsx(Button, { type: "submit", children: "Send invite" })
|
|
786
812
|
] })
|
|
787
|
-
]
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
/* @__PURE__ */ jsx(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "outline", children: "Cancel" }) }),
|
|
791
|
-
/* @__PURE__ */ jsx(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx(Button, { disabled: !email, onClick: () => onInvite?.(email, role), children: "Send invite" }) })
|
|
792
|
-
] })
|
|
793
|
-
] });
|
|
813
|
+
]
|
|
814
|
+
}
|
|
815
|
+
) });
|
|
794
816
|
}
|
|
795
817
|
function TeamMembersPanel({
|
|
796
818
|
members,
|
|
@@ -801,7 +823,8 @@ function TeamMembersPanel({
|
|
|
801
823
|
title = "Team members",
|
|
802
824
|
description = "Manage who has access to this workspace."
|
|
803
825
|
}) {
|
|
804
|
-
const
|
|
826
|
+
const [inviteOpen, setInviteOpen] = React31.useState(false);
|
|
827
|
+
const columns = React31.useMemo(() => [
|
|
805
828
|
{
|
|
806
829
|
accessorKey: "name",
|
|
807
830
|
header: "Name",
|
|
@@ -824,7 +847,7 @@ function TeamMembersPanel({
|
|
|
824
847
|
/* @__PURE__ */ jsx(SelectContent, { children: roles.map((r) => /* @__PURE__ */ jsx(SelectItem, { value: r, children: r }, r)) })
|
|
825
848
|
] }) : /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", children: row.original.role })
|
|
826
849
|
},
|
|
827
|
-
{
|
|
850
|
+
...onRemove ? [{
|
|
828
851
|
id: "actions",
|
|
829
852
|
header: "",
|
|
830
853
|
cell: ({ row }) => /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
@@ -832,23 +855,23 @@ function TeamMembersPanel({
|
|
|
832
855
|
/* @__PURE__ */ jsx(MoreHorizontal, { className: "size-4" }),
|
|
833
856
|
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Row actions" })
|
|
834
857
|
] }) }),
|
|
835
|
-
/* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsx(DropdownMenuItem, { className: "text-destructive", onClick: () => onRemove
|
|
858
|
+
/* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsx(DropdownMenuItem, { className: "text-destructive", onClick: () => onRemove(row.original.id), children: "Remove member" }) })
|
|
836
859
|
] }),
|
|
837
860
|
enableSorting: false
|
|
838
|
-
}
|
|
861
|
+
}] : []
|
|
839
862
|
], [roles, onRoleChange, onRemove]);
|
|
840
863
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
841
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4", children: [
|
|
864
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [
|
|
842
865
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
843
866
|
/* @__PURE__ */ jsx("h2", { className: "text-base font-semibold", children: title }),
|
|
844
867
|
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: description })
|
|
845
868
|
] }),
|
|
846
|
-
/* @__PURE__ */ jsxs(Dialog, { children: [
|
|
869
|
+
onInvite && /* @__PURE__ */ jsxs(Dialog, { open: inviteOpen, onOpenChange: setInviteOpen, children: [
|
|
847
870
|
/* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { children: [
|
|
848
871
|
/* @__PURE__ */ jsx(UserPlus, { className: "size-4" }),
|
|
849
872
|
" Invite member"
|
|
850
873
|
] }) }),
|
|
851
|
-
/* @__PURE__ */ jsx(InviteDialog, { roles, onInvite })
|
|
874
|
+
/* @__PURE__ */ jsx(InviteDialog, { roles, onInvite, onClose: () => setInviteOpen(false) }, String(inviteOpen))
|
|
852
875
|
] })
|
|
853
876
|
] }),
|
|
854
877
|
/* @__PURE__ */ jsx(DataTable, { columns, data: members, searchKey: "name", searchPlaceholder: "Search members\u2026", pageSize: 0 })
|
|
@@ -870,12 +893,13 @@ function BillingPanel({
|
|
|
870
893
|
onUpdatePaymentMethod,
|
|
871
894
|
className
|
|
872
895
|
}) {
|
|
873
|
-
const invoiceColumns =
|
|
874
|
-
{ accessorKey: "date", header: "Date" },
|
|
875
|
-
{ accessorKey: "amount", header: "Amount" },
|
|
896
|
+
const invoiceColumns = React31.useMemo(() => [
|
|
897
|
+
{ accessorKey: "date", header: "Date", enableSorting: false },
|
|
898
|
+
{ accessorKey: "amount", header: "Amount", enableSorting: false },
|
|
876
899
|
{
|
|
877
900
|
accessorKey: "status",
|
|
878
901
|
header: "Status",
|
|
902
|
+
enableSorting: false,
|
|
879
903
|
cell: ({ row }) => /* @__PURE__ */ jsx(Badge$1, { variant: invoiceStatusVariant[row.original.status], className: "capitalize", children: row.original.status })
|
|
880
904
|
},
|
|
881
905
|
{
|
|
@@ -903,19 +927,23 @@ function BillingPanel({
|
|
|
903
927
|
] }),
|
|
904
928
|
onManagePlan && /* @__PURE__ */ jsx(Button, { onClick: onManagePlan, children: "Manage plan" })
|
|
905
929
|
] }),
|
|
906
|
-
usage && usage.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-4", children: usage.map((metric) =>
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
metric.
|
|
912
|
-
"
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
930
|
+
usage && usage.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-4", children: usage.map((metric) => {
|
|
931
|
+
const overLimit = metric.limit > 0 && metric.used > metric.limit;
|
|
932
|
+
const percent = metric.limit > 0 ? Math.min(100, metric.used / metric.limit * 100) : 0;
|
|
933
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
934
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [
|
|
935
|
+
/* @__PURE__ */ jsx("span", { children: metric.label }),
|
|
936
|
+
/* @__PURE__ */ jsxs("span", { className: overLimit ? "font-medium text-destructive" : "text-muted-foreground", children: [
|
|
937
|
+
metric.used,
|
|
938
|
+
metric.unit,
|
|
939
|
+
" / ",
|
|
940
|
+
metric.limit,
|
|
941
|
+
metric.unit
|
|
942
|
+
] })
|
|
943
|
+
] }),
|
|
944
|
+
/* @__PURE__ */ jsx(Progress, { value: percent, className: overLimit ? "[&>div]:bg-destructive" : void 0 })
|
|
945
|
+
] }, metric.label);
|
|
946
|
+
}) })
|
|
919
947
|
] }),
|
|
920
948
|
paymentMethod && /* @__PURE__ */ jsx(SettingsSection, { title: "Payment method", description: "Used for your subscription renewal.", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4 rounded-lg border bg-card/60 p-4", children: [
|
|
921
949
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
@@ -944,9 +972,9 @@ function OnboardingWizard({
|
|
|
944
972
|
completeLabel = "Finish",
|
|
945
973
|
className
|
|
946
974
|
}) {
|
|
947
|
-
const [internalStep, setInternalStep] =
|
|
948
|
-
const [error, setError] =
|
|
949
|
-
const [pending, setPending] =
|
|
975
|
+
const [internalStep, setInternalStep] = React31.useState(0);
|
|
976
|
+
const [error, setError] = React31.useState(null);
|
|
977
|
+
const [pending, setPending] = React31.useState(false);
|
|
950
978
|
const index = stepProp ?? internalStep;
|
|
951
979
|
const current = steps[index];
|
|
952
980
|
const isLast = index === steps.length - 1;
|
|
@@ -959,8 +987,15 @@ function OnboardingWizard({
|
|
|
959
987
|
const handleNext = async () => {
|
|
960
988
|
if (current.onNext) {
|
|
961
989
|
setPending(true);
|
|
962
|
-
|
|
963
|
-
|
|
990
|
+
let result;
|
|
991
|
+
try {
|
|
992
|
+
result = await current.onNext();
|
|
993
|
+
} catch (err) {
|
|
994
|
+
setError(err instanceof Error ? err.message : "Something went wrong. Please try again.");
|
|
995
|
+
return;
|
|
996
|
+
} finally {
|
|
997
|
+
setPending(false);
|
|
998
|
+
}
|
|
964
999
|
if (result === false) {
|
|
965
1000
|
setError("Please complete this step before continuing.");
|
|
966
1001
|
return;
|
|
@@ -980,30 +1015,47 @@ function OnboardingWizard({
|
|
|
980
1015
|
if (index > 0) goTo(index - 1);
|
|
981
1016
|
};
|
|
982
1017
|
return /* @__PURE__ */ jsxs("div", { className: cn$1("w-full max-w-lg space-y-8", className), children: [
|
|
983
|
-
/* @__PURE__ */ jsx("ol", { className: "flex items-center", children: steps.map((step, i) => /* @__PURE__ */ jsxs(
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1018
|
+
/* @__PURE__ */ jsx("ol", { className: "flex items-center", "aria-label": "Progress", children: steps.map((step, i) => /* @__PURE__ */ jsxs(
|
|
1019
|
+
"li",
|
|
1020
|
+
{
|
|
1021
|
+
"aria-current": i === index ? "step" : void 0,
|
|
1022
|
+
className: cn$1("flex items-center", i !== steps.length - 1 && "flex-1"),
|
|
1023
|
+
children: [
|
|
1024
|
+
/* @__PURE__ */ jsxs(
|
|
1025
|
+
"div",
|
|
1026
|
+
{
|
|
1027
|
+
className: cn$1(
|
|
1028
|
+
"flex size-8 shrink-0 items-center justify-center rounded-full border text-xs font-medium",
|
|
1029
|
+
i < index ? "border-primary bg-primary text-primary-foreground" : i === index ? "border-primary text-primary" : "border-border text-muted-foreground"
|
|
1030
|
+
),
|
|
1031
|
+
children: [
|
|
1032
|
+
i < index ? /* @__PURE__ */ jsx(Check, { className: "size-4" }) : i + 1,
|
|
1033
|
+
/* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
|
|
1034
|
+
step.title,
|
|
1035
|
+
i < index ? " (completed)" : ""
|
|
1036
|
+
] })
|
|
1037
|
+
]
|
|
1038
|
+
}
|
|
990
1039
|
),
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1040
|
+
i !== steps.length - 1 && /* @__PURE__ */ jsx("div", { className: cn$1("mx-2 h-px flex-1", i < index ? "bg-primary" : "bg-border") })
|
|
1041
|
+
]
|
|
1042
|
+
},
|
|
1043
|
+
step.id
|
|
1044
|
+
)) }),
|
|
996
1045
|
/* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
997
1046
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
998
1047
|
/* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold tracking-tight", children: current.title }),
|
|
999
1048
|
current.description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: current.description })
|
|
1000
1049
|
] }),
|
|
1001
1050
|
/* @__PURE__ */ jsx("div", { children: current.content }),
|
|
1002
|
-
error && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-destructive", children: error })
|
|
1051
|
+
error && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm font-medium text-destructive", children: error })
|
|
1003
1052
|
] }),
|
|
1004
1053
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
1005
1054
|
/* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", onClick: handleBack, disabled: index === 0 || pending, children: "Back" }),
|
|
1006
|
-
/* @__PURE__ */
|
|
1055
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", onClick: handleNext, disabled: pending, children: [
|
|
1056
|
+
pending && /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin" }),
|
|
1057
|
+
pending ? "Please wait\u2026" : isLast ? completeLabel : "Continue"
|
|
1058
|
+
] })
|
|
1007
1059
|
] })
|
|
1008
1060
|
] });
|
|
1009
1061
|
}
|
|
@@ -1256,9 +1308,9 @@ function FadeIn({
|
|
|
1256
1308
|
style,
|
|
1257
1309
|
...props
|
|
1258
1310
|
}) {
|
|
1259
|
-
const ref =
|
|
1260
|
-
const [visible, setVisible] =
|
|
1261
|
-
|
|
1311
|
+
const ref = React31.useRef(null);
|
|
1312
|
+
const [visible, setVisible] = React31.useState(false);
|
|
1313
|
+
React31.useEffect(() => {
|
|
1262
1314
|
const el = ref.current;
|
|
1263
1315
|
if (!el) return;
|
|
1264
1316
|
const observer = new IntersectionObserver(
|
|
@@ -1365,27 +1417,28 @@ function HeroSection({
|
|
|
1365
1417
|
socialProofText,
|
|
1366
1418
|
renderLink = defaultRenderLink4
|
|
1367
1419
|
}) {
|
|
1420
|
+
const mode = useUIVariant();
|
|
1368
1421
|
return /* @__PURE__ */ jsx("section", { className: "overflow-hidden", children: /* @__PURE__ */ jsxs("div", { className: marketingSectionSpacing.hero, children: [
|
|
1369
1422
|
/* @__PURE__ */ jsxs("div", { className: "mx-auto grid max-w-6xl items-center gap-10 lg:grid-cols-2 lg:gap-16", children: [
|
|
1370
1423
|
/* @__PURE__ */ jsx(FadeIn, { direction: "left", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
1371
|
-
badge && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Badge
|
|
1424
|
+
badge && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: badge }) }),
|
|
1372
1425
|
/* @__PURE__ */ jsx("h1", { className: "text-balance text-4xl font-semibold tracking-tight sm:text-5xl lg:text-6xl", children: heading }),
|
|
1373
1426
|
/* @__PURE__ */ jsx("p", { className: "max-w-lg text-pretty text-lg text-muted-foreground", children: description }),
|
|
1374
1427
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
1375
1428
|
renderLink({
|
|
1376
1429
|
href: primaryCta.href,
|
|
1377
|
-
children: /* @__PURE__ */ jsxs(Button
|
|
1430
|
+
children: /* @__PURE__ */ jsxs(Button, { size: "lg", children: [
|
|
1378
1431
|
primaryCta.label,
|
|
1379
1432
|
/* @__PURE__ */ jsx(ArrowRight, { className: "ml-2 size-4" })
|
|
1380
1433
|
] })
|
|
1381
1434
|
}),
|
|
1382
1435
|
secondaryCta && renderLink({
|
|
1383
1436
|
href: secondaryCta.href,
|
|
1384
|
-
children: /* @__PURE__ */ jsx(Button
|
|
1437
|
+
children: /* @__PURE__ */ jsx(Button, { size: "lg", variant: "outline", children: secondaryCta.label })
|
|
1385
1438
|
})
|
|
1386
1439
|
] })
|
|
1387
1440
|
] }) }),
|
|
1388
|
-
media !== "none" && /* @__PURE__ */ jsx(FadeIn, { direction: "right", delay: 200, children: media === "phone" ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(PhoneFrame, { size: phoneSize, children: heroImage }) }) : /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-2xl", children: heroImage }) })
|
|
1441
|
+
media !== "none" && /* @__PURE__ */ jsx(FadeIn, { direction: "right", delay: 200, children: media === "phone" ? /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(PhoneFrame, { size: phoneSize, children: heroImage }) }) : /* @__PURE__ */ jsx("div", { className: cn$1("overflow-hidden", mode === "smooth" ? "rounded-3xl" : "rounded-2xl"), children: heroImage }) })
|
|
1389
1442
|
] }),
|
|
1390
1443
|
(avatarUrls?.length || socialProofText) && /* @__PURE__ */ jsx(FadeIn, { direction: "up", delay: 400, children: /* @__PURE__ */ jsxs("div", { className: "mx-auto mt-12 flex max-w-6xl items-center gap-4", children: [
|
|
1391
1444
|
avatarUrls && avatarUrls.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex -space-x-3", children: avatarUrls.map((url, i) => /* @__PURE__ */ jsxs(Avatar, { className: "size-9 border-2 border-background", children: [
|
|
@@ -1444,6 +1497,88 @@ function FeatureCard({ icon: Icon, title, description, href, className, ...props
|
|
|
1444
1497
|
}
|
|
1445
1498
|
return content;
|
|
1446
1499
|
}
|
|
1500
|
+
function Carousel({
|
|
1501
|
+
children,
|
|
1502
|
+
itemClassName = "w-[280px] sm:w-[320px]",
|
|
1503
|
+
controls = "top-right",
|
|
1504
|
+
ariaLabel,
|
|
1505
|
+
className
|
|
1506
|
+
}) {
|
|
1507
|
+
const mode = useUIVariant();
|
|
1508
|
+
const trackRef = React31.useRef(null);
|
|
1509
|
+
const [canPrev, setCanPrev] = React31.useState(false);
|
|
1510
|
+
const [canNext, setCanNext] = React31.useState(true);
|
|
1511
|
+
const updateScrollState = React31.useCallback(() => {
|
|
1512
|
+
const track = trackRef.current;
|
|
1513
|
+
if (!track) return;
|
|
1514
|
+
setCanPrev(track.scrollLeft > 8);
|
|
1515
|
+
setCanNext(track.scrollLeft < track.scrollWidth - track.clientWidth - 8);
|
|
1516
|
+
}, []);
|
|
1517
|
+
React31.useEffect(() => {
|
|
1518
|
+
const track = trackRef.current;
|
|
1519
|
+
if (!track) return;
|
|
1520
|
+
updateScrollState();
|
|
1521
|
+
track.addEventListener("scroll", updateScrollState, { passive: true });
|
|
1522
|
+
const observer = new ResizeObserver(updateScrollState);
|
|
1523
|
+
observer.observe(track);
|
|
1524
|
+
return () => {
|
|
1525
|
+
track.removeEventListener("scroll", updateScrollState);
|
|
1526
|
+
observer.disconnect();
|
|
1527
|
+
};
|
|
1528
|
+
}, [updateScrollState]);
|
|
1529
|
+
const scrollByItem = (direction) => {
|
|
1530
|
+
const track = trackRef.current;
|
|
1531
|
+
if (!track) return;
|
|
1532
|
+
const item = track.querySelector("[data-carousel-item]");
|
|
1533
|
+
const gap = parseFloat(getComputedStyle(track).columnGap) || 24;
|
|
1534
|
+
const step = item ? item.offsetWidth + gap : track.clientWidth * 0.8;
|
|
1535
|
+
track.scrollBy({ left: direction * step, behavior: "smooth" });
|
|
1536
|
+
};
|
|
1537
|
+
const controlClasses = cn$1(
|
|
1538
|
+
"flex size-9 items-center justify-center border bg-background text-foreground transition-colors",
|
|
1539
|
+
"hover:bg-muted disabled:opacity-40 disabled:hover:bg-background",
|
|
1540
|
+
mode === "smooth" ? "rounded-2xl" : "rounded-xl"
|
|
1541
|
+
);
|
|
1542
|
+
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
1543
|
+
controls === "top-right" && /* @__PURE__ */ jsxs("div", { className: "mb-4 flex items-center justify-end gap-2", children: [
|
|
1544
|
+
/* @__PURE__ */ jsx(
|
|
1545
|
+
"button",
|
|
1546
|
+
{
|
|
1547
|
+
type: "button",
|
|
1548
|
+
"aria-label": "Previous",
|
|
1549
|
+
className: controlClasses,
|
|
1550
|
+
onClick: () => scrollByItem(-1),
|
|
1551
|
+
disabled: !canPrev,
|
|
1552
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" })
|
|
1553
|
+
}
|
|
1554
|
+
),
|
|
1555
|
+
/* @__PURE__ */ jsx(
|
|
1556
|
+
"button",
|
|
1557
|
+
{
|
|
1558
|
+
type: "button",
|
|
1559
|
+
"aria-label": "Next",
|
|
1560
|
+
className: controlClasses,
|
|
1561
|
+
onClick: () => scrollByItem(1),
|
|
1562
|
+
disabled: !canNext,
|
|
1563
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })
|
|
1564
|
+
}
|
|
1565
|
+
)
|
|
1566
|
+
] }),
|
|
1567
|
+
/* @__PURE__ */ jsx(
|
|
1568
|
+
"div",
|
|
1569
|
+
{
|
|
1570
|
+
ref: trackRef,
|
|
1571
|
+
role: "region",
|
|
1572
|
+
"aria-label": ariaLabel,
|
|
1573
|
+
className: "flex snap-x snap-mandatory gap-6 overflow-x-auto pb-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
1574
|
+
children: React31.Children.map(
|
|
1575
|
+
children,
|
|
1576
|
+
(child) => child == null ? null : /* @__PURE__ */ jsx("div", { "data-carousel-item": true, className: cn$1("shrink-0 snap-start", itemClassName), children: child })
|
|
1577
|
+
)
|
|
1578
|
+
}
|
|
1579
|
+
)
|
|
1580
|
+
] });
|
|
1581
|
+
}
|
|
1447
1582
|
var translateMap2 = {
|
|
1448
1583
|
up: [0, 20],
|
|
1449
1584
|
down: [0, -20],
|
|
@@ -1461,9 +1596,9 @@ function StaggerChildren({
|
|
|
1461
1596
|
className,
|
|
1462
1597
|
...props
|
|
1463
1598
|
}) {
|
|
1464
|
-
const ref =
|
|
1465
|
-
const [visible, setVisible] =
|
|
1466
|
-
|
|
1599
|
+
const ref = React31.useRef(null);
|
|
1600
|
+
const [visible, setVisible] = React31.useState(false);
|
|
1601
|
+
React31.useEffect(() => {
|
|
1467
1602
|
const el = ref.current;
|
|
1468
1603
|
if (!el) return;
|
|
1469
1604
|
const observer = new IntersectionObserver(
|
|
@@ -1481,7 +1616,7 @@ function StaggerChildren({
|
|
|
1481
1616
|
return () => observer.disconnect();
|
|
1482
1617
|
}, [once]);
|
|
1483
1618
|
const [tx, ty] = translateMap2[direction];
|
|
1484
|
-
return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children:
|
|
1619
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React31.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
|
|
1485
1620
|
"div",
|
|
1486
1621
|
{
|
|
1487
1622
|
className: "h-full",
|
|
@@ -1499,7 +1634,8 @@ function FeaturesSection({
|
|
|
1499
1634
|
title = "Everything you need to ship fast",
|
|
1500
1635
|
description = "A complete system of components, blocks, and hooks designed to work together - and get out of your way.",
|
|
1501
1636
|
badge = "Features",
|
|
1502
|
-
features
|
|
1637
|
+
features,
|
|
1638
|
+
layout = "grid"
|
|
1503
1639
|
}) {
|
|
1504
1640
|
const mode = useUIVariant();
|
|
1505
1641
|
const sectionClasses = cn$1(
|
|
@@ -1508,18 +1644,19 @@ function FeaturesSection({
|
|
|
1508
1644
|
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1509
1645
|
!mode && "rounded-2xl border"
|
|
1510
1646
|
);
|
|
1511
|
-
|
|
1647
|
+
const cards = features.map((feature) => /* @__PURE__ */ jsx(
|
|
1648
|
+
FeatureCard,
|
|
1649
|
+
{
|
|
1650
|
+
icon: feature.icon,
|
|
1651
|
+
title: feature.title,
|
|
1652
|
+
description: feature.description,
|
|
1653
|
+
href: feature.href
|
|
1654
|
+
},
|
|
1655
|
+
feature.title
|
|
1656
|
+
));
|
|
1657
|
+
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: cn$1("mx-auto", layout === "carousel" ? "max-w-5xl" : "max-w-4xl"), children: [
|
|
1512
1658
|
/* @__PURE__ */ jsx(SectionTitle, { title, description, badge }),
|
|
1513
|
-
/* @__PURE__ */ jsx(StaggerChildren, { className: "mt-12 grid gap-8 sm:grid-cols-2 lg:grid-cols-3", children:
|
|
1514
|
-
FeatureCard,
|
|
1515
|
-
{
|
|
1516
|
-
icon: feature.icon,
|
|
1517
|
-
title: feature.title,
|
|
1518
|
-
description: feature.description,
|
|
1519
|
-
href: feature.href
|
|
1520
|
-
},
|
|
1521
|
-
feature.title
|
|
1522
|
-
)) })
|
|
1659
|
+
layout === "carousel" ? /* @__PURE__ */ jsx(FadeIn, { direction: "up", children: /* @__PURE__ */ jsx(Carousel, { className: "mt-10", ariaLabel: title, children: cards }) }) : /* @__PURE__ */ jsx(StaggerChildren, { className: "mt-12 grid gap-8 sm:grid-cols-2 lg:grid-cols-3", children: cards })
|
|
1523
1660
|
] }) }) });
|
|
1524
1661
|
}
|
|
1525
1662
|
function GroupedFeaturesSection({
|
|
@@ -1649,106 +1786,6 @@ function TechStackSection({
|
|
|
1649
1786
|
}) })
|
|
1650
1787
|
] }) }) });
|
|
1651
1788
|
}
|
|
1652
|
-
function CarouselSection({
|
|
1653
|
-
title = "Explore the platform",
|
|
1654
|
-
description,
|
|
1655
|
-
badge = "Features",
|
|
1656
|
-
features
|
|
1657
|
-
}) {
|
|
1658
|
-
const mode = useUIVariant();
|
|
1659
|
-
const trackRef = React30.useRef(null);
|
|
1660
|
-
const [canPrev, setCanPrev] = React30.useState(false);
|
|
1661
|
-
const [canNext, setCanNext] = React30.useState(true);
|
|
1662
|
-
const updateScrollState = React30.useCallback(() => {
|
|
1663
|
-
const track = trackRef.current;
|
|
1664
|
-
if (!track) return;
|
|
1665
|
-
setCanPrev(track.scrollLeft > 8);
|
|
1666
|
-
setCanNext(track.scrollLeft < track.scrollWidth - track.clientWidth - 8);
|
|
1667
|
-
}, []);
|
|
1668
|
-
React30.useEffect(() => {
|
|
1669
|
-
const track = trackRef.current;
|
|
1670
|
-
if (!track) return;
|
|
1671
|
-
updateScrollState();
|
|
1672
|
-
track.addEventListener("scroll", updateScrollState, { passive: true });
|
|
1673
|
-
const observer = new ResizeObserver(updateScrollState);
|
|
1674
|
-
observer.observe(track);
|
|
1675
|
-
return () => {
|
|
1676
|
-
track.removeEventListener("scroll", updateScrollState);
|
|
1677
|
-
observer.disconnect();
|
|
1678
|
-
};
|
|
1679
|
-
}, [updateScrollState]);
|
|
1680
|
-
const scrollByCard = (direction) => {
|
|
1681
|
-
const track = trackRef.current;
|
|
1682
|
-
if (!track) return;
|
|
1683
|
-
const card = track.querySelector("[data-carousel-item]");
|
|
1684
|
-
const step = card ? card.offsetWidth + 24 : track.clientWidth * 0.8;
|
|
1685
|
-
track.scrollBy({ left: direction * step, behavior: "smooth" });
|
|
1686
|
-
};
|
|
1687
|
-
const sectionClasses = cn$1(
|
|
1688
|
-
"overflow-hidden bg-card",
|
|
1689
|
-
mode === "smooth" && "rounded-3xl border",
|
|
1690
|
-
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1691
|
-
!mode && "rounded-2xl border"
|
|
1692
|
-
);
|
|
1693
|
-
const controlClasses = cn$1(
|
|
1694
|
-
"flex size-9 items-center justify-center border bg-background text-foreground transition-colors",
|
|
1695
|
-
"hover:bg-muted disabled:opacity-40 disabled:hover:bg-background",
|
|
1696
|
-
mode === "smooth" ? "rounded-2xl" : "rounded-xl"
|
|
1697
|
-
);
|
|
1698
|
-
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-5xl", children: [
|
|
1699
|
-
/* @__PURE__ */ jsx(SectionTitle, { title, description, badge }),
|
|
1700
|
-
/* @__PURE__ */ jsxs(FadeIn, { direction: "up", children: [
|
|
1701
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-10 flex items-center justify-end gap-2", children: [
|
|
1702
|
-
/* @__PURE__ */ jsx(
|
|
1703
|
-
"button",
|
|
1704
|
-
{
|
|
1705
|
-
type: "button",
|
|
1706
|
-
"aria-label": "Previous",
|
|
1707
|
-
className: controlClasses,
|
|
1708
|
-
onClick: () => scrollByCard(-1),
|
|
1709
|
-
disabled: !canPrev,
|
|
1710
|
-
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" })
|
|
1711
|
-
}
|
|
1712
|
-
),
|
|
1713
|
-
/* @__PURE__ */ jsx(
|
|
1714
|
-
"button",
|
|
1715
|
-
{
|
|
1716
|
-
type: "button",
|
|
1717
|
-
"aria-label": "Next",
|
|
1718
|
-
className: controlClasses,
|
|
1719
|
-
onClick: () => scrollByCard(1),
|
|
1720
|
-
disabled: !canNext,
|
|
1721
|
-
children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })
|
|
1722
|
-
}
|
|
1723
|
-
)
|
|
1724
|
-
] }),
|
|
1725
|
-
/* @__PURE__ */ jsx(
|
|
1726
|
-
"div",
|
|
1727
|
-
{
|
|
1728
|
-
ref: trackRef,
|
|
1729
|
-
className: "mt-4 flex snap-x snap-mandatory gap-6 overflow-x-auto pb-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
1730
|
-
children: features.map((feature) => /* @__PURE__ */ jsx(
|
|
1731
|
-
"div",
|
|
1732
|
-
{
|
|
1733
|
-
"data-carousel-item": true,
|
|
1734
|
-
className: "w-[280px] shrink-0 snap-start sm:w-[320px]",
|
|
1735
|
-
children: /* @__PURE__ */ jsx(
|
|
1736
|
-
FeatureCard,
|
|
1737
|
-
{
|
|
1738
|
-
icon: feature.icon,
|
|
1739
|
-
title: feature.title,
|
|
1740
|
-
description: feature.description,
|
|
1741
|
-
href: feature.href
|
|
1742
|
-
}
|
|
1743
|
-
)
|
|
1744
|
-
},
|
|
1745
|
-
feature.title
|
|
1746
|
-
))
|
|
1747
|
-
}
|
|
1748
|
-
)
|
|
1749
|
-
] })
|
|
1750
|
-
] }) }) });
|
|
1751
|
-
}
|
|
1752
1789
|
var speedDuration = {
|
|
1753
1790
|
slow: "280s",
|
|
1754
1791
|
normal: "180s",
|
|
@@ -1829,79 +1866,42 @@ function FeatureMarqueeSection({
|
|
|
1829
1866
|
` })
|
|
1830
1867
|
] });
|
|
1831
1868
|
}
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
})
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1846
|
-
!mode && "rounded-2xl border"
|
|
1847
|
-
);
|
|
1848
|
-
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsxs("div", { className: "relative px-6 py-16 sm:px-10 sm:py-24", children: [
|
|
1849
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(ellipse_at_center,hsl(var(--primary)/0.15),transparent_70%)]" }),
|
|
1850
|
-
/* @__PURE__ */ jsx(FadeIn, { direction: "up", children: /* @__PURE__ */ jsxs("div", { className: "relative mx-auto max-w-2xl text-center", children: [
|
|
1851
|
-
/* @__PURE__ */ jsx("div", { className: cn$1("mb-4 inline-flex h-10 w-10 items-center justify-center bg-primary/10 text-primary", mode === "smooth" ? "rounded-3xl" : "rounded-2xl"), children: /* @__PURE__ */ jsx(Sparkles, { className: "size-5" }) }),
|
|
1852
|
-
/* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: heading }),
|
|
1853
|
-
/* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-lg text-pretty text-muted-foreground", children: description }),
|
|
1854
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-8 flex flex-wrap items-center justify-center gap-3", children: [
|
|
1855
|
-
renderLink({
|
|
1856
|
-
href: primaryCta.href,
|
|
1857
|
-
children: /* @__PURE__ */ jsxs(Button$1, { size: "lg", children: [
|
|
1858
|
-
primaryCta.label,
|
|
1859
|
-
/* @__PURE__ */ jsx(ArrowRight, { className: "ml-2 size-4" })
|
|
1860
|
-
] })
|
|
1861
|
-
}),
|
|
1862
|
-
secondaryCta && renderLink({
|
|
1863
|
-
href: secondaryCta.href,
|
|
1864
|
-
children: /* @__PURE__ */ jsx(Button$1, { size: "lg", variant: "outline", children: secondaryCta.label })
|
|
1865
|
-
})
|
|
1866
|
-
] }),
|
|
1867
|
-
footnote && /* @__PURE__ */ jsx("p", { className: "mt-4 text-sm text-muted-foreground", children: footnote })
|
|
1868
|
-
] }) })
|
|
1869
|
-
] }) });
|
|
1869
|
+
function useIntersectionObserver(options) {
|
|
1870
|
+
const ref = React31.useRef(null);
|
|
1871
|
+
const [isIntersecting, setIsIntersecting] = React31.useState(false);
|
|
1872
|
+
React31.useEffect(() => {
|
|
1873
|
+
const el = ref.current;
|
|
1874
|
+
if (!el) return;
|
|
1875
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
1876
|
+
setIsIntersecting(entry.isIntersecting);
|
|
1877
|
+
}, options);
|
|
1878
|
+
observer.observe(el);
|
|
1879
|
+
return () => observer.disconnect();
|
|
1880
|
+
}, []);
|
|
1881
|
+
return [ref, isIntersecting];
|
|
1870
1882
|
}
|
|
1871
|
-
var
|
|
1872
|
-
function
|
|
1883
|
+
var defaultRenderLink5 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
1884
|
+
function ShowcaseCta({
|
|
1873
1885
|
heading,
|
|
1874
1886
|
description,
|
|
1875
1887
|
primaryCta,
|
|
1876
1888
|
footnote,
|
|
1877
1889
|
icon,
|
|
1878
|
-
renderLink =
|
|
1890
|
+
renderLink = defaultRenderLink5,
|
|
1891
|
+
sectionClasses
|
|
1879
1892
|
}) {
|
|
1880
|
-
const ref =
|
|
1881
|
-
const [visible, setVisible] =
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
const observer = new IntersectionObserver(
|
|
1886
|
-
([entry]) => {
|
|
1887
|
-
if (entry.isIntersecting) {
|
|
1888
|
-
setVisible(true);
|
|
1889
|
-
observer.disconnect();
|
|
1890
|
-
}
|
|
1891
|
-
},
|
|
1892
|
-
{ threshold: 0.15 }
|
|
1893
|
-
);
|
|
1894
|
-
observer.observe(el);
|
|
1895
|
-
return () => observer.disconnect();
|
|
1896
|
-
}, []);
|
|
1893
|
+
const [ref, intersecting] = useIntersectionObserver({ threshold: 0.15 });
|
|
1894
|
+
const [visible, setVisible] = React31.useState(false);
|
|
1895
|
+
React31.useEffect(() => {
|
|
1896
|
+
if (intersecting) setVisible(true);
|
|
1897
|
+
}, [intersecting]);
|
|
1897
1898
|
return /* @__PURE__ */ jsxs(
|
|
1898
1899
|
"section",
|
|
1899
1900
|
{
|
|
1900
1901
|
ref,
|
|
1901
1902
|
className: cn$1(
|
|
1902
|
-
|
|
1903
|
-
"
|
|
1904
|
-
"transition-[opacity,transform] duration-700 ease-out",
|
|
1903
|
+
sectionClasses,
|
|
1904
|
+
"relative transition-[opacity,transform] duration-700 ease-out",
|
|
1905
1905
|
visible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-6"
|
|
1906
1906
|
),
|
|
1907
1907
|
children: [
|
|
@@ -1910,11 +1910,11 @@ function CtaCardSection({
|
|
|
1910
1910
|
{
|
|
1911
1911
|
className: "pointer-events-none absolute inset-0 flex items-center justify-center",
|
|
1912
1912
|
style: {
|
|
1913
|
-
opacity: visible ? 0.
|
|
1913
|
+
opacity: visible ? 0.1 : 0,
|
|
1914
1914
|
transform: visible ? "scale(1) rotate(0deg)" : "scale(0.9) rotate(-5deg)",
|
|
1915
1915
|
transition: "opacity 700ms ease 200ms, transform 700ms ease 200ms"
|
|
1916
1916
|
},
|
|
1917
|
-
children: icon ?? /* @__PURE__ */ jsx(Rocket, { className: "size-72 text-foreground
|
|
1917
|
+
children: icon ?? /* @__PURE__ */ jsx(Rocket, { className: "size-72 text-foreground", strokeWidth: 0.75 })
|
|
1918
1918
|
}
|
|
1919
1919
|
),
|
|
1920
1920
|
/* @__PURE__ */ jsxs("div", { className: "relative z-10 px-6 py-20 text-center sm:px-10 sm:py-28", children: [
|
|
@@ -1922,9 +1922,9 @@ function CtaCardSection({
|
|
|
1922
1922
|
description && /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-lg text-pretty text-muted-foreground", children: description }),
|
|
1923
1923
|
/* @__PURE__ */ jsx("div", { className: "mt-8", children: renderLink({
|
|
1924
1924
|
href: primaryCta.href,
|
|
1925
|
-
children: /* @__PURE__ */ jsxs(
|
|
1925
|
+
children: /* @__PURE__ */ jsxs(Button, { size: "lg", className: "rounded-full px-6", children: [
|
|
1926
1926
|
primaryCta.label,
|
|
1927
|
-
/* @__PURE__ */ jsx(ArrowRight, { className: "size-4" })
|
|
1927
|
+
/* @__PURE__ */ jsx(ArrowRight, { className: "ml-2 size-4" })
|
|
1928
1928
|
] })
|
|
1929
1929
|
}) }),
|
|
1930
1930
|
footnote && /* @__PURE__ */ jsx("p", { className: "mt-5 text-sm text-muted-foreground", children: footnote })
|
|
@@ -1933,6 +1933,49 @@ function CtaCardSection({
|
|
|
1933
1933
|
}
|
|
1934
1934
|
);
|
|
1935
1935
|
}
|
|
1936
|
+
function CtaSection(props) {
|
|
1937
|
+
const {
|
|
1938
|
+
heading,
|
|
1939
|
+
description,
|
|
1940
|
+
primaryCta,
|
|
1941
|
+
secondaryCta,
|
|
1942
|
+
footnote,
|
|
1943
|
+
variant = "default",
|
|
1944
|
+
renderLink = defaultRenderLink5
|
|
1945
|
+
} = props;
|
|
1946
|
+
const mode = useUIVariant();
|
|
1947
|
+
const sectionClasses = cn$1(
|
|
1948
|
+
"overflow-hidden bg-card",
|
|
1949
|
+
mode === "smooth" && "rounded-3xl border",
|
|
1950
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1951
|
+
!mode && "rounded-2xl border"
|
|
1952
|
+
);
|
|
1953
|
+
if (variant === "showcase") {
|
|
1954
|
+
return /* @__PURE__ */ jsx(ShowcaseCta, { ...props, sectionClasses });
|
|
1955
|
+
}
|
|
1956
|
+
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsxs("div", { className: "relative px-6 py-16 sm:px-10 sm:py-24", children: [
|
|
1957
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(ellipse_at_center,hsl(var(--primary)/0.15),transparent_70%)]" }),
|
|
1958
|
+
/* @__PURE__ */ jsx(FadeIn, { direction: "up", children: /* @__PURE__ */ jsxs("div", { className: "relative mx-auto max-w-2xl text-center", children: [
|
|
1959
|
+
/* @__PURE__ */ jsx("div", { className: cn$1("mb-4 inline-flex h-10 w-10 items-center justify-center bg-primary/10 text-primary", mode === "smooth" ? "rounded-3xl" : "rounded-2xl"), children: /* @__PURE__ */ jsx(Sparkles, { className: "size-5" }) }),
|
|
1960
|
+
/* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: heading }),
|
|
1961
|
+
description && /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-lg text-pretty text-muted-foreground", children: description }),
|
|
1962
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-8 flex flex-wrap items-center justify-center gap-3", children: [
|
|
1963
|
+
renderLink({
|
|
1964
|
+
href: primaryCta.href,
|
|
1965
|
+
children: /* @__PURE__ */ jsxs(Button, { size: "lg", children: [
|
|
1966
|
+
primaryCta.label,
|
|
1967
|
+
/* @__PURE__ */ jsx(ArrowRight, { className: "ml-2 size-4" })
|
|
1968
|
+
] })
|
|
1969
|
+
}),
|
|
1970
|
+
secondaryCta && renderLink({
|
|
1971
|
+
href: secondaryCta.href,
|
|
1972
|
+
children: /* @__PURE__ */ jsx(Button, { size: "lg", variant: "outline", children: secondaryCta.label })
|
|
1973
|
+
})
|
|
1974
|
+
] }),
|
|
1975
|
+
footnote && /* @__PURE__ */ jsx("p", { className: "mt-4 text-sm text-muted-foreground", children: footnote })
|
|
1976
|
+
] }) })
|
|
1977
|
+
] }) });
|
|
1978
|
+
}
|
|
1936
1979
|
function PricingCard({
|
|
1937
1980
|
name,
|
|
1938
1981
|
price,
|
|
@@ -2026,8 +2069,8 @@ function CountdownTimer({
|
|
|
2026
2069
|
className,
|
|
2027
2070
|
compact = false
|
|
2028
2071
|
}) {
|
|
2029
|
-
const [timeLeft, setTimeLeft] =
|
|
2030
|
-
|
|
2072
|
+
const [timeLeft, setTimeLeft] = React31.useState(() => getTimeLeft(deadline));
|
|
2073
|
+
React31.useEffect(() => {
|
|
2031
2074
|
setTimeLeft(getTimeLeft(deadline));
|
|
2032
2075
|
const id = setInterval(() => setTimeLeft(getTimeLeft(deadline)), 1e3);
|
|
2033
2076
|
return () => clearInterval(id);
|
|
@@ -2053,7 +2096,7 @@ function CountdownTimer({
|
|
|
2053
2096
|
];
|
|
2054
2097
|
return /* @__PURE__ */ jsxs("div", { className: cn$1("flex items-center justify-center gap-2 text-sm", className), children: [
|
|
2055
2098
|
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
|
|
2056
|
-
/* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 font-mono font-semibold tabular-nums", children: units.map(({ value, unit }, i) => /* @__PURE__ */ jsxs(
|
|
2099
|
+
/* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 font-mono font-semibold tabular-nums", children: units.map(({ value, unit }, i) => /* @__PURE__ */ jsxs(React31.Fragment, { children: [
|
|
2057
2100
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
2058
2101
|
String(value).padStart(2, "0"),
|
|
2059
2102
|
/* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: unit })
|
|
@@ -2062,7 +2105,7 @@ function CountdownTimer({
|
|
|
2062
2105
|
] }, unit)) })
|
|
2063
2106
|
] });
|
|
2064
2107
|
}
|
|
2065
|
-
var
|
|
2108
|
+
var defaultRenderLink6 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
2066
2109
|
function PricingSection({
|
|
2067
2110
|
title = "Simple, transparent pricing",
|
|
2068
2111
|
description = "Start for free. Scale as you grow. No hidden fees.",
|
|
@@ -2070,13 +2113,13 @@ function PricingSection({
|
|
|
2070
2113
|
plans,
|
|
2071
2114
|
saveBadge = "Save 34%",
|
|
2072
2115
|
isAuthenticated,
|
|
2073
|
-
renderLink =
|
|
2116
|
+
renderLink = defaultRenderLink6,
|
|
2074
2117
|
footnote,
|
|
2075
2118
|
mode = "subscription",
|
|
2076
2119
|
foundingDeadline,
|
|
2077
2120
|
renderPlanFooter
|
|
2078
2121
|
}) {
|
|
2079
|
-
const [annual, setAnnual] =
|
|
2122
|
+
const [annual, setAnnual] = React31.useState(false);
|
|
2080
2123
|
const isOneTime = mode === "one-time";
|
|
2081
2124
|
const uiMode = useUIVariant();
|
|
2082
2125
|
const sectionClasses = cn$1(
|
|
@@ -2280,9 +2323,16 @@ function TeamSection({
|
|
|
2280
2323
|
title = "The people behind Olwiba",
|
|
2281
2324
|
description = "A small team with deep experience in design systems, open source, and developer tooling."
|
|
2282
2325
|
}) {
|
|
2283
|
-
|
|
2326
|
+
const mode = useUIVariant();
|
|
2327
|
+
const sectionClasses = cn$1(
|
|
2328
|
+
"overflow-hidden bg-card",
|
|
2329
|
+
mode === "smooth" && "rounded-3xl border",
|
|
2330
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
2331
|
+
!mode && "rounded-2xl border"
|
|
2332
|
+
);
|
|
2333
|
+
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-5xl", children: [
|
|
2284
2334
|
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
2285
|
-
/* @__PURE__ */ jsx(Badge
|
|
2335
|
+
/* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "mb-4", children: badge }),
|
|
2286
2336
|
/* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: title }),
|
|
2287
2337
|
/* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-xl text-pretty text-muted-foreground", children: description })
|
|
2288
2338
|
] }),
|
|
@@ -2338,10 +2388,10 @@ function CountUp({
|
|
|
2338
2388
|
className,
|
|
2339
2389
|
...props
|
|
2340
2390
|
}) {
|
|
2341
|
-
const ref =
|
|
2342
|
-
const [value, setValue] =
|
|
2343
|
-
const hasStarted =
|
|
2344
|
-
|
|
2391
|
+
const ref = React31.useRef(null);
|
|
2392
|
+
const [value, setValue] = React31.useState(from);
|
|
2393
|
+
const hasStarted = React31.useRef(false);
|
|
2394
|
+
React31.useEffect(() => {
|
|
2345
2395
|
const el = ref.current;
|
|
2346
2396
|
if (!el) return;
|
|
2347
2397
|
const observer = new IntersectionObserver(
|
|
@@ -2434,20 +2484,27 @@ function NewsletterSection({
|
|
|
2434
2484
|
successDescription = defaults.successDescription,
|
|
2435
2485
|
onSubscribe
|
|
2436
2486
|
} = {}) {
|
|
2437
|
-
const [email, setEmail] =
|
|
2438
|
-
const [submitted, setSubmitted] =
|
|
2487
|
+
const [email, setEmail] = React31.useState("");
|
|
2488
|
+
const [submitted, setSubmitted] = React31.useState(false);
|
|
2489
|
+
const mode = useUIVariant();
|
|
2490
|
+
const sectionClasses = cn$1(
|
|
2491
|
+
"overflow-hidden bg-card",
|
|
2492
|
+
mode === "smooth" && "rounded-3xl border",
|
|
2493
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
2494
|
+
!mode && "rounded-2xl border"
|
|
2495
|
+
);
|
|
2439
2496
|
async function handleSubmit(e) {
|
|
2440
2497
|
e.preventDefault();
|
|
2441
2498
|
if (!email) return;
|
|
2442
2499
|
await onSubscribe?.(email);
|
|
2443
2500
|
setSubmitted(true);
|
|
2444
2501
|
}
|
|
2445
|
-
return /* @__PURE__ */ jsx("section", { className:
|
|
2502
|
+
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsxs("div", { className: "relative px-6 py-14 sm:px-10 sm:py-20", children: [
|
|
2446
2503
|
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,hsl(var(--primary)/0.1),transparent_60%)]" }),
|
|
2447
2504
|
/* @__PURE__ */ jsxs("div", { className: "relative mx-auto max-w-xl text-center", children: [
|
|
2448
2505
|
/* @__PURE__ */ jsxs("div", { className: "mb-4 flex items-center justify-center gap-2", children: [
|
|
2449
2506
|
/* @__PURE__ */ jsx("div", { className: "inline-flex h-8 w-8 items-center justify-center rounded-xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Mail, { className: "size-4" }) }),
|
|
2450
|
-
/* @__PURE__ */ jsx(Badge
|
|
2507
|
+
/* @__PURE__ */ jsx(Badge, { variant: "secondary", children: badge })
|
|
2451
2508
|
] }),
|
|
2452
2509
|
/* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: title }),
|
|
2453
2510
|
/* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-sm text-pretty text-muted-foreground", children: description }),
|
|
@@ -2468,7 +2525,7 @@ function NewsletterSection({
|
|
|
2468
2525
|
}
|
|
2469
2526
|
),
|
|
2470
2527
|
/* @__PURE__ */ jsx(
|
|
2471
|
-
Input
|
|
2528
|
+
Input,
|
|
2472
2529
|
{
|
|
2473
2530
|
type: "email",
|
|
2474
2531
|
placeholder,
|
|
@@ -2478,7 +2535,7 @@ function NewsletterSection({
|
|
|
2478
2535
|
className: "flex-1"
|
|
2479
2536
|
}
|
|
2480
2537
|
),
|
|
2481
|
-
/* @__PURE__ */ jsxs(Button
|
|
2538
|
+
/* @__PURE__ */ jsxs(Button, { type: "submit", children: [
|
|
2482
2539
|
submitLabel,
|
|
2483
2540
|
/* @__PURE__ */ jsx(ArrowRight, { className: "ml-2 size-4" })
|
|
2484
2541
|
] })
|
|
@@ -2519,15 +2576,22 @@ function ContactSection({
|
|
|
2519
2576
|
sendAnotherLabel = defaults2.sendAnotherLabel,
|
|
2520
2577
|
onSubmit
|
|
2521
2578
|
} = {}) {
|
|
2522
|
-
const [submitted, setSubmitted] =
|
|
2579
|
+
const [submitted, setSubmitted] = React31.useState(false);
|
|
2580
|
+
const mode = useUIVariant();
|
|
2581
|
+
const sectionClasses = cn$1(
|
|
2582
|
+
"overflow-hidden bg-card",
|
|
2583
|
+
mode === "smooth" && "rounded-3xl border",
|
|
2584
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
2585
|
+
!mode && "rounded-2xl border"
|
|
2586
|
+
);
|
|
2523
2587
|
async function handleSubmit(e) {
|
|
2524
2588
|
e.preventDefault();
|
|
2525
2589
|
await onSubmit?.(e);
|
|
2526
2590
|
setSubmitted(true);
|
|
2527
2591
|
}
|
|
2528
|
-
return /* @__PURE__ */ jsx("section", { className:
|
|
2592
|
+
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsxs("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: [
|
|
2529
2593
|
/* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-2xl text-center", children: [
|
|
2530
|
-
badge && /* @__PURE__ */ jsx("div", { className: "mb-4 flex justify-center", children: /* @__PURE__ */ jsx(Badge
|
|
2594
|
+
badge && /* @__PURE__ */ jsx("div", { className: "mb-4 flex justify-center", children: /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: badge }) }),
|
|
2531
2595
|
/* @__PURE__ */ jsx("h2", { className: "text-balance text-4xl font-semibold tracking-tight sm:text-5xl", children: title }),
|
|
2532
2596
|
/* @__PURE__ */ jsx("p", { className: "mt-4 text-lg text-muted-foreground", children: description }),
|
|
2533
2597
|
contactInfo && contactInfo.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-8 flex flex-wrap justify-center gap-6", children: contactInfo.map(({ icon: Icon = Mail, label, value }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
@@ -2539,7 +2603,7 @@ function ContactSection({
|
|
|
2539
2603
|
/* @__PURE__ */ jsx("div", { className: "mx-auto flex h-14 w-14 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(MessageSquare, { className: "size-6" }) }),
|
|
2540
2604
|
/* @__PURE__ */ jsx("h3", { className: "mt-5 text-lg font-semibold", children: successTitle }),
|
|
2541
2605
|
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: successDescription }),
|
|
2542
|
-
/* @__PURE__ */ jsx(Button
|
|
2606
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: "mt-6", onClick: () => setSubmitted(false), children: sendAnotherLabel })
|
|
2543
2607
|
] }) : /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "mx-auto mt-16 max-w-xl sm:mt-20", children: [
|
|
2544
2608
|
/* @__PURE__ */ jsx(
|
|
2545
2609
|
"input",
|
|
@@ -2556,7 +2620,7 @@ function ContactSection({
|
|
|
2556
2620
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
2557
2621
|
/* @__PURE__ */ jsx(Label, { htmlFor: "contact-first", className: "block text-sm/6 font-semibold", children: "First name" }),
|
|
2558
2622
|
/* @__PURE__ */ jsx("div", { className: "mt-2.5", children: /* @__PURE__ */ jsx(
|
|
2559
|
-
Input
|
|
2623
|
+
Input,
|
|
2560
2624
|
{
|
|
2561
2625
|
id: "contact-first",
|
|
2562
2626
|
name: "firstName",
|
|
@@ -2569,7 +2633,7 @@ function ContactSection({
|
|
|
2569
2633
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
2570
2634
|
/* @__PURE__ */ jsx(Label, { htmlFor: "contact-last", className: "block text-sm/6 font-semibold", children: "Last name" }),
|
|
2571
2635
|
/* @__PURE__ */ jsx("div", { className: "mt-2.5", children: /* @__PURE__ */ jsx(
|
|
2572
|
-
Input
|
|
2636
|
+
Input,
|
|
2573
2637
|
{
|
|
2574
2638
|
id: "contact-last",
|
|
2575
2639
|
name: "lastName",
|
|
@@ -2586,7 +2650,7 @@ function ContactSection({
|
|
|
2586
2650
|
/* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: "(optional)" })
|
|
2587
2651
|
] }),
|
|
2588
2652
|
/* @__PURE__ */ jsx("div", { className: "mt-2.5", children: /* @__PURE__ */ jsx(
|
|
2589
|
-
Input
|
|
2653
|
+
Input,
|
|
2590
2654
|
{
|
|
2591
2655
|
id: "contact-company",
|
|
2592
2656
|
name: "company",
|
|
@@ -2598,7 +2662,7 @@ function ContactSection({
|
|
|
2598
2662
|
/* @__PURE__ */ jsxs("div", { className: "sm:col-span-2", children: [
|
|
2599
2663
|
/* @__PURE__ */ jsx(Label, { htmlFor: "contact-email", className: "block text-sm/6 font-semibold", children: "Email" }),
|
|
2600
2664
|
/* @__PURE__ */ jsx("div", { className: "mt-2.5", children: /* @__PURE__ */ jsx(
|
|
2601
|
-
Input
|
|
2665
|
+
Input,
|
|
2602
2666
|
{
|
|
2603
2667
|
id: "contact-email",
|
|
2604
2668
|
name: "email",
|
|
@@ -2644,7 +2708,7 @@ function ContactSection({
|
|
|
2644
2708
|
/* @__PURE__ */ jsxs("div", { className: "sm:col-span-2", children: [
|
|
2645
2709
|
/* @__PURE__ */ jsx(Label, { htmlFor: "contact-message", className: "block text-sm/6 font-semibold", children: "Message" }),
|
|
2646
2710
|
/* @__PURE__ */ jsx("div", { className: "mt-2.5", children: /* @__PURE__ */ jsx(
|
|
2647
|
-
Textarea
|
|
2711
|
+
Textarea,
|
|
2648
2712
|
{
|
|
2649
2713
|
id: "contact-message",
|
|
2650
2714
|
name: "message",
|
|
@@ -2692,7 +2756,7 @@ function ContactSection({
|
|
|
2692
2756
|
)
|
|
2693
2757
|
] })
|
|
2694
2758
|
] }),
|
|
2695
|
-
/* @__PURE__ */ jsx("div", { className: "mt-10", children: /* @__PURE__ */ jsxs(Button
|
|
2759
|
+
/* @__PURE__ */ jsx("div", { className: "mt-10", children: /* @__PURE__ */ jsxs(Button, { type: "submit", className: "w-full", children: [
|
|
2696
2760
|
"Let's talk",
|
|
2697
2761
|
/* @__PURE__ */ jsx(Send, { className: "ml-2 size-4" })
|
|
2698
2762
|
] }) })
|
|
@@ -2802,15 +2866,15 @@ function QualificationSection({
|
|
|
2802
2866
|
}) })
|
|
2803
2867
|
] }) }) });
|
|
2804
2868
|
}
|
|
2805
|
-
var
|
|
2869
|
+
var defaultRenderLink7 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
2806
2870
|
function Navbar({
|
|
2807
2871
|
brand,
|
|
2808
2872
|
navLinks,
|
|
2809
2873
|
cta,
|
|
2810
2874
|
controls,
|
|
2811
|
-
renderLink =
|
|
2875
|
+
renderLink = defaultRenderLink7
|
|
2812
2876
|
}) {
|
|
2813
|
-
const [open, setOpen] =
|
|
2877
|
+
const [open, setOpen] = React31.useState(false);
|
|
2814
2878
|
const brandHref = brand.href ?? "/";
|
|
2815
2879
|
const hasRightContent = controls?.length || cta?.primary || cta?.secondary;
|
|
2816
2880
|
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: [
|
|
@@ -2827,7 +2891,7 @@ function Navbar({
|
|
|
2827
2891
|
children: link.label
|
|
2828
2892
|
}) }, link.label)) }),
|
|
2829
2893
|
hasRightContent && /* @__PURE__ */ jsxs("div", { className: "hidden items-center justify-end gap-2 md:flex", children: [
|
|
2830
|
-
controls?.map((control, i) => /* @__PURE__ */ jsx(
|
|
2894
|
+
controls?.map((control, i) => /* @__PURE__ */ jsx(React31.Fragment, { children: control }, i)),
|
|
2831
2895
|
(cta?.secondary || cta?.primary) && controls?.length ? /* @__PURE__ */ jsx("div", { className: "mx-1 h-4 w-px bg-border" }) : null,
|
|
2832
2896
|
cta?.secondary && renderLink({
|
|
2833
2897
|
href: cta.secondary.href,
|
|
@@ -2851,7 +2915,7 @@ function Navbar({
|
|
|
2851
2915
|
/* @__PURE__ */ jsx("span", { children: brand.name })
|
|
2852
2916
|
] })
|
|
2853
2917
|
}) }) }),
|
|
2854
|
-
controls?.length ? /* @__PURE__ */ jsx("div", { className: "mb-4 flex w-full items-center justify-between gap-1", children: controls.map((control, i) => /* @__PURE__ */ jsx(
|
|
2918
|
+
controls?.length ? /* @__PURE__ */ jsx("div", { className: "mb-4 flex w-full items-center justify-between gap-1", children: controls.map((control, i) => /* @__PURE__ */ jsx(React31.Fragment, { children: control }, i)) }) : null,
|
|
2855
2919
|
/* @__PURE__ */ jsx(Separator, {}),
|
|
2856
2920
|
/* @__PURE__ */ jsx("nav", { className: "mt-4 flex flex-col gap-1", children: navLinks.map((link) => /* @__PURE__ */ jsx("span", { onClick: () => setOpen(false), children: renderLink({
|
|
2857
2921
|
href: link.href,
|
|
@@ -2872,14 +2936,14 @@ function Navbar({
|
|
|
2872
2936
|
] })
|
|
2873
2937
|
] }) });
|
|
2874
2938
|
}
|
|
2875
|
-
var
|
|
2939
|
+
var defaultRenderLink8 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
2876
2940
|
function Footer({
|
|
2877
2941
|
brand,
|
|
2878
2942
|
navLinks,
|
|
2879
2943
|
socialLinks,
|
|
2880
2944
|
legal,
|
|
2881
2945
|
status,
|
|
2882
|
-
renderLink =
|
|
2946
|
+
renderLink = defaultRenderLink8
|
|
2883
2947
|
}) {
|
|
2884
2948
|
const brandHref = brand.href ?? "/";
|
|
2885
2949
|
const copyrightText = legal ?? `\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${brand.name}. All rights reserved.`;
|
|
@@ -3000,7 +3064,7 @@ function LogoStrip({
|
|
|
3000
3064
|
] });
|
|
3001
3065
|
}
|
|
3002
3066
|
function GridUnderlay({ variant, size = 24, className, ...props }) {
|
|
3003
|
-
const id =
|
|
3067
|
+
const id = React31.useId();
|
|
3004
3068
|
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: [
|
|
3005
3069
|
/* @__PURE__ */ jsx("line", { x1: size / 2, y1: 0, x2: size / 2, y2: size, stroke: "currentColor", strokeWidth: 0.5 }),
|
|
3006
3070
|
/* @__PURE__ */ jsx("line", { x1: 0, y1: size / 2, x2: size, y2: size / 2, stroke: "currentColor", strokeWidth: 0.5 })
|
|
@@ -3028,9 +3092,9 @@ function GlowUnderlay({
|
|
|
3028
3092
|
style,
|
|
3029
3093
|
...props
|
|
3030
3094
|
}) {
|
|
3031
|
-
const [pos, setPos] =
|
|
3032
|
-
const containerRef =
|
|
3033
|
-
|
|
3095
|
+
const [pos, setPos] = React31.useState({ x: "50%", y: "50%" });
|
|
3096
|
+
const containerRef = React31.useRef(null);
|
|
3097
|
+
React31.useEffect(() => {
|
|
3034
3098
|
if (!followCursor) return;
|
|
3035
3099
|
const handleMouseMove = (e) => {
|
|
3036
3100
|
const el = containerRef.current;
|
|
@@ -3169,8 +3233,8 @@ function PageTransition({
|
|
|
3169
3233
|
style,
|
|
3170
3234
|
...props
|
|
3171
3235
|
}) {
|
|
3172
|
-
const [mounted, setMounted] =
|
|
3173
|
-
|
|
3236
|
+
const [mounted, setMounted] = React31.useState(false);
|
|
3237
|
+
React31.useEffect(() => {
|
|
3174
3238
|
const id = requestAnimationFrame(() => setMounted(true));
|
|
3175
3239
|
return () => cancelAnimationFrame(id);
|
|
3176
3240
|
}, []);
|
|
@@ -3197,8 +3261,8 @@ function Spotlight({
|
|
|
3197
3261
|
triggerClassName,
|
|
3198
3262
|
shortcut = "\u2318K"
|
|
3199
3263
|
}) {
|
|
3200
|
-
const [open, setOpen] =
|
|
3201
|
-
|
|
3264
|
+
const [open, setOpen] = React31.useState(false);
|
|
3265
|
+
React31.useEffect(() => {
|
|
3202
3266
|
const down = (e) => {
|
|
3203
3267
|
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
|
3204
3268
|
e.preventDefault();
|
|
@@ -3228,7 +3292,7 @@ function Spotlight({
|
|
|
3228
3292
|
/* @__PURE__ */ jsx(CommandInput, { placeholder }),
|
|
3229
3293
|
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
3230
3294
|
/* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
|
|
3231
|
-
groups.map((group, i) => /* @__PURE__ */ jsxs(
|
|
3295
|
+
groups.map((group, i) => /* @__PURE__ */ jsxs(React31.Fragment, { children: [
|
|
3232
3296
|
i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
3233
3297
|
/* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
3234
3298
|
CommandItem,
|
|
@@ -3253,8 +3317,8 @@ function Spotlight({
|
|
|
3253
3317
|
var BASE = 40;
|
|
3254
3318
|
var MAGNIFY_RADIUS = 80;
|
|
3255
3319
|
function Dock({ items, iconSize = BASE, magnification = 1.7, className, ...props }) {
|
|
3256
|
-
const [mouseX, setMouseX] =
|
|
3257
|
-
const containerRef =
|
|
3320
|
+
const [mouseX, setMouseX] = React31.useState(null);
|
|
3321
|
+
const containerRef = React31.useRef(null);
|
|
3258
3322
|
function getScale(index) {
|
|
3259
3323
|
if (mouseX === null || !containerRef.current) return 1;
|
|
3260
3324
|
const container = containerRef.current;
|
|
@@ -3353,7 +3417,7 @@ function ConfirmDialog({ isOpen, options, handleConfirm, handleCancel, destructi
|
|
|
3353
3417
|
] }) });
|
|
3354
3418
|
}
|
|
3355
3419
|
function RegisterHotkeys({ hotkeys }) {
|
|
3356
|
-
|
|
3420
|
+
React31.useEffect(() => {
|
|
3357
3421
|
const handleKeyDown = (event) => {
|
|
3358
3422
|
for (const hotkey of hotkeys) {
|
|
3359
3423
|
const matches = event.key.toLowerCase() === hotkey.key.toLowerCase() && !!event.ctrlKey === !!hotkey.ctrl && !!event.metaKey === !!hotkey.meta && !!event.shiftKey === !!hotkey.shift && !!event.altKey === !!hotkey.alt;
|
|
@@ -3370,10 +3434,10 @@ function RegisterHotkeys({ hotkeys }) {
|
|
|
3370
3434
|
return null;
|
|
3371
3435
|
}
|
|
3372
3436
|
function useControlledOpen(defaultOpen = false) {
|
|
3373
|
-
const [isOpen, setIsOpen] =
|
|
3374
|
-
const open =
|
|
3375
|
-
const close =
|
|
3376
|
-
const toggle =
|
|
3437
|
+
const [isOpen, setIsOpen] = React31.useState(defaultOpen);
|
|
3438
|
+
const open = React31.useCallback(() => setIsOpen(true), []);
|
|
3439
|
+
const close = React31.useCallback(() => setIsOpen(false), []);
|
|
3440
|
+
const toggle = React31.useCallback(() => setIsOpen((prev) => !prev), []);
|
|
3377
3441
|
return { isOpen, open, close, toggle, setIsOpen };
|
|
3378
3442
|
}
|
|
3379
3443
|
function CommandMenu({
|
|
@@ -3386,7 +3450,13 @@ function CommandMenu({
|
|
|
3386
3450
|
}) {
|
|
3387
3451
|
const internal = useControlledOpen(false);
|
|
3388
3452
|
const isOpen = openProp ?? internal.isOpen;
|
|
3389
|
-
const setOpen =
|
|
3453
|
+
const setOpen = React31.useCallback(
|
|
3454
|
+
(next) => {
|
|
3455
|
+
if (openProp === void 0) internal.setIsOpen(next);
|
|
3456
|
+
onOpenChange?.(next);
|
|
3457
|
+
},
|
|
3458
|
+
[openProp, onOpenChange, internal.setIsOpen]
|
|
3459
|
+
);
|
|
3390
3460
|
const runItem = (item) => {
|
|
3391
3461
|
setOpen(false);
|
|
3392
3462
|
item.onSelect();
|
|
@@ -3405,7 +3475,7 @@ function CommandMenu({
|
|
|
3405
3475
|
/* @__PURE__ */ jsx(CommandInput, { placeholder }),
|
|
3406
3476
|
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
3407
3477
|
/* @__PURE__ */ jsx(CommandEmpty, { children: emptyMessage }),
|
|
3408
|
-
groups.map((group, i) => /* @__PURE__ */ jsxs(
|
|
3478
|
+
groups.map((group, i) => /* @__PURE__ */ jsxs(React31.Fragment, { children: [
|
|
3409
3479
|
i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
3410
3480
|
/* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
3411
3481
|
CommandItem,
|
|
@@ -3446,19 +3516,20 @@ function FileUpload({
|
|
|
3446
3516
|
hint,
|
|
3447
3517
|
className
|
|
3448
3518
|
}) {
|
|
3449
|
-
const [internalFiles, setInternalFiles] =
|
|
3450
|
-
const [isDragging, setIsDragging] =
|
|
3451
|
-
const [validationError, setValidationError] =
|
|
3452
|
-
const inputRef =
|
|
3519
|
+
const [internalFiles, setInternalFiles] = React31.useState(defaultFiles ?? []);
|
|
3520
|
+
const [isDragging, setIsDragging] = React31.useState(false);
|
|
3521
|
+
const [validationError, setValidationError] = React31.useState(null);
|
|
3522
|
+
const inputRef = React31.useRef(null);
|
|
3523
|
+
const dragDepth = React31.useRef(0);
|
|
3453
3524
|
const files = filesProp ?? internalFiles;
|
|
3454
|
-
const setFiles =
|
|
3525
|
+
const setFiles = React31.useCallback(
|
|
3455
3526
|
(next) => {
|
|
3456
3527
|
if (!filesProp) setInternalFiles(next);
|
|
3457
3528
|
onFilesChange?.(next);
|
|
3458
3529
|
},
|
|
3459
3530
|
[filesProp, onFilesChange]
|
|
3460
3531
|
);
|
|
3461
|
-
const acceptList =
|
|
3532
|
+
const acceptList = React31.useMemo(
|
|
3462
3533
|
() => accept?.split(",").map((a) => a.trim().toLowerCase()).filter(Boolean) ?? [],
|
|
3463
3534
|
[accept]
|
|
3464
3535
|
);
|
|
@@ -3472,7 +3543,7 @@ function FileUpload({
|
|
|
3472
3543
|
const handleFiles = (fileList) => {
|
|
3473
3544
|
if (!fileList || disabled) return;
|
|
3474
3545
|
const incoming = Array.from(fileList);
|
|
3475
|
-
const room = maxFiles ? Math.max(0, maxFiles - files.length) : Infinity;
|
|
3546
|
+
const room = maxFiles && multiple ? Math.max(0, maxFiles - files.length) : maxFiles || Infinity;
|
|
3476
3547
|
if (maxFiles && room <= 0) {
|
|
3477
3548
|
setValidationError(`You can only add up to ${maxFiles} file${maxFiles === 1 ? "" : "s"}.`);
|
|
3478
3549
|
return;
|
|
@@ -3507,15 +3578,25 @@ function FileUpload({
|
|
|
3507
3578
|
tabIndex: disabled ? -1 : 0,
|
|
3508
3579
|
onClick: () => !disabled && inputRef.current?.click(),
|
|
3509
3580
|
onKeyDown: (e) => {
|
|
3510
|
-
if (
|
|
3581
|
+
if (disabled) return;
|
|
3582
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
3583
|
+
e.preventDefault();
|
|
3584
|
+
inputRef.current?.click();
|
|
3585
|
+
}
|
|
3511
3586
|
},
|
|
3512
|
-
onDragOver: (e) =>
|
|
3587
|
+
onDragOver: (e) => e.preventDefault(),
|
|
3588
|
+
onDragEnter: (e) => {
|
|
3513
3589
|
e.preventDefault();
|
|
3590
|
+
dragDepth.current += 1;
|
|
3514
3591
|
if (!disabled) setIsDragging(true);
|
|
3515
3592
|
},
|
|
3516
|
-
onDragLeave: () =>
|
|
3593
|
+
onDragLeave: () => {
|
|
3594
|
+
dragDepth.current = Math.max(0, dragDepth.current - 1);
|
|
3595
|
+
if (dragDepth.current === 0) setIsDragging(false);
|
|
3596
|
+
},
|
|
3517
3597
|
onDrop: (e) => {
|
|
3518
3598
|
e.preventDefault();
|
|
3599
|
+
dragDepth.current = 0;
|
|
3519
3600
|
setIsDragging(false);
|
|
3520
3601
|
handleFiles(e.dataTransfer.files);
|
|
3521
3602
|
},
|
|
@@ -3549,7 +3630,7 @@ function FileUpload({
|
|
|
3549
3630
|
]
|
|
3550
3631
|
}
|
|
3551
3632
|
),
|
|
3552
|
-
validationError && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-destructive", children: validationError }),
|
|
3633
|
+
validationError && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm font-medium text-destructive", children: validationError }),
|
|
3553
3634
|
files.length > 0 && /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: files.map(({ id, file, progress, status = "pending", error }) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-3 rounded-lg border bg-card/60 px-3 py-2.5", children: [
|
|
3554
3635
|
/* @__PURE__ */ jsx(File, { className: "size-5 shrink-0 text-muted-foreground" }),
|
|
3555
3636
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
@@ -3586,6 +3667,8 @@ function FileUpload({
|
|
|
3586
3667
|
var variantIcon = {
|
|
3587
3668
|
success: /* @__PURE__ */ jsx(CheckCircle2, { className: "size-5 text-primary" }),
|
|
3588
3669
|
info: /* @__PURE__ */ jsx(Info, { className: "size-5 text-muted-foreground" }),
|
|
3670
|
+
warning: /* @__PURE__ */ jsx(AlertTriangle, { className: "size-5 text-amber-500 dark:text-amber-400" }),
|
|
3671
|
+
error: /* @__PURE__ */ jsx(AlertCircle, { className: "size-5 text-destructive" }),
|
|
3589
3672
|
message: /* @__PURE__ */ jsx(Inbox, { className: "size-5 text-muted-foreground" })
|
|
3590
3673
|
};
|
|
3591
3674
|
function NotificationToast({
|
|
@@ -3620,6 +3703,104 @@ function notify(options) {
|
|
|
3620
3703
|
const { duration, ...toastProps } = options;
|
|
3621
3704
|
return toast.custom((id) => /* @__PURE__ */ jsx(NotificationToast, { ...toastProps, onDismiss: () => toast.dismiss(id) }), { duration });
|
|
3622
3705
|
}
|
|
3706
|
+
function NotificationsPopover({
|
|
3707
|
+
notifications,
|
|
3708
|
+
onNotificationClick,
|
|
3709
|
+
onMarkAllRead,
|
|
3710
|
+
title = "Notifications",
|
|
3711
|
+
emptyMessage = "Nothing new \u2014 you\u2019re all caught up.",
|
|
3712
|
+
align = "end",
|
|
3713
|
+
open,
|
|
3714
|
+
onOpenChange,
|
|
3715
|
+
className
|
|
3716
|
+
}) {
|
|
3717
|
+
const unreadCount = notifications.filter((n) => !n.read).length;
|
|
3718
|
+
return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange, children: [
|
|
3719
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "icon", className: cn$1("relative size-8", className), children: [
|
|
3720
|
+
/* @__PURE__ */ jsx(Bell, { className: "size-4" }),
|
|
3721
|
+
unreadCount > 0 && /* @__PURE__ */ jsx("span", { className: "absolute -right-0.5 -top-0.5 flex min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-semibold leading-4 text-primary-foreground", children: unreadCount > 9 ? "9+" : unreadCount }),
|
|
3722
|
+
/* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
|
|
3723
|
+
title,
|
|
3724
|
+
unreadCount > 0 ? ` (${unreadCount} unread)` : ""
|
|
3725
|
+
] })
|
|
3726
|
+
] }) }),
|
|
3727
|
+
/* @__PURE__ */ jsxs(PopoverContent, { align, className: "w-80 p-0", children: [
|
|
3728
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b px-4 py-3", children: [
|
|
3729
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: title }),
|
|
3730
|
+
onMarkAllRead && unreadCount > 0 && /* @__PURE__ */ jsx(
|
|
3731
|
+
"button",
|
|
3732
|
+
{
|
|
3733
|
+
type: "button",
|
|
3734
|
+
onClick: onMarkAllRead,
|
|
3735
|
+
className: "text-xs font-medium text-muted-foreground hover:text-foreground",
|
|
3736
|
+
children: "Mark all read"
|
|
3737
|
+
}
|
|
3738
|
+
)
|
|
3739
|
+
] }),
|
|
3740
|
+
notifications.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 px-4 py-10 text-center", children: [
|
|
3741
|
+
/* @__PURE__ */ jsx(Inbox, { className: "size-6 text-muted-foreground" }),
|
|
3742
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: emptyMessage })
|
|
3743
|
+
] }) : /* @__PURE__ */ jsx("ul", { className: "max-h-80 overflow-y-auto", children: notifications.map((notification) => /* @__PURE__ */ jsx("li", { className: "border-b last:border-b-0", children: /* @__PURE__ */ jsxs(
|
|
3744
|
+
"button",
|
|
3745
|
+
{
|
|
3746
|
+
type: "button",
|
|
3747
|
+
onClick: () => onNotificationClick?.(notification),
|
|
3748
|
+
className: cn$1(
|
|
3749
|
+
"flex w-full items-start gap-3 px-4 py-3 text-left transition-colors hover:bg-muted/60",
|
|
3750
|
+
!notification.read && "bg-muted/40"
|
|
3751
|
+
),
|
|
3752
|
+
children: [
|
|
3753
|
+
/* @__PURE__ */ jsx(
|
|
3754
|
+
"span",
|
|
3755
|
+
{
|
|
3756
|
+
"aria-hidden": true,
|
|
3757
|
+
className: cn$1(
|
|
3758
|
+
"mt-1.5 size-2 shrink-0 rounded-full",
|
|
3759
|
+
notification.read ? "bg-transparent" : "bg-primary"
|
|
3760
|
+
)
|
|
3761
|
+
}
|
|
3762
|
+
),
|
|
3763
|
+
notification.avatar ? /* @__PURE__ */ jsxs(Avatar, { className: "size-8 shrink-0", children: [
|
|
3764
|
+
/* @__PURE__ */ jsx(AvatarImage, { src: notification.avatar, alt: "" }),
|
|
3765
|
+
/* @__PURE__ */ jsx(AvatarFallback, { children: notification.title.slice(0, 2).toUpperCase() })
|
|
3766
|
+
] }) : notification.icon ? /* @__PURE__ */ jsx("span", { className: "mt-0.5 shrink-0 text-muted-foreground", children: notification.icon }) : null,
|
|
3767
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
|
|
3768
|
+
/* @__PURE__ */ jsx("span", { className: cn$1("block truncate text-sm", !notification.read && "font-medium"), children: notification.title }),
|
|
3769
|
+
notification.description && /* @__PURE__ */ jsx("span", { className: "mt-0.5 line-clamp-2 block text-xs text-muted-foreground", children: notification.description }),
|
|
3770
|
+
notification.timestamp && /* @__PURE__ */ jsx("span", { className: "mt-1 block text-xs text-muted-foreground/70", children: notification.timestamp })
|
|
3771
|
+
] })
|
|
3772
|
+
]
|
|
3773
|
+
}
|
|
3774
|
+
) }, notification.id)) })
|
|
3775
|
+
] })
|
|
3776
|
+
] });
|
|
3777
|
+
}
|
|
3778
|
+
function ActivityFeed({
|
|
3779
|
+
items,
|
|
3780
|
+
emptyMessage = "No activity yet.",
|
|
3781
|
+
className
|
|
3782
|
+
}) {
|
|
3783
|
+
if (items.length === 0) {
|
|
3784
|
+
return /* @__PURE__ */ jsxs("div", { className: cn$1("flex flex-col items-center gap-2 py-10 text-center", className), children: [
|
|
3785
|
+
/* @__PURE__ */ jsx(Activity, { className: "size-6 text-muted-foreground" }),
|
|
3786
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: emptyMessage })
|
|
3787
|
+
] });
|
|
3788
|
+
}
|
|
3789
|
+
return /* @__PURE__ */ jsx("ol", { className, children: items.map((item, i) => /* @__PURE__ */ jsxs("li", { className: "relative flex gap-3 pb-6 last:pb-0", children: [
|
|
3790
|
+
i !== items.length - 1 && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "absolute left-4 top-9 bottom-0 w-px -translate-x-1/2 bg-border" }),
|
|
3791
|
+
/* @__PURE__ */ jsx("span", { className: "relative z-10 flex size-8 shrink-0 items-center justify-center", children: item.avatar ? /* @__PURE__ */ jsxs(Avatar, { className: "size-8", children: [
|
|
3792
|
+
/* @__PURE__ */ jsx(AvatarImage, { src: item.avatar, alt: "" }),
|
|
3793
|
+
/* @__PURE__ */ jsx(AvatarFallback, { className: "text-xs", children: item.initials ?? "?" })
|
|
3794
|
+
] }) : /* @__PURE__ */ jsx("span", { className: "flex size-8 items-center justify-center rounded-full border bg-card text-muted-foreground [&>svg]:size-4", children: item.icon ?? /* @__PURE__ */ jsx(Activity, {}) }) }),
|
|
3795
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 pt-1", children: [
|
|
3796
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [
|
|
3797
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm", children: item.title }),
|
|
3798
|
+
item.timestamp && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: item.timestamp })
|
|
3799
|
+
] }),
|
|
3800
|
+
item.description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: item.description })
|
|
3801
|
+
] })
|
|
3802
|
+
] }, item.id)) });
|
|
3803
|
+
}
|
|
3623
3804
|
function AppScreenRoot({ children, className }) {
|
|
3624
3805
|
return /* @__PURE__ */ jsx("div", { className: cn("flex h-full flex-col", className), children });
|
|
3625
3806
|
}
|
|
@@ -4002,20 +4183,20 @@ function FullPageSpinner({ message }) {
|
|
|
4002
4183
|
message && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: message })
|
|
4003
4184
|
] });
|
|
4004
4185
|
}
|
|
4005
|
-
var
|
|
4186
|
+
var defaultRenderLink9 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
4006
4187
|
function PageHeader({
|
|
4007
4188
|
title,
|
|
4008
4189
|
description,
|
|
4009
4190
|
breadcrumbs,
|
|
4010
4191
|
backButton,
|
|
4011
|
-
renderLink =
|
|
4192
|
+
renderLink = defaultRenderLink9,
|
|
4012
4193
|
className,
|
|
4013
4194
|
children
|
|
4014
4195
|
}) {
|
|
4015
4196
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1 pb-6", className), children: [
|
|
4016
4197
|
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) => {
|
|
4017
4198
|
const isLast = i === breadcrumbs.length - 1;
|
|
4018
|
-
return /* @__PURE__ */ jsxs(
|
|
4199
|
+
return /* @__PURE__ */ jsxs(React31.Fragment, { children: [
|
|
4019
4200
|
i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0" }),
|
|
4020
4201
|
isLast || !crumb.href ? /* @__PURE__ */ jsx("span", { className: cn(isLast && "text-foreground font-medium"), children: crumb.label }) : renderLink({
|
|
4021
4202
|
href: crumb.href,
|
|
@@ -4051,7 +4232,7 @@ function PageHeader({
|
|
|
4051
4232
|
] });
|
|
4052
4233
|
}
|
|
4053
4234
|
function Suspensed({ children, fallback }) {
|
|
4054
|
-
return /* @__PURE__ */ jsx(
|
|
4235
|
+
return /* @__PURE__ */ jsx(React31.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
|
|
4055
4236
|
}
|
|
4056
4237
|
function getInitialTheme() {
|
|
4057
4238
|
if (typeof document === "undefined") return "dark";
|
|
@@ -4059,7 +4240,7 @@ function getInitialTheme() {
|
|
|
4059
4240
|
return stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
|
|
4060
4241
|
}
|
|
4061
4242
|
function ThemeSwitchMinimal() {
|
|
4062
|
-
const [theme, setThemeState] =
|
|
4243
|
+
const [theme, setThemeState] = React31.useState(getInitialTheme);
|
|
4063
4244
|
const toggle = () => {
|
|
4064
4245
|
const next = theme === "dark" ? "light" : "dark";
|
|
4065
4246
|
setThemeState(next);
|
|
@@ -4185,9 +4366,9 @@ function getInitialColorName() {
|
|
|
4185
4366
|
return localStorage.getItem(STORAGE_KEY) ?? "emerald";
|
|
4186
4367
|
}
|
|
4187
4368
|
function BrandColorSwitchMinimal() {
|
|
4188
|
-
const [active, setActive] =
|
|
4189
|
-
const [open, setOpen] =
|
|
4190
|
-
|
|
4369
|
+
const [active, setActive] = React31.useState(getInitialColorName);
|
|
4370
|
+
const [open, setOpen] = React31.useState(false);
|
|
4371
|
+
React31.useEffect(() => {
|
|
4191
4372
|
const saved = localStorage.getItem(STORAGE_KEY) ?? "emerald";
|
|
4192
4373
|
const color = BRAND_COLORS.find((c) => c.name === saved);
|
|
4193
4374
|
if (color) applyColor(color);
|
|
@@ -4248,7 +4429,7 @@ function BrandColorSwitchMinimal() {
|
|
|
4248
4429
|
] });
|
|
4249
4430
|
}
|
|
4250
4431
|
function ThemeColorUpdater({ colorTheme }) {
|
|
4251
|
-
|
|
4432
|
+
React31.useEffect(() => {
|
|
4252
4433
|
if (colorTheme) {
|
|
4253
4434
|
document.documentElement.setAttribute("data-theme", colorTheme);
|
|
4254
4435
|
} else {
|
|
@@ -4258,7 +4439,7 @@ function ThemeColorUpdater({ colorTheme }) {
|
|
|
4258
4439
|
return null;
|
|
4259
4440
|
}
|
|
4260
4441
|
function VersionBanner({ version, message, className, onDismiss }) {
|
|
4261
|
-
const [dismissed, setDismissed] =
|
|
4442
|
+
const [dismissed, setDismissed] = React31.useState(false);
|
|
4262
4443
|
if (dismissed) return null;
|
|
4263
4444
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-4 bg-primary/10 px-4 py-2 text-sm", className), children: [
|
|
4264
4445
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -4515,29 +4696,29 @@ function useMounted() {
|
|
|
4515
4696
|
return mounted;
|
|
4516
4697
|
}
|
|
4517
4698
|
function useConfirm() {
|
|
4518
|
-
const [isOpen, setIsOpen] =
|
|
4519
|
-
const [options, setOptions] =
|
|
4520
|
-
const resolveRef =
|
|
4521
|
-
const confirm =
|
|
4699
|
+
const [isOpen, setIsOpen] = React31.useState(false);
|
|
4700
|
+
const [options, setOptions] = React31.useState({});
|
|
4701
|
+
const resolveRef = React31.useRef(null);
|
|
4702
|
+
const confirm = React31.useCallback((opts = {}) => {
|
|
4522
4703
|
setOptions(opts);
|
|
4523
4704
|
setIsOpen(true);
|
|
4524
4705
|
return new Promise((resolve) => {
|
|
4525
4706
|
resolveRef.current = resolve;
|
|
4526
4707
|
});
|
|
4527
4708
|
}, []);
|
|
4528
|
-
const handleConfirm =
|
|
4709
|
+
const handleConfirm = React31.useCallback(() => {
|
|
4529
4710
|
resolveRef.current?.(true);
|
|
4530
4711
|
setIsOpen(false);
|
|
4531
4712
|
}, []);
|
|
4532
|
-
const handleCancel =
|
|
4713
|
+
const handleCancel = React31.useCallback(() => {
|
|
4533
4714
|
resolveRef.current?.(false);
|
|
4534
4715
|
setIsOpen(false);
|
|
4535
4716
|
}, []);
|
|
4536
4717
|
return { confirm, isOpen, options, handleConfirm, handleCancel };
|
|
4537
4718
|
}
|
|
4538
4719
|
function useScrolledPast(threshold) {
|
|
4539
|
-
const [scrolledPast, setScrolledPast] =
|
|
4540
|
-
|
|
4720
|
+
const [scrolledPast, setScrolledPast] = React31.useState(false);
|
|
4721
|
+
React31.useEffect(() => {
|
|
4541
4722
|
const handleScroll = () => {
|
|
4542
4723
|
setScrolledPast(window.scrollY > threshold);
|
|
4543
4724
|
};
|
|
@@ -4548,42 +4729,28 @@ function useScrolledPast(threshold) {
|
|
|
4548
4729
|
return scrolledPast;
|
|
4549
4730
|
}
|
|
4550
4731
|
function useCopyToClipboard() {
|
|
4551
|
-
const [copied, setCopied] =
|
|
4552
|
-
const timeoutRef =
|
|
4553
|
-
const copy =
|
|
4732
|
+
const [copied, setCopied] = React31.useState(false);
|
|
4733
|
+
const timeoutRef = React31.useRef(void 0);
|
|
4734
|
+
const copy = React31.useCallback((text) => {
|
|
4554
4735
|
navigator.clipboard.writeText(text).then(() => {
|
|
4555
4736
|
setCopied(true);
|
|
4556
4737
|
clearTimeout(timeoutRef.current);
|
|
4557
4738
|
timeoutRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
4558
4739
|
});
|
|
4559
4740
|
}, []);
|
|
4560
|
-
|
|
4741
|
+
React31.useEffect(() => () => clearTimeout(timeoutRef.current), []);
|
|
4561
4742
|
return [copied, copy];
|
|
4562
4743
|
}
|
|
4563
4744
|
function useDebounce(value, delay) {
|
|
4564
|
-
const [debounced, setDebounced] =
|
|
4565
|
-
|
|
4745
|
+
const [debounced, setDebounced] = React31.useState(value);
|
|
4746
|
+
React31.useEffect(() => {
|
|
4566
4747
|
const timer = setTimeout(() => setDebounced(value), delay);
|
|
4567
4748
|
return () => clearTimeout(timer);
|
|
4568
4749
|
}, [value, delay]);
|
|
4569
4750
|
return debounced;
|
|
4570
4751
|
}
|
|
4571
|
-
function useIntersectionObserver(options) {
|
|
4572
|
-
const ref = React30.useRef(null);
|
|
4573
|
-
const [isIntersecting, setIsIntersecting] = React30.useState(false);
|
|
4574
|
-
React30.useEffect(() => {
|
|
4575
|
-
const el = ref.current;
|
|
4576
|
-
if (!el) return;
|
|
4577
|
-
const observer = new IntersectionObserver(([entry]) => {
|
|
4578
|
-
setIsIntersecting(entry.isIntersecting);
|
|
4579
|
-
}, options);
|
|
4580
|
-
observer.observe(el);
|
|
4581
|
-
return () => observer.disconnect();
|
|
4582
|
-
}, []);
|
|
4583
|
-
return [ref, isIntersecting];
|
|
4584
|
-
}
|
|
4585
4752
|
function useLocalStorage(key, initialValue) {
|
|
4586
|
-
const [storedValue, setStoredValue] =
|
|
4753
|
+
const [storedValue, setStoredValue] = React31.useState(() => {
|
|
4587
4754
|
if (typeof window === "undefined") return initialValue;
|
|
4588
4755
|
try {
|
|
4589
4756
|
const item = window.localStorage.getItem(key);
|
|
@@ -4592,7 +4759,7 @@ function useLocalStorage(key, initialValue) {
|
|
|
4592
4759
|
return initialValue;
|
|
4593
4760
|
}
|
|
4594
4761
|
});
|
|
4595
|
-
const setValue =
|
|
4762
|
+
const setValue = React31.useCallback(
|
|
4596
4763
|
(value) => {
|
|
4597
4764
|
try {
|
|
4598
4765
|
setStoredValue(value);
|
|
@@ -4607,11 +4774,11 @@ function useLocalStorage(key, initialValue) {
|
|
|
4607
4774
|
return [storedValue, setValue];
|
|
4608
4775
|
}
|
|
4609
4776
|
function useMediaQuery(query) {
|
|
4610
|
-
const [matches, setMatches] =
|
|
4777
|
+
const [matches, setMatches] = React31.useState(() => {
|
|
4611
4778
|
if (typeof window === "undefined") return false;
|
|
4612
4779
|
return window.matchMedia(query).matches;
|
|
4613
4780
|
});
|
|
4614
|
-
|
|
4781
|
+
React31.useEffect(() => {
|
|
4615
4782
|
if (typeof window === "undefined") return;
|
|
4616
4783
|
const mql = window.matchMedia(query);
|
|
4617
4784
|
setMatches(mql.matches);
|
|
@@ -4622,18 +4789,18 @@ function useMediaQuery(query) {
|
|
|
4622
4789
|
return matches;
|
|
4623
4790
|
}
|
|
4624
4791
|
function usePagination(total, pageSize) {
|
|
4625
|
-
const [page, setPage] =
|
|
4792
|
+
const [page, setPage] = React31.useState(1);
|
|
4626
4793
|
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
4627
4794
|
const offset = (page - 1) * pageSize;
|
|
4628
|
-
const goTo =
|
|
4795
|
+
const goTo = React31.useCallback(
|
|
4629
4796
|
(p) => setPage(Math.min(Math.max(1, p), totalPages)),
|
|
4630
4797
|
[totalPages]
|
|
4631
4798
|
);
|
|
4632
|
-
const next =
|
|
4633
|
-
const prev =
|
|
4799
|
+
const next = React31.useCallback(() => goTo(page + 1), [page, goTo]);
|
|
4800
|
+
const prev = React31.useCallback(() => goTo(page - 1), [page, goTo]);
|
|
4634
4801
|
return { page, pageSize, totalPages, offset, hasPrev: page > 1, hasNext: page < totalPages, goTo, next, prev };
|
|
4635
4802
|
}
|
|
4636
4803
|
|
|
4637
|
-
export { AnimatedPill, AppContent, AppGrid, AppGridCell, AppScreen, AppShell, AuthSection, Badge, BillingPanel, BrandColorSwitchMinimal, Button, Card,
|
|
4804
|
+
export { ActivityFeed, AnimatedPill, AppContent, AppGrid, AppGridCell, AppScreen, AppShell, AuthSection, Badge, BillingPanel, BrandColorSwitchMinimal, Button, Card, Carousel, ChangelogCard, ChangelogList, 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, Spotlight, Stack, StaggerChildren, StatCard, StatsSection, StepsSection, Suspensed, Switch, TeamMembersPanel, TeamSection, TechStackSection, TestimonialCard, TestimonialsSection, Textarea, ThemeColorUpdater, ThemeSwitchMinimal, Underlay, UpgradePrompt, VersionBanner, marketingSectionSpacing, notify, useConfirm, useControlledOpen, useCopyToClipboard, useDebounce, useIntersectionObserver, useLocalStorage, useMediaQuery, useMounted, useOlwibaUI, usePagination, useScrolledPast, useUIMode };
|
|
4638
4805
|
//# sourceMappingURL=index.js.map
|
|
4639
4806
|
//# sourceMappingURL=index.js.map
|