@olwiba/ui 0.0.28

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.
Files changed (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +98 -0
  3. package/dist/index.d.ts +762 -0
  4. package/dist/index.js +2102 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +88 -0
  7. package/src/app/AppShell.tsx +365 -0
  8. package/src/app/AuthSection.tsx +141 -0
  9. package/src/app/EmptyState.tsx +34 -0
  10. package/src/app/ErrorPage.tsx +78 -0
  11. package/src/app/UpgradePrompt.tsx +203 -0
  12. package/src/blog/PostCard.tsx +66 -0
  13. package/src/blog/PostList.tsx +27 -0
  14. package/src/components/ConfirmDialog.tsx +43 -0
  15. package/src/components/ContextMenu.tsx +86 -0
  16. package/src/components/DevBanner.tsx +22 -0
  17. package/src/components/Dock.tsx +94 -0
  18. package/src/components/FeatureCard.tsx +45 -0
  19. package/src/components/GlassCard.tsx +30 -0
  20. package/src/components/ImageCard.tsx +60 -0
  21. package/src/components/PageHeader.tsx +101 -0
  22. package/src/components/PricingCard.tsx +90 -0
  23. package/src/components/RegisterHotkeys.tsx +43 -0
  24. package/src/components/RootErrorFallback.tsx +29 -0
  25. package/src/components/Spinner.tsx +14 -0
  26. package/src/components/Spotlight.tsx +104 -0
  27. package/src/components/StatCard.tsx +44 -0
  28. package/src/components/Suspensed.tsx +17 -0
  29. package/src/components/TestimonialCard.tsx +64 -0
  30. package/src/components/ThemeColorUpdater.tsx +23 -0
  31. package/src/components/ThemeSwitchMinimal.tsx +28 -0
  32. package/src/components/VersionBanner.tsx +38 -0
  33. package/src/context/OlwibaUIContext.tsx +58 -0
  34. package/src/hooks/use-confirm.ts +64 -0
  35. package/src/hooks/use-controlled-open.ts +33 -0
  36. package/src/hooks/use-copy-to-clipboard.ts +20 -0
  37. package/src/hooks/use-debounce.ts +14 -0
  38. package/src/hooks/use-intersection-observer.ts +25 -0
  39. package/src/hooks/use-local-storage.ts +31 -0
  40. package/src/hooks/use-media-query.ts +21 -0
  41. package/src/hooks/use-mounted.ts +11 -0
  42. package/src/hooks/use-pagination.ts +31 -0
  43. package/src/hooks/use-scrolled-past.ts +27 -0
  44. package/src/index.ts +113 -0
  45. package/src/lib/utils.ts +6 -0
  46. package/src/marketing/ContactSection.tsx +110 -0
  47. package/src/marketing/CtaSection.tsx +74 -0
  48. package/src/marketing/FaqSection.tsx +44 -0
  49. package/src/marketing/FeaturesSection.tsx +42 -0
  50. package/src/marketing/Footer.tsx +87 -0
  51. package/src/marketing/HeroSection.tsx +112 -0
  52. package/src/marketing/LogoStrip.tsx +94 -0
  53. package/src/marketing/Navbar.tsx +142 -0
  54. package/src/marketing/NewsletterSection.tsx +64 -0
  55. package/src/marketing/PricingSection.tsx +120 -0
  56. package/src/marketing/SectionTitle.tsx +30 -0
  57. package/src/marketing/StatsSection.tsx +63 -0
  58. package/src/marketing/TeamSection.tsx +110 -0
  59. package/src/marketing/TestimonialsSection.tsx +56 -0
  60. package/src/motion/CountUp.tsx +64 -0
  61. package/src/motion/FadeIn.tsx +69 -0
  62. package/src/motion/PageTransition.tsx +49 -0
  63. package/src/motion/StaggerChildren.tsx +74 -0
  64. package/src/overlays/Overlay.tsx +88 -0
  65. package/src/overlays/Underlay.tsx +114 -0
  66. package/src/primitives/Badge.tsx +11 -0
  67. package/src/primitives/Button.tsx +16 -0
  68. package/src/primitives/Card.tsx +22 -0
  69. package/src/primitives/Checkbox.tsx +17 -0
  70. package/src/primitives/Input.tsx +16 -0
  71. package/src/primitives/Switch.tsx +16 -0
  72. package/src/primitives/Textarea.tsx +16 -0
  73. package/src/primitives/index.ts +7 -0
  74. package/src/types/external-packages.d.ts +79 -0
package/dist/index.js ADDED
@@ -0,0 +1,2102 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+ import * as React25 from 'react';
4
+ import { useState, useEffect } 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, Separator, Accordion, AccordionItem, AccordionTrigger, AccordionContent, Label, Sheet, SheetTrigger, SheetContent, 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, Spinner, SidebarProvider, SidebarInset, CardHeader, CardTitle, CardDescription, CardContent, ContextMenuSeparator, ContextMenuLabel, ContextMenuSub, ContextMenuSubTrigger, ContextMenuSubContent, ContextMenuItem, ContextMenuShortcut, Sidebar, SidebarHeader, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarFooter, SidebarTrigger, useSidebar, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuGroup, DropdownMenuItem } from '@olwiba/cn';
6
+ export { CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@olwiba/cn';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+ import { Compass, ArrowLeft, X, ArrowRight, Sparkles, Check, Minus, Quote, Star, Twitter, Github, Linkedin, Mail, Phone, MapPin, MessageSquare, Send, Sun, Moon, Menu, Search, TrendingUp, TrendingDown, ChevronRight, ChevronLeft, AlertTriangle, Loader2, ShieldCheck, Building2, MoreVerticalIcon, CreditCardIcon, BellIcon, LogOutIcon } from 'lucide-react';
9
+
10
+ // src/lib/utils.ts
11
+ function cn(...inputs) {
12
+ return twMerge(clsx(inputs));
13
+ }
14
+ var OlwibaUIContext = React25.createContext({
15
+ isMobile: false,
16
+ mode: "default"
17
+ });
18
+ function OlwibaUIProvider({ children, isMobile: isMobileProp, mode = "default" }) {
19
+ const detectedMobile = useIsMobile();
20
+ const isMobile = isMobileProp ?? detectedMobile;
21
+ const variant = mode !== "default" ? mode : void 0;
22
+ return /* @__PURE__ */ jsx(OlwibaUIContext.Provider, { value: { isMobile, mode }, children: /* @__PURE__ */ jsx(UIVariantProvider, { mode: variant, children }) });
23
+ }
24
+ function useOlwibaUI() {
25
+ return React25.useContext(OlwibaUIContext);
26
+ }
27
+ function useUIMode() {
28
+ return React25.useContext(OlwibaUIContext).mode;
29
+ }
30
+ var Button = React25.forwardRef(
31
+ ({ mode, ...props }, ref) => {
32
+ const ctxMode = useUIMode();
33
+ const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
34
+ return /* @__PURE__ */ jsx(Button$1, { mode: resolvedMode, ...props, ref });
35
+ }
36
+ );
37
+ Button.displayName = "Button";
38
+ var Card = React25.forwardRef(
39
+ ({ mode, ...props }, ref) => {
40
+ const ctxMode = useUIMode();
41
+ const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
42
+ return /* @__PURE__ */ jsx(Card$1, { mode: resolvedMode, ...props, ref });
43
+ }
44
+ );
45
+ Card.displayName = "Card";
46
+ function Badge(props) {
47
+ return /* @__PURE__ */ jsx(Badge$1, { ...props });
48
+ }
49
+ var Input = React25.forwardRef(
50
+ ({ mode, ...props }, ref) => {
51
+ const ctxMode = useUIMode();
52
+ const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
53
+ return /* @__PURE__ */ jsx(Input$1, { mode: resolvedMode, ...props, ref });
54
+ }
55
+ );
56
+ Input.displayName = "Input";
57
+ var Textarea = React25.forwardRef(
58
+ ({ mode, ...props }, ref) => {
59
+ const ctxMode = useUIMode();
60
+ const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
61
+ return /* @__PURE__ */ jsx(Textarea$1, { mode: resolvedMode, ...props, ref });
62
+ }
63
+ );
64
+ Textarea.displayName = "Textarea";
65
+ var Checkbox = React25.forwardRef(({ mode, ...props }, ref) => {
66
+ const ctxMode = useUIMode();
67
+ const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
68
+ return /* @__PURE__ */ jsx(Checkbox$1, { mode: resolvedMode, ...props, ref });
69
+ });
70
+ Checkbox.displayName = "Checkbox";
71
+ var Switch = React25.forwardRef(({ mode: _mode, ...props }, ref) => {
72
+ return /* @__PURE__ */ jsx(Switch$1, { ...props, ref });
73
+ });
74
+ Switch.displayName = "Switch";
75
+ function NavUser({ user }) {
76
+ const { isMobile } = useSidebar();
77
+ const uiMode = useUIMode();
78
+ const avatarMode = uiMode !== "default" ? uiMode : void 0;
79
+ const initials = (user.name ?? user.email).slice(0, 2).toUpperCase();
80
+ return /* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
81
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
82
+ SidebarMenuButton,
83
+ {
84
+ size: "lg",
85
+ className: "data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground",
86
+ children: [
87
+ /* @__PURE__ */ jsxs(Avatar, { mode: avatarMode, size: "sm", className: "grayscale", children: [
88
+ user.avatar && /* @__PURE__ */ jsx(AvatarImage, { src: user.avatar, alt: user.name }),
89
+ /* @__PURE__ */ jsx(AvatarFallback, { children: initials })
90
+ ] }),
91
+ /* @__PURE__ */ jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [
92
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: user.name ?? user.email }),
93
+ /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: user.plan ? `${user.plan} plan` : user.email })
94
+ ] }),
95
+ /* @__PURE__ */ jsx(MoreVerticalIcon, { className: "ml-auto size-4" })
96
+ ]
97
+ }
98
+ ) }),
99
+ /* @__PURE__ */ jsxs(
100
+ DropdownMenuContent,
101
+ {
102
+ className: "w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg",
103
+ side: isMobile ? "bottom" : "right",
104
+ align: "end",
105
+ sideOffset: 4,
106
+ children: [
107
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "p-0 font-normal", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-1 py-1.5 text-left text-sm", children: [
108
+ /* @__PURE__ */ jsxs(Avatar, { mode: avatarMode, size: "sm", children: [
109
+ user.avatar && /* @__PURE__ */ jsx(AvatarImage, { src: user.avatar, alt: user.name }),
110
+ /* @__PURE__ */ jsx(AvatarFallback, { children: initials })
111
+ ] }),
112
+ /* @__PURE__ */ jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [
113
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: user.name ?? user.email }),
114
+ /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: user.email })
115
+ ] })
116
+ ] }) }),
117
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
118
+ /* @__PURE__ */ jsxs(DropdownMenuGroup, { children: [
119
+ user.onBilling && /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: user.onBilling, children: [
120
+ /* @__PURE__ */ jsx(CreditCardIcon, {}),
121
+ "Billing"
122
+ ] }),
123
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { children: [
124
+ /* @__PURE__ */ jsx(BellIcon, {}),
125
+ "Notifications"
126
+ ] })
127
+ ] }),
128
+ user.onSignOut && /* @__PURE__ */ jsxs(Fragment, { children: [
129
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
130
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: user.onSignOut, children: [
131
+ /* @__PURE__ */ jsx(LogOutIcon, {}),
132
+ "Sign out"
133
+ ] })
134
+ ] })
135
+ ]
136
+ }
137
+ )
138
+ ] }) }) });
139
+ }
140
+ function ShellSidebar({
141
+ brand,
142
+ navItems,
143
+ action,
144
+ user,
145
+ renderLink,
146
+ collapsible,
147
+ side,
148
+ sidebarPosition
149
+ }) {
150
+ return /* @__PURE__ */ jsxs(Sidebar, { side, collapsible, sidebarPosition, children: [
151
+ /* @__PURE__ */ jsx(SidebarHeader, { children: /* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsx(SidebarMenuButton, { asChild: true, className: "data-[slot=sidebar-menu-button]:!p-1.5", children: renderLink({
152
+ href: brand.href ?? "#",
153
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
154
+ brand.logo,
155
+ /* @__PURE__ */ jsx("span", { className: "text-base font-semibold", children: brand.name })
156
+ ] })
157
+ }) }) }) }) }),
158
+ /* @__PURE__ */ jsx(SidebarContent, { children: /* @__PURE__ */ jsx(SidebarGroup, { children: /* @__PURE__ */ jsxs(SidebarGroupContent, { className: "flex flex-col gap-2", children: [
159
+ action && /* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: action.href ? /* @__PURE__ */ jsx(
160
+ SidebarMenuButton,
161
+ {
162
+ asChild: true,
163
+ tooltip: action.label,
164
+ className: "min-w-8 bg-primary text-primary-foreground duration-200 ease-linear hover:bg-primary/90 hover:text-primary-foreground active:bg-primary/90 active:text-primary-foreground",
165
+ children: renderLink({
166
+ href: action.href,
167
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
168
+ action.icon && /* @__PURE__ */ jsx(action.icon, {}),
169
+ /* @__PURE__ */ jsx("span", { children: action.label })
170
+ ] })
171
+ })
172
+ }
173
+ ) : /* @__PURE__ */ jsxs(
174
+ SidebarMenuButton,
175
+ {
176
+ tooltip: action.label,
177
+ onClick: action.onClick,
178
+ className: "min-w-8 bg-primary text-primary-foreground duration-200 ease-linear hover:bg-primary/90 hover:text-primary-foreground active:bg-primary/90 active:text-primary-foreground",
179
+ children: [
180
+ action.icon && /* @__PURE__ */ jsx(action.icon, {}),
181
+ /* @__PURE__ */ jsx("span", { children: action.label })
182
+ ]
183
+ }
184
+ ) }) }),
185
+ /* @__PURE__ */ jsx(SidebarMenu, { children: navItems.map((item) => /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsx(SidebarMenuButton, { asChild: true, tooltip: item.label, isActive: item.isActive, children: renderLink({
186
+ href: item.href,
187
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
188
+ /* @__PURE__ */ jsx(item.icon, {}),
189
+ /* @__PURE__ */ jsx("span", { children: item.label })
190
+ ] })
191
+ }) }) }, item.label)) })
192
+ ] }) }) }),
193
+ /* @__PURE__ */ jsx(SidebarFooter, { children: /* @__PURE__ */ jsx(NavUser, { user }) })
194
+ ] });
195
+ }
196
+ function ShellHeader({ pageTitle }) {
197
+ return /* @__PURE__ */ jsx("header", { className: "flex h-12 shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12", children: /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-1 px-4 lg:gap-2 lg:px-6", children: [
198
+ /* @__PURE__ */ jsx(SidebarTrigger, { className: "-ml-1" }),
199
+ /* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "mx-2 data-[orientation=vertical]:h-4" }),
200
+ /* @__PURE__ */ jsx("h1", { className: "text-base font-medium", children: pageTitle })
201
+ ] }) });
202
+ }
203
+ var defaultBrand = {
204
+ name: "App",
205
+ href: "#"
206
+ };
207
+ var defaultUser = {
208
+ name: "User",
209
+ email: "user@example.com"
210
+ };
211
+ var defaultRenderLink = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
212
+ function AppShell({
213
+ brand = defaultBrand,
214
+ navItems = [],
215
+ action,
216
+ user = defaultUser,
217
+ pageTitle = "Dashboard",
218
+ renderLink = defaultRenderLink,
219
+ collapsible = "icon",
220
+ sidebarPosition = "viewport",
221
+ side = "left",
222
+ children
223
+ } = {}) {
224
+ const isContained = sidebarPosition === "contained";
225
+ const inner = /* @__PURE__ */ jsxs(
226
+ SidebarProvider,
227
+ {
228
+ layout: isContained ? "embedded" : "viewport",
229
+ className: isContained ? "overflow-hidden" : "h-svh overflow-hidden",
230
+ children: [
231
+ /* @__PURE__ */ jsx(
232
+ ShellSidebar,
233
+ {
234
+ brand,
235
+ navItems,
236
+ action,
237
+ user,
238
+ renderLink,
239
+ collapsible,
240
+ side,
241
+ sidebarPosition
242
+ }
243
+ ),
244
+ /* @__PURE__ */ jsxs(SidebarInset, { className: isContained ? void 0 : "overflow-y-auto", children: [
245
+ /* @__PURE__ */ jsx(ShellHeader, { pageTitle }),
246
+ children
247
+ ] })
248
+ ]
249
+ }
250
+ );
251
+ if (isContained) {
252
+ return /* @__PURE__ */ jsx("div", { className: "relative flex h-full min-h-0 w-full max-w-full flex-col overflow-hidden", children: inner });
253
+ }
254
+ return inner;
255
+ }
256
+ function CenteredAuth({ children }) {
257
+ return /* @__PURE__ */ jsx("section", { className: "flex h-full min-h-[720px] w-full flex-col items-center justify-center gap-6 rounded-2xl bg-muted p-6 md:p-10", children: /* @__PURE__ */ jsx("div", { className: "flex w-full max-w-sm flex-col gap-6", children }) });
258
+ }
259
+ function SplitAuth({ children, panel }) {
260
+ const defaultPanel = /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
261
+ /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "w-fit", children: "Welcome" }),
262
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
263
+ /* @__PURE__ */ jsx("h2", { className: "text-3xl font-semibold tracking-tight", children: "Build better, ship faster" }),
264
+ /* @__PURE__ */ jsx("p", { className: "max-w-md text-muted-foreground", children: "Sign in to continue building with ready-made components and layouts." })
265
+ ] }),
266
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3 text-sm text-muted-foreground", children: [
267
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
268
+ /* @__PURE__ */ jsx(ShieldCheck, { className: "size-4" }),
269
+ " Type-safe components"
270
+ ] }),
271
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
272
+ /* @__PURE__ */ jsx(Sparkles, { className: "size-4" }),
273
+ " Polished defaults"
274
+ ] }),
275
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
276
+ /* @__PURE__ */ jsx(Building2, { className: "size-4" }),
277
+ " Plug-and-play shells"
278
+ ] })
279
+ ] })
280
+ ] });
281
+ return /* @__PURE__ */ jsxs("section", { className: "grid h-full min-h-[560px] overflow-hidden rounded-2xl border bg-card lg:grid-cols-2", children: [
282
+ /* @__PURE__ */ jsxs("div", { className: "relative hidden p-8 pb-16 lg:flex lg:flex-col lg:justify-center", children: [
283
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-br from-primary/20 via-transparent to-muted" }),
284
+ /* @__PURE__ */ jsx("div", { className: "relative z-10", children: panel ?? defaultPanel })
285
+ ] }),
286
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center p-6 lg:p-10", children })
287
+ ] });
288
+ }
289
+ function DefaultForm({ onSubmit, onSso, signUpHref = "#", forgotPasswordHref = "#", brand }) {
290
+ return /* @__PURE__ */ jsxs(Card$1, { className: "w-full max-w-md", children: [
291
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
292
+ brand && /* @__PURE__ */ jsx("div", { className: "mb-2", children: brand }),
293
+ /* @__PURE__ */ jsx(CardTitle, { children: "Sign in" }),
294
+ /* @__PURE__ */ jsx(CardDescription, { children: "Enter your email and password to continue." })
295
+ ] }),
296
+ /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
297
+ /* @__PURE__ */ jsxs("form", { onSubmit, className: "space-y-4", children: [
298
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
299
+ /* @__PURE__ */ jsx(Label, { htmlFor: "auth-email", children: "Email" }),
300
+ /* @__PURE__ */ jsx(Input$1, { id: "auth-email", type: "email", placeholder: "name@company.com" })
301
+ ] }),
302
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
303
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
304
+ /* @__PURE__ */ jsx(Label, { htmlFor: "auth-password", children: "Password" }),
305
+ forgotPasswordHref && /* @__PURE__ */ jsx("a", { className: "text-xs text-muted-foreground underline underline-offset-4 hover:text-foreground", href: forgotPasswordHref, children: "Forgot password?" })
306
+ ] }),
307
+ /* @__PURE__ */ jsx(Input$1, { id: "auth-password", type: "password", placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" })
308
+ ] }),
309
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
310
+ /* @__PURE__ */ jsx(Button$1, { type: "submit", className: "w-full", children: "Continue" }),
311
+ onSso && /* @__PURE__ */ jsx(Button$1, { type: "button", variant: "outline", className: "w-full", onClick: onSso, children: "Use SSO" })
312
+ ] })
313
+ ] }),
314
+ signUpHref && /* @__PURE__ */ jsxs("p", { className: "text-center text-xs text-muted-foreground", children: [
315
+ "New here?",
316
+ " ",
317
+ /* @__PURE__ */ jsx("a", { className: "text-foreground underline underline-offset-4", href: signUpHref, children: "Create an account" })
318
+ ] })
319
+ ] })
320
+ ] });
321
+ }
322
+ function AuthSection({
323
+ layout = "centered",
324
+ children,
325
+ panel,
326
+ className,
327
+ ...formProps
328
+ }) {
329
+ const form = children ?? /* @__PURE__ */ jsx(DefaultForm, { ...formProps });
330
+ if (layout === "split") {
331
+ return /* @__PURE__ */ jsx("div", { className: cn$1("h-full", className), children: /* @__PURE__ */ jsx(SplitAuth, { panel, children: form }) });
332
+ }
333
+ return /* @__PURE__ */ jsx("div", { className: cn$1("h-full", className), children: /* @__PURE__ */ jsx(CenteredAuth, { children: form }) });
334
+ }
335
+ function EmptyState({ icon: Icon, title, description, action, className, ...props }) {
336
+ return /* @__PURE__ */ jsxs(
337
+ "div",
338
+ {
339
+ className: cn$1("flex flex-col items-center justify-center gap-3 py-12 text-center", className),
340
+ ...props,
341
+ children: [
342
+ Icon && /* @__PURE__ */ jsx("div", { className: "flex h-12 w-12 items-center justify-center rounded-2xl border bg-muted", children: /* @__PURE__ */ jsx(Icon, { className: "size-6 text-muted-foreground" }) }),
343
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
344
+ /* @__PURE__ */ jsx("h3", { className: "font-semibold", children: title }),
345
+ description && /* @__PURE__ */ jsx("p", { className: "max-w-xs text-sm text-muted-foreground", children: description })
346
+ ] }),
347
+ action
348
+ ]
349
+ }
350
+ );
351
+ }
352
+ var defaultRenderLink2 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
353
+ function ErrorPage({
354
+ statusCode = "404",
355
+ title = "Page not found",
356
+ description = "The page you're looking for doesn't exist or has been moved. Check the URL or head back home.",
357
+ action = { label: "Take me home", href: "/" },
358
+ backAction = { label: "Go back" },
359
+ renderLink = defaultRenderLink2
360
+ }) {
361
+ return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", children: /* @__PURE__ */ jsxs("div", { className: "relative flex min-h-[560px] flex-col items-center justify-center px-6 py-16 text-center", children: [
362
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(circle_at_center,hsl(var(--muted)/0.8),transparent_70%)]" }),
363
+ /* @__PURE__ */ jsxs("div", { className: "relative space-y-6", children: [
364
+ /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx("div", { className: "flex h-16 w-16 items-center justify-center rounded-2xl border bg-muted", children: /* @__PURE__ */ jsx(Compass, { className: "size-8 text-muted-foreground" }) }) }),
365
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
366
+ /* @__PURE__ */ jsx("div", { className: "text-8xl font-bold tracking-tight text-muted-foreground/20", children: statusCode }),
367
+ /* @__PURE__ */ jsx("h1", { className: "-mt-4 text-2xl font-semibold tracking-tight", children: title }),
368
+ /* @__PURE__ */ jsx("p", { className: "mx-auto max-w-sm text-sm text-muted-foreground", children: description })
369
+ ] }),
370
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3", children: [
371
+ backAction && (backAction.href ? renderLink({
372
+ href: backAction.href,
373
+ children: /* @__PURE__ */ jsxs(Button, { variant: "outline", children: [
374
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "mr-2 size-4" }),
375
+ backAction.label
376
+ ] })
377
+ }) : /* @__PURE__ */ jsxs(Button, { variant: "outline", onClick: backAction.onClick, children: [
378
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "mr-2 size-4" }),
379
+ backAction.label
380
+ ] })),
381
+ action && renderLink({
382
+ href: action.href,
383
+ children: /* @__PURE__ */ jsx(Button, { children: action.label })
384
+ })
385
+ ] })
386
+ ] })
387
+ ] }) });
388
+ }
389
+ function UpgradePrompt({
390
+ variant,
391
+ title,
392
+ description,
393
+ primaryActionLabel,
394
+ onPrimaryAction,
395
+ secondaryActionLabel,
396
+ onSecondaryAction,
397
+ eyebrow,
398
+ rows,
399
+ currentPlanLabel = "Current",
400
+ upgradedPlanLabel = "Upgrade",
401
+ footer,
402
+ onClose,
403
+ closeLabel = "Close",
404
+ className
405
+ }) {
406
+ const hasSecondaryAction = Boolean(secondaryActionLabel && onSecondaryAction);
407
+ if (variant === "banner") {
408
+ return /* @__PURE__ */ jsx(
409
+ "section",
410
+ {
411
+ className: cn$1(
412
+ "rounded-xl border border-dashed bg-card/40 p-5 sm:p-6",
413
+ className
414
+ ),
415
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between", children: [
416
+ /* @__PURE__ */ jsxs("div", { children: [
417
+ /* @__PURE__ */ jsx("h3", { className: "text-xl font-semibold", children: title }),
418
+ /* @__PURE__ */ jsx("p", { className: "mt-2 max-w-xl text-sm leading-6 text-muted-foreground", children: description })
419
+ ] }),
420
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
421
+ hasSecondaryAction ? /* @__PURE__ */ jsx(
422
+ Button$1,
423
+ {
424
+ type: "button",
425
+ variant: "ghost",
426
+ onClick: onSecondaryAction,
427
+ className: "border",
428
+ children: secondaryActionLabel
429
+ }
430
+ ) : null,
431
+ /* @__PURE__ */ jsx(Button$1, { type: "button", onClick: onPrimaryAction, children: primaryActionLabel })
432
+ ] })
433
+ ] })
434
+ }
435
+ );
436
+ }
437
+ return /* @__PURE__ */ jsxs(
438
+ "section",
439
+ {
440
+ className: cn$1(
441
+ "w-full max-w-3xl rounded-2xl border bg-card p-6 shadow-sm sm:p-7",
442
+ className
443
+ ),
444
+ children: [
445
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
446
+ /* @__PURE__ */ jsxs("div", { children: [
447
+ eyebrow ? /* @__PURE__ */ jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-primary", children: eyebrow }) : null,
448
+ /* @__PURE__ */ jsx(
449
+ "h3",
450
+ {
451
+ className: cn$1(
452
+ "text-2xl font-semibold sm:text-[1.75rem]",
453
+ eyebrow ? "mt-3" : ""
454
+ ),
455
+ children: title
456
+ }
457
+ ),
458
+ /* @__PURE__ */ jsx("p", { className: "mt-3 max-w-2xl text-sm leading-6 text-muted-foreground sm:text-base", children: description })
459
+ ] }),
460
+ onClose ? /* @__PURE__ */ jsx(
461
+ "button",
462
+ {
463
+ type: "button",
464
+ onClick: onClose,
465
+ className: "inline-flex size-9 shrink-0 items-center justify-center rounded-lg border transition-colors hover:bg-muted",
466
+ "aria-label": closeLabel,
467
+ children: /* @__PURE__ */ jsx(X, { className: "size-4" })
468
+ }
469
+ ) : null
470
+ ] }),
471
+ rows && rows.length > 0 ? /* @__PURE__ */ jsx("div", { className: "mt-6 overflow-hidden rounded-xl border bg-muted/30", children: /* @__PURE__ */ jsxs(Table, { children: [
472
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
473
+ /* @__PURE__ */ jsx(TableHead, {}),
474
+ /* @__PURE__ */ jsx(TableHead, { className: "font-mono text-xs uppercase tracking-wider text-muted-foreground", children: currentPlanLabel }),
475
+ /* @__PURE__ */ jsx(TableHead, { className: "font-mono text-xs uppercase tracking-wider text-primary", children: upgradedPlanLabel })
476
+ ] }) }),
477
+ /* @__PURE__ */ jsx(TableBody, { children: rows.map((row, index) => /* @__PURE__ */ jsxs(TableRow, { children: [
478
+ /* @__PURE__ */ jsx(TableCell, { className: "font-medium", children: row.label }),
479
+ /* @__PURE__ */ jsx(TableCell, { className: "font-mono text-muted-foreground", children: row.currentValue }),
480
+ /* @__PURE__ */ jsx(TableCell, { className: "font-mono", children: row.upgradedValue })
481
+ ] }, row.key ?? index)) })
482
+ ] }) }) : null,
483
+ /* @__PURE__ */ jsxs(
484
+ "div",
485
+ {
486
+ className: cn$1(
487
+ "mt-6 flex flex-col gap-3 sm:flex-row sm:items-center",
488
+ footer || hasSecondaryAction ? "sm:justify-between" : "sm:justify-end"
489
+ ),
490
+ children: [
491
+ footer ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: footer }) : null,
492
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
493
+ hasSecondaryAction ? /* @__PURE__ */ jsx(
494
+ Button$1,
495
+ {
496
+ type: "button",
497
+ variant: "ghost",
498
+ onClick: onSecondaryAction,
499
+ className: "border",
500
+ children: secondaryActionLabel
501
+ }
502
+ ) : null,
503
+ /* @__PURE__ */ jsx(Button$1, { type: "button", onClick: onPrimaryAction, children: primaryActionLabel })
504
+ ] })
505
+ ]
506
+ }
507
+ )
508
+ ]
509
+ }
510
+ );
511
+ }
512
+ var translateMap = {
513
+ up: "translate-y-6",
514
+ down: "-translate-y-6",
515
+ left: "translate-x-6",
516
+ right: "-translate-x-6",
517
+ none: ""
518
+ };
519
+ function FadeIn({
520
+ delay = 0,
521
+ duration = 600,
522
+ direction = "up",
523
+ once = true,
524
+ children,
525
+ className,
526
+ style,
527
+ ...props
528
+ }) {
529
+ const ref = React25.useRef(null);
530
+ const [visible, setVisible] = React25.useState(false);
531
+ React25.useEffect(() => {
532
+ const el = ref.current;
533
+ if (!el) return;
534
+ const observer = new IntersectionObserver(
535
+ ([entry]) => {
536
+ if (entry.isIntersecting) {
537
+ setVisible(true);
538
+ if (once) observer.disconnect();
539
+ } else if (!once) {
540
+ setVisible(false);
541
+ }
542
+ },
543
+ { threshold: 0.1 }
544
+ );
545
+ observer.observe(el);
546
+ return () => observer.disconnect();
547
+ }, [once]);
548
+ return /* @__PURE__ */ jsx(
549
+ "div",
550
+ {
551
+ ref,
552
+ className: cn$1(
553
+ "transition-all",
554
+ visible ? "opacity-100 translate-x-0 translate-y-0" : `opacity-0 ${translateMap[direction]}`,
555
+ className
556
+ ),
557
+ style: { transitionDuration: `${duration}ms`, transitionDelay: `${delay}ms`, ...style },
558
+ ...props,
559
+ children
560
+ }
561
+ );
562
+ }
563
+ function SectionTitle({ title, description, badge, className }) {
564
+ return /* @__PURE__ */ jsx(FadeIn, { direction: "up", children: /* @__PURE__ */ jsxs("div", { className: cn$1("text-center", className), children: [
565
+ badge && /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-4", children: badge }),
566
+ /* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: title }),
567
+ description && /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-2xl text-pretty text-muted-foreground", children: description })
568
+ ] }) });
569
+ }
570
+ var defaultRenderLink3 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
571
+ function HeroSection({
572
+ heading,
573
+ badge,
574
+ description,
575
+ primaryCta,
576
+ secondaryCta,
577
+ heroImage,
578
+ avatarUrls,
579
+ socialProofText,
580
+ renderLink = defaultRenderLink3
581
+ }) {
582
+ return /* @__PURE__ */ jsx("section", { className: "overflow-hidden", children: /* @__PURE__ */ jsxs("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: [
583
+ /* @__PURE__ */ jsxs("div", { className: "mx-auto grid max-w-6xl items-center gap-10 lg:grid-cols-2 lg:gap-16", children: [
584
+ /* @__PURE__ */ jsx(FadeIn, { direction: "left", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-6", children: [
585
+ badge && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", children: badge }) }),
586
+ /* @__PURE__ */ jsx("h1", { className: "text-balance text-4xl font-semibold tracking-tight sm:text-5xl lg:text-6xl", children: heading }),
587
+ /* @__PURE__ */ jsx("p", { className: "max-w-lg text-pretty text-lg text-muted-foreground", children: description }),
588
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
589
+ renderLink({
590
+ href: primaryCta.href,
591
+ children: /* @__PURE__ */ jsxs(Button$1, { size: "lg", children: [
592
+ primaryCta.label,
593
+ /* @__PURE__ */ jsx(ArrowRight, { className: "ml-2 size-4" })
594
+ ] })
595
+ }),
596
+ secondaryCta && renderLink({
597
+ href: secondaryCta.href,
598
+ children: /* @__PURE__ */ jsx(Button$1, { size: "lg", variant: "outline", children: secondaryCta.label })
599
+ })
600
+ ] })
601
+ ] }) }),
602
+ /* @__PURE__ */ jsx(FadeIn, { direction: "right", delay: 200, children: /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-2xl", children: heroImage }) })
603
+ ] }),
604
+ (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: [
605
+ 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: [
606
+ /* @__PURE__ */ jsx(AvatarImage, { src: url, alt: "" }),
607
+ /* @__PURE__ */ jsx(AvatarFallback, { className: "text-xs", children: String.fromCharCode(65 + i % 26) })
608
+ ] }, i)) }),
609
+ socialProofText && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: socialProofText })
610
+ ] }) })
611
+ ] }) });
612
+ }
613
+ function FeatureCard({ icon: Icon, title, description, href, className, ...props }) {
614
+ const content = /* @__PURE__ */ jsxs(
615
+ "div",
616
+ {
617
+ className: cn$1(
618
+ "group relative flex flex-col gap-4 rounded-2xl border bg-card p-6 transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md",
619
+ href && "cursor-pointer",
620
+ className
621
+ ),
622
+ ...props,
623
+ children: [
624
+ /* @__PURE__ */ jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-xl bg-primary/10 text-primary transition-colors group-hover:bg-primary group-hover:text-primary-foreground", children: /* @__PURE__ */ jsx(Icon, { className: "size-5" }) }),
625
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
626
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
627
+ /* @__PURE__ */ jsx("h3", { className: "font-semibold leading-tight", children: title }),
628
+ href && /* @__PURE__ */ jsx(ArrowRight, { className: "size-4 shrink-0 text-muted-foreground opacity-0 transition-all group-hover:translate-x-0.5 group-hover:opacity-100" })
629
+ ] }),
630
+ /* @__PURE__ */ jsx("p", { className: "text-sm leading-relaxed text-muted-foreground", children: description })
631
+ ] })
632
+ ]
633
+ }
634
+ );
635
+ if (href) {
636
+ return /* @__PURE__ */ jsx("a", { href, className: "block", children: content });
637
+ }
638
+ return content;
639
+ }
640
+ var translateMap2 = {
641
+ up: [0, 20],
642
+ down: [0, -20],
643
+ left: [20, 0],
644
+ right: [-20, 0],
645
+ none: [0, 0]
646
+ };
647
+ function StaggerChildren({
648
+ stagger = 80,
649
+ delay = 0,
650
+ duration = 500,
651
+ direction = "up",
652
+ once = true,
653
+ children,
654
+ className,
655
+ ...props
656
+ }) {
657
+ const ref = React25.useRef(null);
658
+ const [visible, setVisible] = React25.useState(false);
659
+ React25.useEffect(() => {
660
+ const el = ref.current;
661
+ if (!el) return;
662
+ const observer = new IntersectionObserver(
663
+ ([entry]) => {
664
+ if (entry.isIntersecting) {
665
+ setVisible(true);
666
+ if (once) observer.disconnect();
667
+ } else if (!once) {
668
+ setVisible(false);
669
+ }
670
+ },
671
+ { threshold: 0.1 }
672
+ );
673
+ observer.observe(el);
674
+ return () => observer.disconnect();
675
+ }, [once]);
676
+ const [tx, ty] = translateMap2[direction];
677
+ return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React25.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
678
+ "div",
679
+ {
680
+ style: {
681
+ transition: `opacity ${duration}ms ease, transform ${duration}ms ease`,
682
+ transitionDelay: `${delay + i * stagger}ms`,
683
+ opacity: visible ? 1 : 0,
684
+ transform: visible ? "translate(0,0)" : `translate(${tx}px,${ty}px)`
685
+ },
686
+ children: child
687
+ }
688
+ )) });
689
+ }
690
+ function FeaturesSection({
691
+ title = "Everything you need to ship fast",
692
+ description = "A complete system of components, blocks, and hooks designed to work together - and get out of your way.",
693
+ badge = "Features",
694
+ features
695
+ }) {
696
+ return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl", children: [
697
+ /* @__PURE__ */ jsx(SectionTitle, { title, description, badge }),
698
+ /* @__PURE__ */ jsx(StaggerChildren, { className: "mt-12 grid gap-8 sm:grid-cols-2 lg:grid-cols-3", children: features.map((feature) => /* @__PURE__ */ jsx(
699
+ FeatureCard,
700
+ {
701
+ icon: feature.icon,
702
+ title: feature.title,
703
+ description: feature.description,
704
+ href: feature.href
705
+ },
706
+ feature.title
707
+ )) })
708
+ ] }) }) });
709
+ }
710
+ var defaultRenderLink4 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
711
+ function CtaSection({
712
+ heading,
713
+ description,
714
+ primaryCta,
715
+ secondaryCta,
716
+ footnote,
717
+ renderLink = defaultRenderLink4
718
+ }) {
719
+ return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", children: /* @__PURE__ */ jsxs("div", { className: "relative px-6 py-16 sm:px-10 sm:py-24", children: [
720
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(ellipse_at_center,hsl(var(--primary)/0.15),transparent_70%)]" }),
721
+ /* @__PURE__ */ jsx(FadeIn, { direction: "up", children: /* @__PURE__ */ jsxs("div", { className: "relative mx-auto max-w-2xl text-center", children: [
722
+ /* @__PURE__ */ jsx("div", { className: "mb-4 inline-flex h-10 w-10 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Sparkles, { className: "size-5" }) }),
723
+ /* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: heading }),
724
+ /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-lg text-pretty text-muted-foreground", children: description }),
725
+ /* @__PURE__ */ jsxs("div", { className: "mt-8 flex flex-wrap items-center justify-center gap-3", children: [
726
+ renderLink({
727
+ href: primaryCta.href,
728
+ children: /* @__PURE__ */ jsxs(Button$1, { size: "lg", children: [
729
+ primaryCta.label,
730
+ /* @__PURE__ */ jsx(ArrowRight, { className: "ml-2 size-4" })
731
+ ] })
732
+ }),
733
+ secondaryCta && renderLink({
734
+ href: secondaryCta.href,
735
+ children: /* @__PURE__ */ jsx(Button$1, { size: "lg", variant: "outline", children: secondaryCta.label })
736
+ })
737
+ ] }),
738
+ footnote && /* @__PURE__ */ jsx("p", { className: "mt-4 text-sm text-muted-foreground", children: footnote })
739
+ ] }) })
740
+ ] }) });
741
+ }
742
+ function PricingCard({
743
+ name,
744
+ price,
745
+ period = "/mo",
746
+ description,
747
+ features,
748
+ cta,
749
+ highlighted = false,
750
+ badge,
751
+ onSelect,
752
+ className,
753
+ ...props
754
+ }) {
755
+ return /* @__PURE__ */ jsxs(
756
+ "div",
757
+ {
758
+ className: cn$1(
759
+ "relative flex flex-col rounded-2xl border p-6",
760
+ highlighted ? "border-primary bg-primary/5 shadow-sm" : "bg-card",
761
+ className
762
+ ),
763
+ ...props,
764
+ children: [
765
+ badge && /* @__PURE__ */ jsx("div", { className: "absolute -top-3 left-1/2 -translate-x-1/2", children: /* @__PURE__ */ jsx(Badge$1, { children: badge }) }),
766
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
767
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-muted-foreground", children: name }),
768
+ /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-1", children: [
769
+ /* @__PURE__ */ jsx("span", { className: "text-4xl font-bold tracking-tight", children: price }),
770
+ /* @__PURE__ */ jsx("span", { className: "mb-1 text-sm text-muted-foreground", children: period })
771
+ ] }),
772
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description })
773
+ ] }),
774
+ /* @__PURE__ */ jsx(
775
+ Button$1,
776
+ {
777
+ variant: highlighted ? "default" : "outline",
778
+ className: "mt-6 w-full",
779
+ onClick: onSelect,
780
+ children: cta
781
+ }
782
+ ),
783
+ /* @__PURE__ */ jsx(Separator, { className: "my-6" }),
784
+ /* @__PURE__ */ jsx("ul", { className: "space-y-3 text-sm", children: features.map((feat) => /* @__PURE__ */ jsx("li", { className: "flex items-center gap-2", children: feat.included ? /* @__PURE__ */ jsxs(Fragment, { children: [
785
+ /* @__PURE__ */ jsx(Check, { className: "size-4 shrink-0 text-primary" }),
786
+ /* @__PURE__ */ jsx("span", { children: feat.label })
787
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
788
+ /* @__PURE__ */ jsx(Minus, { className: "size-4 shrink-0 text-muted-foreground/40" }),
789
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: feat.label })
790
+ ] }) }, feat.label)) })
791
+ ]
792
+ }
793
+ );
794
+ }
795
+ var defaultRenderLink5 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
796
+ function PricingSection({
797
+ title = "Simple, transparent pricing",
798
+ description = "Start for free. Scale as you grow. No hidden fees.",
799
+ badge = "Pricing",
800
+ plans,
801
+ saveBadge = "Save 34%",
802
+ isAuthenticated,
803
+ renderLink = defaultRenderLink5,
804
+ footnote
805
+ }) {
806
+ const [annual, setAnnual] = React25.useState(false);
807
+ return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", 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: [
808
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
809
+ badge && /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-4", children: badge }),
810
+ /* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: title }),
811
+ description && /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-xl text-pretty text-muted-foreground", children: description }),
812
+ /* @__PURE__ */ jsxs("div", { className: "mt-6 inline-flex items-center gap-3 rounded-full border bg-muted p-1", children: [
813
+ /* @__PURE__ */ jsx(
814
+ "button",
815
+ {
816
+ onClick: () => setAnnual(false),
817
+ className: cn$1(
818
+ "rounded-full px-4 py-1.5 text-sm font-medium transition-colors",
819
+ !annual ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
820
+ ),
821
+ children: "Monthly"
822
+ }
823
+ ),
824
+ /* @__PURE__ */ jsxs(
825
+ "button",
826
+ {
827
+ onClick: () => setAnnual(true),
828
+ className: cn$1(
829
+ "flex items-center gap-2 rounded-full px-4 py-1.5 text-sm font-medium transition-colors",
830
+ annual ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
831
+ ),
832
+ children: [
833
+ "Annual",
834
+ saveBadge && /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "text-xs", children: saveBadge })
835
+ ]
836
+ }
837
+ )
838
+ ] })
839
+ ] }),
840
+ /* @__PURE__ */ jsx(StaggerChildren, { className: "mt-10 grid gap-4 lg:grid-cols-3", children: plans.map((plan) => {
841
+ const price = annual ? plan.annual : plan.monthly;
842
+ return /* @__PURE__ */ jsx(
843
+ PricingCard,
844
+ {
845
+ name: plan.name,
846
+ price: `$${price}`,
847
+ period: price > 0 ? "/mo" : "",
848
+ description: plan.description,
849
+ features: plan.features,
850
+ cta: plan.cta,
851
+ highlighted: plan.highlighted,
852
+ badge: plan.highlighted ? "Most popular" : void 0
853
+ },
854
+ plan.name
855
+ );
856
+ }) }),
857
+ footnote && /* @__PURE__ */ jsx("p", { className: "mt-8 text-center text-sm text-muted-foreground", children: footnote })
858
+ ] }) }) });
859
+ }
860
+ function TestimonialCard({
861
+ quote,
862
+ name,
863
+ role,
864
+ company,
865
+ avatar,
866
+ initials,
867
+ rating,
868
+ className,
869
+ ...props
870
+ }) {
871
+ return /* @__PURE__ */ jsxs(
872
+ "div",
873
+ {
874
+ className: cn$1("flex flex-col gap-4 rounded-2xl border bg-card p-6", className),
875
+ ...props,
876
+ children: [
877
+ /* @__PURE__ */ jsx(Quote, { className: "size-4 text-muted-foreground/40" }),
878
+ rating != null && /* @__PURE__ */ jsx("div", { className: "flex gap-0.5", children: Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx(
879
+ Star,
880
+ {
881
+ className: cn$1(
882
+ "size-4",
883
+ i < rating ? "fill-current text-amber-400" : "text-muted-foreground/30"
884
+ )
885
+ },
886
+ i
887
+ )) }),
888
+ /* @__PURE__ */ jsx("p", { className: "flex-1 text-sm leading-relaxed", children: quote }),
889
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
890
+ /* @__PURE__ */ jsxs(Avatar, { className: "size-9 rounded-xl", children: [
891
+ /* @__PURE__ */ jsx(AvatarImage, { src: avatar, alt: name }),
892
+ /* @__PURE__ */ jsx(AvatarFallback, { className: "rounded-xl text-xs", children: initials ?? name.slice(0, 2).toUpperCase() })
893
+ ] }),
894
+ /* @__PURE__ */ jsxs("div", { children: [
895
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-medium leading-tight", children: name }),
896
+ /* @__PURE__ */ jsxs("div", { className: "text-xs text-muted-foreground", children: [
897
+ role,
898
+ company ? ` \xB7 ${company}` : ""
899
+ ] })
900
+ ] })
901
+ ] })
902
+ ]
903
+ }
904
+ );
905
+ }
906
+ function TestimonialsSection({
907
+ title = "Trusted by teams shipping real products",
908
+ description = "Here's what engineers and product teams say after using Olwiba in production.",
909
+ badge = "Testimonials",
910
+ testimonials
911
+ }) {
912
+ return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", 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: [
913
+ /* @__PURE__ */ jsx(SectionTitle, { title, description, badge }),
914
+ /* @__PURE__ */ jsx(StaggerChildren, { className: "mt-12 columns-1 gap-4 sm:columns-2 lg:columns-3", children: testimonials.map((t) => /* @__PURE__ */ jsx(
915
+ "div",
916
+ {
917
+ className: "mb-4 break-inside-avoid transition-transform hover:-translate-y-0.5",
918
+ children: /* @__PURE__ */ jsx(
919
+ TestimonialCard,
920
+ {
921
+ quote: t.quote,
922
+ name: t.name,
923
+ role: t.role,
924
+ company: t.company,
925
+ avatar: t.avatar,
926
+ initials: t.initials,
927
+ rating: t.rating
928
+ }
929
+ )
930
+ },
931
+ t.name
932
+ )) })
933
+ ] }) }) });
934
+ }
935
+ var team = [
936
+ {
937
+ name: "Olivia Reed",
938
+ role: "Co-Founder & CEO",
939
+ bio: "Previously led product at two YC companies. Obsessed with design systems and developer experience.",
940
+ avatar: "https://ui.shadcn.com/avatars/01.png",
941
+ initials: "OR",
942
+ social: { twitter: "#", github: "#", linkedin: "#" }
943
+ },
944
+ {
945
+ name: "Marcus Webb",
946
+ role: "Co-Founder & CTO",
947
+ bio: "Full-stack engineer with 12 years building UI infrastructure. Open source maintainer.",
948
+ avatar: "https://ui.shadcn.com/avatars/02.png",
949
+ initials: "MW",
950
+ social: { twitter: "#", github: "#", linkedin: "#" }
951
+ },
952
+ {
953
+ name: "Priya Nair",
954
+ role: "Head of Design",
955
+ bio: "Interaction designer turned design systems engineer. Bridges the gap between Figma and production.",
956
+ avatar: "https://ui.shadcn.com/avatars/03.png",
957
+ initials: "PN",
958
+ social: { twitter: "#", github: null, linkedin: "#" }
959
+ },
960
+ {
961
+ name: "Daniel Frost",
962
+ role: "Senior Engineer",
963
+ bio: "Accessibility and performance specialist. If it doesn't work with a keyboard, it's broken.",
964
+ avatar: "https://ui.shadcn.com/avatars/04.png",
965
+ initials: "DF",
966
+ social: { twitter: null, github: "#", linkedin: "#" }
967
+ },
968
+ {
969
+ name: "Aisha Okafor",
970
+ role: "Developer Relations",
971
+ bio: "Writes docs, builds examples, and makes sure every engineer can ship their first block in under an hour.",
972
+ avatar: "https://ui.shadcn.com/avatars/05.png",
973
+ initials: "AO",
974
+ social: { twitter: "#", github: "#", linkedin: "#" }
975
+ },
976
+ {
977
+ name: "Tom Halvorsen",
978
+ role: "Growth",
979
+ bio: "Turns happy users into loud advocates. Runs the community and keeps the changelog sharp.",
980
+ avatar: "https://ui.shadcn.com/avatars/06.png",
981
+ initials: "TH",
982
+ social: { twitter: "#", github: null, linkedin: "#" }
983
+ }
984
+ ];
985
+ function TeamSection() {
986
+ return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", 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: [
987
+ /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
988
+ /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-4", children: "Team" }),
989
+ /* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: "The people behind Olwiba" }),
990
+ /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-xl text-pretty text-muted-foreground", children: "A small team with deep experience in design systems, open source, and developer tooling." })
991
+ ] }),
992
+ /* @__PURE__ */ jsx("div", { className: "mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3", children: team.map((member) => /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border bg-muted/40 p-5", children: [
993
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-4", children: [
994
+ /* @__PURE__ */ jsxs(Avatar, { className: "size-12 rounded-xl", children: [
995
+ /* @__PURE__ */ jsx(AvatarImage, { src: member.avatar, alt: member.name }),
996
+ /* @__PURE__ */ jsx(AvatarFallback, { className: "rounded-xl", children: member.initials })
997
+ ] }),
998
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
999
+ /* @__PURE__ */ jsx("div", { className: "font-semibold leading-tight", children: member.name }),
1000
+ /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: member.role })
1001
+ ] })
1002
+ ] }),
1003
+ /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm leading-relaxed text-muted-foreground", children: member.bio }),
1004
+ /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center gap-2", children: [
1005
+ member.social.twitter && /* @__PURE__ */ jsx("a", { href: member.social.twitter, "aria-label": "Twitter", className: "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground", children: /* @__PURE__ */ jsx(Twitter, { className: "size-3.5" }) }),
1006
+ member.social.github && /* @__PURE__ */ jsx("a", { href: member.social.github, "aria-label": "GitHub", className: "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground", children: /* @__PURE__ */ jsx(Github, { className: "size-3.5" }) }),
1007
+ member.social.linkedin && /* @__PURE__ */ jsx("a", { href: member.social.linkedin, "aria-label": "LinkedIn", className: "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground", children: /* @__PURE__ */ jsx(Linkedin, { className: "size-3.5" }) })
1008
+ ] })
1009
+ ] }, member.name)) })
1010
+ ] }) }) });
1011
+ }
1012
+ function FaqSection({
1013
+ title = "Frequently asked questions",
1014
+ description = "Everything you need to know before getting started.",
1015
+ badge = "FAQ",
1016
+ items
1017
+ }) {
1018
+ return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-3xl", children: [
1019
+ /* @__PURE__ */ jsx(SectionTitle, { title, description, badge }),
1020
+ /* @__PURE__ */ jsx(FadeIn, { direction: "up", children: /* @__PURE__ */ jsx(Accordion, { type: "single", collapsible: true, className: "mt-10 w-full", children: items.map((item, i) => /* @__PURE__ */ jsxs(AccordionItem, { value: `item-${i}`, children: [
1021
+ /* @__PURE__ */ jsx(AccordionTrigger, { className: "text-left text-sm font-medium", children: item.question }),
1022
+ /* @__PURE__ */ jsx(AccordionContent, { className: "text-sm text-muted-foreground", children: item.answer })
1023
+ ] }, i)) }) })
1024
+ ] }) }) });
1025
+ }
1026
+ function CountUp({
1027
+ from = 0,
1028
+ to,
1029
+ duration = 1500,
1030
+ decimals = 0,
1031
+ prefix = "",
1032
+ suffix = "",
1033
+ once = true,
1034
+ className,
1035
+ ...props
1036
+ }) {
1037
+ const ref = React25.useRef(null);
1038
+ const [value, setValue] = React25.useState(from);
1039
+ const hasStarted = React25.useRef(false);
1040
+ React25.useEffect(() => {
1041
+ const el = ref.current;
1042
+ if (!el) return;
1043
+ const observer = new IntersectionObserver(
1044
+ ([entry]) => {
1045
+ if (entry.isIntersecting && (!once || !hasStarted.current)) {
1046
+ hasStarted.current = true;
1047
+ const start = performance.now();
1048
+ const tick = (now) => {
1049
+ const elapsed = now - start;
1050
+ const progress = Math.min(elapsed / duration, 1);
1051
+ const eased = 1 - Math.pow(1 - progress, 3);
1052
+ setValue(from + (to - from) * eased);
1053
+ if (progress < 1) requestAnimationFrame(tick);
1054
+ };
1055
+ requestAnimationFrame(tick);
1056
+ }
1057
+ },
1058
+ { threshold: 0.5 }
1059
+ );
1060
+ observer.observe(el);
1061
+ return () => observer.disconnect();
1062
+ }, [from, to, duration, once]);
1063
+ return /* @__PURE__ */ jsxs("span", { ref, className: cn$1(className), ...props, children: [
1064
+ prefix,
1065
+ value.toFixed(decimals),
1066
+ suffix
1067
+ ] });
1068
+ }
1069
+ function parseStatValue(value) {
1070
+ const match = value.match(/^(\d+(?:\.\d+)?)(.*)/);
1071
+ if (!match) return null;
1072
+ const num = parseFloat(match[1]);
1073
+ const suffix = match[2] || "";
1074
+ const decimals = match[1].includes(".") ? match[1].split(".")[1].length : 0;
1075
+ return { num, suffix, decimals };
1076
+ }
1077
+ function StatValue({ value }) {
1078
+ const parsed = parseStatValue(value);
1079
+ if (!parsed) return /* @__PURE__ */ jsx(Fragment, { children: value });
1080
+ return /* @__PURE__ */ jsx(CountUp, { to: parsed.num, decimals: parsed.decimals, suffix: parsed.suffix });
1081
+ }
1082
+ function StatsSection({
1083
+ title = "Built for scale, used in production",
1084
+ description,
1085
+ badge = "By the numbers",
1086
+ stats
1087
+ }) {
1088
+ return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", children: /* @__PURE__ */ jsxs("div", { className: "relative px-6 py-14 sm:px-10 sm:py-20", children: [
1089
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(ellipse_at_bottom,hsl(var(--primary)/0.08),transparent_60%)]" }),
1090
+ /* @__PURE__ */ jsxs("div", { className: "relative mx-auto max-w-4xl", children: [
1091
+ /* @__PURE__ */ jsx(SectionTitle, { title, description, badge }),
1092
+ /* @__PURE__ */ jsx(StaggerChildren, { className: "mt-12 grid gap-px overflow-hidden rounded-2xl border bg-border sm:grid-cols-2 lg:grid-cols-4", children: stats.map((stat) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 bg-card px-6 py-8", children: [
1093
+ /* @__PURE__ */ jsx("div", { className: "text-4xl font-bold tracking-tight", children: /* @__PURE__ */ jsx(StatValue, { value: stat.value }) }),
1094
+ /* @__PURE__ */ jsx("div", { className: "font-medium", children: stat.label }),
1095
+ stat.description && /* @__PURE__ */ jsxs(Fragment, { children: [
1096
+ /* @__PURE__ */ jsx(Separator, {}),
1097
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: stat.description })
1098
+ ] })
1099
+ ] }, stat.label)) })
1100
+ ] })
1101
+ ] }) });
1102
+ }
1103
+ function NewsletterSection() {
1104
+ const [email, setEmail] = React25.useState("");
1105
+ const [submitted, setSubmitted] = React25.useState(false);
1106
+ function handleSubmit(e) {
1107
+ e.preventDefault();
1108
+ if (!email) return;
1109
+ setSubmitted(true);
1110
+ }
1111
+ return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", children: /* @__PURE__ */ jsxs("div", { className: "relative px-6 py-14 sm:px-10 sm:py-20", children: [
1112
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,hsl(var(--primary)/0.1),transparent_60%)]" }),
1113
+ /* @__PURE__ */ jsxs("div", { className: "relative mx-auto max-w-xl text-center", children: [
1114
+ /* @__PURE__ */ jsx("div", { className: "mb-4 inline-flex h-10 w-10 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Mail, { className: "size-5" }) }),
1115
+ /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-3", children: "Newsletter" }),
1116
+ /* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: "Stay in the loop" }),
1117
+ /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-sm text-pretty text-muted-foreground", children: "New components, release notes, and product tips \u2014 straight to your inbox. No spam, unsubscribe any time." }),
1118
+ submitted ? /* @__PURE__ */ jsxs("div", { className: "mt-8 rounded-2xl border bg-muted/50 px-6 py-5 text-sm", children: [
1119
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "You're on the list." }),
1120
+ " ",
1121
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "We'll be in touch soon." })
1122
+ ] }) : /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "mt-8 flex flex-col gap-3 sm:flex-row", children: [
1123
+ /* @__PURE__ */ jsx(
1124
+ Input$1,
1125
+ {
1126
+ type: "email",
1127
+ placeholder: "you@company.com",
1128
+ value: email,
1129
+ onChange: (e) => setEmail(e.target.value),
1130
+ required: true,
1131
+ className: "flex-1"
1132
+ }
1133
+ ),
1134
+ /* @__PURE__ */ jsxs(Button$1, { type: "submit", children: [
1135
+ "Subscribe",
1136
+ /* @__PURE__ */ jsx(ArrowRight, { className: "ml-2 size-4" })
1137
+ ] })
1138
+ ] }),
1139
+ /* @__PURE__ */ jsxs("p", { className: "mt-4 text-xs text-muted-foreground", children: [
1140
+ "By subscribing you agree to our",
1141
+ " ",
1142
+ /* @__PURE__ */ jsx("a", { href: "#", className: "underline underline-offset-4 hover:text-foreground", children: "Privacy Policy" }),
1143
+ "."
1144
+ ] })
1145
+ ] })
1146
+ ] }) });
1147
+ }
1148
+ var contactInfo = [
1149
+ { Icon: Mail, label: "Email", value: "hello@olwiba.com" },
1150
+ { Icon: Phone, label: "Phone", value: "+1 (555) 000-0000" },
1151
+ { Icon: MapPin, label: "Office", value: "San Francisco, CA" }
1152
+ ];
1153
+ function ContactSection() {
1154
+ const [submitted, setSubmitted] = React25.useState(false);
1155
+ function handleSubmit(e) {
1156
+ e.preventDefault();
1157
+ setSubmitted(true);
1158
+ }
1159
+ return /* @__PURE__ */ jsx("section", { className: "overflow-hidden rounded-2xl border bg-card", children: /* @__PURE__ */ jsxs("div", { className: "grid lg:grid-cols-[1fr_1.4fr]", children: [
1160
+ /* @__PURE__ */ jsxs("div", { className: "relative overflow-hidden bg-primary px-8 py-12 text-primary-foreground", children: [
1161
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(circle_at_top_right,hsl(var(--primary-foreground)/0.1),transparent_60%)]" }),
1162
+ /* @__PURE__ */ jsxs("div", { className: "relative space-y-6", children: [
1163
+ /* @__PURE__ */ jsxs("div", { children: [
1164
+ /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-3 bg-primary-foreground/15 text-primary-foreground hover:bg-primary-foreground/20", children: "Contact us" }),
1165
+ /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold", children: "Let's talk" }),
1166
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-primary-foreground/70", children: "Have a question or want to work together? Fill in the form and we'll get back to you within one business day." })
1167
+ ] }),
1168
+ /* @__PURE__ */ jsx(Separator, { className: "bg-primary-foreground/20" }),
1169
+ /* @__PURE__ */ jsx("div", { className: "space-y-4", children: contactInfo.map(({ Icon, label, value }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1170
+ /* @__PURE__ */ jsx("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary-foreground/10", children: /* @__PURE__ */ jsx(Icon, { className: "size-4" }) }),
1171
+ /* @__PURE__ */ jsxs("div", { children: [
1172
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-primary-foreground/60", children: label }),
1173
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: value })
1174
+ ] })
1175
+ ] }, label)) })
1176
+ ] })
1177
+ ] }),
1178
+ /* @__PURE__ */ jsx("div", { className: "p-8", children: submitted ? /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-[320px] flex-col items-center justify-center gap-4 text-center", children: [
1179
+ /* @__PURE__ */ jsx("div", { className: "flex h-12 w-12 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(MessageSquare, { className: "size-6" }) }),
1180
+ /* @__PURE__ */ jsxs("div", { children: [
1181
+ /* @__PURE__ */ jsx("h3", { className: "font-semibold", children: "Message sent" }),
1182
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Thanks for reaching out. We'll get back to you within one business day." })
1183
+ ] }),
1184
+ /* @__PURE__ */ jsx(Button$1, { variant: "outline", onClick: () => setSubmitted(false), children: "Send another" })
1185
+ ] }) : /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-5", children: [
1186
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
1187
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1188
+ /* @__PURE__ */ jsx(Label, { htmlFor: "contact-first", children: "First name" }),
1189
+ /* @__PURE__ */ jsx(Input$1, { id: "contact-first", placeholder: "Olivia", required: true })
1190
+ ] }),
1191
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1192
+ /* @__PURE__ */ jsx(Label, { htmlFor: "contact-last", children: "Last name" }),
1193
+ /* @__PURE__ */ jsx(Input$1, { id: "contact-last", placeholder: "Reed", required: true })
1194
+ ] })
1195
+ ] }),
1196
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1197
+ /* @__PURE__ */ jsx(Label, { htmlFor: "contact-email", children: "Email" }),
1198
+ /* @__PURE__ */ jsx(Input$1, { id: "contact-email", type: "email", placeholder: "olivia@company.com", required: true })
1199
+ ] }),
1200
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1201
+ /* @__PURE__ */ jsx(Label, { htmlFor: "contact-subject", children: "Subject" }),
1202
+ /* @__PURE__ */ jsx(Input$1, { id: "contact-subject", placeholder: "How can we help?", required: true })
1203
+ ] }),
1204
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1205
+ /* @__PURE__ */ jsx(Label, { htmlFor: "contact-message", children: "Message" }),
1206
+ /* @__PURE__ */ jsx(
1207
+ Textarea$1,
1208
+ {
1209
+ id: "contact-message",
1210
+ placeholder: "Tell us what you're working on...",
1211
+ className: "min-h-28 resize-none",
1212
+ required: true
1213
+ }
1214
+ )
1215
+ ] }),
1216
+ /* @__PURE__ */ jsxs(Button$1, { type: "submit", className: "w-full", children: [
1217
+ "Send message",
1218
+ /* @__PURE__ */ jsx(Send, { className: "ml-2 size-4" })
1219
+ ] })
1220
+ ] }) })
1221
+ ] }) });
1222
+ }
1223
+ function ThemeSwitchMinimal() {
1224
+ const [theme, setThemeState] = React25.useState("dark");
1225
+ React25.useEffect(() => {
1226
+ const stored = localStorage.getItem("theme");
1227
+ const resolved = stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
1228
+ setThemeState(resolved);
1229
+ }, []);
1230
+ const toggle = () => {
1231
+ const next = theme === "dark" ? "light" : "dark";
1232
+ setThemeState(next);
1233
+ localStorage.setItem("theme", next);
1234
+ document.documentElement.classList.toggle("dark", next === "dark");
1235
+ };
1236
+ return /* @__PURE__ */ jsx(Button$1, { variant: "ghost", size: "icon", onClick: toggle, className: "size-8", "aria-label": "Toggle theme", children: theme === "dark" ? /* @__PURE__ */ jsx(Sun, { className: "size-4" }) : /* @__PURE__ */ jsx(Moon, { className: "size-4" }) });
1237
+ }
1238
+ var defaultRenderLink6 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
1239
+ function Navbar({
1240
+ brand,
1241
+ navLinks,
1242
+ cta,
1243
+ showThemeToggle = false,
1244
+ renderLink = defaultRenderLink6
1245
+ }) {
1246
+ const [open, setOpen] = React25.useState(false);
1247
+ const brandHref = brand.href ?? "/";
1248
+ 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: [
1249
+ renderLink({
1250
+ href: brandHref,
1251
+ children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 font-semibold", children: [
1252
+ brand.logo && /* @__PURE__ */ jsx("span", { className: "flex h-7 w-7 items-center justify-center rounded-lg bg-primary text-primary-foreground", children: brand.logo }),
1253
+ /* @__PURE__ */ jsx("span", { children: brand.name })
1254
+ ] })
1255
+ }),
1256
+ /* @__PURE__ */ jsx("div", { className: "hidden items-center gap-1 md:flex", children: navLinks.map((link) => /* @__PURE__ */ jsx("span", { children: renderLink({
1257
+ href: link.href,
1258
+ className: "rounded-md px-3 py-1.5 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
1259
+ children: link.label
1260
+ }) }, link.label)) }),
1261
+ /* @__PURE__ */ jsxs("div", { className: "hidden items-center justify-end gap-3 md:flex", children: [
1262
+ cta?.secondary && renderLink({
1263
+ href: cta.secondary.href,
1264
+ children: /* @__PURE__ */ jsx(Button$1, { variant: "ghost", size: "sm", children: cta.secondary.label })
1265
+ }),
1266
+ cta?.primary && renderLink({
1267
+ href: cta.primary.href,
1268
+ children: /* @__PURE__ */ jsx(Button$1, { size: "sm", children: cta.primary.label })
1269
+ }),
1270
+ showThemeToggle && /* @__PURE__ */ jsx(ThemeSwitchMinimal, {})
1271
+ ] }),
1272
+ /* @__PURE__ */ jsxs(Sheet, { open, onOpenChange: setOpen, children: [
1273
+ /* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button$1, { variant: "ghost", size: "icon", className: "justify-self-end md:hidden", children: [
1274
+ /* @__PURE__ */ jsx(Menu, { className: "size-5" }),
1275
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Open menu" })
1276
+ ] }) }),
1277
+ /* @__PURE__ */ jsxs(SheetContent, { side: "right", className: "w-72", children: [
1278
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pb-4", children: [
1279
+ /* @__PURE__ */ jsx("span", { onClick: () => setOpen(false), className: "cursor-pointer", children: renderLink({
1280
+ href: brandHref,
1281
+ children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 font-semibold", children: [
1282
+ brand.logo && /* @__PURE__ */ jsx("span", { className: "flex h-7 w-7 items-center justify-center rounded-lg bg-primary text-primary-foreground", children: brand.logo }),
1283
+ /* @__PURE__ */ jsx("span", { children: brand.name })
1284
+ ] })
1285
+ }) }),
1286
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1287
+ showThemeToggle && /* @__PURE__ */ jsx(ThemeSwitchMinimal, {}),
1288
+ /* @__PURE__ */ jsxs(Button$1, { variant: "ghost", size: "icon", onClick: () => setOpen(false), children: [
1289
+ /* @__PURE__ */ jsx(X, { className: "size-4" }),
1290
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close menu" })
1291
+ ] })
1292
+ ] })
1293
+ ] }),
1294
+ /* @__PURE__ */ jsx(Separator, {}),
1295
+ /* @__PURE__ */ jsx("nav", { className: "mt-4 flex flex-col gap-1", children: navLinks.map((link) => /* @__PURE__ */ jsx("span", { onClick: () => setOpen(false), children: renderLink({
1296
+ href: link.href,
1297
+ className: "block rounded-md px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
1298
+ children: link.label
1299
+ }) }, link.label)) }),
1300
+ /* @__PURE__ */ jsxs("div", { className: "mt-6 flex flex-col gap-2", children: [
1301
+ cta?.secondary && renderLink({
1302
+ href: cta.secondary.href,
1303
+ children: /* @__PURE__ */ jsx(Button$1, { variant: "outline", className: "w-full", children: cta.secondary.label })
1304
+ }),
1305
+ cta?.primary && renderLink({
1306
+ href: cta.primary.href,
1307
+ children: /* @__PURE__ */ jsx(Button$1, { className: "w-full", children: cta.primary.label })
1308
+ })
1309
+ ] })
1310
+ ] })
1311
+ ] })
1312
+ ] }) });
1313
+ }
1314
+ var defaultRenderLink7 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
1315
+ function Footer({
1316
+ brand,
1317
+ navLinks,
1318
+ socialLinks,
1319
+ legal,
1320
+ renderLink = defaultRenderLink7
1321
+ }) {
1322
+ const brandHref = brand.href ?? "/";
1323
+ const copyrightText = legal ?? `\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${brand.name}. All rights reserved.`;
1324
+ return /* @__PURE__ */ jsx("footer", { className: "bg-gray-900", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-7xl overflow-hidden px-6 py-20 sm:py-24 lg:px-8", children: [
1325
+ /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: renderLink({
1326
+ href: brandHref,
1327
+ className: "flex items-center gap-2",
1328
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
1329
+ brand.logo && /* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-white/10 text-white", children: brand.logo }),
1330
+ /* @__PURE__ */ jsx("span", { className: "text-lg font-semibold text-white", children: brand.name })
1331
+ ] })
1332
+ }) }),
1333
+ navLinks && navLinks.length > 0 && /* @__PURE__ */ jsx("nav", { className: "mt-10 flex flex-wrap justify-center gap-x-12 gap-y-3", "aria-label": "Footer", children: navLinks.map(({ label, href }) => /* @__PURE__ */ jsx("div", { children: renderLink({
1334
+ href,
1335
+ className: "text-sm/6 text-gray-400 hover:text-white transition-colors",
1336
+ children: label
1337
+ }) }, label)) }),
1338
+ socialLinks && socialLinks.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-10 flex justify-center gap-x-10", children: socialLinks.map(({ label, href, icon }) => /* @__PURE__ */ jsx(
1339
+ "a",
1340
+ {
1341
+ href,
1342
+ "aria-label": label,
1343
+ className: "text-gray-400 hover:text-gray-300 transition-colors",
1344
+ children: icon
1345
+ },
1346
+ label
1347
+ )) }),
1348
+ /* @__PURE__ */ jsx("p", { className: "mt-10 text-center text-sm/6 text-gray-500", children: copyrightText })
1349
+ ] }) });
1350
+ }
1351
+ var speedDuration = {
1352
+ slow: "60s",
1353
+ normal: "40s",
1354
+ fast: "25s"
1355
+ };
1356
+ function LogoStrip({
1357
+ logos,
1358
+ label,
1359
+ speed = "normal"
1360
+ }) {
1361
+ const duration = speedDuration[speed];
1362
+ return /* @__PURE__ */ jsxs(FadeIn, { direction: "up", children: [
1363
+ /* @__PURE__ */ jsxs("section", { className: "overflow-hidden py-8", children: [
1364
+ label && /* @__PURE__ */ jsx("p", { className: "mb-6 text-center text-sm text-muted-foreground", children: label }),
1365
+ /* @__PURE__ */ jsx(
1366
+ "div",
1367
+ {
1368
+ className: "relative",
1369
+ style: {
1370
+ maskImage: "linear-gradient(to right, transparent, black 10%, black 90%, transparent)",
1371
+ WebkitMaskImage: "linear-gradient(to right, transparent, black 10%, black 90%, transparent)"
1372
+ },
1373
+ children: /* @__PURE__ */ jsx(
1374
+ "div",
1375
+ {
1376
+ className: "flex w-max gap-12",
1377
+ style: {
1378
+ animation: `logo-strip-scroll ${duration} linear infinite`
1379
+ },
1380
+ children: [...logos, ...logos].map((logo, i) => {
1381
+ const img = logo.darkSrc ? /* @__PURE__ */ jsxs(Fragment, { children: [
1382
+ /* @__PURE__ */ jsx(
1383
+ "img",
1384
+ {
1385
+ src: logo.src,
1386
+ alt: logo.alt,
1387
+ className: "h-8 w-auto object-contain opacity-60 grayscale transition-all hover:opacity-100 hover:grayscale-0 dark:hidden"
1388
+ }
1389
+ ),
1390
+ /* @__PURE__ */ jsx(
1391
+ "img",
1392
+ {
1393
+ src: logo.darkSrc,
1394
+ alt: logo.alt,
1395
+ className: "hidden h-8 w-auto object-contain opacity-60 grayscale transition-all hover:opacity-100 hover:grayscale-0 dark:block"
1396
+ }
1397
+ )
1398
+ ] }) : /* @__PURE__ */ jsx(
1399
+ "img",
1400
+ {
1401
+ src: logo.src,
1402
+ alt: logo.alt,
1403
+ className: "h-8 w-auto object-contain opacity-60 grayscale transition-all hover:opacity-100 hover:grayscale-0"
1404
+ }
1405
+ );
1406
+ return logo.href ? /* @__PURE__ */ jsx(
1407
+ "a",
1408
+ {
1409
+ href: logo.href,
1410
+ target: "_blank",
1411
+ rel: "noopener noreferrer",
1412
+ className: "flex shrink-0 items-center",
1413
+ children: img
1414
+ },
1415
+ `${logo.alt}-${i}`
1416
+ ) : /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center", children: img }, `${logo.alt}-${i}`);
1417
+ })
1418
+ }
1419
+ )
1420
+ }
1421
+ )
1422
+ ] }),
1423
+ /* @__PURE__ */ jsx("style", { children: `
1424
+ @keyframes logo-strip-scroll {
1425
+ from { transform: translateX(0); }
1426
+ to { transform: translateX(-50%); }
1427
+ }
1428
+ ` })
1429
+ ] });
1430
+ }
1431
+ function GridUnderlay({ variant, size = 24, className, ...props }) {
1432
+ const id = React25.useId();
1433
+ 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: [
1434
+ /* @__PURE__ */ jsx("line", { x1: size / 2, y1: 0, x2: size / 2, y2: size, stroke: "currentColor", strokeWidth: 0.5 }),
1435
+ /* @__PURE__ */ jsx("line", { x1: 0, y1: size / 2, x2: size, y2: size / 2, stroke: "currentColor", strokeWidth: 0.5 })
1436
+ ] });
1437
+ return /* @__PURE__ */ jsxs(
1438
+ "svg",
1439
+ {
1440
+ "aria-hidden": "true",
1441
+ className: cn$1("pointer-events-none absolute inset-0 h-full w-full text-foreground/15", className),
1442
+ ...props,
1443
+ children: [
1444
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("pattern", { id, width: size, height: size, patternUnits: "userSpaceOnUse", children: pattern }) }),
1445
+ /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })
1446
+ ]
1447
+ }
1448
+ );
1449
+ }
1450
+ var blurClass = { sm: "blur-xl", md: "blur-2xl", lg: "blur-3xl", xl: "blur-[80px]" };
1451
+ function GlowUnderlay({
1452
+ size = 400,
1453
+ color = "color-mix(in oklch, var(--primary) 45%, transparent)",
1454
+ followCursor = false,
1455
+ blur = "lg",
1456
+ className,
1457
+ style,
1458
+ ...props
1459
+ }) {
1460
+ const [pos, setPos] = React25.useState({ x: "50%", y: "50%" });
1461
+ const containerRef = React25.useRef(null);
1462
+ React25.useEffect(() => {
1463
+ if (!followCursor) return;
1464
+ const handleMouseMove = (e) => {
1465
+ const el = containerRef.current;
1466
+ if (!el) return;
1467
+ const rect = el.getBoundingClientRect();
1468
+ setPos({ x: `${e.clientX - rect.left}px`, y: `${e.clientY - rect.top}px` });
1469
+ };
1470
+ window.addEventListener("mousemove", handleMouseMove);
1471
+ return () => window.removeEventListener("mousemove", handleMouseMove);
1472
+ }, [followCursor]);
1473
+ return /* @__PURE__ */ jsx("div", { ref: containerRef, className: cn$1("pointer-events-none absolute inset-0 overflow-hidden", className), ...props, children: /* @__PURE__ */ jsx(
1474
+ "div",
1475
+ {
1476
+ "aria-hidden": "true",
1477
+ className: cn$1("absolute rounded-full", blurClass[blur]),
1478
+ style: {
1479
+ width: size,
1480
+ height: size,
1481
+ background: color,
1482
+ left: pos.x,
1483
+ top: pos.y,
1484
+ transform: "translate(-50%, -50%)",
1485
+ ...style
1486
+ }
1487
+ }
1488
+ ) });
1489
+ }
1490
+ function Underlay(props) {
1491
+ if (props.variant === "glow") {
1492
+ return /* @__PURE__ */ jsx(GlowUnderlay, { ...props });
1493
+ }
1494
+ return /* @__PURE__ */ jsx(GridUnderlay, { ...props });
1495
+ }
1496
+ function DimOverlay({ opacity = 0.5, className, style, ...props }) {
1497
+ return /* @__PURE__ */ jsx(
1498
+ "div",
1499
+ {
1500
+ "aria-hidden": "true",
1501
+ className: cn$1("absolute inset-0 bg-background", className),
1502
+ style: { opacity, ...style },
1503
+ ...props
1504
+ }
1505
+ );
1506
+ }
1507
+ var scrimGradients = {
1508
+ bottom: "to bottom",
1509
+ top: "to top",
1510
+ left: "to left",
1511
+ right: "to right"
1512
+ };
1513
+ function ScrimOverlay({ direction = "bottom", color = "var(--background)", className, style, ...props }) {
1514
+ return /* @__PURE__ */ jsx(
1515
+ "div",
1516
+ {
1517
+ "aria-hidden": "true",
1518
+ className: cn$1("pointer-events-none absolute inset-x-0 bottom-0 h-1/2", className),
1519
+ style: {
1520
+ background: `linear-gradient(${scrimGradients[direction]}, transparent, ${color})`,
1521
+ ...style
1522
+ },
1523
+ ...props
1524
+ }
1525
+ );
1526
+ }
1527
+ function LoadingOverlay({ label, className, ...props }) {
1528
+ return /* @__PURE__ */ jsxs(
1529
+ "div",
1530
+ {
1531
+ role: "status",
1532
+ className: cn$1("absolute inset-0 flex flex-col items-center justify-center gap-2 bg-background/80 backdrop-blur-sm", className),
1533
+ ...props,
1534
+ children: [
1535
+ /* @__PURE__ */ jsx(Loader2, { className: "size-5 animate-spin text-muted-foreground" }),
1536
+ label && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: label })
1537
+ ]
1538
+ }
1539
+ );
1540
+ }
1541
+ function Overlay(props) {
1542
+ if (props.variant === "dim") return /* @__PURE__ */ jsx(DimOverlay, { ...props });
1543
+ if (props.variant === "scrim") return /* @__PURE__ */ jsx(ScrimOverlay, { ...props });
1544
+ return /* @__PURE__ */ jsx(LoadingOverlay, { ...props });
1545
+ }
1546
+ function PageTransition({
1547
+ variant = "fade",
1548
+ duration = 300,
1549
+ children,
1550
+ className,
1551
+ style,
1552
+ ...props
1553
+ }) {
1554
+ const [mounted, setMounted] = React25.useState(false);
1555
+ React25.useEffect(() => {
1556
+ const id = requestAnimationFrame(() => setMounted(true));
1557
+ return () => cancelAnimationFrame(id);
1558
+ }, []);
1559
+ const initial = variant === "slide-up" ? { opacity: 0, transform: "translateY(16px)" } : variant === "slide-down" ? { opacity: 0, transform: "translateY(-16px)" } : { opacity: 0 };
1560
+ const entered = { opacity: 1, transform: "translateY(0)" };
1561
+ return /* @__PURE__ */ jsx(
1562
+ "div",
1563
+ {
1564
+ className: cn$1(className),
1565
+ style: {
1566
+ transition: `opacity ${duration}ms ease, transform ${duration}ms ease`,
1567
+ ...mounted ? entered : initial,
1568
+ ...style
1569
+ },
1570
+ ...props,
1571
+ children
1572
+ }
1573
+ );
1574
+ }
1575
+ function Spotlight({
1576
+ groups,
1577
+ placeholder = "Search anything...",
1578
+ trigger,
1579
+ triggerClassName,
1580
+ shortcut = "\u2318K"
1581
+ }) {
1582
+ const [open, setOpen] = React25.useState(false);
1583
+ React25.useEffect(() => {
1584
+ const down = (e) => {
1585
+ if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
1586
+ e.preventDefault();
1587
+ setOpen((v) => !v);
1588
+ }
1589
+ };
1590
+ document.addEventListener("keydown", down);
1591
+ return () => document.removeEventListener("keydown", down);
1592
+ }, []);
1593
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1594
+ trigger ? /* @__PURE__ */ jsx("div", { onClick: () => setOpen(true), children: trigger }) : /* @__PURE__ */ jsxs(
1595
+ Button$1,
1596
+ {
1597
+ variant: "outline",
1598
+ onClick: () => setOpen(true),
1599
+ className: cn$1("w-64 justify-between text-muted-foreground", triggerClassName),
1600
+ children: [
1601
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
1602
+ /* @__PURE__ */ jsx(Search, { className: "size-4" }),
1603
+ placeholder
1604
+ ] }),
1605
+ /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "font-mono text-xs", children: shortcut })
1606
+ ]
1607
+ }
1608
+ ),
1609
+ /* @__PURE__ */ jsxs(CommandDialog, { open, onOpenChange: setOpen, children: [
1610
+ /* @__PURE__ */ jsx(CommandInput, { placeholder }),
1611
+ /* @__PURE__ */ jsxs(CommandList, { children: [
1612
+ /* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
1613
+ groups.map((group, i) => /* @__PURE__ */ jsxs(React25.Fragment, { children: [
1614
+ i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
1615
+ /* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
1616
+ CommandItem,
1617
+ {
1618
+ onSelect: () => {
1619
+ item.onSelect();
1620
+ setOpen(false);
1621
+ },
1622
+ children: [
1623
+ item.icon && /* @__PURE__ */ jsx("span", { className: "mr-2", children: item.icon }),
1624
+ /* @__PURE__ */ jsx("span", { children: item.label }),
1625
+ item.description && /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs text-muted-foreground", children: item.description })
1626
+ ]
1627
+ },
1628
+ item.id
1629
+ )) })
1630
+ ] }, group.heading))
1631
+ ] })
1632
+ ] })
1633
+ ] });
1634
+ }
1635
+ var BASE = 40;
1636
+ var MAGNIFY_RADIUS = 80;
1637
+ function Dock({ items, iconSize = BASE, magnification = 1.7, className, ...props }) {
1638
+ const [mouseX, setMouseX] = React25.useState(null);
1639
+ const containerRef = React25.useRef(null);
1640
+ function getScale(index) {
1641
+ if (mouseX === null || !containerRef.current) return 1;
1642
+ const container = containerRef.current;
1643
+ const buttons = container.querySelectorAll("[data-dock-item]");
1644
+ const btn = buttons[index];
1645
+ if (!btn) return 1;
1646
+ const rect = btn.getBoundingClientRect();
1647
+ const centerX = rect.left + rect.width / 2;
1648
+ const distance = Math.abs(mouseX - centerX);
1649
+ if (distance > MAGNIFY_RADIUS) return 1;
1650
+ const t = 1 - distance / MAGNIFY_RADIUS;
1651
+ return 1 + (magnification - 1) * t;
1652
+ }
1653
+ return /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ jsx(
1654
+ "div",
1655
+ {
1656
+ ref: containerRef,
1657
+ onMouseMove: (e) => setMouseX(e.clientX),
1658
+ onMouseLeave: () => setMouseX(null),
1659
+ className: cn$1(
1660
+ "inline-flex items-end gap-2 rounded-2xl border bg-background/80 px-4 py-3 shadow-lg backdrop-blur-md",
1661
+ className
1662
+ ),
1663
+ ...props,
1664
+ children: items.map((item, i) => {
1665
+ const scale = getScale(i);
1666
+ const size = iconSize * scale;
1667
+ const button = /* @__PURE__ */ jsxs(Tooltip, { children: [
1668
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
1669
+ "button",
1670
+ {
1671
+ "data-dock-item": true,
1672
+ onClick: item.onClick,
1673
+ className: "flex items-center justify-center rounded-xl bg-muted text-foreground transition-colors hover:bg-accent",
1674
+ style: {
1675
+ width: size,
1676
+ height: size,
1677
+ transition: "width 100ms ease, height 100ms ease",
1678
+ transformOrigin: "bottom center"
1679
+ },
1680
+ "aria-label": item.label,
1681
+ children: /* @__PURE__ */ jsx(item.icon, { style: { width: size * 0.5, height: size * 0.5 } })
1682
+ }
1683
+ ) }),
1684
+ /* @__PURE__ */ jsx(TooltipContent, { side: "top", sideOffset: 8, children: /* @__PURE__ */ jsx("p", { children: item.label }) })
1685
+ ] }, item.label);
1686
+ if (item.href) {
1687
+ return /* @__PURE__ */ jsx("a", { href: item.href, children: button }, item.label);
1688
+ }
1689
+ return button;
1690
+ })
1691
+ }
1692
+ ) });
1693
+ }
1694
+ function renderItems(items) {
1695
+ return items.map((item, i) => {
1696
+ if (item.type === "separator") return /* @__PURE__ */ jsx(ContextMenuSeparator, {}, i);
1697
+ if (item.type === "label") return /* @__PURE__ */ jsx(ContextMenuLabel, { children: item.label }, i);
1698
+ if (item.type === "sub") {
1699
+ return /* @__PURE__ */ jsxs(ContextMenuSub, { children: [
1700
+ /* @__PURE__ */ jsx(ContextMenuSubTrigger, { children: item.label }),
1701
+ /* @__PURE__ */ jsx(ContextMenuSubContent, { children: renderItems(item.items) })
1702
+ ] }, i);
1703
+ }
1704
+ return /* @__PURE__ */ jsxs(ContextMenuItem, { disabled: item.disabled, onSelect: item.onSelect, children: [
1705
+ item.label,
1706
+ item.shortcut && /* @__PURE__ */ jsx(ContextMenuShortcut, { children: item.shortcut })
1707
+ ] }, i);
1708
+ });
1709
+ }
1710
+ function ContextMenu({ items, children }) {
1711
+ return /* @__PURE__ */ jsxs(ContextMenu$1, { children: [
1712
+ /* @__PURE__ */ jsx(ContextMenuTrigger, { asChild: true, children }),
1713
+ /* @__PURE__ */ jsx(ContextMenuContent, { children: renderItems(items) })
1714
+ ] });
1715
+ }
1716
+ function ConfirmDialog({ isOpen, options, handleConfirm, handleCancel, destructive = false }) {
1717
+ return /* @__PURE__ */ jsx(AlertDialog, { open: isOpen, onOpenChange: (open) => {
1718
+ if (!open) handleCancel();
1719
+ }, children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
1720
+ /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
1721
+ /* @__PURE__ */ jsx(AlertDialogTitle, { children: options.title ?? "Are you sure?" }),
1722
+ options.description && /* @__PURE__ */ jsx(AlertDialogDescription, { children: options.description })
1723
+ ] }),
1724
+ /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [
1725
+ /* @__PURE__ */ jsx(AlertDialogCancel, { onClick: handleCancel, children: options.cancelLabel ?? "Cancel" }),
1726
+ /* @__PURE__ */ jsx(
1727
+ AlertDialogAction,
1728
+ {
1729
+ onClick: handleConfirm,
1730
+ className: destructive ? "bg-destructive text-destructive-foreground hover:bg-destructive/90" : void 0,
1731
+ children: options.confirmLabel ?? "Confirm"
1732
+ }
1733
+ )
1734
+ ] })
1735
+ ] }) });
1736
+ }
1737
+ var blurClass2 = {
1738
+ sm: "backdrop-blur-sm",
1739
+ md: "backdrop-blur-md",
1740
+ lg: "backdrop-blur-lg"
1741
+ };
1742
+ function GlassCard({ blur = "md", className, children, ...props }) {
1743
+ return /* @__PURE__ */ jsx(
1744
+ "div",
1745
+ {
1746
+ className: cn$1(
1747
+ "rounded-2xl border border-white/20 bg-background/50 shadow-sm",
1748
+ blurClass2[blur],
1749
+ className
1750
+ ),
1751
+ ...props,
1752
+ children
1753
+ }
1754
+ );
1755
+ }
1756
+ function StatCard({ value, label, delta, trend = "neutral", description, className, ...props }) {
1757
+ return /* @__PURE__ */ jsxs(
1758
+ "div",
1759
+ {
1760
+ className: cn$1("rounded-2xl border bg-card p-5", className),
1761
+ ...props,
1762
+ children: [
1763
+ /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: label }),
1764
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-end justify-between gap-3", children: [
1765
+ /* @__PURE__ */ jsx("div", { className: "text-3xl font-bold tracking-tight", children: value }),
1766
+ delta && /* @__PURE__ */ jsxs(
1767
+ "div",
1768
+ {
1769
+ className: cn$1(
1770
+ "flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium",
1771
+ trend === "up" && "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
1772
+ trend === "down" && "bg-red-500/10 text-red-600 dark:text-red-400",
1773
+ trend === "neutral" && "bg-muted text-muted-foreground"
1774
+ ),
1775
+ children: [
1776
+ trend === "up" && /* @__PURE__ */ jsx(TrendingUp, { className: "size-3" }),
1777
+ trend === "down" && /* @__PURE__ */ jsx(TrendingDown, { className: "size-3" }),
1778
+ delta
1779
+ ]
1780
+ }
1781
+ )
1782
+ ] }),
1783
+ description && /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-xs text-muted-foreground", children: description })
1784
+ ]
1785
+ }
1786
+ );
1787
+ }
1788
+ var overlayClass = {
1789
+ none: "",
1790
+ subtle: "bg-gradient-to-t from-black/60 via-black/10 to-transparent",
1791
+ strong: "bg-gradient-to-t from-black/80 via-black/30 to-black/10"
1792
+ };
1793
+ var aspectClass = {
1794
+ video: "aspect-video",
1795
+ square: "aspect-square",
1796
+ portrait: "aspect-[3/4]",
1797
+ auto: ""
1798
+ };
1799
+ function ImageCard({
1800
+ src,
1801
+ alt = "",
1802
+ overlay = "subtle",
1803
+ aspectRatio = "video",
1804
+ children,
1805
+ className,
1806
+ ...props
1807
+ }) {
1808
+ return /* @__PURE__ */ jsxs(
1809
+ "div",
1810
+ {
1811
+ className: cn$1(
1812
+ "group relative overflow-hidden rounded-2xl bg-muted",
1813
+ aspectClass[aspectRatio],
1814
+ className
1815
+ ),
1816
+ ...props,
1817
+ children: [
1818
+ /* @__PURE__ */ jsx(
1819
+ "img",
1820
+ {
1821
+ src,
1822
+ alt,
1823
+ className: "h-full w-full object-cover transition-transform duration-500 group-hover:scale-105"
1824
+ }
1825
+ ),
1826
+ overlay !== "none" && /* @__PURE__ */ jsx("div", { className: cn$1("absolute inset-0", overlayClass[overlay]) }),
1827
+ children && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex flex-col justify-end p-5 text-white", children })
1828
+ ]
1829
+ }
1830
+ );
1831
+ }
1832
+ function FullPageSpinner({ message }) {
1833
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-4", children: [
1834
+ /* @__PURE__ */ jsx(Spinner, { className: "size-8" }),
1835
+ message && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: message })
1836
+ ] });
1837
+ }
1838
+ var defaultRenderLink8 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
1839
+ function PageHeader({
1840
+ title,
1841
+ description,
1842
+ breadcrumbs,
1843
+ backButton,
1844
+ renderLink = defaultRenderLink8,
1845
+ className,
1846
+ children
1847
+ }) {
1848
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1 pb-6", className), children: [
1849
+ 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) => {
1850
+ const isLast = i === breadcrumbs.length - 1;
1851
+ return /* @__PURE__ */ jsxs(React25.Fragment, { children: [
1852
+ i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0" }),
1853
+ isLast || !crumb.href ? /* @__PURE__ */ jsx("span", { className: cn(isLast && "text-foreground font-medium"), children: crumb.label }) : renderLink({
1854
+ href: crumb.href,
1855
+ children: crumb.label,
1856
+ className: "hover:text-foreground transition-colors"
1857
+ })
1858
+ ] }, i);
1859
+ }) }),
1860
+ backButton && /* @__PURE__ */ jsx("div", { className: "mb-2", children: backButton.href ? renderLink({
1861
+ href: backButton.href,
1862
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
1863
+ /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" }),
1864
+ /* @__PURE__ */ jsx("span", { children: backButton.label ?? "Back" })
1865
+ ] }),
1866
+ className: "inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors"
1867
+ }) : /* @__PURE__ */ jsxs(
1868
+ "button",
1869
+ {
1870
+ type: "button",
1871
+ onClick: backButton.onClick,
1872
+ className: "inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors",
1873
+ children: [
1874
+ /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" }),
1875
+ /* @__PURE__ */ jsx("span", { children: backButton.label ?? "Back" })
1876
+ ]
1877
+ }
1878
+ ) }),
1879
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
1880
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl font-semibold tracking-tight", children: title }),
1881
+ children && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-2", children })
1882
+ ] }),
1883
+ description && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description })
1884
+ ] });
1885
+ }
1886
+ function Suspensed({ children, fallback }) {
1887
+ return /* @__PURE__ */ jsx(React25.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
1888
+ }
1889
+ function ThemeColorUpdater({ colorTheme }) {
1890
+ React25.useEffect(() => {
1891
+ if (colorTheme) {
1892
+ document.documentElement.setAttribute("data-theme", colorTheme);
1893
+ } else {
1894
+ document.documentElement.removeAttribute("data-theme");
1895
+ }
1896
+ }, [colorTheme]);
1897
+ return null;
1898
+ }
1899
+ function VersionBanner({ version, message, className, onDismiss }) {
1900
+ const [dismissed, setDismissed] = React25.useState(false);
1901
+ if (dismissed) return null;
1902
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-4 bg-primary/10 px-4 py-2 text-sm", className), children: [
1903
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1904
+ /* @__PURE__ */ jsxs("span", { className: "rounded bg-primary/20 px-1.5 py-0.5 font-mono text-xs font-semibold text-primary", children: [
1905
+ "v",
1906
+ version
1907
+ ] }),
1908
+ message && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: message })
1909
+ ] }),
1910
+ onDismiss && /* @__PURE__ */ jsx(
1911
+ "button",
1912
+ {
1913
+ onClick: () => {
1914
+ setDismissed(true);
1915
+ onDismiss();
1916
+ },
1917
+ className: "text-muted-foreground transition-colors hover:text-foreground",
1918
+ "aria-label": "Dismiss",
1919
+ children: /* @__PURE__ */ jsx(X, { className: "size-4" })
1920
+ }
1921
+ )
1922
+ ] });
1923
+ }
1924
+ function DevBanner({ environment = "development", className }) {
1925
+ return /* @__PURE__ */ jsxs(
1926
+ "div",
1927
+ {
1928
+ className: cn(
1929
+ "flex items-center justify-center gap-2 bg-amber-500/15 px-4 py-1 text-xs font-medium text-amber-700 dark:text-amber-400",
1930
+ className
1931
+ ),
1932
+ children: [
1933
+ /* @__PURE__ */ jsx("span", { className: "size-1.5 rounded-full bg-amber-500" }),
1934
+ /* @__PURE__ */ jsx("span", { children: environment })
1935
+ ]
1936
+ }
1937
+ );
1938
+ }
1939
+ function RegisterHotkeys({ hotkeys }) {
1940
+ React25.useEffect(() => {
1941
+ const handleKeyDown = (event) => {
1942
+ for (const hotkey of hotkeys) {
1943
+ const matches = event.key.toLowerCase() === hotkey.key.toLowerCase() && !!event.ctrlKey === !!hotkey.ctrl && !!event.metaKey === !!hotkey.meta && !!event.shiftKey === !!hotkey.shift && !!event.altKey === !!hotkey.alt;
1944
+ if (matches) {
1945
+ event.preventDefault();
1946
+ hotkey.handler();
1947
+ break;
1948
+ }
1949
+ }
1950
+ };
1951
+ document.addEventListener("keydown", handleKeyDown);
1952
+ return () => document.removeEventListener("keydown", handleKeyDown);
1953
+ }, [hotkeys]);
1954
+ return null;
1955
+ }
1956
+ function RootErrorFallback({ error, resetErrorBoundary }) {
1957
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-h-svh flex-col items-center justify-center gap-6 p-8 text-center", children: [
1958
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-3", children: [
1959
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "size-12 text-destructive" }),
1960
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold", children: "Something went wrong" }),
1961
+ /* @__PURE__ */ jsx("p", { className: "max-w-md text-sm text-muted-foreground", children: error.message || "An unexpected error occurred." })
1962
+ ] }),
1963
+ resetErrorBoundary && /* @__PURE__ */ jsx(Button$1, { onClick: resetErrorBoundary, variant: "outline", children: "Try again" })
1964
+ ] });
1965
+ }
1966
+ function useMounted() {
1967
+ const [mounted, setMounted] = useState(false);
1968
+ useEffect(() => {
1969
+ setMounted(true);
1970
+ }, []);
1971
+ return mounted;
1972
+ }
1973
+ function useConfirm() {
1974
+ const [isOpen, setIsOpen] = React25.useState(false);
1975
+ const [options, setOptions] = React25.useState({});
1976
+ const resolveRef = React25.useRef(null);
1977
+ const confirm = React25.useCallback((opts = {}) => {
1978
+ setOptions(opts);
1979
+ setIsOpen(true);
1980
+ return new Promise((resolve) => {
1981
+ resolveRef.current = resolve;
1982
+ });
1983
+ }, []);
1984
+ const handleConfirm = React25.useCallback(() => {
1985
+ resolveRef.current?.(true);
1986
+ setIsOpen(false);
1987
+ }, []);
1988
+ const handleCancel = React25.useCallback(() => {
1989
+ resolveRef.current?.(false);
1990
+ setIsOpen(false);
1991
+ }, []);
1992
+ return { confirm, isOpen, options, handleConfirm, handleCancel };
1993
+ }
1994
+ function useControlledOpen(defaultOpen = false) {
1995
+ const [isOpen, setIsOpen] = React25.useState(defaultOpen);
1996
+ const open = React25.useCallback(() => setIsOpen(true), []);
1997
+ const close = React25.useCallback(() => setIsOpen(false), []);
1998
+ const toggle = React25.useCallback(() => setIsOpen((prev) => !prev), []);
1999
+ return { isOpen, open, close, toggle, setIsOpen };
2000
+ }
2001
+ function useScrolledPast(threshold) {
2002
+ const [scrolledPast, setScrolledPast] = React25.useState(false);
2003
+ React25.useEffect(() => {
2004
+ const handleScroll = () => {
2005
+ setScrolledPast(window.scrollY > threshold);
2006
+ };
2007
+ handleScroll();
2008
+ window.addEventListener("scroll", handleScroll, { passive: true });
2009
+ return () => window.removeEventListener("scroll", handleScroll);
2010
+ }, [threshold]);
2011
+ return scrolledPast;
2012
+ }
2013
+ function useCopyToClipboard() {
2014
+ const [copied, setCopied] = React25.useState(false);
2015
+ const timeoutRef = React25.useRef(void 0);
2016
+ const copy = React25.useCallback((text) => {
2017
+ navigator.clipboard.writeText(text).then(() => {
2018
+ setCopied(true);
2019
+ clearTimeout(timeoutRef.current);
2020
+ timeoutRef.current = setTimeout(() => setCopied(false), 2e3);
2021
+ });
2022
+ }, []);
2023
+ React25.useEffect(() => () => clearTimeout(timeoutRef.current), []);
2024
+ return [copied, copy];
2025
+ }
2026
+ function useDebounce(value, delay) {
2027
+ const [debounced, setDebounced] = React25.useState(value);
2028
+ React25.useEffect(() => {
2029
+ const timer = setTimeout(() => setDebounced(value), delay);
2030
+ return () => clearTimeout(timer);
2031
+ }, [value, delay]);
2032
+ return debounced;
2033
+ }
2034
+ function useIntersectionObserver(options) {
2035
+ const ref = React25.useRef(null);
2036
+ const [isIntersecting, setIsIntersecting] = React25.useState(false);
2037
+ React25.useEffect(() => {
2038
+ const el = ref.current;
2039
+ if (!el) return;
2040
+ const observer = new IntersectionObserver(([entry]) => {
2041
+ setIsIntersecting(entry.isIntersecting);
2042
+ }, options);
2043
+ observer.observe(el);
2044
+ return () => observer.disconnect();
2045
+ }, []);
2046
+ return [ref, isIntersecting];
2047
+ }
2048
+ function useLocalStorage(key, initialValue) {
2049
+ const [storedValue, setStoredValue] = React25.useState(() => {
2050
+ if (typeof window === "undefined") return initialValue;
2051
+ try {
2052
+ const item = window.localStorage.getItem(key);
2053
+ return item ? JSON.parse(item) : initialValue;
2054
+ } catch {
2055
+ return initialValue;
2056
+ }
2057
+ });
2058
+ const setValue = React25.useCallback(
2059
+ (value) => {
2060
+ try {
2061
+ setStoredValue(value);
2062
+ if (typeof window !== "undefined") {
2063
+ window.localStorage.setItem(key, JSON.stringify(value));
2064
+ }
2065
+ } catch {
2066
+ }
2067
+ },
2068
+ [key]
2069
+ );
2070
+ return [storedValue, setValue];
2071
+ }
2072
+ function useMediaQuery(query) {
2073
+ const [matches, setMatches] = React25.useState(() => {
2074
+ if (typeof window === "undefined") return false;
2075
+ return window.matchMedia(query).matches;
2076
+ });
2077
+ React25.useEffect(() => {
2078
+ if (typeof window === "undefined") return;
2079
+ const mql = window.matchMedia(query);
2080
+ setMatches(mql.matches);
2081
+ const handler = (e) => setMatches(e.matches);
2082
+ mql.addEventListener("change", handler);
2083
+ return () => mql.removeEventListener("change", handler);
2084
+ }, [query]);
2085
+ return matches;
2086
+ }
2087
+ function usePagination(total, pageSize) {
2088
+ const [page, setPage] = React25.useState(1);
2089
+ const totalPages = Math.max(1, Math.ceil(total / pageSize));
2090
+ const offset = (page - 1) * pageSize;
2091
+ const goTo = React25.useCallback(
2092
+ (p) => setPage(Math.min(Math.max(1, p), totalPages)),
2093
+ [totalPages]
2094
+ );
2095
+ const next = React25.useCallback(() => goTo(page + 1), [page, goTo]);
2096
+ const prev = React25.useCallback(() => goTo(page - 1), [page, goTo]);
2097
+ return { page, pageSize, totalPages, offset, hasPrev: page > 1, hasNext: page < totalPages, goTo, next, prev };
2098
+ }
2099
+
2100
+ export { AppShell, AuthSection, Badge, Button, Card, Checkbox, ConfirmDialog, ContactSection, ContextMenu, CountUp, CtaSection, DevBanner, Dock, EmptyState, ErrorPage, FadeIn, FaqSection, FeatureCard, FeaturesSection, Footer, FullPageSpinner, GlassCard, HeroSection, ImageCard, Input, LogoStrip, Navbar, NewsletterSection, OlwibaUIProvider, Overlay, PageHeader, PageTransition, PricingCard, PricingSection, RegisterHotkeys, RootErrorFallback, SectionTitle, Spotlight, StaggerChildren, StatCard, StatsSection, Suspensed, Switch, TeamSection, TestimonialCard, TestimonialsSection, Textarea, ThemeColorUpdater, ThemeSwitchMinimal, Underlay, UpgradePrompt, VersionBanner, cn, useConfirm, useControlledOpen, useCopyToClipboard, useDebounce, useIntersectionObserver, useLocalStorage, useMediaQuery, useMounted, useOlwibaUI, usePagination, useScrolledPast, useUIMode };
2101
+ //# sourceMappingURL=index.js.map
2102
+ //# sourceMappingURL=index.js.map