@olwiba/ui 0.1.2 → 0.1.4
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 +18 -1
- package/dist/index.js +307 -103
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/components/FeatureCard.tsx +32 -7
- package/src/components/PricingCard.tsx +29 -5
- package/src/components/TestimonialCard.tsx +30 -6
- package/src/index.ts +1 -0
- package/src/marketing/CarouselSection.tsx +126 -0
- package/src/marketing/CtaSection.tsx +10 -3
- package/src/marketing/FaqSection.tsx +9 -2
- package/src/marketing/FeaturesSection.tsx +9 -1
- package/src/marketing/PricingSection.tsx +17 -6
- package/src/marketing/StatsSection.tsx +9 -2
- package/src/marketing/TestimonialsSection.tsx +9 -1
- package/src/motion/StaggerChildren.tsx +1 -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
|
|
3
|
+
import * as React26 from 'react';
|
|
4
4
|
import { useState, useEffect } from 'react';
|
|
5
|
-
import { Button as Button$1, Card as Card$1, Input as Input$1, Textarea as Textarea$1, Checkbox as Checkbox$1, Switch as Switch$1, useIsMobile, UIVariantProvider, Badge as Badge$1, cn as cn$1, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Avatar, AvatarImage, AvatarFallback, Separator, Accordion, AccordionItem, AccordionTrigger, AccordionContent, Label, Sheet, SheetTrigger, SheetContent, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandSeparator, CommandGroup, CommandItem, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, ContextMenu as ContextMenu$1, ContextMenuTrigger, ContextMenuContent, AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, Spinner, SidebarProvider, SidebarInset, CardHeader, CardTitle, CardDescription, CardContent, ContextMenuSeparator, ContextMenuLabel, ContextMenuSub, ContextMenuSubTrigger, ContextMenuSubContent, ContextMenuItem, ContextMenuShortcut, Sidebar, SidebarHeader, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarFooter, SidebarTrigger, useSidebar, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuGroup, DropdownMenuItem } from '@olwiba/cn';
|
|
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';
|
|
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, Sparkles, Check, Minus, Quote, Star, Twitter, Github, Linkedin, Mail, Phone, MapPin, MessageSquare, Send, Menu, Search, TrendingUp, TrendingDown,
|
|
8
|
+
import { Compass, ArrowLeft, X, ArrowRight, ChevronLeft, ChevronRight, Sparkles, Check, Minus, Quote, Star, Twitter, Github, Linkedin, Mail, Phone, MapPin, MessageSquare, Send, Menu, Search, TrendingUp, TrendingDown, Sun, Moon, AlertTriangle, Loader2, Layers, LayoutGrid, ShieldCheck, Building2, MoreVerticalIcon, CreditCardIcon, BellIcon, LogOutIcon } from 'lucide-react';
|
|
9
9
|
|
|
10
|
-
var OlwibaUIContext =
|
|
10
|
+
var OlwibaUIContext = React26.createContext({
|
|
11
11
|
isMobile: false,
|
|
12
12
|
mode: "default",
|
|
13
13
|
setMode: () => {
|
|
@@ -16,17 +16,17 @@ var OlwibaUIContext = React25.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] = React26.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 React26.useContext(OlwibaUIContext);
|
|
25
25
|
}
|
|
26
26
|
function useUIMode() {
|
|
27
|
-
return
|
|
27
|
+
return React26.useContext(OlwibaUIContext).mode;
|
|
28
28
|
}
|
|
29
|
-
var Button =
|
|
29
|
+
var Button = React26.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 = React25.forwardRef(
|
|
|
34
34
|
}
|
|
35
35
|
);
|
|
36
36
|
Button.displayName = "Button";
|
|
37
|
-
var Card =
|
|
37
|
+
var Card = React26.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 = React26.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 = React25.forwardRef(
|
|
|
53
53
|
}
|
|
54
54
|
);
|
|
55
55
|
Input.displayName = "Input";
|
|
56
|
-
var Textarea =
|
|
56
|
+
var Textarea = React26.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 = React25.forwardRef(
|
|
|
61
61
|
}
|
|
62
62
|
);
|
|
63
63
|
Textarea.displayName = "Textarea";
|
|
64
|
-
var Checkbox =
|
|
64
|
+
var Checkbox = React26.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 = React26.forwardRef(({ mode: _mode, ...props }, ref) => {
|
|
71
71
|
return /* @__PURE__ */ jsx(Switch$1, { ...props, ref });
|
|
72
72
|
});
|
|
73
73
|
Switch.displayName = "Switch";
|
|
@@ -757,9 +757,9 @@ function FadeIn({
|
|
|
757
757
|
style,
|
|
758
758
|
...props
|
|
759
759
|
}) {
|
|
760
|
-
const ref =
|
|
761
|
-
const [visible, setVisible] =
|
|
762
|
-
|
|
760
|
+
const ref = React26.useRef(null);
|
|
761
|
+
const [visible, setVisible] = React26.useState(false);
|
|
762
|
+
React26.useEffect(() => {
|
|
763
763
|
const el = ref.current;
|
|
764
764
|
if (!el) return;
|
|
765
765
|
const observer = new IntersectionObserver(
|
|
@@ -892,17 +892,28 @@ function HeroSection({
|
|
|
892
892
|
] }) });
|
|
893
893
|
}
|
|
894
894
|
function FeatureCard({ icon: Icon, title, description, href, className, ...props }) {
|
|
895
|
-
const
|
|
895
|
+
const mode = useUIVariant();
|
|
896
|
+
const cardInner = /* @__PURE__ */ jsxs(
|
|
896
897
|
"div",
|
|
897
898
|
{
|
|
898
899
|
className: cn$1(
|
|
899
|
-
"group relative flex flex-col gap-4
|
|
900
|
+
"group relative flex h-full flex-col gap-4 border bg-card p-6 transition-all duration-200",
|
|
901
|
+
mode === "playful" ? "rounded-2xl rotate-[0.3deg]" : mode === "smooth" ? "rounded-3xl hover:-translate-y-0.5 hover:shadow-md" : "rounded-2xl hover:-translate-y-0.5 hover:shadow-md",
|
|
900
902
|
href && "cursor-pointer",
|
|
901
|
-
className
|
|
903
|
+
mode !== "playful" && className
|
|
902
904
|
),
|
|
903
|
-
...props,
|
|
905
|
+
...mode !== "playful" ? props : {},
|
|
904
906
|
children: [
|
|
905
|
-
/* @__PURE__ */ jsx(
|
|
907
|
+
/* @__PURE__ */ jsx(
|
|
908
|
+
"div",
|
|
909
|
+
{
|
|
910
|
+
className: cn$1(
|
|
911
|
+
"flex h-10 w-10 items-center justify-center bg-primary/10 text-primary transition-colors group-hover:bg-primary group-hover:text-primary-foreground",
|
|
912
|
+
mode === "smooth" ? "rounded-2xl" : "rounded-xl"
|
|
913
|
+
),
|
|
914
|
+
children: /* @__PURE__ */ jsx(Icon, { className: "size-5" })
|
|
915
|
+
}
|
|
916
|
+
),
|
|
906
917
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
907
918
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
908
919
|
/* @__PURE__ */ jsx("h3", { className: "font-semibold leading-tight", children: title }),
|
|
@@ -913,8 +924,18 @@ function FeatureCard({ icon: Icon, title, description, href, className, ...props
|
|
|
913
924
|
]
|
|
914
925
|
}
|
|
915
926
|
);
|
|
927
|
+
const content = mode === "playful" ? /* @__PURE__ */ jsxs("div", { className: cn$1("group/playful relative h-full", className), ...props, children: [
|
|
928
|
+
/* @__PURE__ */ jsx(
|
|
929
|
+
"div",
|
|
930
|
+
{
|
|
931
|
+
"aria-hidden": "true",
|
|
932
|
+
className: "absolute inset-0 rounded-2xl bg-border transition-transform duration-200 translate-x-[5px] translate-y-[5px] -rotate-[0.5deg] group-hover/playful:-rotate-[1.5deg] group-hover/playful:translate-x-[6px] group-hover/playful:translate-y-[6px]"
|
|
933
|
+
}
|
|
934
|
+
),
|
|
935
|
+
cardInner
|
|
936
|
+
] }) : cardInner;
|
|
916
937
|
if (href) {
|
|
917
|
-
return /* @__PURE__ */ jsx("a", { href, className: "block", children: content });
|
|
938
|
+
return /* @__PURE__ */ jsx("a", { href, className: "block h-full", children: content });
|
|
918
939
|
}
|
|
919
940
|
return content;
|
|
920
941
|
}
|
|
@@ -935,9 +956,9 @@ function StaggerChildren({
|
|
|
935
956
|
className,
|
|
936
957
|
...props
|
|
937
958
|
}) {
|
|
938
|
-
const ref =
|
|
939
|
-
const [visible, setVisible] =
|
|
940
|
-
|
|
959
|
+
const ref = React26.useRef(null);
|
|
960
|
+
const [visible, setVisible] = React26.useState(false);
|
|
961
|
+
React26.useEffect(() => {
|
|
941
962
|
const el = ref.current;
|
|
942
963
|
if (!el) return;
|
|
943
964
|
const observer = new IntersectionObserver(
|
|
@@ -955,9 +976,10 @@ function StaggerChildren({
|
|
|
955
976
|
return () => observer.disconnect();
|
|
956
977
|
}, [once]);
|
|
957
978
|
const [tx, ty] = translateMap2[direction];
|
|
958
|
-
return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children:
|
|
979
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cn$1(className), ...props, children: React26.Children.map(children, (child, i) => /* @__PURE__ */ jsx(
|
|
959
980
|
"div",
|
|
960
981
|
{
|
|
982
|
+
className: "h-full",
|
|
961
983
|
style: {
|
|
962
984
|
transition: `opacity ${duration}ms ease, transform ${duration}ms ease`,
|
|
963
985
|
transitionDelay: `${delay + i * stagger}ms`,
|
|
@@ -974,7 +996,14 @@ function FeaturesSection({
|
|
|
974
996
|
badge = "Features",
|
|
975
997
|
features
|
|
976
998
|
}) {
|
|
977
|
-
|
|
999
|
+
const mode = useUIVariant();
|
|
1000
|
+
const sectionClasses = cn$1(
|
|
1001
|
+
"overflow-hidden bg-card",
|
|
1002
|
+
mode === "smooth" && "rounded-3xl border",
|
|
1003
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1004
|
+
!mode && "rounded-2xl border"
|
|
1005
|
+
);
|
|
1006
|
+
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: [
|
|
978
1007
|
/* @__PURE__ */ jsx(SectionTitle, { title, description, badge }),
|
|
979
1008
|
/* @__PURE__ */ jsx(StaggerChildren, { className: "mt-12 grid gap-8 sm:grid-cols-2 lg:grid-cols-3", children: features.map((feature) => /* @__PURE__ */ jsx(
|
|
980
1009
|
FeatureCard,
|
|
@@ -988,6 +1017,106 @@ function FeaturesSection({
|
|
|
988
1017
|
)) })
|
|
989
1018
|
] }) }) });
|
|
990
1019
|
}
|
|
1020
|
+
function CarouselSection({
|
|
1021
|
+
title = "Explore the platform",
|
|
1022
|
+
description,
|
|
1023
|
+
badge = "Features",
|
|
1024
|
+
features
|
|
1025
|
+
}) {
|
|
1026
|
+
const mode = useUIVariant();
|
|
1027
|
+
const trackRef = React26.useRef(null);
|
|
1028
|
+
const [canPrev, setCanPrev] = React26.useState(false);
|
|
1029
|
+
const [canNext, setCanNext] = React26.useState(true);
|
|
1030
|
+
const updateScrollState = React26.useCallback(() => {
|
|
1031
|
+
const track = trackRef.current;
|
|
1032
|
+
if (!track) return;
|
|
1033
|
+
setCanPrev(track.scrollLeft > 8);
|
|
1034
|
+
setCanNext(track.scrollLeft < track.scrollWidth - track.clientWidth - 8);
|
|
1035
|
+
}, []);
|
|
1036
|
+
React26.useEffect(() => {
|
|
1037
|
+
const track = trackRef.current;
|
|
1038
|
+
if (!track) return;
|
|
1039
|
+
updateScrollState();
|
|
1040
|
+
track.addEventListener("scroll", updateScrollState, { passive: true });
|
|
1041
|
+
const observer = new ResizeObserver(updateScrollState);
|
|
1042
|
+
observer.observe(track);
|
|
1043
|
+
return () => {
|
|
1044
|
+
track.removeEventListener("scroll", updateScrollState);
|
|
1045
|
+
observer.disconnect();
|
|
1046
|
+
};
|
|
1047
|
+
}, [updateScrollState]);
|
|
1048
|
+
const scrollByCard = (direction) => {
|
|
1049
|
+
const track = trackRef.current;
|
|
1050
|
+
if (!track) return;
|
|
1051
|
+
const card = track.querySelector("[data-carousel-item]");
|
|
1052
|
+
const step = card ? card.offsetWidth + 24 : track.clientWidth * 0.8;
|
|
1053
|
+
track.scrollBy({ left: direction * step, behavior: "smooth" });
|
|
1054
|
+
};
|
|
1055
|
+
const sectionClasses = cn$1(
|
|
1056
|
+
"overflow-hidden bg-card",
|
|
1057
|
+
mode === "smooth" && "rounded-3xl border",
|
|
1058
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1059
|
+
!mode && "rounded-2xl border"
|
|
1060
|
+
);
|
|
1061
|
+
const controlClasses = cn$1(
|
|
1062
|
+
"flex size-9 items-center justify-center border bg-background text-foreground transition-colors",
|
|
1063
|
+
"hover:bg-muted disabled:opacity-40 disabled:hover:bg-background",
|
|
1064
|
+
mode === "smooth" ? "rounded-2xl" : "rounded-xl"
|
|
1065
|
+
);
|
|
1066
|
+
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: [
|
|
1067
|
+
/* @__PURE__ */ jsx(SectionTitle, { title, description, badge }),
|
|
1068
|
+
/* @__PURE__ */ jsxs(FadeIn, { direction: "up", children: [
|
|
1069
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-10 flex items-center justify-end gap-2", children: [
|
|
1070
|
+
/* @__PURE__ */ jsx(
|
|
1071
|
+
"button",
|
|
1072
|
+
{
|
|
1073
|
+
type: "button",
|
|
1074
|
+
"aria-label": "Previous",
|
|
1075
|
+
className: controlClasses,
|
|
1076
|
+
onClick: () => scrollByCard(-1),
|
|
1077
|
+
disabled: !canPrev,
|
|
1078
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" })
|
|
1079
|
+
}
|
|
1080
|
+
),
|
|
1081
|
+
/* @__PURE__ */ jsx(
|
|
1082
|
+
"button",
|
|
1083
|
+
{
|
|
1084
|
+
type: "button",
|
|
1085
|
+
"aria-label": "Next",
|
|
1086
|
+
className: controlClasses,
|
|
1087
|
+
onClick: () => scrollByCard(1),
|
|
1088
|
+
disabled: !canNext,
|
|
1089
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" })
|
|
1090
|
+
}
|
|
1091
|
+
)
|
|
1092
|
+
] }),
|
|
1093
|
+
/* @__PURE__ */ jsx(
|
|
1094
|
+
"div",
|
|
1095
|
+
{
|
|
1096
|
+
ref: trackRef,
|
|
1097
|
+
className: "mt-4 flex snap-x snap-mandatory gap-6 overflow-x-auto pb-4 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
1098
|
+
children: features.map((feature) => /* @__PURE__ */ jsx(
|
|
1099
|
+
"div",
|
|
1100
|
+
{
|
|
1101
|
+
"data-carousel-item": true,
|
|
1102
|
+
className: "w-[280px] shrink-0 snap-start sm:w-[320px]",
|
|
1103
|
+
children: /* @__PURE__ */ jsx(
|
|
1104
|
+
FeatureCard,
|
|
1105
|
+
{
|
|
1106
|
+
icon: feature.icon,
|
|
1107
|
+
title: feature.title,
|
|
1108
|
+
description: feature.description,
|
|
1109
|
+
href: feature.href
|
|
1110
|
+
}
|
|
1111
|
+
)
|
|
1112
|
+
},
|
|
1113
|
+
feature.title
|
|
1114
|
+
))
|
|
1115
|
+
}
|
|
1116
|
+
)
|
|
1117
|
+
] })
|
|
1118
|
+
] }) }) });
|
|
1119
|
+
}
|
|
991
1120
|
var defaultRenderLink5 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
992
1121
|
function CtaSection({
|
|
993
1122
|
heading,
|
|
@@ -997,10 +1126,17 @@ function CtaSection({
|
|
|
997
1126
|
footnote,
|
|
998
1127
|
renderLink = defaultRenderLink5
|
|
999
1128
|
}) {
|
|
1000
|
-
|
|
1129
|
+
const mode = useUIVariant();
|
|
1130
|
+
const sectionClasses = cn$1(
|
|
1131
|
+
"overflow-hidden bg-card",
|
|
1132
|
+
mode === "smooth" && "rounded-3xl border",
|
|
1133
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1134
|
+
!mode && "rounded-2xl border"
|
|
1135
|
+
);
|
|
1136
|
+
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsxs("div", { className: "relative px-6 py-16 sm:px-10 sm:py-24", children: [
|
|
1001
1137
|
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(ellipse_at_center,hsl(var(--primary)/0.15),transparent_70%)]" }),
|
|
1002
1138
|
/* @__PURE__ */ jsx(FadeIn, { direction: "up", children: /* @__PURE__ */ jsxs("div", { className: "relative mx-auto max-w-2xl text-center", children: [
|
|
1003
|
-
/* @__PURE__ */ jsx("div", { className: "mb-4 inline-flex h-10 w-10 items-center justify-center
|
|
1139
|
+
/* @__PURE__ */ jsx("div", { className: cn$1("mb-4 inline-flex h-10 w-10 items-center justify-center bg-primary/10 text-primary", mode === "smooth" ? "rounded-3xl" : "rounded-2xl"), children: /* @__PURE__ */ jsx(Sparkles, { className: "size-5" }) }),
|
|
1004
1140
|
/* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: heading }),
|
|
1005
1141
|
/* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-lg text-pretty text-muted-foreground", children: description }),
|
|
1006
1142
|
/* @__PURE__ */ jsxs("div", { className: "mt-8 flex flex-wrap items-center justify-center gap-3", children: [
|
|
@@ -1033,15 +1169,17 @@ function PricingCard({
|
|
|
1033
1169
|
className,
|
|
1034
1170
|
...props
|
|
1035
1171
|
}) {
|
|
1036
|
-
|
|
1172
|
+
const mode = useUIVariant();
|
|
1173
|
+
const cardInner = /* @__PURE__ */ jsxs(
|
|
1037
1174
|
"div",
|
|
1038
1175
|
{
|
|
1039
1176
|
className: cn$1(
|
|
1040
|
-
"relative flex flex-col
|
|
1177
|
+
"relative flex flex-col border p-6",
|
|
1178
|
+
mode === "playful" ? "rounded-2xl rotate-[0.3deg]" : mode === "smooth" ? "rounded-3xl" : "rounded-2xl",
|
|
1041
1179
|
highlighted ? "border-primary bg-primary/5 shadow-sm" : "bg-card",
|
|
1042
|
-
className
|
|
1180
|
+
mode !== "playful" && className
|
|
1043
1181
|
),
|
|
1044
|
-
...props,
|
|
1182
|
+
...mode !== "playful" ? props : {},
|
|
1045
1183
|
children: [
|
|
1046
1184
|
badge && /* @__PURE__ */ jsx("div", { className: "absolute -top-3 left-1/2 -translate-x-1/2", children: /* @__PURE__ */ jsx(Badge$1, { children: badge }) }),
|
|
1047
1185
|
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
@@ -1072,6 +1210,22 @@ function PricingCard({
|
|
|
1072
1210
|
]
|
|
1073
1211
|
}
|
|
1074
1212
|
);
|
|
1213
|
+
if (mode === "playful") {
|
|
1214
|
+
return /* @__PURE__ */ jsxs("div", { className: cn$1("group/playful relative", className), ...props, children: [
|
|
1215
|
+
/* @__PURE__ */ jsx(
|
|
1216
|
+
"div",
|
|
1217
|
+
{
|
|
1218
|
+
"aria-hidden": "true",
|
|
1219
|
+
className: cn$1(
|
|
1220
|
+
"absolute inset-0 rounded-2xl transition-transform duration-200 translate-x-[5px] translate-y-[5px] -rotate-[0.5deg] group-hover/playful:-rotate-[1.5deg] group-hover/playful:translate-x-[6px] group-hover/playful:translate-y-[6px]",
|
|
1221
|
+
highlighted ? "bg-primary/20" : "bg-border"
|
|
1222
|
+
)
|
|
1223
|
+
}
|
|
1224
|
+
),
|
|
1225
|
+
cardInner
|
|
1226
|
+
] });
|
|
1227
|
+
}
|
|
1228
|
+
return cardInner;
|
|
1075
1229
|
}
|
|
1076
1230
|
var defaultRenderLink6 = ({ href, children, className }) => /* @__PURE__ */ jsx("a", { href, className, children });
|
|
1077
1231
|
function PricingSection({
|
|
@@ -1084,16 +1238,25 @@ function PricingSection({
|
|
|
1084
1238
|
renderLink = defaultRenderLink6,
|
|
1085
1239
|
footnote
|
|
1086
1240
|
}) {
|
|
1087
|
-
const [annual, setAnnual] =
|
|
1088
|
-
|
|
1241
|
+
const [annual, setAnnual] = React26.useState(false);
|
|
1242
|
+
const mode = useUIVariant();
|
|
1243
|
+
const sectionClasses = cn$1(
|
|
1244
|
+
"overflow-hidden bg-card",
|
|
1245
|
+
mode === "smooth" && "rounded-3xl border",
|
|
1246
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1247
|
+
!mode && "rounded-2xl border"
|
|
1248
|
+
);
|
|
1249
|
+
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: [
|
|
1089
1250
|
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
1090
1251
|
badge && /* @__PURE__ */ jsx(Badge$1, { variant: "secondary", className: "mb-4", children: badge }),
|
|
1091
1252
|
/* @__PURE__ */ jsx("h2", { className: "text-balance text-3xl font-semibold tracking-tight sm:text-4xl", children: title }),
|
|
1092
1253
|
description && /* @__PURE__ */ jsx("p", { className: "mx-auto mt-4 max-w-xl text-pretty text-muted-foreground", children: description }),
|
|
1093
1254
|
/* @__PURE__ */ jsxs("div", { className: "mt-6 inline-flex items-center gap-3 rounded-full border bg-muted p-1", children: [
|
|
1094
1255
|
/* @__PURE__ */ jsx(
|
|
1095
|
-
|
|
1256
|
+
Button$1,
|
|
1096
1257
|
{
|
|
1258
|
+
variant: "ghost",
|
|
1259
|
+
size: "sm",
|
|
1097
1260
|
onClick: () => setAnnual(false),
|
|
1098
1261
|
className: cn$1(
|
|
1099
1262
|
"rounded-full px-4 py-1.5 text-sm font-medium transition-colors",
|
|
@@ -1103,8 +1266,10 @@ function PricingSection({
|
|
|
1103
1266
|
}
|
|
1104
1267
|
),
|
|
1105
1268
|
/* @__PURE__ */ jsxs(
|
|
1106
|
-
|
|
1269
|
+
Button$1,
|
|
1107
1270
|
{
|
|
1271
|
+
variant: "ghost",
|
|
1272
|
+
size: "sm",
|
|
1108
1273
|
onClick: () => setAnnual(true),
|
|
1109
1274
|
className: cn$1(
|
|
1110
1275
|
"flex items-center gap-2 rounded-full px-4 py-1.5 text-sm font-medium transition-colors",
|
|
@@ -1149,11 +1314,16 @@ function TestimonialCard({
|
|
|
1149
1314
|
className,
|
|
1150
1315
|
...props
|
|
1151
1316
|
}) {
|
|
1152
|
-
|
|
1317
|
+
const mode = useUIVariant();
|
|
1318
|
+
const cardInner = /* @__PURE__ */ jsxs(
|
|
1153
1319
|
"div",
|
|
1154
1320
|
{
|
|
1155
|
-
className: cn$1(
|
|
1156
|
-
|
|
1321
|
+
className: cn$1(
|
|
1322
|
+
"flex flex-col gap-4 border bg-card p-6",
|
|
1323
|
+
mode === "playful" ? "rounded-2xl rotate-[0.3deg]" : mode === "smooth" ? "rounded-3xl" : "rounded-2xl",
|
|
1324
|
+
mode !== "playful" && className
|
|
1325
|
+
),
|
|
1326
|
+
...mode !== "playful" ? props : {},
|
|
1157
1327
|
children: [
|
|
1158
1328
|
/* @__PURE__ */ jsx(Quote, { className: "size-4 text-muted-foreground/40" }),
|
|
1159
1329
|
rating != null && /* @__PURE__ */ jsx("div", { className: "flex gap-0.5", children: Array.from({ length: 5 }, (_, i) => /* @__PURE__ */ jsx(
|
|
@@ -1168,9 +1338,9 @@ function TestimonialCard({
|
|
|
1168
1338
|
)) }),
|
|
1169
1339
|
/* @__PURE__ */ jsx("p", { className: "flex-1 text-sm leading-relaxed", children: quote }),
|
|
1170
1340
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1171
|
-
/* @__PURE__ */ jsxs(Avatar, { className: "size-9
|
|
1341
|
+
/* @__PURE__ */ jsxs(Avatar, { className: "size-9", children: [
|
|
1172
1342
|
/* @__PURE__ */ jsx(AvatarImage, { src: avatar, alt: name }),
|
|
1173
|
-
/* @__PURE__ */ jsx(AvatarFallback, { className: "
|
|
1343
|
+
/* @__PURE__ */ jsx(AvatarFallback, { className: "text-xs", children: initials ?? name.slice(0, 2).toUpperCase() })
|
|
1174
1344
|
] }),
|
|
1175
1345
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1176
1346
|
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium leading-tight", children: name }),
|
|
@@ -1183,6 +1353,19 @@ function TestimonialCard({
|
|
|
1183
1353
|
]
|
|
1184
1354
|
}
|
|
1185
1355
|
);
|
|
1356
|
+
if (mode === "playful") {
|
|
1357
|
+
return /* @__PURE__ */ jsxs("div", { className: cn$1("group/playful relative", className), ...props, children: [
|
|
1358
|
+
/* @__PURE__ */ jsx(
|
|
1359
|
+
"div",
|
|
1360
|
+
{
|
|
1361
|
+
"aria-hidden": "true",
|
|
1362
|
+
className: "absolute inset-0 rounded-2xl bg-border transition-transform duration-200 translate-x-[5px] translate-y-[5px] -rotate-[0.5deg] group-hover/playful:-rotate-[1.5deg] group-hover/playful:translate-x-[6px] group-hover/playful:translate-y-[6px]"
|
|
1363
|
+
}
|
|
1364
|
+
),
|
|
1365
|
+
cardInner
|
|
1366
|
+
] });
|
|
1367
|
+
}
|
|
1368
|
+
return cardInner;
|
|
1186
1369
|
}
|
|
1187
1370
|
function TestimonialsSection({
|
|
1188
1371
|
title = "Trusted by teams shipping real products",
|
|
@@ -1190,7 +1373,14 @@ function TestimonialsSection({
|
|
|
1190
1373
|
badge = "Testimonials",
|
|
1191
1374
|
testimonials
|
|
1192
1375
|
}) {
|
|
1193
|
-
|
|
1376
|
+
const mode = useUIVariant();
|
|
1377
|
+
const sectionClasses = cn$1(
|
|
1378
|
+
"overflow-hidden bg-card",
|
|
1379
|
+
mode === "smooth" && "rounded-3xl border",
|
|
1380
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1381
|
+
!mode && "rounded-2xl border"
|
|
1382
|
+
);
|
|
1383
|
+
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: [
|
|
1194
1384
|
/* @__PURE__ */ jsx(SectionTitle, { title, description, badge }),
|
|
1195
1385
|
/* @__PURE__ */ jsx(StaggerChildren, { className: "mt-12 columns-1 gap-4 sm:columns-2 lg:columns-3", children: testimonials.map((t) => /* @__PURE__ */ jsx(
|
|
1196
1386
|
"div",
|
|
@@ -1296,7 +1486,14 @@ function FaqSection({
|
|
|
1296
1486
|
badge = "FAQ",
|
|
1297
1487
|
items
|
|
1298
1488
|
}) {
|
|
1299
|
-
|
|
1489
|
+
const mode = useUIVariant();
|
|
1490
|
+
const sectionClasses = cn$1(
|
|
1491
|
+
"overflow-hidden bg-card",
|
|
1492
|
+
mode === "smooth" && "rounded-3xl border",
|
|
1493
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1494
|
+
!mode && "rounded-2xl border"
|
|
1495
|
+
);
|
|
1496
|
+
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-3xl", children: [
|
|
1300
1497
|
/* @__PURE__ */ jsx(SectionTitle, { title, description, badge }),
|
|
1301
1498
|
/* @__PURE__ */ jsx(FadeIn, { direction: "up", children: /* @__PURE__ */ jsx(Accordion, { type: "single", collapsible: true, className: "mt-10 w-full", children: items.map((item, i) => /* @__PURE__ */ jsxs(AccordionItem, { value: `item-${i}`, children: [
|
|
1302
1499
|
/* @__PURE__ */ jsx(AccordionTrigger, { className: "text-left text-sm font-medium", children: item.question }),
|
|
@@ -1315,10 +1512,10 @@ function CountUp({
|
|
|
1315
1512
|
className,
|
|
1316
1513
|
...props
|
|
1317
1514
|
}) {
|
|
1318
|
-
const ref =
|
|
1319
|
-
const [value, setValue] =
|
|
1320
|
-
const hasStarted =
|
|
1321
|
-
|
|
1515
|
+
const ref = React26.useRef(null);
|
|
1516
|
+
const [value, setValue] = React26.useState(from);
|
|
1517
|
+
const hasStarted = React26.useRef(false);
|
|
1518
|
+
React26.useEffect(() => {
|
|
1322
1519
|
const el = ref.current;
|
|
1323
1520
|
if (!el) return;
|
|
1324
1521
|
const observer = new IntersectionObserver(
|
|
@@ -1366,7 +1563,14 @@ function StatsSection({
|
|
|
1366
1563
|
badge = "By the numbers",
|
|
1367
1564
|
stats
|
|
1368
1565
|
}) {
|
|
1369
|
-
|
|
1566
|
+
const mode = useUIVariant();
|
|
1567
|
+
const sectionClasses = cn$1(
|
|
1568
|
+
"overflow-hidden bg-card",
|
|
1569
|
+
mode === "smooth" && "rounded-3xl border",
|
|
1570
|
+
mode === "playful" && "rounded-2xl border-primary/25 border",
|
|
1571
|
+
!mode && "rounded-2xl border"
|
|
1572
|
+
);
|
|
1573
|
+
return /* @__PURE__ */ jsx("section", { className: sectionClasses, children: /* @__PURE__ */ jsxs("div", { className: "relative px-6 py-14 sm:px-10 sm:py-20", children: [
|
|
1370
1574
|
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[radial-gradient(ellipse_at_bottom,hsl(var(--primary)/0.08),transparent_60%)]" }),
|
|
1371
1575
|
/* @__PURE__ */ jsxs("div", { className: "relative mx-auto max-w-4xl", children: [
|
|
1372
1576
|
/* @__PURE__ */ jsx(SectionTitle, { title, description, badge }),
|
|
@@ -1404,8 +1608,8 @@ function NewsletterSection({
|
|
|
1404
1608
|
successDescription = defaults.successDescription,
|
|
1405
1609
|
onSubscribe
|
|
1406
1610
|
} = {}) {
|
|
1407
|
-
const [email, setEmail] =
|
|
1408
|
-
const [submitted, setSubmitted] =
|
|
1611
|
+
const [email, setEmail] = React26.useState("");
|
|
1612
|
+
const [submitted, setSubmitted] = React26.useState(false);
|
|
1409
1613
|
async function handleSubmit(e) {
|
|
1410
1614
|
e.preventDefault();
|
|
1411
1615
|
if (!email) return;
|
|
@@ -1483,7 +1687,7 @@ function ContactSection({
|
|
|
1483
1687
|
sendAnotherLabel = defaults2.sendAnotherLabel,
|
|
1484
1688
|
onSubmit
|
|
1485
1689
|
} = {}) {
|
|
1486
|
-
const [submitted, setSubmitted] =
|
|
1690
|
+
const [submitted, setSubmitted] = React26.useState(false);
|
|
1487
1691
|
async function handleSubmit(e) {
|
|
1488
1692
|
e.preventDefault();
|
|
1489
1693
|
await onSubmit?.(e);
|
|
@@ -1580,7 +1784,7 @@ function Navbar({
|
|
|
1580
1784
|
controls,
|
|
1581
1785
|
renderLink = defaultRenderLink7
|
|
1582
1786
|
}) {
|
|
1583
|
-
const [open, setOpen] =
|
|
1787
|
+
const [open, setOpen] = React26.useState(false);
|
|
1584
1788
|
const brandHref = brand.href ?? "/";
|
|
1585
1789
|
const hasRightContent = controls?.length || cta?.primary || cta?.secondary;
|
|
1586
1790
|
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: [
|
|
@@ -1597,7 +1801,7 @@ function Navbar({
|
|
|
1597
1801
|
children: link.label
|
|
1598
1802
|
}) }, link.label)) }),
|
|
1599
1803
|
hasRightContent && /* @__PURE__ */ jsxs("div", { className: "hidden items-center justify-end gap-2 md:flex", children: [
|
|
1600
|
-
controls?.map((control, i) => /* @__PURE__ */ jsx(
|
|
1804
|
+
controls?.map((control, i) => /* @__PURE__ */ jsx(React26.Fragment, { children: control }, i)),
|
|
1601
1805
|
(cta?.secondary || cta?.primary) && controls?.length ? /* @__PURE__ */ jsx("div", { className: "mx-1 h-4 w-px bg-border" }) : null,
|
|
1602
1806
|
cta?.secondary && renderLink({
|
|
1603
1807
|
href: cta.secondary.href,
|
|
@@ -1623,7 +1827,7 @@ function Navbar({
|
|
|
1623
1827
|
] })
|
|
1624
1828
|
}) }),
|
|
1625
1829
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
1626
|
-
controls?.map((control, i) => /* @__PURE__ */ jsx(
|
|
1830
|
+
controls?.map((control, i) => /* @__PURE__ */ jsx(React26.Fragment, { children: control }, i)),
|
|
1627
1831
|
/* @__PURE__ */ jsxs(Button$1, { variant: "ghost", size: "icon", onClick: () => setOpen(false), children: [
|
|
1628
1832
|
/* @__PURE__ */ jsx(X, { className: "size-4" }),
|
|
1629
1833
|
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close menu" })
|
|
@@ -1768,7 +1972,7 @@ function LogoStrip({
|
|
|
1768
1972
|
] });
|
|
1769
1973
|
}
|
|
1770
1974
|
function GridUnderlay({ variant, size = 24, className, ...props }) {
|
|
1771
|
-
const id =
|
|
1975
|
+
const id = React26.useId();
|
|
1772
1976
|
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: [
|
|
1773
1977
|
/* @__PURE__ */ jsx("line", { x1: size / 2, y1: 0, x2: size / 2, y2: size, stroke: "currentColor", strokeWidth: 0.5 }),
|
|
1774
1978
|
/* @__PURE__ */ jsx("line", { x1: 0, y1: size / 2, x2: size, y2: size / 2, stroke: "currentColor", strokeWidth: 0.5 })
|
|
@@ -1796,9 +2000,9 @@ function GlowUnderlay({
|
|
|
1796
2000
|
style,
|
|
1797
2001
|
...props
|
|
1798
2002
|
}) {
|
|
1799
|
-
const [pos, setPos] =
|
|
1800
|
-
const containerRef =
|
|
1801
|
-
|
|
2003
|
+
const [pos, setPos] = React26.useState({ x: "50%", y: "50%" });
|
|
2004
|
+
const containerRef = React26.useRef(null);
|
|
2005
|
+
React26.useEffect(() => {
|
|
1802
2006
|
if (!followCursor) return;
|
|
1803
2007
|
const handleMouseMove = (e) => {
|
|
1804
2008
|
const el = containerRef.current;
|
|
@@ -1890,8 +2094,8 @@ function PageTransition({
|
|
|
1890
2094
|
style,
|
|
1891
2095
|
...props
|
|
1892
2096
|
}) {
|
|
1893
|
-
const [mounted, setMounted] =
|
|
1894
|
-
|
|
2097
|
+
const [mounted, setMounted] = React26.useState(false);
|
|
2098
|
+
React26.useEffect(() => {
|
|
1895
2099
|
const id = requestAnimationFrame(() => setMounted(true));
|
|
1896
2100
|
return () => cancelAnimationFrame(id);
|
|
1897
2101
|
}, []);
|
|
@@ -1918,8 +2122,8 @@ function Spotlight({
|
|
|
1918
2122
|
triggerClassName,
|
|
1919
2123
|
shortcut = "\u2318K"
|
|
1920
2124
|
}) {
|
|
1921
|
-
const [open, setOpen] =
|
|
1922
|
-
|
|
2125
|
+
const [open, setOpen] = React26.useState(false);
|
|
2126
|
+
React26.useEffect(() => {
|
|
1923
2127
|
const down = (e) => {
|
|
1924
2128
|
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
|
1925
2129
|
e.preventDefault();
|
|
@@ -1949,7 +2153,7 @@ function Spotlight({
|
|
|
1949
2153
|
/* @__PURE__ */ jsx(CommandInput, { placeholder }),
|
|
1950
2154
|
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
1951
2155
|
/* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
|
|
1952
|
-
groups.map((group, i) => /* @__PURE__ */ jsxs(
|
|
2156
|
+
groups.map((group, i) => /* @__PURE__ */ jsxs(React26.Fragment, { children: [
|
|
1953
2157
|
i > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
1954
2158
|
/* @__PURE__ */ jsx(CommandGroup, { heading: group.heading, children: group.items.map((item) => /* @__PURE__ */ jsxs(
|
|
1955
2159
|
CommandItem,
|
|
@@ -1974,8 +2178,8 @@ function Spotlight({
|
|
|
1974
2178
|
var BASE = 40;
|
|
1975
2179
|
var MAGNIFY_RADIUS = 80;
|
|
1976
2180
|
function Dock({ items, iconSize = BASE, magnification = 1.7, className, ...props }) {
|
|
1977
|
-
const [mouseX, setMouseX] =
|
|
1978
|
-
const containerRef =
|
|
2181
|
+
const [mouseX, setMouseX] = React26.useState(null);
|
|
2182
|
+
const containerRef = React26.useRef(null);
|
|
1979
2183
|
function getScale(index) {
|
|
1980
2184
|
if (mouseX === null || !containerRef.current) return 1;
|
|
1981
2185
|
const container = containerRef.current;
|
|
@@ -2200,7 +2404,7 @@ function PageHeader({
|
|
|
2200
2404
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-1 pb-6", className), children: [
|
|
2201
2405
|
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) => {
|
|
2202
2406
|
const isLast = i === breadcrumbs.length - 1;
|
|
2203
|
-
return /* @__PURE__ */ jsxs(
|
|
2407
|
+
return /* @__PURE__ */ jsxs(React26.Fragment, { children: [
|
|
2204
2408
|
i > 0 && /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0" }),
|
|
2205
2409
|
isLast || !crumb.href ? /* @__PURE__ */ jsx("span", { className: cn(isLast && "text-foreground font-medium"), children: crumb.label }) : renderLink({
|
|
2206
2410
|
href: crumb.href,
|
|
@@ -2236,11 +2440,11 @@ function PageHeader({
|
|
|
2236
2440
|
] });
|
|
2237
2441
|
}
|
|
2238
2442
|
function Suspensed({ children, fallback }) {
|
|
2239
|
-
return /* @__PURE__ */ jsx(
|
|
2443
|
+
return /* @__PURE__ */ jsx(React26.Suspense, { fallback: fallback ?? /* @__PURE__ */ jsx(Spinner, {}), children });
|
|
2240
2444
|
}
|
|
2241
2445
|
function ThemeSwitchMinimal() {
|
|
2242
|
-
const [theme, setThemeState] =
|
|
2243
|
-
|
|
2446
|
+
const [theme, setThemeState] = React26.useState("dark");
|
|
2447
|
+
React26.useEffect(() => {
|
|
2244
2448
|
const stored = localStorage.getItem("theme");
|
|
2245
2449
|
const resolved = stored ?? (document.documentElement.classList.contains("dark") ? "dark" : "light");
|
|
2246
2450
|
setThemeState(resolved);
|
|
@@ -2287,7 +2491,7 @@ function ModeSwitchMinimal() {
|
|
|
2287
2491
|
) });
|
|
2288
2492
|
}
|
|
2289
2493
|
function ThemeColorUpdater({ colorTheme }) {
|
|
2290
|
-
|
|
2494
|
+
React26.useEffect(() => {
|
|
2291
2495
|
if (colorTheme) {
|
|
2292
2496
|
document.documentElement.setAttribute("data-theme", colorTheme);
|
|
2293
2497
|
} else {
|
|
@@ -2297,7 +2501,7 @@ function ThemeColorUpdater({ colorTheme }) {
|
|
|
2297
2501
|
return null;
|
|
2298
2502
|
}
|
|
2299
2503
|
function VersionBanner({ version, message, className, onDismiss }) {
|
|
2300
|
-
const [dismissed, setDismissed] =
|
|
2504
|
+
const [dismissed, setDismissed] = React26.useState(false);
|
|
2301
2505
|
if (dismissed) return null;
|
|
2302
2506
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-4 bg-primary/10 px-4 py-2 text-sm", className), children: [
|
|
2303
2507
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
@@ -2337,7 +2541,7 @@ function DevBanner({ environment = "development", className }) {
|
|
|
2337
2541
|
);
|
|
2338
2542
|
}
|
|
2339
2543
|
function RegisterHotkeys({ hotkeys }) {
|
|
2340
|
-
|
|
2544
|
+
React26.useEffect(() => {
|
|
2341
2545
|
const handleKeyDown = (event) => {
|
|
2342
2546
|
for (const hotkey of hotkeys) {
|
|
2343
2547
|
const matches = event.key.toLowerCase() === hotkey.key.toLowerCase() && !!event.ctrlKey === !!hotkey.ctrl && !!event.metaKey === !!hotkey.meta && !!event.shiftKey === !!hotkey.shift && !!event.altKey === !!hotkey.alt;
|
|
@@ -2457,36 +2661,36 @@ function useMounted() {
|
|
|
2457
2661
|
return mounted;
|
|
2458
2662
|
}
|
|
2459
2663
|
function useConfirm() {
|
|
2460
|
-
const [isOpen, setIsOpen] =
|
|
2461
|
-
const [options, setOptions] =
|
|
2462
|
-
const resolveRef =
|
|
2463
|
-
const confirm =
|
|
2664
|
+
const [isOpen, setIsOpen] = React26.useState(false);
|
|
2665
|
+
const [options, setOptions] = React26.useState({});
|
|
2666
|
+
const resolveRef = React26.useRef(null);
|
|
2667
|
+
const confirm = React26.useCallback((opts = {}) => {
|
|
2464
2668
|
setOptions(opts);
|
|
2465
2669
|
setIsOpen(true);
|
|
2466
2670
|
return new Promise((resolve) => {
|
|
2467
2671
|
resolveRef.current = resolve;
|
|
2468
2672
|
});
|
|
2469
2673
|
}, []);
|
|
2470
|
-
const handleConfirm =
|
|
2674
|
+
const handleConfirm = React26.useCallback(() => {
|
|
2471
2675
|
resolveRef.current?.(true);
|
|
2472
2676
|
setIsOpen(false);
|
|
2473
2677
|
}, []);
|
|
2474
|
-
const handleCancel =
|
|
2678
|
+
const handleCancel = React26.useCallback(() => {
|
|
2475
2679
|
resolveRef.current?.(false);
|
|
2476
2680
|
setIsOpen(false);
|
|
2477
2681
|
}, []);
|
|
2478
2682
|
return { confirm, isOpen, options, handleConfirm, handleCancel };
|
|
2479
2683
|
}
|
|
2480
2684
|
function useControlledOpen(defaultOpen = false) {
|
|
2481
|
-
const [isOpen, setIsOpen] =
|
|
2482
|
-
const open =
|
|
2483
|
-
const close =
|
|
2484
|
-
const toggle =
|
|
2685
|
+
const [isOpen, setIsOpen] = React26.useState(defaultOpen);
|
|
2686
|
+
const open = React26.useCallback(() => setIsOpen(true), []);
|
|
2687
|
+
const close = React26.useCallback(() => setIsOpen(false), []);
|
|
2688
|
+
const toggle = React26.useCallback(() => setIsOpen((prev) => !prev), []);
|
|
2485
2689
|
return { isOpen, open, close, toggle, setIsOpen };
|
|
2486
2690
|
}
|
|
2487
2691
|
function useScrolledPast(threshold) {
|
|
2488
|
-
const [scrolledPast, setScrolledPast] =
|
|
2489
|
-
|
|
2692
|
+
const [scrolledPast, setScrolledPast] = React26.useState(false);
|
|
2693
|
+
React26.useEffect(() => {
|
|
2490
2694
|
const handleScroll = () => {
|
|
2491
2695
|
setScrolledPast(window.scrollY > threshold);
|
|
2492
2696
|
};
|
|
@@ -2497,30 +2701,30 @@ function useScrolledPast(threshold) {
|
|
|
2497
2701
|
return scrolledPast;
|
|
2498
2702
|
}
|
|
2499
2703
|
function useCopyToClipboard() {
|
|
2500
|
-
const [copied, setCopied] =
|
|
2501
|
-
const timeoutRef =
|
|
2502
|
-
const copy =
|
|
2704
|
+
const [copied, setCopied] = React26.useState(false);
|
|
2705
|
+
const timeoutRef = React26.useRef(void 0);
|
|
2706
|
+
const copy = React26.useCallback((text) => {
|
|
2503
2707
|
navigator.clipboard.writeText(text).then(() => {
|
|
2504
2708
|
setCopied(true);
|
|
2505
2709
|
clearTimeout(timeoutRef.current);
|
|
2506
2710
|
timeoutRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
2507
2711
|
});
|
|
2508
2712
|
}, []);
|
|
2509
|
-
|
|
2713
|
+
React26.useEffect(() => () => clearTimeout(timeoutRef.current), []);
|
|
2510
2714
|
return [copied, copy];
|
|
2511
2715
|
}
|
|
2512
2716
|
function useDebounce(value, delay) {
|
|
2513
|
-
const [debounced, setDebounced] =
|
|
2514
|
-
|
|
2717
|
+
const [debounced, setDebounced] = React26.useState(value);
|
|
2718
|
+
React26.useEffect(() => {
|
|
2515
2719
|
const timer = setTimeout(() => setDebounced(value), delay);
|
|
2516
2720
|
return () => clearTimeout(timer);
|
|
2517
2721
|
}, [value, delay]);
|
|
2518
2722
|
return debounced;
|
|
2519
2723
|
}
|
|
2520
2724
|
function useIntersectionObserver(options) {
|
|
2521
|
-
const ref =
|
|
2522
|
-
const [isIntersecting, setIsIntersecting] =
|
|
2523
|
-
|
|
2725
|
+
const ref = React26.useRef(null);
|
|
2726
|
+
const [isIntersecting, setIsIntersecting] = React26.useState(false);
|
|
2727
|
+
React26.useEffect(() => {
|
|
2524
2728
|
const el = ref.current;
|
|
2525
2729
|
if (!el) return;
|
|
2526
2730
|
const observer = new IntersectionObserver(([entry]) => {
|
|
@@ -2532,7 +2736,7 @@ function useIntersectionObserver(options) {
|
|
|
2532
2736
|
return [ref, isIntersecting];
|
|
2533
2737
|
}
|
|
2534
2738
|
function useLocalStorage(key, initialValue) {
|
|
2535
|
-
const [storedValue, setStoredValue] =
|
|
2739
|
+
const [storedValue, setStoredValue] = React26.useState(() => {
|
|
2536
2740
|
if (typeof window === "undefined") return initialValue;
|
|
2537
2741
|
try {
|
|
2538
2742
|
const item = window.localStorage.getItem(key);
|
|
@@ -2541,7 +2745,7 @@ function useLocalStorage(key, initialValue) {
|
|
|
2541
2745
|
return initialValue;
|
|
2542
2746
|
}
|
|
2543
2747
|
});
|
|
2544
|
-
const setValue =
|
|
2748
|
+
const setValue = React26.useCallback(
|
|
2545
2749
|
(value) => {
|
|
2546
2750
|
try {
|
|
2547
2751
|
setStoredValue(value);
|
|
@@ -2556,11 +2760,11 @@ function useLocalStorage(key, initialValue) {
|
|
|
2556
2760
|
return [storedValue, setValue];
|
|
2557
2761
|
}
|
|
2558
2762
|
function useMediaQuery(query) {
|
|
2559
|
-
const [matches, setMatches] =
|
|
2763
|
+
const [matches, setMatches] = React26.useState(() => {
|
|
2560
2764
|
if (typeof window === "undefined") return false;
|
|
2561
2765
|
return window.matchMedia(query).matches;
|
|
2562
2766
|
});
|
|
2563
|
-
|
|
2767
|
+
React26.useEffect(() => {
|
|
2564
2768
|
if (typeof window === "undefined") return;
|
|
2565
2769
|
const mql = window.matchMedia(query);
|
|
2566
2770
|
setMatches(mql.matches);
|
|
@@ -2571,18 +2775,18 @@ function useMediaQuery(query) {
|
|
|
2571
2775
|
return matches;
|
|
2572
2776
|
}
|
|
2573
2777
|
function usePagination(total, pageSize) {
|
|
2574
|
-
const [page, setPage] =
|
|
2778
|
+
const [page, setPage] = React26.useState(1);
|
|
2575
2779
|
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
2576
2780
|
const offset = (page - 1) * pageSize;
|
|
2577
|
-
const goTo =
|
|
2781
|
+
const goTo = React26.useCallback(
|
|
2578
2782
|
(p) => setPage(Math.min(Math.max(1, p), totalPages)),
|
|
2579
2783
|
[totalPages]
|
|
2580
2784
|
);
|
|
2581
|
-
const next =
|
|
2582
|
-
const prev =
|
|
2785
|
+
const next = React26.useCallback(() => goTo(page + 1), [page, goTo]);
|
|
2786
|
+
const prev = React26.useCallback(() => goTo(page - 1), [page, goTo]);
|
|
2583
2787
|
return { page, pageSize, totalPages, offset, hasPrev: page > 1, hasNext: page < totalPages, goTo, next, prev };
|
|
2584
2788
|
}
|
|
2585
2789
|
|
|
2586
|
-
export { AppContent, AppGrid, AppGridCell, AppScreen, AppShell, AuthSection, Badge, Button, Card, 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 };
|
|
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 };
|
|
2587
2791
|
//# sourceMappingURL=index.js.map
|
|
2588
2792
|
//# sourceMappingURL=index.js.map
|