@olwiba/ui 0.1.4 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +246 -8
- package/dist/index.js +1126 -197
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/app/AuthSection.tsx +23 -1
- package/src/blog/ChangelogCard.tsx +73 -15
- package/src/components/BrandColorSwitchMinimal.tsx +172 -0
- package/src/components/FlowBracket.tsx +166 -0
- package/src/components/FlowConnector.tsx +135 -0
- package/src/components/PricingCard.tsx +7 -3
- package/src/components/ThemeSwitchMinimal.tsx +7 -7
- package/src/index.ts +16 -2
- package/src/marketing/ComparisonSection.tsx +109 -0
- package/src/marketing/ContactSection.tsx +74 -33
- package/src/marketing/CtaCardSection.tsx +95 -0
- package/src/marketing/FeatureMarqueeSection.tsx +120 -0
- package/src/marketing/Footer.tsx +2 -6
- package/src/marketing/GroupedFeaturesSection.tsx +71 -0
- package/src/marketing/Navbar.tsx +2 -10
- package/src/marketing/NewsletterSection.tsx +7 -6
- package/src/marketing/PricingSection.tsx +66 -39
- package/src/marketing/QualificationSection.tsx +86 -0
- package/src/marketing/StepsSection.tsx +97 -0
- package/src/marketing/TeamSection.tsx +50 -47
- package/src/marketing/TechStackSection.tsx +83 -0
- package/src/motion/AnimatedPill.tsx +71 -0
- package/src/motion/CountdownTimer.tsx +81 -0
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { cn } from './chunk-AMWLSHD6.js';
|
|
2
2
|
export { MdxContent, cn } from './chunk-AMWLSHD6.js';
|
|
3
|
-
import * as
|
|
4
|
-
import {
|
|
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, useUIVariant, 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';
|
|
3
|
+
import * as React29 from 'react';
|
|
4
|
+
import { useRef, useEffect, useState } from 'react';
|
|
5
|
+
import { Button as Button$1, Card as Card$1, Input as Input$1, Textarea as Textarea$1, Checkbox as Checkbox$1, Switch as Switch$1, useIsMobile, UIVariantProvider, Badge as Badge$1, cn as cn$1, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Avatar, AvatarImage, AvatarFallback, useUIVariant, 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, Popover, PopoverTrigger, PopoverContent, 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
6
|
export { CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@olwiba/cn';
|
|
7
7
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
-
import { Compass, ArrowLeft, X, ArrowRight, ChevronLeft, ChevronRight, Sparkles, Check, Minus, Quote, Star, Twitter, Github, Linkedin, Mail,
|
|
8
|
+
import { Compass, ArrowLeft, X, ArrowRight, ChevronLeft, ChevronRight, Sparkles, Rocket, Check, Minus, Quote, Star, Twitter, Github, Linkedin, Mail, MapPin, MessageSquare, Send, Menu, Search, TrendingUp, TrendingDown, Sun, Moon, Palette, AlertTriangle, Loader2, Layers, LayoutGrid, ShieldCheck, Building2, MoreVerticalIcon, CreditCardIcon, BellIcon, LogOutIcon } from 'lucide-react';
|
|
9
9
|
|
|
10
|
-
var OlwibaUIContext =
|
|
10
|
+
var OlwibaUIContext = React29.createContext({
|
|
11
11
|
isMobile: false,
|
|
12
12
|
mode: "default",
|
|
13
13
|
setMode: () => {
|
|
@@ -16,17 +16,17 @@ var OlwibaUIContext = React26.createContext({
|
|
|
16
16
|
function OlwibaUIProvider({ children, isMobile: isMobileProp, mode: initialMode = "default" }) {
|
|
17
17
|
const detectedMobile = useIsMobile();
|
|
18
18
|
const isMobile = isMobileProp ?? detectedMobile;
|
|
19
|
-
const [mode, setMode] =
|
|
19
|
+
const [mode, setMode] = React29.useState(initialMode);
|
|
20
20
|
const variant = mode !== "default" ? mode : void 0;
|
|
21
21
|
return /* @__PURE__ */ jsx(OlwibaUIContext.Provider, { value: { isMobile, mode, setMode }, children: /* @__PURE__ */ jsx(UIVariantProvider, { mode: variant, children }) });
|
|
22
22
|
}
|
|
23
23
|
function useOlwibaUI() {
|
|
24
|
-
return
|
|
24
|
+
return React29.useContext(OlwibaUIContext);
|
|
25
25
|
}
|
|
26
26
|
function useUIMode() {
|
|
27
|
-
return
|
|
27
|
+
return React29.useContext(OlwibaUIContext).mode;
|
|
28
28
|
}
|
|
29
|
-
var Button =
|
|
29
|
+
var Button = React29.forwardRef(
|
|
30
30
|
({ mode, ...props }, ref) => {
|
|
31
31
|
const ctxMode = useUIMode();
|
|
32
32
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
@@ -34,7 +34,7 @@ var Button = React26.forwardRef(
|
|
|
34
34
|
}
|
|
35
35
|
);
|
|
36
36
|
Button.displayName = "Button";
|
|
37
|
-
var Card =
|
|
37
|
+
var Card = React29.forwardRef(
|
|
38
38
|
({ mode, ...props }, ref) => {
|
|
39
39
|
const ctxMode = useUIMode();
|
|
40
40
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
@@ -45,7 +45,7 @@ Card.displayName = "Card";
|
|
|
45
45
|
function Badge(props) {
|
|
46
46
|
return /* @__PURE__ */ jsx(Badge$1, { ...props });
|
|
47
47
|
}
|
|
48
|
-
var Input =
|
|
48
|
+
var Input = React29.forwardRef(
|
|
49
49
|
({ mode, ...props }, ref) => {
|
|
50
50
|
const ctxMode = useUIMode();
|
|
51
51
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
@@ -53,7 +53,7 @@ var Input = React26.forwardRef(
|
|
|
53
53
|
}
|
|
54
54
|
);
|
|
55
55
|
Input.displayName = "Input";
|
|
56
|
-
var Textarea =
|
|
56
|
+
var Textarea = React29.forwardRef(
|
|
57
57
|
({ mode, ...props }, ref) => {
|
|
58
58
|
const ctxMode = useUIMode();
|
|
59
59
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
@@ -61,13 +61,13 @@ var Textarea = React26.forwardRef(
|
|
|
61
61
|
}
|
|
62
62
|
);
|
|
63
63
|
Textarea.displayName = "Textarea";
|
|
64
|
-
var Checkbox =
|
|
64
|
+
var Checkbox = React29.forwardRef(({ mode, ...props }, ref) => {
|
|
65
65
|
const ctxMode = useUIMode();
|
|
66
66
|
const resolvedMode = mode ?? (ctxMode !== "default" ? ctxMode : void 0);
|
|
67
67
|
return /* @__PURE__ */ jsx(Checkbox$1, { mode: resolvedMode, ...props, ref });
|
|
68
68
|
});
|
|
69
69
|
Checkbox.displayName = "Checkbox";
|
|
70
|
-
var Switch =
|
|
70
|
+
var Switch = React29.forwardRef(({ mode: _mode, ...props }, ref) => {
|
|
71
71
|
return /* @__PURE__ */ jsx(Switch$1, { ...props, ref });
|
|
72
72
|
});
|
|
73
73
|
Switch.displayName = "Switch";
|
|
@@ -490,10 +490,15 @@ function DefaultForm({
|
|
|
490
490
|
error,
|
|
491
491
|
loading,
|
|
492
492
|
renderLink = defaultRenderLink2,
|
|
493
|
-
footer
|
|
493
|
+
footer,
|
|
494
|
+
defaultEmail,
|
|
495
|
+
defaultPassword
|
|
494
496
|
}) {
|
|
495
497
|
const isSignUp = mode === "signup";
|
|
498
|
+
const hasPrefill = !!(defaultEmail || defaultPassword);
|
|
499
|
+
const prefillStyle = (active) => active ? { animation: "auth-prefill 1.6s ease-out 0.35s 1 both" } : void 0;
|
|
496
500
|
return /* @__PURE__ */ jsxs(Card, { className: "w-full", children: [
|
|
501
|
+
hasPrefill && /* @__PURE__ */ jsx("style", { children: `@keyframes auth-prefill{0%{box-shadow:0 0 0 0 hsl(var(--primary)/0)}40%{box-shadow:0 0 0 3px hsl(var(--primary)/0.4)}100%{box-shadow:0 0 0 0 hsl(var(--primary)/0)}}` }),
|
|
497
502
|
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
498
503
|
brand && /* @__PURE__ */ jsx("div", { className: "mb-2", children: brand }),
|
|
499
504
|
/* @__PURE__ */ jsx(CardTitle, { children: isSignUp ? "Create an account" : "Sign in" }),
|
|
@@ -507,7 +512,18 @@ function DefaultForm({
|
|
|
507
512
|
] }),
|
|
508
513
|
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
509
514
|
/* @__PURE__ */ jsx(Label, { htmlFor: "auth-email", children: "Email address" }),
|
|
510
|
-
/* @__PURE__ */ jsx(
|
|
515
|
+
/* @__PURE__ */ jsx(
|
|
516
|
+
Input,
|
|
517
|
+
{
|
|
518
|
+
id: "auth-email",
|
|
519
|
+
name: "email",
|
|
520
|
+
type: "email",
|
|
521
|
+
placeholder: "name@company.com",
|
|
522
|
+
autoComplete: "email",
|
|
523
|
+
defaultValue: defaultEmail,
|
|
524
|
+
style: prefillStyle(!!defaultEmail)
|
|
525
|
+
}
|
|
526
|
+
)
|
|
511
527
|
] }),
|
|
512
528
|
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
513
529
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
@@ -525,7 +541,9 @@ function DefaultForm({
|
|
|
525
541
|
name: "password",
|
|
526
542
|
type: "password",
|
|
527
543
|
placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
528
|
-
autoComplete: isSignUp ? "new-password" : "current-password"
|
|
544
|
+
autoComplete: isSignUp ? "new-password" : "current-password",
|
|
545
|
+
defaultValue: defaultPassword,
|
|
546
|
+
style: prefillStyle(!!defaultPassword)
|
|
529
547
|
}
|
|
530
548
|
)
|
|
531
549
|
] }),
|
|
@@ -757,9 +775,9 @@ function FadeIn({
|
|
|
757
775
|
style,
|
|
758
776
|
...props
|
|
759
777
|
}) {
|
|
760
|
-
const ref =
|
|
761
|
-
const [visible, setVisible] =
|
|
762
|
-
|
|
778
|
+
const ref = React29.useRef(null);
|
|
779
|
+
const [visible, setVisible] = React29.useState(false);
|
|
780
|
+
React29.useEffect(() => {
|
|
763
781
|
const el = ref.current;
|
|
764
782
|
if (!el) return;
|
|
765
783
|
const observer = new IntersectionObserver(
|
|
@@ -956,9 +974,9 @@ function StaggerChildren({
|
|
|
956
974
|
className,
|
|
957
975
|
...props
|
|
958
976
|
}) {
|
|
959
|
-
const ref =
|
|
960
|
-
const [visible, setVisible] =
|
|
961
|
-
|
|
977
|
+
const ref = React29.useRef(null);
|
|
978
|
+
const [visible, setVisible] = React29.useState(false);
|
|
979
|
+
React29.useEffect(() => {
|
|
962
980
|
const el = ref.current;
|
|
963
981
|
if (!el) return;
|
|
964
982
|
const observer = new IntersectionObserver(
|
|
@@ -976,7 +994,7 @@ function StaggerChildren({
|
|
|
976
994
|
return () => observer.disconnect();
|
|
977
995
|
}, [once]);
|
|
978
996
|
const [tx, ty] = translateMap2[direction];
|
|
979
|
-
return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children:
|
|
997
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React29.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
|
|
980
998
|
"div",
|
|
981
999
|
{
|
|
982
1000
|
className: "h-full",
|
|
@@ -1017,6 +1035,133 @@ function FeaturesSection({
|
|
|
1017
1035
|
)) })
|
|
1018
1036
|
] }) }) });
|
|
1019
1037
|
}
|
|
1038
|
+
function GroupedFeaturesSection({
|
|
1039
|
+
badge = "Features",
|
|
1040
|
+
title = "Everything you need to ship",
|
|
1041
|
+
description,
|
|
1042
|
+
groups
|
|
1043
|
+
}) {
|
|
1044
|
+
const mode = useUIVariant();
|
|
1045
|
+
const sectionClasses = cn$1(
|
|
1046
|
+
"overflow-hidden bg-card",
|
|
1047
|
+
mode === "smooth" && "rounded-3xl border",
|
|
1048
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1049
|
+
!mode && "rounded-2xl border"
|
|
1050
|
+
);
|
|
1051
|
+
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl", children: [
|
|
1052
|
+
/* @__PURE__ */ jsx(SectionTitle, { title, description, badge }),
|
|
1053
|
+
/* @__PURE__ */ jsx("div", { className: "mt-14 space-y-14", children: groups.map((group, i) => /* @__PURE__ */ jsxs("div", { children: [
|
|
1054
|
+
/* @__PURE__ */ jsx(FadeIn, { direction: "up", delay: i * 60, children: /* @__PURE__ */ jsxs("div", { className: "mb-6 flex items-center gap-3", children: [
|
|
1055
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold tracking-wide text-muted-foreground uppercase", children: group.label }),
|
|
1056
|
+
/* @__PURE__ */ jsx("div", { className: "h-px flex-1 bg-border" })
|
|
1057
|
+
] }) }),
|
|
1058
|
+
/* @__PURE__ */ jsx(StaggerChildren, { className: "grid gap-6 sm:grid-cols-2 lg:grid-cols-3", children: group.features.map((feature) => /* @__PURE__ */ jsx(
|
|
1059
|
+
FeatureCard,
|
|
1060
|
+
{
|
|
1061
|
+
icon: feature.icon,
|
|
1062
|
+
title: feature.title,
|
|
1063
|
+
description: feature.description,
|
|
1064
|
+
href: feature.href
|
|
1065
|
+
},
|
|
1066
|
+
feature.title
|
|
1067
|
+
)) })
|
|
1068
|
+
] }, group.label)) })
|
|
1069
|
+
] }) }) });
|
|
1070
|
+
}
|
|
1071
|
+
function StepsSection({
|
|
1072
|
+
badge = "How it works",
|
|
1073
|
+
title = "From zero to shipped",
|
|
1074
|
+
description,
|
|
1075
|
+
steps
|
|
1076
|
+
}) {
|
|
1077
|
+
const mode = useUIVariant();
|
|
1078
|
+
const sectionClasses = cn$1(
|
|
1079
|
+
"overflow-hidden bg-card",
|
|
1080
|
+
mode === "smooth" && "rounded-3xl border",
|
|
1081
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1082
|
+
!mode && "rounded-2xl border"
|
|
1083
|
+
);
|
|
1084
|
+
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl", children: [
|
|
1085
|
+
/* @__PURE__ */ jsx(SectionTitle, { badge, title, description }),
|
|
1086
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-12", children: [
|
|
1087
|
+
/* @__PURE__ */ jsx("div", { className: "hidden sm:grid", style: { gridTemplateColumns: `repeat(${steps.length}, 1fr)` }, children: steps.map((step, i) => /* @__PURE__ */ jsx(FadeIn, { direction: "up", delay: i * 80, children: /* @__PURE__ */ jsxs("div", { className: "relative flex flex-col items-center text-center px-4", children: [
|
|
1088
|
+
i < steps.length - 1 && /* @__PURE__ */ jsx(
|
|
1089
|
+
"div",
|
|
1090
|
+
{
|
|
1091
|
+
"aria-hidden": "true",
|
|
1092
|
+
className: "absolute top-6 left-1/2 w-full border-t border-dashed border-border"
|
|
1093
|
+
}
|
|
1094
|
+
),
|
|
1095
|
+
/* @__PURE__ */ jsx("div", { className: "relative z-10 mb-3 flex h-12 w-12 items-center justify-center rounded-full bg-muted text-2xl", children: step.emoji ?? /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-primary", children: i + 1 }) }),
|
|
1096
|
+
/* @__PURE__ */ jsx("h3", { className: "font-semibold text-foreground", children: step.title }),
|
|
1097
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm leading-relaxed text-muted-foreground", children: step.description })
|
|
1098
|
+
] }) }, step.title)) }),
|
|
1099
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-0 sm:hidden", children: steps.map((step, i) => /* @__PURE__ */ jsx(FadeIn, { direction: "up", delay: i * 80, children: /* @__PURE__ */ jsxs("div", { className: "relative flex gap-4 pb-8 last:pb-0", children: [
|
|
1100
|
+
i < steps.length - 1 && /* @__PURE__ */ jsx(
|
|
1101
|
+
"div",
|
|
1102
|
+
{
|
|
1103
|
+
"aria-hidden": "true",
|
|
1104
|
+
className: "absolute left-[23px] top-14 bottom-0 w-px border-l border-dashed border-border"
|
|
1105
|
+
}
|
|
1106
|
+
),
|
|
1107
|
+
/* @__PURE__ */ jsx("div", { className: "relative z-10 flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-muted text-2xl", children: step.emoji ?? /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold text-primary", children: i + 1 }) }),
|
|
1108
|
+
/* @__PURE__ */ jsxs("div", { className: "pt-3", children: [
|
|
1109
|
+
/* @__PURE__ */ jsx("h3", { className: "font-semibold text-foreground", children: step.title }),
|
|
1110
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm leading-relaxed text-muted-foreground", children: step.description })
|
|
1111
|
+
] })
|
|
1112
|
+
] }) }, step.title)) })
|
|
1113
|
+
] })
|
|
1114
|
+
] }) }) });
|
|
1115
|
+
}
|
|
1116
|
+
function TechStackSection({
|
|
1117
|
+
badge = "Built on",
|
|
1118
|
+
title = "The stack",
|
|
1119
|
+
description,
|
|
1120
|
+
items
|
|
1121
|
+
}) {
|
|
1122
|
+
const mode = useUIVariant();
|
|
1123
|
+
const sectionClasses = cn$1(
|
|
1124
|
+
"overflow-hidden bg-card",
|
|
1125
|
+
mode === "smooth" && "rounded-3xl border",
|
|
1126
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1127
|
+
!mode && "rounded-2xl border"
|
|
1128
|
+
);
|
|
1129
|
+
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl", children: [
|
|
1130
|
+
/* @__PURE__ */ jsx(SectionTitle, { badge, title, description }),
|
|
1131
|
+
/* @__PURE__ */ jsx(StaggerChildren, { className: "mt-12 grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: items.map((item) => {
|
|
1132
|
+
const Icon = item.icon;
|
|
1133
|
+
const card = /* @__PURE__ */ jsxs(
|
|
1134
|
+
"div",
|
|
1135
|
+
{
|
|
1136
|
+
className: cn$1(
|
|
1137
|
+
"group flex flex-col gap-3 border bg-background p-5 transition-all duration-200",
|
|
1138
|
+
mode === "smooth" ? "rounded-2xl hover:-translate-y-0.5 hover:shadow-md" : "rounded-xl hover:-translate-y-0.5 hover:shadow-md"
|
|
1139
|
+
),
|
|
1140
|
+
children: [
|
|
1141
|
+
/* @__PURE__ */ jsx(
|
|
1142
|
+
"div",
|
|
1143
|
+
{
|
|
1144
|
+
className: cn$1(
|
|
1145
|
+
"flex h-9 w-9 items-center justify-center bg-muted text-muted-foreground transition-colors group-hover:bg-primary/10 group-hover:text-primary",
|
|
1146
|
+
mode === "smooth" ? "rounded-xl" : "rounded-lg"
|
|
1147
|
+
),
|
|
1148
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "size-4" })
|
|
1149
|
+
}
|
|
1150
|
+
),
|
|
1151
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1152
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold leading-tight", children: item.name }),
|
|
1153
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: item.description })
|
|
1154
|
+
] })
|
|
1155
|
+
]
|
|
1156
|
+
}
|
|
1157
|
+
);
|
|
1158
|
+
if (item.href) {
|
|
1159
|
+
return /* @__PURE__ */ jsx("a", { href: item.href, className: "block", children: card }, item.name);
|
|
1160
|
+
}
|
|
1161
|
+
return /* @__PURE__ */ jsx("div", { children: card }, item.name);
|
|
1162
|
+
}) })
|
|
1163
|
+
] }) }) });
|
|
1164
|
+
}
|
|
1020
1165
|
function CarouselSection({
|
|
1021
1166
|
title = "Explore the platform",
|
|
1022
1167
|
description,
|
|
@@ -1024,16 +1169,16 @@ function CarouselSection({
|
|
|
1024
1169
|
features
|
|
1025
1170
|
}) {
|
|
1026
1171
|
const mode = useUIVariant();
|
|
1027
|
-
const trackRef =
|
|
1028
|
-
const [canPrev, setCanPrev] =
|
|
1029
|
-
const [canNext, setCanNext] =
|
|
1030
|
-
const updateScrollState =
|
|
1172
|
+
const trackRef = React29.useRef(null);
|
|
1173
|
+
const [canPrev, setCanPrev] = React29.useState(false);
|
|
1174
|
+
const [canNext, setCanNext] = React29.useState(true);
|
|
1175
|
+
const updateScrollState = React29.useCallback(() => {
|
|
1031
1176
|
const track = trackRef.current;
|
|
1032
1177
|
if (!track) return;
|
|
1033
1178
|
setCanPrev(track.scrollLeft > 8);
|
|
1034
1179
|
setCanNext(track.scrollLeft < track.scrollWidth - track.clientWidth - 8);
|
|
1035
1180
|
}, []);
|
|
1036
|
-
|
|
1181
|
+
React29.useEffect(() => {
|
|
1037
1182
|
const track = trackRef.current;
|
|
1038
1183
|
if (!track) return;
|
|
1039
1184
|
updateScrollState();
|
|
@@ -1117,6 +1262,83 @@ function CarouselSection({
|
|
|
1117
1262
|
] })
|
|
1118
1263
|
] }) }) });
|
|
1119
1264
|
}
|
|
1265
|
+
var speedDuration = {
|
|
1266
|
+
slow: "280s",
|
|
1267
|
+
normal: "180s",
|
|
1268
|
+
fast: "100s"
|
|
1269
|
+
};
|
|
1270
|
+
function FeatureMarqueeSection({
|
|
1271
|
+
badge,
|
|
1272
|
+
title,
|
|
1273
|
+
description,
|
|
1274
|
+
rows,
|
|
1275
|
+
speed = "normal",
|
|
1276
|
+
pauseOnHover = true
|
|
1277
|
+
}) {
|
|
1278
|
+
const mode = useUIVariant();
|
|
1279
|
+
const duration = speedDuration[speed];
|
|
1280
|
+
const sectionClasses = cn$1(
|
|
1281
|
+
"overflow-hidden bg-card",
|
|
1282
|
+
mode === "smooth" && "rounded-3xl border",
|
|
1283
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1284
|
+
!mode && "rounded-2xl border"
|
|
1285
|
+
);
|
|
1286
|
+
return /* @__PURE__ */ jsxs("section", { className: sectionClasses, children: [
|
|
1287
|
+
/* @__PURE__ */ jsxs("div", { className: "py-14 sm:py-20", children: [
|
|
1288
|
+
(title || badge || description) && /* @__PURE__ */ jsx(FadeIn, { direction: "up", children: /* @__PURE__ */ jsx("div", { className: "mx-auto mb-10 max-w-4xl px-6 sm:px-10", children: /* @__PURE__ */ jsx(SectionTitle, { title: title ?? "", description, badge }) }) }),
|
|
1289
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-3", children: rows.map((row, i) => {
|
|
1290
|
+
const direction = row.direction ?? (i % 2 === 0 ? "left" : "right");
|
|
1291
|
+
const reversed = direction === "right";
|
|
1292
|
+
const source = reversed ? [...row.items].reverse() : row.items;
|
|
1293
|
+
const set = Array.from({ length: 4 }, () => source).flat();
|
|
1294
|
+
const items = [...set, ...set];
|
|
1295
|
+
return /* @__PURE__ */ jsx(
|
|
1296
|
+
"div",
|
|
1297
|
+
{
|
|
1298
|
+
className: "group relative overflow-hidden",
|
|
1299
|
+
style: {
|
|
1300
|
+
maskImage: "linear-gradient(to right, transparent, black 8%, black 92%, transparent)",
|
|
1301
|
+
WebkitMaskImage: "linear-gradient(to right, transparent, black 8%, black 92%, transparent)"
|
|
1302
|
+
},
|
|
1303
|
+
children: /* @__PURE__ */ jsx(
|
|
1304
|
+
"div",
|
|
1305
|
+
{
|
|
1306
|
+
className: cn$1(
|
|
1307
|
+
"flex w-max gap-3 py-0.5",
|
|
1308
|
+
pauseOnHover && "group-hover:[animation-play-state:paused]"
|
|
1309
|
+
),
|
|
1310
|
+
style: {
|
|
1311
|
+
animation: `feature-marquee-left ${duration} linear infinite`
|
|
1312
|
+
},
|
|
1313
|
+
children: items.map((item, j) => {
|
|
1314
|
+
const Icon = item.icon;
|
|
1315
|
+
return /* @__PURE__ */ jsxs(
|
|
1316
|
+
"div",
|
|
1317
|
+
{
|
|
1318
|
+
className: "flex shrink-0 items-center gap-2 rounded-full border bg-background px-4 py-2 text-sm shadow-sm",
|
|
1319
|
+
children: [
|
|
1320
|
+
/* @__PURE__ */ jsx(Icon, { className: "size-3.5 shrink-0 text-primary" }),
|
|
1321
|
+
/* @__PURE__ */ jsx("span", { className: "whitespace-nowrap text-foreground", children: item.title })
|
|
1322
|
+
]
|
|
1323
|
+
},
|
|
1324
|
+
`${item.title}-${j}`
|
|
1325
|
+
);
|
|
1326
|
+
})
|
|
1327
|
+
}
|
|
1328
|
+
)
|
|
1329
|
+
},
|
|
1330
|
+
i
|
|
1331
|
+
);
|
|
1332
|
+
}) })
|
|
1333
|
+
] }),
|
|
1334
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
1335
|
+
@keyframes feature-marquee-left {
|
|
1336
|
+
from { transform: translateX(0); }
|
|
1337
|
+
to { transform: translateX(-50%); }
|
|
1338
|
+
}
|
|
1339
|
+
` })
|
|
1340
|
+
] });
|
|
1341
|
+
}
|
|
1120
1342
|
var defaultRenderLink5 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
1121
1343
|
function CtaSection({
|
|
1122
1344
|
heading,
|
|
@@ -1156,6 +1378,71 @@ function CtaSection({
|
|
|
1156
1378
|
] }) })
|
|
1157
1379
|
] }) });
|
|
1158
1380
|
}
|
|
1381
|
+
var defaultRenderLink6 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
1382
|
+
function CtaCardSection({
|
|
1383
|
+
heading,
|
|
1384
|
+
description,
|
|
1385
|
+
primaryCta,
|
|
1386
|
+
footnote,
|
|
1387
|
+
icon,
|
|
1388
|
+
renderLink = defaultRenderLink6
|
|
1389
|
+
}) {
|
|
1390
|
+
const ref = React29.useRef(null);
|
|
1391
|
+
const [visible, setVisible] = React29.useState(false);
|
|
1392
|
+
React29.useEffect(() => {
|
|
1393
|
+
const el = ref.current;
|
|
1394
|
+
if (!el) return;
|
|
1395
|
+
const observer = new IntersectionObserver(
|
|
1396
|
+
([entry]) => {
|
|
1397
|
+
if (entry.isIntersecting) {
|
|
1398
|
+
setVisible(true);
|
|
1399
|
+
observer.disconnect();
|
|
1400
|
+
}
|
|
1401
|
+
},
|
|
1402
|
+
{ threshold: 0.15 }
|
|
1403
|
+
);
|
|
1404
|
+
observer.observe(el);
|
|
1405
|
+
return () => observer.disconnect();
|
|
1406
|
+
}, []);
|
|
1407
|
+
return /* @__PURE__ */ jsxs(
|
|
1408
|
+
"section",
|
|
1409
|
+
{
|
|
1410
|
+
ref,
|
|
1411
|
+
className: cn$1(
|
|
1412
|
+
"relative overflow-hidden rounded-3xl border border-gray-200 shadow-sm dark:border-border",
|
|
1413
|
+
"bg-[#E0DFDB] dark:bg-card",
|
|
1414
|
+
"transition-[opacity,transform] duration-700 ease-out",
|
|
1415
|
+
visible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-6"
|
|
1416
|
+
),
|
|
1417
|
+
children: [
|
|
1418
|
+
/* @__PURE__ */ jsx(
|
|
1419
|
+
"div",
|
|
1420
|
+
{
|
|
1421
|
+
className: "pointer-events-none absolute inset-0 flex items-center justify-center",
|
|
1422
|
+
style: {
|
|
1423
|
+
opacity: visible ? 0.12 : 0,
|
|
1424
|
+
transform: visible ? "scale(1) rotate(0deg)" : "scale(0.9) rotate(-5deg)",
|
|
1425
|
+
transition: "opacity 700ms ease 200ms, transform 700ms ease 200ms"
|
|
1426
|
+
},
|
|
1427
|
+
children: icon ?? /* @__PURE__ */ jsx(Rocket, { className: "size-72 text-foreground dark:text-foreground", strokeWidth: 0.75 })
|
|
1428
|
+
}
|
|
1429
|
+
),
|
|
1430
|
+
/* @__PURE__ */ jsxs("div", { className: "relative z-10 px-6 py-20 text-center sm:px-10 sm:py-28", children: [
|
|
1431
|
+
/* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: heading }),
|
|
1432
|
+
description && /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-lg text-pretty text-muted-foreground", children: description }),
|
|
1433
|
+
/* @__PURE__ */ jsx("div", { className: "mt-8", children: renderLink({
|
|
1434
|
+
href: primaryCta.href,
|
|
1435
|
+
children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2 rounded-full bg-foreground px-6 py-3 text-sm font-medium text-background transition-opacity hover:opacity-80", children: [
|
|
1436
|
+
primaryCta.label,
|
|
1437
|
+
/* @__PURE__ */ jsx(ArrowRight, { className: "size-4" })
|
|
1438
|
+
] })
|
|
1439
|
+
}) }),
|
|
1440
|
+
footnote && /* @__PURE__ */ jsx("p", { className: "mt-5 text-sm text-muted-foreground", children: footnote })
|
|
1441
|
+
] })
|
|
1442
|
+
]
|
|
1443
|
+
}
|
|
1444
|
+
);
|
|
1445
|
+
}
|
|
1159
1446
|
function PricingCard({
|
|
1160
1447
|
name,
|
|
1161
1448
|
price,
|
|
@@ -1164,6 +1451,7 @@ function PricingCard({
|
|
|
1164
1451
|
features,
|
|
1165
1452
|
cta,
|
|
1166
1453
|
highlighted = false,
|
|
1454
|
+
disabled = false,
|
|
1167
1455
|
badge,
|
|
1168
1456
|
onSelect,
|
|
1169
1457
|
className,
|
|
@@ -1174,14 +1462,15 @@ function PricingCard({
|
|
|
1174
1462
|
"div",
|
|
1175
1463
|
{
|
|
1176
1464
|
className: cn$1(
|
|
1177
|
-
"relative flex flex-col border p-6",
|
|
1465
|
+
"relative flex flex-col border p-6 transition-opacity",
|
|
1178
1466
|
mode === "playful" ? "rounded-2xl rotate-[0.3deg]" : mode === "smooth" ? "rounded-3xl" : "rounded-2xl",
|
|
1179
1467
|
highlighted ? "border-primary bg-primary/5 shadow-sm" : "bg-card",
|
|
1468
|
+
disabled && "pointer-events-none opacity-40 select-none",
|
|
1180
1469
|
mode !== "playful" && className
|
|
1181
1470
|
),
|
|
1182
1471
|
...mode !== "playful" ? props : {},
|
|
1183
1472
|
children: [
|
|
1184
|
-
badge && /* @__PURE__ */ jsx("div", { className: "absolute -top-3 left-1/2 -translate-x-1/2", children: /* @__PURE__ */ jsx(Badge$1, { children: badge }) }),
|
|
1473
|
+
badge && /* @__PURE__ */ jsx("div", { className: "absolute -top-3 left-1/2 -translate-x-1/2", children: typeof badge === "string" ? /* @__PURE__ */ jsx(Badge$1, { children: badge }) : badge }),
|
|
1185
1474
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
1186
1475
|
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-muted-foreground", children: name }),
|
|
1187
1476
|
/* @__PURE__ */ jsxs("div", { className: "flex items-end gap-1", children: [
|
|
@@ -1196,6 +1485,7 @@ function PricingCard({
|
|
|
1196
1485
|
variant: highlighted ? "default" : "outline",
|
|
1197
1486
|
className: "mt-6 w-full",
|
|
1198
1487
|
onClick: onSelect,
|
|
1488
|
+
disabled,
|
|
1199
1489
|
children: cta
|
|
1200
1490
|
}
|
|
1201
1491
|
),
|
|
@@ -1227,7 +1517,59 @@ function PricingCard({
|
|
|
1227
1517
|
}
|
|
1228
1518
|
return cardInner;
|
|
1229
1519
|
}
|
|
1230
|
-
|
|
1520
|
+
function getTimeLeft(deadline) {
|
|
1521
|
+
const diff = new Date(deadline).getTime() - Date.now();
|
|
1522
|
+
if (diff <= 0) return null;
|
|
1523
|
+
return {
|
|
1524
|
+
days: Math.floor(diff / (1e3 * 60 * 60 * 24)),
|
|
1525
|
+
hours: Math.floor(diff / (1e3 * 60 * 60) % 24),
|
|
1526
|
+
minutes: Math.floor(diff / 1e3 / 60 % 60),
|
|
1527
|
+
seconds: Math.floor(diff / 1e3 % 60)
|
|
1528
|
+
};
|
|
1529
|
+
}
|
|
1530
|
+
function CountdownTimer({
|
|
1531
|
+
deadline,
|
|
1532
|
+
label = "Founding price closes in",
|
|
1533
|
+
className,
|
|
1534
|
+
compact = false
|
|
1535
|
+
}) {
|
|
1536
|
+
const [timeLeft, setTimeLeft] = React29.useState(() => getTimeLeft(deadline));
|
|
1537
|
+
React29.useEffect(() => {
|
|
1538
|
+
setTimeLeft(getTimeLeft(deadline));
|
|
1539
|
+
const id = setInterval(() => setTimeLeft(getTimeLeft(deadline)), 1e3);
|
|
1540
|
+
return () => clearInterval(id);
|
|
1541
|
+
}, [deadline]);
|
|
1542
|
+
if (!timeLeft) return null;
|
|
1543
|
+
if (compact) {
|
|
1544
|
+
return /* @__PURE__ */ jsxs("span", { className: cn$1("font-mono tabular-nums", className), children: [
|
|
1545
|
+
timeLeft.days,
|
|
1546
|
+
"d \xB7 ",
|
|
1547
|
+
String(timeLeft.hours).padStart(2, "0"),
|
|
1548
|
+
"h \xB7 ",
|
|
1549
|
+
String(timeLeft.minutes).padStart(2, "0"),
|
|
1550
|
+
"m \xB7 ",
|
|
1551
|
+
String(timeLeft.seconds).padStart(2, "0"),
|
|
1552
|
+
"s"
|
|
1553
|
+
] });
|
|
1554
|
+
}
|
|
1555
|
+
const units = [
|
|
1556
|
+
{ value: timeLeft.days, unit: "d" },
|
|
1557
|
+
{ value: timeLeft.hours, unit: "h" },
|
|
1558
|
+
{ value: timeLeft.minutes, unit: "m" },
|
|
1559
|
+
{ value: timeLeft.seconds, unit: "s" }
|
|
1560
|
+
];
|
|
1561
|
+
return /* @__PURE__ */ jsxs("div", { className: cn$1("flex items-center justify-center gap-2 text-sm", className), children: [
|
|
1562
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: label }),
|
|
1563
|
+
/* @__PURE__ */ jsx("span", { className: "flex items-center gap-1 font-mono font-semibold tabular-nums", children: units.map(({ value, unit }, i) => /* @__PURE__ */ jsxs(React29.Fragment, { children: [
|
|
1564
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1565
|
+
String(value).padStart(2, "0"),
|
|
1566
|
+
/* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: unit })
|
|
1567
|
+
] }),
|
|
1568
|
+
i < units.length - 1 && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/50", children: "\xB7" })
|
|
1569
|
+
] }, unit)) })
|
|
1570
|
+
] });
|
|
1571
|
+
}
|
|
1572
|
+
var defaultRenderLink7 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
1231
1573
|
function PricingSection({
|
|
1232
1574
|
title = "Simple, transparent pricing",
|
|
1233
1575
|
description = "Start for free. Scale as you grow. No hidden fees.",
|
|
@@ -1235,23 +1577,26 @@ function PricingSection({
|
|
|
1235
1577
|
plans,
|
|
1236
1578
|
saveBadge = "Save 34%",
|
|
1237
1579
|
isAuthenticated,
|
|
1238
|
-
renderLink =
|
|
1239
|
-
footnote
|
|
1580
|
+
renderLink = defaultRenderLink7,
|
|
1581
|
+
footnote,
|
|
1582
|
+
mode = "subscription",
|
|
1583
|
+
foundingDeadline
|
|
1240
1584
|
}) {
|
|
1241
|
-
const [annual, setAnnual] =
|
|
1242
|
-
const
|
|
1585
|
+
const [annual, setAnnual] = React29.useState(false);
|
|
1586
|
+
const isOneTime = mode === "one-time";
|
|
1587
|
+
const uiMode = useUIVariant();
|
|
1243
1588
|
const sectionClasses = cn$1(
|
|
1244
1589
|
"overflow-hidden bg-card",
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
!
|
|
1590
|
+
uiMode === "smooth" && "rounded-3xl border",
|
|
1591
|
+
uiMode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1592
|
+
!uiMode && "rounded-2xl border"
|
|
1248
1593
|
);
|
|
1249
1594
|
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-5xl", children: [
|
|
1250
1595
|
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
1251
|
-
badge && /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-4", children: badge }),
|
|
1596
|
+
badge && (typeof badge === "string" ? /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-4", children: badge }) : /* @__PURE__ */ jsx("div", { className: "mb-4", children: badge })),
|
|
1252
1597
|
/* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: title }),
|
|
1253
1598
|
description && /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-xl text-pretty text-muted-foreground", children: description }),
|
|
1254
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-6 inline-flex items-center gap-3 rounded-full border bg-muted p-1", children: [
|
|
1599
|
+
!isOneTime && /* @__PURE__ */ jsxs("div", { className: "mt-6 inline-flex items-center gap-3 rounded-full border bg-muted p-1", children: [
|
|
1255
1600
|
/* @__PURE__ */ jsx(
|
|
1256
1601
|
Button$1,
|
|
1257
1602
|
{
|
|
@@ -1284,18 +1629,22 @@ function PricingSection({
|
|
|
1284
1629
|
] })
|
|
1285
1630
|
] }),
|
|
1286
1631
|
/* @__PURE__ */ jsx(StaggerChildren, { className: "mt-10 grid gap-4 lg:grid-cols-3", children: plans.map((plan) => {
|
|
1287
|
-
const
|
|
1632
|
+
const rawPrice = isOneTime ? plan.monthly : annual ? plan.annual : plan.monthly;
|
|
1633
|
+
const price = plan.priceDisplay ?? `$${rawPrice}`;
|
|
1634
|
+
const period = plan.periodDisplay ?? (isOneTime ? "one-time" : rawPrice > 0 ? "/mo" : "");
|
|
1635
|
+
const badge2 = plan.highlighted && foundingDeadline ? /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded-full border bg-secondary px-2.5 py-0.5 text-xs font-semibold text-secondary-foreground", children: /* @__PURE__ */ jsx(CountdownTimer, { deadline: foundingDeadline, compact: true }) }) : plan.highlighted ? "Founding member" : void 0;
|
|
1288
1636
|
return /* @__PURE__ */ jsx(
|
|
1289
1637
|
PricingCard,
|
|
1290
1638
|
{
|
|
1291
1639
|
name: plan.name,
|
|
1292
|
-
price
|
|
1293
|
-
period
|
|
1640
|
+
price,
|
|
1641
|
+
period,
|
|
1294
1642
|
description: plan.description,
|
|
1295
1643
|
features: plan.features,
|
|
1296
1644
|
cta: plan.cta,
|
|
1297
1645
|
highlighted: plan.highlighted,
|
|
1298
|
-
|
|
1646
|
+
disabled: plan.disabled,
|
|
1647
|
+
badge: badge2
|
|
1299
1648
|
},
|
|
1300
1649
|
plan.name
|
|
1301
1650
|
);
|
|
@@ -1403,7 +1752,7 @@ function TestimonialsSection({
|
|
|
1403
1752
|
)) })
|
|
1404
1753
|
] }) }) });
|
|
1405
1754
|
}
|
|
1406
|
-
var
|
|
1755
|
+
var defaultTeam = [
|
|
1407
1756
|
{
|
|
1408
1757
|
name: "Olivia Reed",
|
|
1409
1758
|
role: "Co-Founder & CEO",
|
|
@@ -1427,40 +1776,21 @@ var team = [
|
|
|
1427
1776
|
avatar: "https://ui.shadcn.com/avatars/03.png",
|
|
1428
1777
|
initials: "PN",
|
|
1429
1778
|
social: { twitter: "#", github: null, linkedin: "#" }
|
|
1430
|
-
},
|
|
1431
|
-
{
|
|
1432
|
-
name: "Daniel Frost",
|
|
1433
|
-
role: "Senior Engineer",
|
|
1434
|
-
bio: "Accessibility and performance specialist. If it doesn't work with a keyboard, it's broken.",
|
|
1435
|
-
avatar: "https://ui.shadcn.com/avatars/04.png",
|
|
1436
|
-
initials: "DF",
|
|
1437
|
-
social: { twitter: null, github: "#", linkedin: "#" }
|
|
1438
|
-
},
|
|
1439
|
-
{
|
|
1440
|
-
name: "Aisha Okafor",
|
|
1441
|
-
role: "Developer Relations",
|
|
1442
|
-
bio: "Writes docs, builds examples, and makes sure every engineer can ship their first block in under an hour.",
|
|
1443
|
-
avatar: "https://ui.shadcn.com/avatars/05.png",
|
|
1444
|
-
initials: "AO",
|
|
1445
|
-
social: { twitter: "#", github: "#", linkedin: "#" }
|
|
1446
|
-
},
|
|
1447
|
-
{
|
|
1448
|
-
name: "Tom Halvorsen",
|
|
1449
|
-
role: "Growth",
|
|
1450
|
-
bio: "Turns happy users into loud advocates. Runs the community and keeps the changelog sharp.",
|
|
1451
|
-
avatar: "https://ui.shadcn.com/avatars/06.png",
|
|
1452
|
-
initials: "TH",
|
|
1453
|
-
social: { twitter: "#", github: null, linkedin: "#" }
|
|
1454
1779
|
}
|
|
1455
1780
|
];
|
|
1456
|
-
function TeamSection(
|
|
1781
|
+
function TeamSection({
|
|
1782
|
+
members = defaultTeam,
|
|
1783
|
+
badge = "Team",
|
|
1784
|
+
title = "The people behind Olwiba",
|
|
1785
|
+
description = "A small team with deep experience in design systems, open source, and developer tooling."
|
|
1786
|
+
}) {
|
|
1457
1787
|
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: [
|
|
1458
1788
|
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
1459
|
-
/* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-4", children:
|
|
1460
|
-
/* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children:
|
|
1461
|
-
/* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-xl text-pretty text-muted-foreground", children:
|
|
1789
|
+
/* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-4", children: badge }),
|
|
1790
|
+
/* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: title }),
|
|
1791
|
+
/* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-xl text-pretty text-muted-foreground", children: description })
|
|
1462
1792
|
] }),
|
|
1463
|
-
/* @__PURE__ */ jsx("div", { className: "mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3", children:
|
|
1793
|
+
/* @__PURE__ */ jsx("div", { className: "mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3", children: members.map((member) => /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border bg-muted/40 p-5", children: [
|
|
1464
1794
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-4", children: [
|
|
1465
1795
|
/* @__PURE__ */ jsxs(Avatar, { className: "size-12 rounded-xl", children: [
|
|
1466
1796
|
/* @__PURE__ */ jsx(AvatarImage, { src: member.avatar, alt: member.name }),
|
|
@@ -1472,7 +1802,7 @@ function TeamSection() {
|
|
|
1472
1802
|
] })
|
|
1473
1803
|
] }),
|
|
1474
1804
|
/* @__PURE__ */ jsx("p", { className: "mt-3 text-sm leading-relaxed text-muted-foreground", children: member.bio }),
|
|
1475
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center gap-2", children: [
|
|
1805
|
+
member.social && /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center gap-2", children: [
|
|
1476
1806
|
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" }) }),
|
|
1477
1807
|
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" }) }),
|
|
1478
1808
|
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" }) })
|
|
@@ -1512,10 +1842,10 @@ function CountUp({
|
|
|
1512
1842
|
className,
|
|
1513
1843
|
...props
|
|
1514
1844
|
}) {
|
|
1515
|
-
const ref =
|
|
1516
|
-
const [value, setValue] =
|
|
1517
|
-
const hasStarted =
|
|
1518
|
-
|
|
1845
|
+
const ref = React29.useRef(null);
|
|
1846
|
+
const [value, setValue] = React29.useState(from);
|
|
1847
|
+
const hasStarted = React29.useRef(false);
|
|
1848
|
+
React29.useEffect(() => {
|
|
1519
1849
|
const el = ref.current;
|
|
1520
1850
|
if (!el) return;
|
|
1521
1851
|
const observer = new IntersectionObserver(
|
|
@@ -1608,8 +1938,8 @@ function NewsletterSection({
|
|
|
1608
1938
|
successDescription = defaults.successDescription,
|
|
1609
1939
|
onSubscribe
|
|
1610
1940
|
} = {}) {
|
|
1611
|
-
const [email, setEmail] =
|
|
1612
|
-
const [submitted, setSubmitted] =
|
|
1941
|
+
const [email, setEmail] = React29.useState("");
|
|
1942
|
+
const [submitted, setSubmitted] = React29.useState(false);
|
|
1613
1943
|
async function handleSubmit(e) {
|
|
1614
1944
|
e.preventDefault();
|
|
1615
1945
|
if (!email) return;
|
|
@@ -1619,8 +1949,10 @@ function NewsletterSection({
|
|
|
1619
1949
|
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: [
|
|
1620
1950
|
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(ellipse_at_top_right,hsl(var(--primary)/0.1),transparent_60%)]" }),
|
|
1621
1951
|
/* @__PURE__ */ jsxs("div", { className: "relative mx-auto max-w-xl text-center", children: [
|
|
1622
|
-
/* @__PURE__ */
|
|
1623
|
-
|
|
1952
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-4 flex items-center justify-center gap-2", children: [
|
|
1953
|
+
/* @__PURE__ */ jsx("div", { className: "inline-flex h-8 w-8 items-center justify-center rounded-xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Mail, { className: "size-4" }) }),
|
|
1954
|
+
/* @__PURE__ */ jsx(Badge$1, { variant: "secondary", children: badge })
|
|
1955
|
+
] }),
|
|
1624
1956
|
/* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: title }),
|
|
1625
1957
|
/* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-sm text-pretty text-muted-foreground", children: description }),
|
|
1626
1958
|
submitted ? /* @__PURE__ */ jsxs("div", { className: "mt-8 rounded-2xl border bg-muted/50 px-6 py-5 text-sm", children: [
|
|
@@ -1666,15 +1998,14 @@ function NewsletterSection({
|
|
|
1666
1998
|
}
|
|
1667
1999
|
var defaultContactInfoResolved = [
|
|
1668
2000
|
{ icon: Mail, label: "Email", value: "hello@olwiba.com" },
|
|
1669
|
-
{ icon:
|
|
1670
|
-
{ icon: MapPin, label: "Office", value: "San Francisco, CA" }
|
|
2001
|
+
{ icon: MapPin, label: "Base", value: "Aotearoa New Zealand" }
|
|
1671
2002
|
];
|
|
1672
2003
|
var defaults2 = {
|
|
1673
|
-
badge: "Contact
|
|
2004
|
+
badge: "Contact",
|
|
1674
2005
|
title: "Let's talk",
|
|
1675
|
-
description: "Have a question or want to work together? Fill in the form and
|
|
2006
|
+
description: "Have a question or want to work together? Fill in the form and you'll hear back from the person who built it.",
|
|
1676
2007
|
successTitle: "Message sent",
|
|
1677
|
-
successDescription: "Thanks for reaching out.
|
|
2008
|
+
successDescription: "Thanks for reaching out. You'll get a reply within one business day.",
|
|
1678
2009
|
sendAnotherLabel: "Send another"
|
|
1679
2010
|
};
|
|
1680
2011
|
function ContactSection({
|
|
@@ -1682,12 +2013,13 @@ function ContactSection({
|
|
|
1682
2013
|
title = defaults2.title,
|
|
1683
2014
|
description = defaults2.description,
|
|
1684
2015
|
contactInfo = defaultContactInfoResolved,
|
|
2016
|
+
privacyHref,
|
|
1685
2017
|
successTitle = defaults2.successTitle,
|
|
1686
2018
|
successDescription = defaults2.successDescription,
|
|
1687
2019
|
sendAnotherLabel = defaults2.sendAnotherLabel,
|
|
1688
2020
|
onSubmit
|
|
1689
2021
|
} = {}) {
|
|
1690
|
-
const [submitted, setSubmitted] =
|
|
2022
|
+
const [submitted, setSubmitted] = React29.useState(false);
|
|
1691
2023
|
async function handleSubmit(e) {
|
|
1692
2024
|
e.preventDefault();
|
|
1693
2025
|
await onSubmit?.(e);
|
|
@@ -1695,49 +2027,41 @@ function ContactSection({
|
|
|
1695
2027
|
}
|
|
1696
2028
|
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: [
|
|
1697
2029
|
/* @__PURE__ */ jsxs("div", { className: "relative overflow-hidden bg-primary px-8 py-12 text-primary-foreground", children: [
|
|
1698
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(circle_at_top_right,hsl(var(--primary-foreground)/0.
|
|
1699
|
-
/* @__PURE__ */
|
|
2030
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(circle_at_top_right,hsl(var(--primary-foreground)/0.12),transparent_55%)]" }),
|
|
2031
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(circle_at_bottom_left,hsl(var(--primary-foreground)/0.06),transparent_60%)]" }),
|
|
2032
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex h-full flex-col gap-8", children: [
|
|
1700
2033
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1701
2034
|
/* @__PURE__ */ jsx(
|
|
1702
2035
|
Badge$1,
|
|
1703
2036
|
{
|
|
1704
2037
|
variant: "secondary",
|
|
1705
|
-
className: "mb-
|
|
2038
|
+
className: "mb-4 bg-primary-foreground/15 text-primary-foreground hover:bg-primary-foreground/20",
|
|
1706
2039
|
children: badge
|
|
1707
2040
|
}
|
|
1708
2041
|
),
|
|
1709
|
-
/* @__PURE__ */ jsx("h2", { className: "text-
|
|
1710
|
-
/* @__PURE__ */ jsx("p", { className: "mt-
|
|
2042
|
+
/* @__PURE__ */ jsx("h2", { className: "text-3xl font-semibold leading-tight", children: title }),
|
|
2043
|
+
/* @__PURE__ */ jsx("p", { className: "mt-3 text-sm leading-relaxed text-primary-foreground/70", children: description })
|
|
1711
2044
|
] }),
|
|
1712
2045
|
/* @__PURE__ */ jsx(Separator, { className: "bg-primary-foreground/20" }),
|
|
1713
|
-
/* @__PURE__ */ jsx("div", { className: "space-y-
|
|
1714
|
-
/* @__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" }) }),
|
|
2046
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-5", children: contactInfo.map(({ icon: Icon = Mail, label, value }) => /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
2047
|
+
/* @__PURE__ */ jsx("div", { className: "mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary-foreground/10", children: /* @__PURE__ */ jsx(Icon, { className: "size-4" }) }),
|
|
1715
2048
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1716
|
-
/* @__PURE__ */ jsx("div", { className: "text-xs text-primary-foreground/
|
|
1717
|
-
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: value })
|
|
2049
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs font-medium uppercase tracking-wider text-primary-foreground/50", children: label }),
|
|
2050
|
+
/* @__PURE__ */ jsx("div", { className: "mt-0.5 text-sm font-medium", children: value })
|
|
1718
2051
|
] })
|
|
1719
|
-
] }, label)) })
|
|
2052
|
+
] }, label)) }),
|
|
2053
|
+
/* @__PURE__ */ jsx("div", { className: "mt-auto", children: /* @__PURE__ */ jsx("p", { className: "text-xs text-primary-foreground/40", children: "Response within one business day." }) })
|
|
1720
2054
|
] })
|
|
1721
2055
|
] }),
|
|
1722
|
-
/* @__PURE__ */ jsx("div", { className: "p-8", children: submitted ? /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-[
|
|
1723
|
-
/* @__PURE__ */ jsx("div", { className: "flex h-
|
|
2056
|
+
/* @__PURE__ */ jsx("div", { className: "p-8 sm:p-10", children: submitted ? /* @__PURE__ */ jsxs("div", { className: "flex h-full min-h-[360px] flex-col items-center justify-center gap-5 text-center", children: [
|
|
2057
|
+
/* @__PURE__ */ jsx("div", { className: "flex h-14 w-14 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(MessageSquare, { className: "size-6" }) }),
|
|
1724
2058
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1725
|
-
/* @__PURE__ */ jsx("h3", { className: "font-semibold", children: successTitle }),
|
|
1726
|
-
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: successDescription })
|
|
2059
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: successTitle }),
|
|
2060
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm text-muted-foreground", children: successDescription })
|
|
1727
2061
|
] }),
|
|
1728
|
-
/* @__PURE__ */ jsx(Button$1, { variant: "outline", onClick: () => setSubmitted(false), children: sendAnotherLabel })
|
|
2062
|
+
/* @__PURE__ */ jsx(Button$1, { variant: "outline", size: "sm", onClick: () => setSubmitted(false), children: sendAnotherLabel })
|
|
1729
2063
|
] }) : /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-5", children: [
|
|
1730
|
-
/* @__PURE__ */ jsx(
|
|
1731
|
-
"input",
|
|
1732
|
-
{
|
|
1733
|
-
type: "text",
|
|
1734
|
-
name: "company",
|
|
1735
|
-
tabIndex: -1,
|
|
1736
|
-
autoComplete: "off",
|
|
1737
|
-
"aria-hidden": "true",
|
|
1738
|
-
className: "hidden"
|
|
1739
|
-
}
|
|
1740
|
-
),
|
|
2064
|
+
/* @__PURE__ */ jsx("input", { type: "text", name: "_hp", tabIndex: -1, autoComplete: "off", "aria-hidden": "true", className: "hidden" }),
|
|
1741
2065
|
/* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
|
|
1742
2066
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
1743
2067
|
/* @__PURE__ */ jsx(Label, { htmlFor: "contact-first", children: "First name" }),
|
|
@@ -1748,8 +2072,24 @@ function ContactSection({
|
|
|
1748
2072
|
/* @__PURE__ */ jsx(Input$1, { id: "contact-last", name: "lastName", placeholder: "Reed", required: true })
|
|
1749
2073
|
] })
|
|
1750
2074
|
] }),
|
|
2075
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
|
|
2076
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
2077
|
+
/* @__PURE__ */ jsxs(Label, { htmlFor: "contact-company", className: "flex gap-1", children: [
|
|
2078
|
+
"Company",
|
|
2079
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "(optional)" })
|
|
2080
|
+
] }),
|
|
2081
|
+
/* @__PURE__ */ jsx(Input$1, { id: "contact-company", name: "company", placeholder: "Acme Inc." })
|
|
2082
|
+
] }),
|
|
2083
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
2084
|
+
/* @__PURE__ */ jsxs(Label, { htmlFor: "contact-phone", className: "flex gap-1", children: [
|
|
2085
|
+
"Phone",
|
|
2086
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "(optional)" })
|
|
2087
|
+
] }),
|
|
2088
|
+
/* @__PURE__ */ jsx(Input$1, { id: "contact-phone", name: "phone", type: "tel", placeholder: "+1 (555) 000-0000" })
|
|
2089
|
+
] })
|
|
2090
|
+
] }),
|
|
1751
2091
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
1752
|
-
/* @__PURE__ */ jsx(Label, { htmlFor: "contact-email", children: "
|
|
2092
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "contact-email", children: "Work email" }),
|
|
1753
2093
|
/* @__PURE__ */ jsx(Input$1, { id: "contact-email", name: "email", type: "email", placeholder: "olivia@company.com", required: true })
|
|
1754
2094
|
] }),
|
|
1755
2095
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
@@ -1764,11 +2104,20 @@ function ContactSection({
|
|
|
1764
2104
|
id: "contact-message",
|
|
1765
2105
|
name: "message",
|
|
1766
2106
|
placeholder: "Tell us what you're working on...",
|
|
1767
|
-
className: "min-h-
|
|
2107
|
+
className: "min-h-32 resize-none",
|
|
1768
2108
|
required: true
|
|
1769
2109
|
}
|
|
1770
2110
|
)
|
|
1771
2111
|
] }),
|
|
2112
|
+
privacyHref && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
2113
|
+
/* @__PURE__ */ jsx(Checkbox$1, { id: "contact-privacy", name: "privacy", required: true, className: "mt-0.5" }),
|
|
2114
|
+
/* @__PURE__ */ jsxs(Label, { htmlFor: "contact-privacy", className: "text-sm font-normal leading-snug text-muted-foreground", children: [
|
|
2115
|
+
"By submitting this form you agree to our",
|
|
2116
|
+
" ",
|
|
2117
|
+
/* @__PURE__ */ jsx("a", { href: privacyHref, className: "font-medium text-foreground underline-offset-2 hover:underline", children: "privacy policy" }),
|
|
2118
|
+
"."
|
|
2119
|
+
] })
|
|
2120
|
+
] }),
|
|
1772
2121
|
/* @__PURE__ */ jsxs(Button$1, { type: "submit", className: "w-full", children: [
|
|
1773
2122
|
"Send message",
|
|
1774
2123
|
/* @__PURE__ */ jsx(Send, { className: "ml-2 size-4" })
|
|
@@ -1776,22 +2125,143 @@ function ContactSection({
|
|
|
1776
2125
|
] }) })
|
|
1777
2126
|
] }) });
|
|
1778
2127
|
}
|
|
1779
|
-
|
|
2128
|
+
function ComparisonSection({
|
|
2129
|
+
badge = "The math",
|
|
2130
|
+
title = "The math is simple",
|
|
2131
|
+
description,
|
|
2132
|
+
columns
|
|
2133
|
+
}) {
|
|
2134
|
+
const mode = useUIVariant();
|
|
2135
|
+
const sectionClasses = cn$1(
|
|
2136
|
+
"overflow-hidden bg-card",
|
|
2137
|
+
mode === "smooth" && "rounded-3xl border",
|
|
2138
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
2139
|
+
!mode && "rounded-2xl border"
|
|
2140
|
+
);
|
|
2141
|
+
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl", children: [
|
|
2142
|
+
/* @__PURE__ */ jsx(SectionTitle, { badge, title, description }),
|
|
2143
|
+
/* @__PURE__ */ jsx(StaggerChildren, { className: "mt-12 grid gap-4 sm:grid-cols-3", children: columns.map((col) => /* @__PURE__ */ jsxs(
|
|
2144
|
+
"div",
|
|
2145
|
+
{
|
|
2146
|
+
className: cn$1(
|
|
2147
|
+
"flex flex-col rounded-2xl border p-6",
|
|
2148
|
+
col.highlighted ? "border-foreground bg-foreground text-background" : "border-border bg-muted/40"
|
|
2149
|
+
),
|
|
2150
|
+
children: [
|
|
2151
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
|
|
2152
|
+
/* @__PURE__ */ jsx(
|
|
2153
|
+
"p",
|
|
2154
|
+
{
|
|
2155
|
+
className: cn$1(
|
|
2156
|
+
"text-xs font-semibold uppercase tracking-widest",
|
|
2157
|
+
col.highlighted ? "text-background/60" : "text-muted-foreground"
|
|
2158
|
+
),
|
|
2159
|
+
children: col.label
|
|
2160
|
+
}
|
|
2161
|
+
),
|
|
2162
|
+
/* @__PURE__ */ jsx(
|
|
2163
|
+
"p",
|
|
2164
|
+
{
|
|
2165
|
+
className: cn$1(
|
|
2166
|
+
"mt-2 text-2xl font-bold tracking-tight",
|
|
2167
|
+
col.highlighted ? "text-background" : "text-foreground"
|
|
2168
|
+
),
|
|
2169
|
+
children: col.cost
|
|
2170
|
+
}
|
|
2171
|
+
),
|
|
2172
|
+
col.costDetail && /* @__PURE__ */ jsx(
|
|
2173
|
+
"p",
|
|
2174
|
+
{
|
|
2175
|
+
className: cn$1(
|
|
2176
|
+
"mt-1 text-sm",
|
|
2177
|
+
col.highlighted ? "text-background/60" : "text-muted-foreground"
|
|
2178
|
+
),
|
|
2179
|
+
children: col.costDetail
|
|
2180
|
+
}
|
|
2181
|
+
)
|
|
2182
|
+
] }),
|
|
2183
|
+
/* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-3", children: col.items.map((item) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2.5", children: [
|
|
2184
|
+
col.highlighted ? /* @__PURE__ */ jsx(Check, { className: "mt-0.5 size-4 shrink-0 text-background/70" }) : /* @__PURE__ */ jsx(Minus, { className: "mt-0.5 size-4 shrink-0 text-muted-foreground/50" }),
|
|
2185
|
+
/* @__PURE__ */ jsx(
|
|
2186
|
+
"span",
|
|
2187
|
+
{
|
|
2188
|
+
className: cn$1(
|
|
2189
|
+
"text-sm leading-snug",
|
|
2190
|
+
col.highlighted ? "text-background/90" : "text-muted-foreground"
|
|
2191
|
+
),
|
|
2192
|
+
children: item
|
|
2193
|
+
}
|
|
2194
|
+
)
|
|
2195
|
+
] }, item)) })
|
|
2196
|
+
]
|
|
2197
|
+
},
|
|
2198
|
+
col.label
|
|
2199
|
+
)) })
|
|
2200
|
+
] }) }) });
|
|
2201
|
+
}
|
|
2202
|
+
function QualificationSection({
|
|
2203
|
+
badge = "Who it is for",
|
|
2204
|
+
title = "Is this for you?",
|
|
2205
|
+
description,
|
|
2206
|
+
columns
|
|
2207
|
+
}) {
|
|
2208
|
+
const mode = useUIVariant();
|
|
2209
|
+
const sectionClasses = cn$1(
|
|
2210
|
+
"overflow-hidden bg-card",
|
|
2211
|
+
mode === "smooth" && "rounded-3xl border",
|
|
2212
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
2213
|
+
!mode && "rounded-2xl border"
|
|
2214
|
+
);
|
|
2215
|
+
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsx("div", { className: "px-6 py-14 sm:px-10 sm:py-20", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-4xl", children: [
|
|
2216
|
+
/* @__PURE__ */ jsx(SectionTitle, { badge, title, description }),
|
|
2217
|
+
/* @__PURE__ */ jsx(FadeIn, { direction: "up", className: "mt-12 grid gap-6 sm:grid-cols-2", children: columns.map((col) => {
|
|
2218
|
+
const isPositive = col.variant === "positive";
|
|
2219
|
+
const Icon = isPositive ? Check : X;
|
|
2220
|
+
return /* @__PURE__ */ jsxs(
|
|
2221
|
+
"div",
|
|
2222
|
+
{
|
|
2223
|
+
className: cn$1(
|
|
2224
|
+
"flex flex-col gap-4 rounded-2xl border p-6",
|
|
2225
|
+
isPositive ? "border-border bg-muted/30" : "border-border bg-muted/10"
|
|
2226
|
+
),
|
|
2227
|
+
children: [
|
|
2228
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold uppercase tracking-widest text-muted-foreground", children: col.heading }),
|
|
2229
|
+
/* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-3", children: col.items.map((item) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-3", children: [
|
|
2230
|
+
/* @__PURE__ */ jsx(
|
|
2231
|
+
"span",
|
|
2232
|
+
{
|
|
2233
|
+
className: cn$1(
|
|
2234
|
+
"mt-0.5 flex size-5 shrink-0 items-center justify-center rounded-full",
|
|
2235
|
+
isPositive ? "bg-emerald-500/15 text-emerald-600 dark:text-emerald-400" : "bg-rose-500/15 text-rose-600 dark:text-rose-400"
|
|
2236
|
+
),
|
|
2237
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "size-3" })
|
|
2238
|
+
}
|
|
2239
|
+
),
|
|
2240
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm leading-relaxed text-foreground/80", children: item })
|
|
2241
|
+
] }, item)) })
|
|
2242
|
+
]
|
|
2243
|
+
},
|
|
2244
|
+
col.heading
|
|
2245
|
+
);
|
|
2246
|
+
}) })
|
|
2247
|
+
] }) }) });
|
|
2248
|
+
}
|
|
2249
|
+
var defaultRenderLink8 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
1780
2250
|
function Navbar({
|
|
1781
2251
|
brand,
|
|
1782
2252
|
navLinks,
|
|
1783
2253
|
cta,
|
|
1784
2254
|
controls,
|
|
1785
|
-
renderLink =
|
|
2255
|
+
renderLink = defaultRenderLink8
|
|
1786
2256
|
}) {
|
|
1787
|
-
const [open, setOpen] =
|
|
2257
|
+
const [open, setOpen] = React29.useState(false);
|
|
1788
2258
|
const brandHref = brand.href ?? "/";
|
|
1789
2259
|
const hasRightContent = controls?.length || cta?.primary || cta?.secondary;
|
|
1790
2260
|
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: [
|
|
1791
2261
|
renderLink({
|
|
1792
2262
|
href: brandHref,
|
|
1793
2263
|
children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 font-semibold", children: [
|
|
1794
|
-
brand.logo
|
|
2264
|
+
brand.logo,
|
|
1795
2265
|
/* @__PURE__ */ jsx("span", { children: brand.name })
|
|
1796
2266
|
] })
|
|
1797
2267
|
}),
|
|
@@ -1801,7 +2271,7 @@ function Navbar({
|
|
|
1801
2271
|
children: link.label
|
|
1802
2272
|
}) }, link.label)) }),
|
|
1803
2273
|
hasRightContent && /* @__PURE__ */ jsxs("div", { className: "hidden items-center justify-end gap-2 md:flex", children: [
|
|
1804
|
-
controls?.map((control, i) => /* @__PURE__ */ jsx(
|
|
2274
|
+
controls?.map((control, i) => /* @__PURE__ */ jsx(React29.Fragment, { children: control }, i)),
|
|
1805
2275
|
(cta?.secondary || cta?.primary) && controls?.length ? /* @__PURE__ */ jsx("div", { className: "mx-1 h-4 w-px bg-border" }) : null,
|
|
1806
2276
|
cta?.secondary && renderLink({
|
|
1807
2277
|
href: cta.secondary.href,
|
|
@@ -1822,12 +2292,12 @@ function Navbar({
|
|
|
1822
2292
|
/* @__PURE__ */ jsx("span", { onClick: () => setOpen(false), className: "cursor-pointer", children: renderLink({
|
|
1823
2293
|
href: brandHref,
|
|
1824
2294
|
children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 font-semibold", children: [
|
|
1825
|
-
brand.logo
|
|
2295
|
+
brand.logo,
|
|
1826
2296
|
/* @__PURE__ */ jsx("span", { children: brand.name })
|
|
1827
2297
|
] })
|
|
1828
2298
|
}) }),
|
|
1829
2299
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
1830
|
-
controls?.map((control, i) => /* @__PURE__ */ jsx(
|
|
2300
|
+
controls?.map((control, i) => /* @__PURE__ */ jsx(React29.Fragment, { children: control }, i)),
|
|
1831
2301
|
/* @__PURE__ */ jsxs(Button$1, { variant: "ghost", size: "icon", onClick: () => setOpen(false), children: [
|
|
1832
2302
|
/* @__PURE__ */ jsx(X, { className: "size-4" }),
|
|
1833
2303
|
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close menu" })
|
|
@@ -1854,22 +2324,22 @@ function Navbar({
|
|
|
1854
2324
|
] })
|
|
1855
2325
|
] }) });
|
|
1856
2326
|
}
|
|
1857
|
-
var
|
|
2327
|
+
var defaultRenderLink9 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
1858
2328
|
function Footer({
|
|
1859
2329
|
brand,
|
|
1860
2330
|
navLinks,
|
|
1861
2331
|
socialLinks,
|
|
1862
2332
|
legal,
|
|
1863
|
-
renderLink =
|
|
2333
|
+
renderLink = defaultRenderLink9
|
|
1864
2334
|
}) {
|
|
1865
2335
|
const brandHref = brand.href ?? "/";
|
|
1866
2336
|
const copyrightText = legal ?? `\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${brand.name}. All rights reserved.`;
|
|
1867
|
-
return /* @__PURE__ */ jsx("footer", { className: "overflow-hidden rounded-2xl border bg-
|
|
2337
|
+
return /* @__PURE__ */ jsx("footer", { className: "overflow-hidden rounded-2xl border bg-card text-foreground", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-7xl px-6 py-20 sm:py-24 lg:px-8", children: [
|
|
1868
2338
|
/* @__PURE__ */ jsx("div", { className: "flex justify-center", children: renderLink({
|
|
1869
2339
|
href: brandHref,
|
|
1870
2340
|
className: "flex items-center gap-2",
|
|
1871
2341
|
children: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1872
|
-
brand.logo
|
|
2342
|
+
brand.logo,
|
|
1873
2343
|
/* @__PURE__ */ jsx("span", { className: "text-lg font-semibold text-foreground", children: brand.name })
|
|
1874
2344
|
] })
|
|
1875
2345
|
}) }),
|
|
@@ -1891,7 +2361,7 @@ function Footer({
|
|
|
1891
2361
|
/* @__PURE__ */ jsx("p", { className: "mt-10 text-center text-sm/6 text-muted-foreground/70", children: copyrightText })
|
|
1892
2362
|
] }) });
|
|
1893
2363
|
}
|
|
1894
|
-
var
|
|
2364
|
+
var speedDuration2 = {
|
|
1895
2365
|
slow: "60s",
|
|
1896
2366
|
normal: "40s",
|
|
1897
2367
|
fast: "25s"
|
|
@@ -1901,7 +2371,7 @@ function LogoStrip({
|
|
|
1901
2371
|
label,
|
|
1902
2372
|
speed = "normal"
|
|
1903
2373
|
}) {
|
|
1904
|
-
const duration =
|
|
2374
|
+
const duration = speedDuration2[speed];
|
|
1905
2375
|
return /* @__PURE__ */ jsxs(FadeIn, { direction: "up", children: [
|
|
1906
2376
|
/* @__PURE__ */ jsxs("section", { className: "overflow-hidden py-8", children: [
|
|
1907
2377
|
label && /* @__PURE__ */ jsx("p", { className: "mb-6 text-center text-sm text-muted-foreground", children: label }),
|
|
@@ -1972,7 +2442,7 @@ function LogoStrip({
|
|
|
1972
2442
|
] });
|
|
1973
2443
|
}
|
|
1974
2444
|
function GridUnderlay({ variant, size = 24, className, ...props }) {
|
|
1975
|
-
const id =
|
|
2445
|
+
const id = React29.useId();
|
|
1976
2446
|
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: [
|
|
1977
2447
|
/* @__PURE__ */ jsx("line", { x1: size / 2, y1: 0, x2: size / 2, y2: size, stroke: "currentColor", strokeWidth: 0.5 }),
|
|
1978
2448
|
/* @__PURE__ */ jsx("line", { x1: 0, y1: size / 2, x2: size, y2: size / 2, stroke: "currentColor", strokeWidth: 0.5 })
|
|
@@ -2000,9 +2470,9 @@ function GlowUnderlay({
|
|
|
2000
2470
|
style,
|
|
2001
2471
|
...props
|
|
2002
2472
|
}) {
|
|
2003
|
-
const [pos, setPos] =
|
|
2004
|
-
const containerRef =
|
|
2005
|
-
|
|
2473
|
+
const [pos, setPos] = React29.useState({ x: "50%", y: "50%" });
|
|
2474
|
+
const containerRef = React29.useRef(null);
|
|
2475
|
+
React29.useEffect(() => {
|
|
2006
2476
|
if (!followCursor) return;
|
|
2007
2477
|
const handleMouseMove = (e) => {
|
|
2008
2478
|
const el = containerRef.current;
|
|
@@ -2086,6 +2556,53 @@ function Overlay(props) {
|
|
|
2086
2556
|
if (props.variant === "scrim") return /* @__PURE__ */ jsx(ScrimOverlay, { ...props });
|
|
2087
2557
|
return /* @__PURE__ */ jsx(LoadingOverlay, { ...props });
|
|
2088
2558
|
}
|
|
2559
|
+
function AnimatedPill({ labels, interval = 3800, className }) {
|
|
2560
|
+
const pillRef = useRef(null);
|
|
2561
|
+
const textRef = useRef(null);
|
|
2562
|
+
useEffect(() => {
|
|
2563
|
+
const pill = pillRef.current;
|
|
2564
|
+
const text = textRef.current;
|
|
2565
|
+
if (!pill || !text || labels.length < 2) return;
|
|
2566
|
+
pill.style.width = pill.offsetWidth + "px";
|
|
2567
|
+
pill.dataset.w = String(pill.offsetWidth);
|
|
2568
|
+
let idx = 0;
|
|
2569
|
+
const cycle = () => {
|
|
2570
|
+
idx = (idx + 1) % labels.length;
|
|
2571
|
+
text.style.transition = "opacity 140ms ease";
|
|
2572
|
+
text.style.opacity = "0";
|
|
2573
|
+
setTimeout(() => {
|
|
2574
|
+
text.textContent = labels[idx] ?? "";
|
|
2575
|
+
const oldW = parseFloat(pill.dataset.w ?? "0");
|
|
2576
|
+
pill.style.transition = "none";
|
|
2577
|
+
pill.style.width = "auto";
|
|
2578
|
+
const newW = pill.offsetWidth;
|
|
2579
|
+
pill.style.width = oldW + "px";
|
|
2580
|
+
void pill.offsetWidth;
|
|
2581
|
+
pill.style.transition = "width 280ms cubic-bezier(0.4, 0, 0.2, 1)";
|
|
2582
|
+
pill.style.width = newW + "px";
|
|
2583
|
+
pill.dataset.w = String(newW);
|
|
2584
|
+
setTimeout(() => {
|
|
2585
|
+
text.style.transition = "opacity 140ms ease";
|
|
2586
|
+
text.style.opacity = "1";
|
|
2587
|
+
}, 260);
|
|
2588
|
+
}, 150);
|
|
2589
|
+
};
|
|
2590
|
+
const id = setInterval(cycle, interval);
|
|
2591
|
+
return () => clearInterval(id);
|
|
2592
|
+
}, [labels, interval]);
|
|
2593
|
+
if (!labels.length) return null;
|
|
2594
|
+
return /* @__PURE__ */ jsx(
|
|
2595
|
+
"span",
|
|
2596
|
+
{
|
|
2597
|
+
ref: pillRef,
|
|
2598
|
+
className: cn$1(
|
|
2599
|
+
"inline-flex items-center overflow-hidden whitespace-nowrap rounded-full border bg-secondary px-2.5 py-0.5 text-xs font-semibold text-secondary-foreground",
|
|
2600
|
+
className
|
|
2601
|
+
),
|
|
2602
|
+
children: /* @__PURE__ */ jsx("span", { ref: textRef, children: labels[0] })
|
|
2603
|
+
}
|
|
2604
|
+
);
|
|
2605
|
+
}
|
|
2089
2606
|
function PageTransition({
|
|
2090
2607
|
variant = "fade",
|
|
2091
2608
|
duration = 300,
|
|
@@ -2094,8 +2611,8 @@ function PageTransition({
|
|
|
2094
2611
|
style,
|
|
2095
2612
|
...props
|
|
2096
2613
|
}) {
|
|
2097
|
-
const [mounted, setMounted] =
|
|
2098
|
-
|
|
2614
|
+
const [mounted, setMounted] = React29.useState(false);
|
|
2615
|
+
React29.useEffect(() => {
|
|
2099
2616
|
const id = requestAnimationFrame(() => setMounted(true));
|
|
2100
2617
|
return () => cancelAnimationFrame(id);
|
|
2101
2618
|
}, []);
|
|
@@ -2122,8 +2639,8 @@ function Spotlight({
|
|
|
2122
2639
|
triggerClassName,
|
|
2123
2640
|
shortcut = "\u2318K"
|
|
2124
2641
|
}) {
|
|
2125
|
-
const [open, setOpen] =
|
|
2126
|
-
|
|
2642
|
+
const [open, setOpen] = React29.useState(false);
|
|
2643
|
+
React29.useEffect(() => {
|
|
2127
2644
|
const down = (e) => {
|
|
2128
2645
|
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
|
2129
2646
|
e.preventDefault();
|
|
@@ -2153,7 +2670,7 @@ function Spotlight({
|
|
|
2153
2670
|
/* @__PURE__ */ jsx(CommandInput, { placeholder }),
|
|
2154
2671
|
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
2155
2672
|
/* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
|
|
2156
|
-
groups.map((group, i) => /* @__PURE__ */ jsxs(
|
|
2673
|
+
groups.map((group, i) => /* @__PURE__ */ jsxs(React29.Fragment, { children: [
|
|
2157
2674
|
i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
2158
2675
|
/* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
2159
2676
|
CommandItem,
|
|
@@ -2178,8 +2695,8 @@ function Spotlight({
|
|
|
2178
2695
|
var BASE = 40;
|
|
2179
2696
|
var MAGNIFY_RADIUS = 80;
|
|
2180
2697
|
function Dock({ items, iconSize = BASE, magnification = 1.7, className, ...props }) {
|
|
2181
|
-
const [mouseX, setMouseX] =
|
|
2182
|
-
const containerRef =
|
|
2698
|
+
const [mouseX, setMouseX] = React29.useState(null);
|
|
2699
|
+
const containerRef = React29.useRef(null);
|
|
2183
2700
|
function getScale(index) {
|
|
2184
2701
|
if (mouseX === null || !containerRef.current) return 1;
|
|
2185
2702
|
const container = containerRef.current;
|
|
@@ -2385,26 +2902,254 @@ function ImageCard({
|
|
|
2385
2902
|
}
|
|
2386
2903
|
);
|
|
2387
2904
|
}
|
|
2905
|
+
var DASH_ON = "5px";
|
|
2906
|
+
var DASH_OFF = "4px";
|
|
2907
|
+
function FlowConnector({
|
|
2908
|
+
direction = "vertical",
|
|
2909
|
+
color,
|
|
2910
|
+
arrow = false,
|
|
2911
|
+
animate = false,
|
|
2912
|
+
animateDur = "1.4s",
|
|
2913
|
+
animateDelay = "0s",
|
|
2914
|
+
className,
|
|
2915
|
+
style
|
|
2916
|
+
}) {
|
|
2917
|
+
const stroke = color ?? "currentColor";
|
|
2918
|
+
const opacity = color ? 0.75 : 0.4;
|
|
2919
|
+
if (direction === "vertical") {
|
|
2920
|
+
return /* @__PURE__ */ jsxs(
|
|
2921
|
+
"div",
|
|
2922
|
+
{
|
|
2923
|
+
className: cn$1("relative flex flex-col items-center", className),
|
|
2924
|
+
style,
|
|
2925
|
+
"aria-hidden": true,
|
|
2926
|
+
children: [
|
|
2927
|
+
animate && /* @__PURE__ */ jsx("style", { children: `@keyframes fc-dot-v{0%{top:-4px;opacity:0}8%{opacity:1}88%{opacity:1}100%{top:calc(100% + 4px);opacity:0}}` }),
|
|
2928
|
+
/* @__PURE__ */ jsx(
|
|
2929
|
+
"div",
|
|
2930
|
+
{
|
|
2931
|
+
className: "flex-1",
|
|
2932
|
+
style: {
|
|
2933
|
+
width: 2,
|
|
2934
|
+
opacity,
|
|
2935
|
+
background: `repeating-linear-gradient(to bottom, ${stroke} 0, ${stroke} ${DASH_ON}, transparent ${DASH_ON}, transparent calc(${DASH_ON} + ${DASH_OFF}))`
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
),
|
|
2939
|
+
animate && /* @__PURE__ */ jsx(
|
|
2940
|
+
"div",
|
|
2941
|
+
{
|
|
2942
|
+
style: {
|
|
2943
|
+
position: "absolute",
|
|
2944
|
+
left: "50%",
|
|
2945
|
+
transform: "translateX(-50%)",
|
|
2946
|
+
width: 5,
|
|
2947
|
+
height: 5,
|
|
2948
|
+
borderRadius: "50%",
|
|
2949
|
+
backgroundColor: stroke,
|
|
2950
|
+
animation: `fc-dot-v ${animateDur} ease-in-out ${animateDelay} infinite both`
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
),
|
|
2954
|
+
arrow && /* @__PURE__ */ jsx(
|
|
2955
|
+
"svg",
|
|
2956
|
+
{
|
|
2957
|
+
width: "12",
|
|
2958
|
+
height: "7",
|
|
2959
|
+
viewBox: "0 0 12 7",
|
|
2960
|
+
style: { display: "block", opacity },
|
|
2961
|
+
"aria-hidden": true,
|
|
2962
|
+
children: /* @__PURE__ */ jsx(
|
|
2963
|
+
"polyline",
|
|
2964
|
+
{
|
|
2965
|
+
points: "1,1 6,6 11,1",
|
|
2966
|
+
fill: "none",
|
|
2967
|
+
stroke,
|
|
2968
|
+
strokeWidth: "1.5",
|
|
2969
|
+
strokeLinecap: "round",
|
|
2970
|
+
strokeLinejoin: "round"
|
|
2971
|
+
}
|
|
2972
|
+
)
|
|
2973
|
+
}
|
|
2974
|
+
)
|
|
2975
|
+
]
|
|
2976
|
+
}
|
|
2977
|
+
);
|
|
2978
|
+
}
|
|
2979
|
+
return /* @__PURE__ */ jsxs(
|
|
2980
|
+
"div",
|
|
2981
|
+
{
|
|
2982
|
+
className: cn$1("flex items-center", className),
|
|
2983
|
+
style,
|
|
2984
|
+
"aria-hidden": true,
|
|
2985
|
+
children: [
|
|
2986
|
+
/* @__PURE__ */ jsx(
|
|
2987
|
+
"div",
|
|
2988
|
+
{
|
|
2989
|
+
className: "flex-1",
|
|
2990
|
+
style: {
|
|
2991
|
+
height: 2,
|
|
2992
|
+
opacity,
|
|
2993
|
+
background: `repeating-linear-gradient(to right, ${stroke} 0, ${stroke} ${DASH_ON}, transparent ${DASH_ON}, transparent calc(${DASH_ON} + ${DASH_OFF}))`
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
),
|
|
2997
|
+
arrow && /* @__PURE__ */ jsx(
|
|
2998
|
+
"svg",
|
|
2999
|
+
{
|
|
3000
|
+
width: "7",
|
|
3001
|
+
height: "12",
|
|
3002
|
+
viewBox: "0 0 7 12",
|
|
3003
|
+
style: { display: "block", opacity },
|
|
3004
|
+
"aria-hidden": true,
|
|
3005
|
+
children: /* @__PURE__ */ jsx(
|
|
3006
|
+
"polyline",
|
|
3007
|
+
{
|
|
3008
|
+
points: "1,1 6,6 1,11",
|
|
3009
|
+
fill: "none",
|
|
3010
|
+
stroke,
|
|
3011
|
+
strokeWidth: "1.5",
|
|
3012
|
+
strokeLinecap: "round",
|
|
3013
|
+
strokeLinejoin: "round"
|
|
3014
|
+
}
|
|
3015
|
+
)
|
|
3016
|
+
}
|
|
3017
|
+
)
|
|
3018
|
+
]
|
|
3019
|
+
}
|
|
3020
|
+
);
|
|
3021
|
+
}
|
|
3022
|
+
var MARKER_L = "fb-ml";
|
|
3023
|
+
var MARKER_R = "fb-mr";
|
|
3024
|
+
function FlowBracket({
|
|
3025
|
+
anchorTop = 8,
|
|
3026
|
+
anchorBottom = 92,
|
|
3027
|
+
extent = 22,
|
|
3028
|
+
arrow = true,
|
|
3029
|
+
color = "rgba(148,163,184,0.4)",
|
|
3030
|
+
colorLeft,
|
|
3031
|
+
colorRight,
|
|
3032
|
+
left = true,
|
|
3033
|
+
right = true,
|
|
3034
|
+
animate = false,
|
|
3035
|
+
animateDur = "4s",
|
|
3036
|
+
reverseRight = false,
|
|
3037
|
+
style,
|
|
3038
|
+
className,
|
|
3039
|
+
children
|
|
3040
|
+
}) {
|
|
3041
|
+
const L = -extent;
|
|
3042
|
+
const R = 1e3 + extent;
|
|
3043
|
+
const cl = colorLeft ?? color;
|
|
3044
|
+
const cr = colorRight ?? color;
|
|
3045
|
+
const leftD = `M 0,${anchorBottom} L ${L},${anchorBottom} L ${L},${anchorTop} L 0,${anchorTop}`;
|
|
3046
|
+
const rightD = reverseRight ? `M 1000,${anchorTop} L ${R},${anchorTop} L ${R},${anchorBottom} L 1000,${anchorBottom}` : `M 1000,${anchorBottom} L ${R},${anchorBottom} L ${R},${anchorTop} L 1000,${anchorTop}`;
|
|
3047
|
+
const ep = `${(extent / 10).toFixed(1)}%`;
|
|
3048
|
+
const dotKeyframes = animate ? `
|
|
3049
|
+
@keyframes fb-dl{
|
|
3050
|
+
0%{top:${anchorBottom}%;left:0;opacity:0}
|
|
3051
|
+
6%{opacity:1}
|
|
3052
|
+
20%{top:${anchorBottom}%;left:-${ep}}
|
|
3053
|
+
80%{top:${anchorTop}%;left:-${ep};opacity:1}
|
|
3054
|
+
94%{top:${anchorTop}%;left:0;opacity:0}
|
|
3055
|
+
100%{top:${anchorTop}%;left:0;opacity:0}
|
|
3056
|
+
}
|
|
3057
|
+
@keyframes fb-dr{
|
|
3058
|
+
0%{top:${anchorBottom}%;left:100%;opacity:0}
|
|
3059
|
+
6%{opacity:1}
|
|
3060
|
+
20%{top:${anchorBottom}%;left:calc(100% + ${ep})}
|
|
3061
|
+
80%{top:${anchorTop}%;left:calc(100% + ${ep});opacity:1}
|
|
3062
|
+
94%{top:${anchorTop}%;left:100%;opacity:0}
|
|
3063
|
+
100%{top:${anchorTop}%;left:100%;opacity:0}
|
|
3064
|
+
}` : "";
|
|
3065
|
+
const dotBase = {
|
|
3066
|
+
position: "absolute",
|
|
3067
|
+
width: 5,
|
|
3068
|
+
height: 5,
|
|
3069
|
+
borderRadius: "50%",
|
|
3070
|
+
transform: "translate(-50%, -50%)",
|
|
3071
|
+
pointerEvents: "none",
|
|
3072
|
+
opacity: 0
|
|
3073
|
+
};
|
|
3074
|
+
return /* @__PURE__ */ jsxs("div", { className, style: { position: "relative", ...style }, children: [
|
|
3075
|
+
animate && /* @__PURE__ */ jsx("style", { children: dotKeyframes }),
|
|
3076
|
+
/* @__PURE__ */ jsxs(
|
|
3077
|
+
"svg",
|
|
3078
|
+
{
|
|
3079
|
+
viewBox: "0 0 1000 100",
|
|
3080
|
+
preserveAspectRatio: "none",
|
|
3081
|
+
"aria-hidden": true,
|
|
3082
|
+
className: "pointer-events-none absolute inset-0",
|
|
3083
|
+
style: { width: "100%", height: "100%", overflow: "visible" },
|
|
3084
|
+
children: [
|
|
3085
|
+
/* @__PURE__ */ jsxs("defs", { children: [
|
|
3086
|
+
/* @__PURE__ */ jsx("marker", { id: MARKER_L, markerWidth: "10", markerHeight: "8", refX: "8", refY: "4", orient: "auto", children: /* @__PURE__ */ jsx("polyline", { points: "1,1 8,4 1,7", fill: "none", stroke: cl, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }),
|
|
3087
|
+
/* @__PURE__ */ jsx("marker", { id: MARKER_R, markerWidth: "10", markerHeight: "8", refX: "8", refY: "4", orient: "auto", children: /* @__PURE__ */ jsx("polyline", { points: "1,1 8,4 1,7", fill: "none", stroke: cr, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
|
|
3088
|
+
] }),
|
|
3089
|
+
left && /* @__PURE__ */ jsx(
|
|
3090
|
+
"path",
|
|
3091
|
+
{
|
|
3092
|
+
d: leftD,
|
|
3093
|
+
fill: "none",
|
|
3094
|
+
stroke: cl,
|
|
3095
|
+
strokeWidth: 1.5,
|
|
3096
|
+
strokeDasharray: "5,4",
|
|
3097
|
+
vectorEffect: "non-scaling-stroke",
|
|
3098
|
+
...arrow ? { markerEnd: `url(#${MARKER_L})` } : {}
|
|
3099
|
+
}
|
|
3100
|
+
),
|
|
3101
|
+
right && /* @__PURE__ */ jsx(
|
|
3102
|
+
"path",
|
|
3103
|
+
{
|
|
3104
|
+
d: rightD,
|
|
3105
|
+
fill: "none",
|
|
3106
|
+
stroke: cr,
|
|
3107
|
+
strokeWidth: 1.5,
|
|
3108
|
+
strokeDasharray: "5,4",
|
|
3109
|
+
vectorEffect: "non-scaling-stroke",
|
|
3110
|
+
...arrow ? { markerEnd: `url(#${MARKER_R})` } : {}
|
|
3111
|
+
}
|
|
3112
|
+
)
|
|
3113
|
+
]
|
|
3114
|
+
}
|
|
3115
|
+
),
|
|
3116
|
+
children,
|
|
3117
|
+
animate && left && /* @__PURE__ */ jsx(
|
|
3118
|
+
"div",
|
|
3119
|
+
{
|
|
3120
|
+
"aria-hidden": true,
|
|
3121
|
+
style: { ...dotBase, backgroundColor: cl, animation: `fb-dl ${animateDur} ease-in-out 0s infinite` }
|
|
3122
|
+
}
|
|
3123
|
+
),
|
|
3124
|
+
animate && right && /* @__PURE__ */ jsx(
|
|
3125
|
+
"div",
|
|
3126
|
+
{
|
|
3127
|
+
"aria-hidden": true,
|
|
3128
|
+
style: { ...dotBase, backgroundColor: cr, animation: `fb-dr ${animateDur} ease-in-out 1.8s infinite` }
|
|
3129
|
+
}
|
|
3130
|
+
)
|
|
3131
|
+
] });
|
|
3132
|
+
}
|
|
2388
3133
|
function FullPageSpinner({ message }) {
|
|
2389
3134
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-4", children: [
|
|
2390
3135
|
/* @__PURE__ */ jsx(Spinner, { className: "size-8" }),
|
|
2391
3136
|
message && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: message })
|
|
2392
3137
|
] });
|
|
2393
3138
|
}
|
|
2394
|
-
var
|
|
3139
|
+
var defaultRenderLink10 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
2395
3140
|
function PageHeader({
|
|
2396
3141
|
title,
|
|
2397
3142
|
description,
|
|
2398
3143
|
breadcrumbs,
|
|
2399
3144
|
backButton,
|
|
2400
|
-
renderLink =
|
|
3145
|
+
renderLink = defaultRenderLink10,
|
|
2401
3146
|
className,
|
|
2402
3147
|
children
|
|
2403
3148
|
}) {
|
|
2404
3149
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1 pb-6", className), children: [
|
|
2405
3150
|
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) => {
|
|
2406
3151
|
const isLast = i === breadcrumbs.length - 1;
|
|
2407
|
-
return /* @__PURE__ */ jsxs(
|
|
3152
|
+
return /* @__PURE__ */ jsxs(React29.Fragment, { children: [
|
|
2408
3153
|
i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0" }),
|
|
2409
3154
|
isLast || !crumb.href ? /* @__PURE__ */ jsx("span", { className: cn(isLast && "text-foreground font-medium"), children: crumb.label }) : renderLink({
|
|
2410
3155
|
href: crumb.href,
|
|
@@ -2440,15 +3185,15 @@ function PageHeader({
|
|
|
2440
3185
|
] });
|
|
2441
3186
|
}
|
|
2442
3187
|
function Suspensed({ children, fallback }) {
|
|
2443
|
-
return /* @__PURE__ */ jsx(
|
|
3188
|
+
return /* @__PURE__ */ jsx(React29.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
|
|
3189
|
+
}
|
|
3190
|
+
function getInitialTheme() {
|
|
3191
|
+
if (typeof document === "undefined") return "dark";
|
|
3192
|
+
const stored = localStorage.getItem("theme");
|
|
3193
|
+
return stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
|
|
2444
3194
|
}
|
|
2445
3195
|
function ThemeSwitchMinimal() {
|
|
2446
|
-
const [theme, setThemeState] =
|
|
2447
|
-
React26.useEffect(() => {
|
|
2448
|
-
const stored = localStorage.getItem("theme");
|
|
2449
|
-
const resolved = stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
|
|
2450
|
-
setThemeState(resolved);
|
|
2451
|
-
}, []);
|
|
3196
|
+
const [theme, setThemeState] = React29.useState(getInitialTheme);
|
|
2452
3197
|
const toggle = () => {
|
|
2453
3198
|
const next = theme === "dark" ? "light" : "dark";
|
|
2454
3199
|
setThemeState(next);
|
|
@@ -2490,8 +3235,154 @@ function ModeSwitchMinimal() {
|
|
|
2490
3235
|
mode
|
|
2491
3236
|
) });
|
|
2492
3237
|
}
|
|
3238
|
+
var BRAND_COLORS = [
|
|
3239
|
+
{
|
|
3240
|
+
name: "zinc",
|
|
3241
|
+
label: "Zinc",
|
|
3242
|
+
css: `
|
|
3243
|
+
:root { --primary: oklch(0.205 0 0); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.708 0 0); }
|
|
3244
|
+
.dark { --primary: oklch(0.922 0 0); --primary-foreground: oklch(0.205 0 0); --ring: oklch(0.556 0 0); }
|
|
3245
|
+
`
|
|
3246
|
+
},
|
|
3247
|
+
{
|
|
3248
|
+
name: "blue",
|
|
3249
|
+
label: "Blue",
|
|
3250
|
+
css: `
|
|
3251
|
+
:root { --primary: oklch(0.546 0.245 262.881); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.546 0.245 262.881); }
|
|
3252
|
+
.dark { --primary: oklch(0.623 0.214 259.815); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.623 0.214 259.815); }
|
|
3253
|
+
`
|
|
3254
|
+
},
|
|
3255
|
+
{
|
|
3256
|
+
name: "emerald",
|
|
3257
|
+
label: "Emerald",
|
|
3258
|
+
css: `
|
|
3259
|
+
:root { --primary: oklch(0.596 0.145 163.225); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.596 0.145 163.225); }
|
|
3260
|
+
.dark { --primary: oklch(0.765 0.177 163.223); --primary-foreground: oklch(0.145 0 0); --ring: oklch(0.765 0.177 163.223); }
|
|
3261
|
+
`
|
|
3262
|
+
},
|
|
3263
|
+
{
|
|
3264
|
+
name: "purple",
|
|
3265
|
+
label: "Purple",
|
|
3266
|
+
css: `
|
|
3267
|
+
:root { --primary: oklch(0.558 0.288 302.321); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.558 0.288 302.321); }
|
|
3268
|
+
.dark { --primary: oklch(0.714 0.203 305.504); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.714 0.203 305.504); }
|
|
3269
|
+
`
|
|
3270
|
+
},
|
|
3271
|
+
{
|
|
3272
|
+
name: "rose",
|
|
3273
|
+
label: "Rose",
|
|
3274
|
+
css: `
|
|
3275
|
+
:root { --primary: oklch(0.645 0.246 16.439); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.645 0.246 16.439); }
|
|
3276
|
+
.dark { --primary: oklch(0.717 0.194 17.428); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.717 0.194 17.428); }
|
|
3277
|
+
`
|
|
3278
|
+
},
|
|
3279
|
+
{
|
|
3280
|
+
name: "orange",
|
|
3281
|
+
label: "Orange",
|
|
3282
|
+
css: `
|
|
3283
|
+
:root { --primary: oklch(0.705 0.213 47.604); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.705 0.213 47.604); }
|
|
3284
|
+
.dark { --primary: oklch(0.792 0.184 70.08); --primary-foreground: oklch(0.145 0 0); --ring: oklch(0.792 0.184 70.08); }
|
|
3285
|
+
`
|
|
3286
|
+
},
|
|
3287
|
+
{
|
|
3288
|
+
name: "slate",
|
|
3289
|
+
label: "Slate",
|
|
3290
|
+
css: `
|
|
3291
|
+
:root { --primary: oklch(0.446 0.043 257.281); --primary-foreground: oklch(0.985 0 0); --ring: oklch(0.446 0.043 257.281); }
|
|
3292
|
+
.dark { --primary: oklch(0.704 0.04 256.788); --primary-foreground: oklch(0.129 0.042 264.695); --ring: oklch(0.704 0.04 256.788); }
|
|
3293
|
+
`
|
|
3294
|
+
}
|
|
3295
|
+
];
|
|
3296
|
+
var PREVIEW_HEX = {
|
|
3297
|
+
zinc: "#27272a",
|
|
3298
|
+
blue: "#3b82f6",
|
|
3299
|
+
emerald: "#10b981",
|
|
3300
|
+
purple: "#a855f7",
|
|
3301
|
+
rose: "#f43f5e",
|
|
3302
|
+
orange: "#f97316",
|
|
3303
|
+
slate: "#64748b"
|
|
3304
|
+
};
|
|
3305
|
+
var STORAGE_KEY = "brand-color";
|
|
3306
|
+
var STYLE_ID = "brand-color-override";
|
|
3307
|
+
function applyColor(color) {
|
|
3308
|
+
let el = document.getElementById(STYLE_ID);
|
|
3309
|
+
if (!el) {
|
|
3310
|
+
el = document.createElement("style");
|
|
3311
|
+
el.id = STYLE_ID;
|
|
3312
|
+
document.head.appendChild(el);
|
|
3313
|
+
}
|
|
3314
|
+
el.textContent = color.css;
|
|
3315
|
+
localStorage.setItem(STORAGE_KEY, color.name);
|
|
3316
|
+
}
|
|
3317
|
+
function getInitialColorName() {
|
|
3318
|
+
if (typeof localStorage === "undefined") return "emerald";
|
|
3319
|
+
return localStorage.getItem(STORAGE_KEY) ?? "emerald";
|
|
3320
|
+
}
|
|
3321
|
+
function BrandColorSwitchMinimal() {
|
|
3322
|
+
const [active, setActive] = React29.useState(getInitialColorName);
|
|
3323
|
+
const [open, setOpen] = React29.useState(false);
|
|
3324
|
+
React29.useEffect(() => {
|
|
3325
|
+
const saved = localStorage.getItem(STORAGE_KEY) ?? "emerald";
|
|
3326
|
+
const color = BRAND_COLORS.find((c) => c.name === saved);
|
|
3327
|
+
if (color) applyColor(color);
|
|
3328
|
+
}, []);
|
|
3329
|
+
function select(color) {
|
|
3330
|
+
applyColor(color);
|
|
3331
|
+
setActive(color.name);
|
|
3332
|
+
setOpen(false);
|
|
3333
|
+
}
|
|
3334
|
+
const activeHex = PREVIEW_HEX[active] ?? "#27272a";
|
|
3335
|
+
return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
|
|
3336
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
3337
|
+
Button$1,
|
|
3338
|
+
{
|
|
3339
|
+
variant: "ghost",
|
|
3340
|
+
size: "icon",
|
|
3341
|
+
className: "size-8",
|
|
3342
|
+
"aria-label": "Change brand color",
|
|
3343
|
+
children: /* @__PURE__ */ jsxs("span", { className: "relative inline-flex size-4 items-center justify-center", children: [
|
|
3344
|
+
/* @__PURE__ */ jsx(Palette, { className: "size-4" }),
|
|
3345
|
+
/* @__PURE__ */ jsx(
|
|
3346
|
+
"span",
|
|
3347
|
+
{
|
|
3348
|
+
className: "absolute -bottom-0.5 -right-0.5 size-1.5 rounded-full ring-1 ring-background",
|
|
3349
|
+
style: { background: activeHex }
|
|
3350
|
+
}
|
|
3351
|
+
)
|
|
3352
|
+
] })
|
|
3353
|
+
}
|
|
3354
|
+
) }),
|
|
3355
|
+
/* @__PURE__ */ jsxs(PopoverContent, { className: "w-auto p-3", align: "end", children: [
|
|
3356
|
+
/* @__PURE__ */ jsx("p", { className: "mb-2.5 text-xs font-medium text-muted-foreground", children: "Brand color" }),
|
|
3357
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-4 gap-1.5", children: BRAND_COLORS.map((color) => /* @__PURE__ */ jsxs(
|
|
3358
|
+
"button",
|
|
3359
|
+
{
|
|
3360
|
+
type: "button",
|
|
3361
|
+
onClick: () => select(color),
|
|
3362
|
+
title: color.label,
|
|
3363
|
+
className: "group flex flex-col items-center gap-1",
|
|
3364
|
+
children: [
|
|
3365
|
+
/* @__PURE__ */ jsx(
|
|
3366
|
+
"span",
|
|
3367
|
+
{
|
|
3368
|
+
className: "flex size-7 items-center justify-center rounded-full ring-offset-background transition-all group-hover:scale-110",
|
|
3369
|
+
style: {
|
|
3370
|
+
background: PREVIEW_HEX[color.name],
|
|
3371
|
+
boxShadow: active === color.name ? `0 0 0 2px var(--background), 0 0 0 4px ${PREVIEW_HEX[color.name]}` : void 0
|
|
3372
|
+
},
|
|
3373
|
+
children: active === color.name && /* @__PURE__ */ jsx("svg", { className: "size-3 text-white", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", children: /* @__PURE__ */ jsx("path", { d: "M20 6L9 17l-5-5", strokeLinecap: "round", strokeLinejoin: "round" }) })
|
|
3374
|
+
}
|
|
3375
|
+
),
|
|
3376
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: color.label })
|
|
3377
|
+
]
|
|
3378
|
+
},
|
|
3379
|
+
color.name
|
|
3380
|
+
)) })
|
|
3381
|
+
] })
|
|
3382
|
+
] });
|
|
3383
|
+
}
|
|
2493
3384
|
function ThemeColorUpdater({ colorTheme }) {
|
|
2494
|
-
|
|
3385
|
+
React29.useEffect(() => {
|
|
2495
3386
|
if (colorTheme) {
|
|
2496
3387
|
document.documentElement.setAttribute("data-theme", colorTheme);
|
|
2497
3388
|
} else {
|
|
@@ -2501,7 +3392,7 @@ function ThemeColorUpdater({ colorTheme }) {
|
|
|
2501
3392
|
return null;
|
|
2502
3393
|
}
|
|
2503
3394
|
function VersionBanner({ version, message, className, onDismiss }) {
|
|
2504
|
-
const [dismissed, setDismissed] =
|
|
3395
|
+
const [dismissed, setDismissed] = React29.useState(false);
|
|
2505
3396
|
if (dismissed) return null;
|
|
2506
3397
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-4 bg-primary/10 px-4 py-2 text-sm", className), children: [
|
|
2507
3398
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -2541,7 +3432,7 @@ function DevBanner({ environment = "development", className }) {
|
|
|
2541
3432
|
);
|
|
2542
3433
|
}
|
|
2543
3434
|
function RegisterHotkeys({ hotkeys }) {
|
|
2544
|
-
|
|
3435
|
+
React29.useEffect(() => {
|
|
2545
3436
|
const handleKeyDown = (event) => {
|
|
2546
3437
|
for (const hotkey of hotkeys) {
|
|
2547
3438
|
const matches = event.key.toLowerCase() === hotkey.key.toLowerCase() && !!event.ctrlKey === !!hotkey.ctrl && !!event.metaKey === !!hotkey.meta && !!event.shiftKey === !!hotkey.shift && !!event.altKey === !!hotkey.alt;
|
|
@@ -2600,6 +3491,16 @@ function PostList({ posts, renderLink, emptyMessage = "No posts published yet."
|
|
|
2600
3491
|
}
|
|
2601
3492
|
return /* @__PURE__ */ jsx("div", { className: "grid gap-8 sm:grid-cols-2", children: posts.map((post) => /* @__PURE__ */ jsx(PostCard, { ...post, renderLink }, post.slug)) });
|
|
2602
3493
|
}
|
|
3494
|
+
var releaseTypeLabel = {
|
|
3495
|
+
release: "Major Release",
|
|
3496
|
+
fix: "Fix",
|
|
3497
|
+
enhancement: "Enhancement"
|
|
3498
|
+
};
|
|
3499
|
+
var releaseTypeVariant = {
|
|
3500
|
+
release: "default",
|
|
3501
|
+
fix: "outline",
|
|
3502
|
+
enhancement: "secondary"
|
|
3503
|
+
};
|
|
2603
3504
|
function formatDate2(dateStr) {
|
|
2604
3505
|
return new Date(dateStr).toLocaleDateString("en-US", {
|
|
2605
3506
|
year: "numeric",
|
|
@@ -2613,6 +3514,8 @@ function ChangelogCard({
|
|
|
2613
3514
|
date,
|
|
2614
3515
|
slug,
|
|
2615
3516
|
version,
|
|
3517
|
+
releaseType,
|
|
3518
|
+
highlights,
|
|
2616
3519
|
hrefPrefix = "/changelog",
|
|
2617
3520
|
renderLink
|
|
2618
3521
|
}) {
|
|
@@ -2621,18 +3524,44 @@ function ChangelogCard({
|
|
|
2621
3524
|
children,
|
|
2622
3525
|
className
|
|
2623
3526
|
}) => renderLink ? renderLink({ href, children, className }) : /* @__PURE__ */ jsx("a", { href, className, children });
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
3527
|
+
const hasHighlights = highlights && highlights.length > 0;
|
|
3528
|
+
return /* @__PURE__ */ jsxs(
|
|
3529
|
+
"article",
|
|
3530
|
+
{
|
|
3531
|
+
className: cn$1(
|
|
3532
|
+
"flex flex-col gap-5 rounded-2xl border border-border bg-card p-6 sm:p-8",
|
|
3533
|
+
!hasHighlights && "border-b border-border/60 rounded-none bg-transparent p-0 pb-8 last:pb-0 last:border-0"
|
|
3534
|
+
),
|
|
3535
|
+
children: [
|
|
3536
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
|
|
3537
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
3538
|
+
/* @__PURE__ */ jsx("time", { className: "text-sm text-muted-foreground", dateTime: date, children: formatDate2(date) }),
|
|
3539
|
+
version && /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "font-mono text-xs", children: version }),
|
|
3540
|
+
releaseType && /* @__PURE__ */ jsx(Badge$1, { variant: releaseTypeVariant[releaseType], className: "text-xs", children: releaseTypeLabel[releaseType] })
|
|
3541
|
+
] }),
|
|
3542
|
+
/* @__PURE__ */ jsxs(LinkWrapper, { className: "inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline", children: [
|
|
3543
|
+
"Read update",
|
|
3544
|
+
/* @__PURE__ */ jsx(ArrowRight, { className: "size-3.5" })
|
|
3545
|
+
] })
|
|
3546
|
+
] }),
|
|
3547
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3548
|
+
/* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold leading-snug tracking-tight", children: /* @__PURE__ */ jsx(LinkWrapper, { className: "transition-colors hover:text-primary", children: title }) }),
|
|
3549
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm leading-relaxed text-muted-foreground", children: summary })
|
|
3550
|
+
] }),
|
|
3551
|
+
hasHighlights && /* @__PURE__ */ jsx("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: highlights.map((h) => /* @__PURE__ */ jsxs(
|
|
3552
|
+
"div",
|
|
3553
|
+
{
|
|
3554
|
+
className: "rounded-xl border border-border/70 bg-background p-4",
|
|
3555
|
+
children: [
|
|
3556
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold leading-snug", children: h.title }),
|
|
3557
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: h.description })
|
|
3558
|
+
]
|
|
3559
|
+
},
|
|
3560
|
+
h.title
|
|
3561
|
+
)) })
|
|
3562
|
+
]
|
|
3563
|
+
}
|
|
3564
|
+
);
|
|
2636
3565
|
}
|
|
2637
3566
|
function ChangelogList({
|
|
2638
3567
|
entries,
|
|
@@ -2661,36 +3590,36 @@ function useMounted() {
|
|
|
2661
3590
|
return mounted;
|
|
2662
3591
|
}
|
|
2663
3592
|
function useConfirm() {
|
|
2664
|
-
const [isOpen, setIsOpen] =
|
|
2665
|
-
const [options, setOptions] =
|
|
2666
|
-
const resolveRef =
|
|
2667
|
-
const confirm =
|
|
3593
|
+
const [isOpen, setIsOpen] = React29.useState(false);
|
|
3594
|
+
const [options, setOptions] = React29.useState({});
|
|
3595
|
+
const resolveRef = React29.useRef(null);
|
|
3596
|
+
const confirm = React29.useCallback((opts = {}) => {
|
|
2668
3597
|
setOptions(opts);
|
|
2669
3598
|
setIsOpen(true);
|
|
2670
3599
|
return new Promise((resolve) => {
|
|
2671
3600
|
resolveRef.current = resolve;
|
|
2672
3601
|
});
|
|
2673
3602
|
}, []);
|
|
2674
|
-
const handleConfirm =
|
|
3603
|
+
const handleConfirm = React29.useCallback(() => {
|
|
2675
3604
|
resolveRef.current?.(true);
|
|
2676
3605
|
setIsOpen(false);
|
|
2677
3606
|
}, []);
|
|
2678
|
-
const handleCancel =
|
|
3607
|
+
const handleCancel = React29.useCallback(() => {
|
|
2679
3608
|
resolveRef.current?.(false);
|
|
2680
3609
|
setIsOpen(false);
|
|
2681
3610
|
}, []);
|
|
2682
3611
|
return { confirm, isOpen, options, handleConfirm, handleCancel };
|
|
2683
3612
|
}
|
|
2684
3613
|
function useControlledOpen(defaultOpen = false) {
|
|
2685
|
-
const [isOpen, setIsOpen] =
|
|
2686
|
-
const open =
|
|
2687
|
-
const close =
|
|
2688
|
-
const toggle =
|
|
3614
|
+
const [isOpen, setIsOpen] = React29.useState(defaultOpen);
|
|
3615
|
+
const open = React29.useCallback(() => setIsOpen(true), []);
|
|
3616
|
+
const close = React29.useCallback(() => setIsOpen(false), []);
|
|
3617
|
+
const toggle = React29.useCallback(() => setIsOpen((prev) => !prev), []);
|
|
2689
3618
|
return { isOpen, open, close, toggle, setIsOpen };
|
|
2690
3619
|
}
|
|
2691
3620
|
function useScrolledPast(threshold) {
|
|
2692
|
-
const [scrolledPast, setScrolledPast] =
|
|
2693
|
-
|
|
3621
|
+
const [scrolledPast, setScrolledPast] = React29.useState(false);
|
|
3622
|
+
React29.useEffect(() => {
|
|
2694
3623
|
const handleScroll = () => {
|
|
2695
3624
|
setScrolledPast(window.scrollY > threshold);
|
|
2696
3625
|
};
|
|
@@ -2701,30 +3630,30 @@ function useScrolledPast(threshold) {
|
|
|
2701
3630
|
return scrolledPast;
|
|
2702
3631
|
}
|
|
2703
3632
|
function useCopyToClipboard() {
|
|
2704
|
-
const [copied, setCopied] =
|
|
2705
|
-
const timeoutRef =
|
|
2706
|
-
const copy =
|
|
3633
|
+
const [copied, setCopied] = React29.useState(false);
|
|
3634
|
+
const timeoutRef = React29.useRef(void 0);
|
|
3635
|
+
const copy = React29.useCallback((text) => {
|
|
2707
3636
|
navigator.clipboard.writeText(text).then(() => {
|
|
2708
3637
|
setCopied(true);
|
|
2709
3638
|
clearTimeout(timeoutRef.current);
|
|
2710
3639
|
timeoutRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
2711
3640
|
});
|
|
2712
3641
|
}, []);
|
|
2713
|
-
|
|
3642
|
+
React29.useEffect(() => () => clearTimeout(timeoutRef.current), []);
|
|
2714
3643
|
return [copied, copy];
|
|
2715
3644
|
}
|
|
2716
3645
|
function useDebounce(value, delay) {
|
|
2717
|
-
const [debounced, setDebounced] =
|
|
2718
|
-
|
|
3646
|
+
const [debounced, setDebounced] = React29.useState(value);
|
|
3647
|
+
React29.useEffect(() => {
|
|
2719
3648
|
const timer = setTimeout(() => setDebounced(value), delay);
|
|
2720
3649
|
return () => clearTimeout(timer);
|
|
2721
3650
|
}, [value, delay]);
|
|
2722
3651
|
return debounced;
|
|
2723
3652
|
}
|
|
2724
3653
|
function useIntersectionObserver(options) {
|
|
2725
|
-
const ref =
|
|
2726
|
-
const [isIntersecting, setIsIntersecting] =
|
|
2727
|
-
|
|
3654
|
+
const ref = React29.useRef(null);
|
|
3655
|
+
const [isIntersecting, setIsIntersecting] = React29.useState(false);
|
|
3656
|
+
React29.useEffect(() => {
|
|
2728
3657
|
const el = ref.current;
|
|
2729
3658
|
if (!el) return;
|
|
2730
3659
|
const observer = new IntersectionObserver(([entry]) => {
|
|
@@ -2736,7 +3665,7 @@ function useIntersectionObserver(options) {
|
|
|
2736
3665
|
return [ref, isIntersecting];
|
|
2737
3666
|
}
|
|
2738
3667
|
function useLocalStorage(key, initialValue) {
|
|
2739
|
-
const [storedValue, setStoredValue] =
|
|
3668
|
+
const [storedValue, setStoredValue] = React29.useState(() => {
|
|
2740
3669
|
if (typeof window === "undefined") return initialValue;
|
|
2741
3670
|
try {
|
|
2742
3671
|
const item = window.localStorage.getItem(key);
|
|
@@ -2745,7 +3674,7 @@ function useLocalStorage(key, initialValue) {
|
|
|
2745
3674
|
return initialValue;
|
|
2746
3675
|
}
|
|
2747
3676
|
});
|
|
2748
|
-
const setValue =
|
|
3677
|
+
const setValue = React29.useCallback(
|
|
2749
3678
|
(value) => {
|
|
2750
3679
|
try {
|
|
2751
3680
|
setStoredValue(value);
|
|
@@ -2760,11 +3689,11 @@ function useLocalStorage(key, initialValue) {
|
|
|
2760
3689
|
return [storedValue, setValue];
|
|
2761
3690
|
}
|
|
2762
3691
|
function useMediaQuery(query) {
|
|
2763
|
-
const [matches, setMatches] =
|
|
3692
|
+
const [matches, setMatches] = React29.useState(() => {
|
|
2764
3693
|
if (typeof window === "undefined") return false;
|
|
2765
3694
|
return window.matchMedia(query).matches;
|
|
2766
3695
|
});
|
|
2767
|
-
|
|
3696
|
+
React29.useEffect(() => {
|
|
2768
3697
|
if (typeof window === "undefined") return;
|
|
2769
3698
|
const mql = window.matchMedia(query);
|
|
2770
3699
|
setMatches(mql.matches);
|
|
@@ -2775,18 +3704,18 @@ function useMediaQuery(query) {
|
|
|
2775
3704
|
return matches;
|
|
2776
3705
|
}
|
|
2777
3706
|
function usePagination(total, pageSize) {
|
|
2778
|
-
const [page, setPage] =
|
|
3707
|
+
const [page, setPage] = React29.useState(1);
|
|
2779
3708
|
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
2780
3709
|
const offset = (page - 1) * pageSize;
|
|
2781
|
-
const goTo =
|
|
3710
|
+
const goTo = React29.useCallback(
|
|
2782
3711
|
(p) => setPage(Math.min(Math.max(1, p), totalPages)),
|
|
2783
3712
|
[totalPages]
|
|
2784
3713
|
);
|
|
2785
|
-
const next =
|
|
2786
|
-
const prev =
|
|
3714
|
+
const next = React29.useCallback(() => goTo(page + 1), [page, goTo]);
|
|
3715
|
+
const prev = React29.useCallback(() => goTo(page - 1), [page, goTo]);
|
|
2787
3716
|
return { page, pageSize, totalPages, offset, hasPrev: page > 1, hasNext: page < totalPages, goTo, next, prev };
|
|
2788
3717
|
}
|
|
2789
3718
|
|
|
2790
|
-
export { AppContent, AppGrid, AppGridCell, AppScreen, AppShell, AuthSection, Badge, Button, Card, CarouselSection, ChangelogCard, ChangelogList, Checkbox, ConfirmDialog, ContactSection, ContextMenu, CountUp, CtaSection, DevBanner, Dock, EmptyState, ErrorPage, FadeIn, FaqSection, FeatureCard, FeaturesSection, Footer, FullPageSpinner, GlassCard, Grid, GridItem, HeroSection, ImageCard, Input, LogoStrip, ModeSwitchMinimal, Navbar, NewsletterSection, OlwibaUIProvider, Overlay, PageHeader, PageTransition, PhoneFrame, PostCard, PostList, PricingCard, PricingSection, PublicPageFrame, RegisterHotkeys, RootErrorFallback, Section, SectionTitle, Spotlight, Stack, StaggerChildren, StatCard, StatsSection, Suspensed, Switch, TeamSection, TestimonialCard, TestimonialsSection, Textarea, ThemeColorUpdater, ThemeSwitchMinimal, Underlay, UpgradePrompt, VersionBanner, useConfirm, useControlledOpen, useCopyToClipboard, useDebounce, useIntersectionObserver, useLocalStorage, useMediaQuery, useMounted, useOlwibaUI, usePagination, useScrolledPast, useUIMode };
|
|
3719
|
+
export { AnimatedPill, AppContent, AppGrid, AppGridCell, AppScreen, AppShell, AuthSection, Badge, BrandColorSwitchMinimal, Button, Card, CarouselSection, ChangelogCard, ChangelogList, Checkbox, ComparisonSection, ConfirmDialog, ContactSection, ContextMenu, CountUp, CountdownTimer, CtaCardSection, CtaSection, DevBanner, Dock, EmptyState, ErrorPage, FadeIn, FaqSection, FeatureCard, FeatureMarqueeSection, FeaturesSection, FlowBracket, FlowConnector, Footer, FullPageSpinner, GlassCard, Grid, GridItem, GroupedFeaturesSection, HeroSection, ImageCard, Input, LogoStrip, ModeSwitchMinimal, Navbar, NewsletterSection, OlwibaUIProvider, Overlay, PageHeader, PageTransition, PhoneFrame, PostCard, PostList, PricingCard, PricingSection, PublicPageFrame, QualificationSection, RegisterHotkeys, RootErrorFallback, Section, SectionTitle, Spotlight, Stack, StaggerChildren, StatCard, StatsSection, StepsSection, Suspensed, Switch, TeamSection, TechStackSection, TestimonialCard, TestimonialsSection, Textarea, ThemeColorUpdater, ThemeSwitchMinimal, Underlay, UpgradePrompt, VersionBanner, useConfirm, useControlledOpen, useCopyToClipboard, useDebounce, useIntersectionObserver, useLocalStorage, useMediaQuery, useMounted, useOlwibaUI, usePagination, useScrolledPast, useUIMode };
|
|
2791
3720
|
//# sourceMappingURL=index.js.map
|
|
2792
3721
|
//# sourceMappingURL=index.js.map
|