@web-my-money/blocks 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.d.mts +454 -0
- package/dist/app.d.ts +454 -0
- package/dist/app.js +1293 -0
- package/dist/app.mjs +53 -0
- package/dist/chunk-L6OIX4DG.mjs +70 -0
- package/dist/chunk-PJO7WJ4G.mjs +10 -0
- package/dist/chunk-UM2RDUPI.mjs +1183 -0
- package/dist/chunk-X6SF4TT2.mjs +2205 -0
- package/dist/funnel.d.mts +80 -0
- package/dist/funnel.d.ts +80 -0
- package/dist/funnel.js +281 -0
- package/dist/funnel.mjs +235 -0
- package/dist/fx.d.mts +314 -0
- package/dist/fx.d.ts +314 -0
- package/dist/fx.js +1142 -0
- package/dist/fx.mjs +1084 -0
- package/dist/index-D5sr_PKq.d.mts +29 -0
- package/dist/index-D5sr_PKq.d.ts +29 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3525 -0
- package/dist/index.mjs +121 -0
- package/dist/next.d.mts +32 -0
- package/dist/next.d.ts +32 -0
- package/dist/next.js +65 -0
- package/dist/next.mjs +28 -0
- package/dist/site.d.mts +532 -0
- package/dist/site.d.ts +532 -0
- package/dist/site.js +2338 -0
- package/dist/site.mjs +77 -0
- package/package.json +93 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,3525 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
ActivityFeed: () => ActivityFeed,
|
|
34
|
+
AppBrand: () => AppBrand,
|
|
35
|
+
AppShell: () => AppShell,
|
|
36
|
+
AppearanceSettings: () => AppearanceSettings,
|
|
37
|
+
AvatarGroup: () => AvatarGroup,
|
|
38
|
+
BentoGrid: () => BentoGrid,
|
|
39
|
+
BrandFrame: () => BrandFrame,
|
|
40
|
+
CTABanner: () => CTABanner,
|
|
41
|
+
CaseStudiesSection: () => CaseStudiesSection,
|
|
42
|
+
ComparisonTable: () => ComparisonTable,
|
|
43
|
+
ContactForm: () => ContactForm,
|
|
44
|
+
DEFAULT_WAVES: () => DEFAULT_WAVES,
|
|
45
|
+
DashboardHeader: () => DashboardHeader,
|
|
46
|
+
DataSummaryCards: () => DataSummaryCards,
|
|
47
|
+
DataTable: () => DataTable,
|
|
48
|
+
EmptyState: () => EmptyState,
|
|
49
|
+
FadeUp: () => FadeUp,
|
|
50
|
+
Faq: () => Faq,
|
|
51
|
+
FeatureGrid: () => FeatureGrid,
|
|
52
|
+
Footer: () => Footer,
|
|
53
|
+
GlassPanel: () => GlassPanel,
|
|
54
|
+
HeroCanvas: () => HeroCanvas,
|
|
55
|
+
HeroSection: () => HeroSection,
|
|
56
|
+
KPIRow: () => KPIRow,
|
|
57
|
+
LayeredButton: () => LayeredButton,
|
|
58
|
+
LayoutToggle: () => LayoutToggle,
|
|
59
|
+
LightboxGallery: () => LightboxGallery,
|
|
60
|
+
LogoCloud: () => LogoCloud,
|
|
61
|
+
Marquee: () => Marquee,
|
|
62
|
+
NavBar: () => NavBar,
|
|
63
|
+
NotificationBanner: () => NotificationBanner,
|
|
64
|
+
PageHeader: () => PageHeader,
|
|
65
|
+
PageHeaderBanner: () => PageHeaderBanner,
|
|
66
|
+
PricingTable: () => PricingTable,
|
|
67
|
+
ProcessSteps: () => ProcessSteps,
|
|
68
|
+
ScrollReveal: () => ScrollReveal,
|
|
69
|
+
SectionGlow: () => SectionGlow,
|
|
70
|
+
SectionIntro: () => SectionIntro,
|
|
71
|
+
SectionLabel: () => SectionLabel,
|
|
72
|
+
SidebarNavigation: () => SidebarNavigation,
|
|
73
|
+
SocialProof: () => SocialProof,
|
|
74
|
+
StatCard: () => StatCard,
|
|
75
|
+
StatsSection: () => StatsSection,
|
|
76
|
+
SubTabs: () => SubTabs,
|
|
77
|
+
TechCarousel: () => TechCarousel,
|
|
78
|
+
TestimonialCarousel: () => TestimonialCarousel,
|
|
79
|
+
TestimonialsCarousel: () => TestimonialsCarousel,
|
|
80
|
+
TestimonialsSection: () => TestimonialsSection,
|
|
81
|
+
TextRotator: () => TextRotator,
|
|
82
|
+
Thumbnail: () => Thumbnail,
|
|
83
|
+
UseCasesSection: () => UseCasesSection,
|
|
84
|
+
ValueStackSection: () => ValueStackSection,
|
|
85
|
+
WaveCanvas: () => WaveCanvas,
|
|
86
|
+
useActionRunner: () => useActionRunner,
|
|
87
|
+
useLayoutPreference: () => useLayoutPreference,
|
|
88
|
+
useOptimisticAction: () => useOptimisticAction
|
|
89
|
+
});
|
|
90
|
+
module.exports = __toCommonJS(index_exports);
|
|
91
|
+
|
|
92
|
+
// src/fade-up/index.tsx
|
|
93
|
+
var import_framer_motion = require("framer-motion");
|
|
94
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
95
|
+
var SPRING_EASE = [0.22, 1, 0.36, 1];
|
|
96
|
+
function FadeUp({
|
|
97
|
+
children,
|
|
98
|
+
className,
|
|
99
|
+
delay = 0
|
|
100
|
+
}) {
|
|
101
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
102
|
+
import_framer_motion.motion.div,
|
|
103
|
+
{
|
|
104
|
+
className,
|
|
105
|
+
initial: { opacity: 0, y: 30 },
|
|
106
|
+
whileInView: { opacity: 1, y: 0 },
|
|
107
|
+
viewport: { once: true, amount: 0.2 },
|
|
108
|
+
transition: { duration: 0.7, delay, ease: SPRING_EASE },
|
|
109
|
+
style: { willChange: "transform, opacity" },
|
|
110
|
+
children
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/scroll-reveal/index.tsx
|
|
116
|
+
var React = __toESM(require("react"));
|
|
117
|
+
var import_framer_motion2 = require("framer-motion");
|
|
118
|
+
|
|
119
|
+
// src/utils.ts
|
|
120
|
+
var import_clsx = require("clsx");
|
|
121
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
122
|
+
function cn(...inputs) {
|
|
123
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// src/scroll-reveal/index.tsx
|
|
127
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
128
|
+
var offset = { up: { y: 24 }, down: { y: -24 }, left: { x: 24 }, right: { x: -24 }, none: {} };
|
|
129
|
+
function ScrollReveal({
|
|
130
|
+
children,
|
|
131
|
+
className,
|
|
132
|
+
direction = "up",
|
|
133
|
+
delay = 0,
|
|
134
|
+
once = true,
|
|
135
|
+
amount = 0.3
|
|
136
|
+
}) {
|
|
137
|
+
const ref = React.useRef(null);
|
|
138
|
+
const inView = (0, import_framer_motion2.useInView)(ref, { once, amount });
|
|
139
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
140
|
+
import_framer_motion2.motion.div,
|
|
141
|
+
{
|
|
142
|
+
ref,
|
|
143
|
+
"data-wmm-fx": true,
|
|
144
|
+
className: cn(className),
|
|
145
|
+
initial: { opacity: 0, ...offset[direction] },
|
|
146
|
+
animate: inView ? { opacity: 1, x: 0, y: 0 } : {},
|
|
147
|
+
transition: { duration: 0.5, delay, ease: [0.22, 1, 0.36, 1] },
|
|
148
|
+
children
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/section-label/index.tsx
|
|
154
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
155
|
+
function SectionLabel({
|
|
156
|
+
children,
|
|
157
|
+
variant = "pill",
|
|
158
|
+
index,
|
|
159
|
+
dotColor = "var(--primary)",
|
|
160
|
+
className
|
|
161
|
+
}) {
|
|
162
|
+
if (variant === "rule") {
|
|
163
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: cn("flex items-center gap-3", className), children: [
|
|
164
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "h-px flex-1 bg-border" }),
|
|
165
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-xs font-semibold uppercase tracking-widest text-muted-foreground", children }),
|
|
166
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "h-px flex-1 bg-border" })
|
|
167
|
+
] });
|
|
168
|
+
}
|
|
169
|
+
if (variant === "indexed") {
|
|
170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: cn("inline-flex items-center gap-2.5", className), children: [
|
|
171
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
172
|
+
"span",
|
|
173
|
+
{
|
|
174
|
+
className: "flex h-5 w-5 items-center justify-center rounded-full text-[10px] font-bold",
|
|
175
|
+
style: { background: "var(--primary)", color: "var(--primary-foreground)" },
|
|
176
|
+
children: index ?? "\xB7"
|
|
177
|
+
}
|
|
178
|
+
),
|
|
179
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-xs font-semibold uppercase tracking-widest text-muted-foreground", children })
|
|
180
|
+
] });
|
|
181
|
+
}
|
|
182
|
+
if (variant === "flanked") {
|
|
183
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: cn("inline-flex items-center gap-2 text-muted-foreground", className), children: [
|
|
184
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-primary select-none", children: "\u2014" }),
|
|
185
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-xs font-semibold uppercase tracking-widest", children }),
|
|
186
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-primary select-none", children: "\u2014" })
|
|
187
|
+
] });
|
|
188
|
+
}
|
|
189
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
190
|
+
"div",
|
|
191
|
+
{
|
|
192
|
+
className: cn(
|
|
193
|
+
"inline-flex items-center gap-2 rounded-full border border-border bg-foreground/[0.06] px-4 py-1.5 backdrop-blur-md",
|
|
194
|
+
className
|
|
195
|
+
),
|
|
196
|
+
children: [
|
|
197
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
198
|
+
"div",
|
|
199
|
+
{
|
|
200
|
+
className: "h-1.5 w-1.5 rounded-full shrink-0",
|
|
201
|
+
style: { backgroundColor: dotColor }
|
|
202
|
+
}
|
|
203
|
+
),
|
|
204
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-xs font-medium uppercase tracking-[0.15em] text-muted-foreground", children })
|
|
205
|
+
]
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/section-glow/index.tsx
|
|
211
|
+
var import_framer_motion3 = require("framer-motion");
|
|
212
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
213
|
+
function SectionGlow({ variant = "primary", className }) {
|
|
214
|
+
const reduce = (0, import_framer_motion3.useReducedMotion)();
|
|
215
|
+
const color = variant === "secondary" ? "color-mix(in srgb, var(--secondary, #1f2d56) 18%, transparent)" : "color-mix(in srgb, var(--primary, #8fccb6) 16%, transparent)";
|
|
216
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
217
|
+
"div",
|
|
218
|
+
{
|
|
219
|
+
"aria-hidden": true,
|
|
220
|
+
className: cn(
|
|
221
|
+
"pointer-events-none absolute left-1/2 -top-40 -translate-x-1/2",
|
|
222
|
+
className
|
|
223
|
+
),
|
|
224
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
225
|
+
import_framer_motion3.motion.div,
|
|
226
|
+
{
|
|
227
|
+
className: "h-[460px] w-[min(820px,94vw)] rounded-full blur-[60px]",
|
|
228
|
+
style: {
|
|
229
|
+
background: `radial-gradient(circle at 50% 50%, ${color}, transparent 70%)`
|
|
230
|
+
},
|
|
231
|
+
initial: reduce ? false : { opacity: 0, scale: 0.92 },
|
|
232
|
+
whileInView: { opacity: 1, scale: 1 },
|
|
233
|
+
viewport: { once: true, margin: "-8% 0px -8% 0px" },
|
|
234
|
+
transition: { duration: 1, ease: [0.22, 0.61, 0.36, 1] }
|
|
235
|
+
}
|
|
236
|
+
)
|
|
237
|
+
}
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// src/section-intro/index.tsx
|
|
242
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
243
|
+
function SectionIntro({
|
|
244
|
+
label,
|
|
245
|
+
title,
|
|
246
|
+
body,
|
|
247
|
+
centered = false
|
|
248
|
+
}) {
|
|
249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
250
|
+
"div",
|
|
251
|
+
{
|
|
252
|
+
className: cn(
|
|
253
|
+
"relative z-10 max-w-3xl",
|
|
254
|
+
centered && "mx-auto text-center"
|
|
255
|
+
),
|
|
256
|
+
children: [
|
|
257
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SectionLabel, { children: label }),
|
|
258
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
259
|
+
"h2",
|
|
260
|
+
{
|
|
261
|
+
className: "mt-6 font-display text-4xl font-black tracking-[-0.04em] text-foreground sm:text-5xl md:text-6xl",
|
|
262
|
+
style: { textShadow: "0 18px 60px rgba(0,0,0,0.24)" },
|
|
263
|
+
children: title
|
|
264
|
+
}
|
|
265
|
+
),
|
|
266
|
+
body ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
267
|
+
"p",
|
|
268
|
+
{
|
|
269
|
+
className: cn(
|
|
270
|
+
"mt-6 max-w-2xl text-base leading-8 text-muted-foreground md:text-lg",
|
|
271
|
+
centered && "mx-auto"
|
|
272
|
+
),
|
|
273
|
+
children: body
|
|
274
|
+
}
|
|
275
|
+
) : null
|
|
276
|
+
]
|
|
277
|
+
}
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// src/text-rotator/index.tsx
|
|
282
|
+
var React2 = __toESM(require("react"));
|
|
283
|
+
var import_framer_motion4 = require("framer-motion");
|
|
284
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
285
|
+
var SPRING = [0.16, 1, 0.3, 1];
|
|
286
|
+
function TextRotator({
|
|
287
|
+
phrases,
|
|
288
|
+
interval = 2800,
|
|
289
|
+
className,
|
|
290
|
+
phraseClassName
|
|
291
|
+
}) {
|
|
292
|
+
const [index, setIndex] = React2.useState(0);
|
|
293
|
+
React2.useEffect(() => {
|
|
294
|
+
const id = setInterval(
|
|
295
|
+
() => setIndex((i) => (i + 1) % phrases.length),
|
|
296
|
+
interval
|
|
297
|
+
);
|
|
298
|
+
return () => clearInterval(id);
|
|
299
|
+
}, [phrases.length, interval]);
|
|
300
|
+
return (
|
|
301
|
+
/* clip container so exiting phrase doesn't overflow */
|
|
302
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
303
|
+
"span",
|
|
304
|
+
{
|
|
305
|
+
className: cn("relative inline-flex overflow-hidden align-bottom", className),
|
|
306
|
+
style: { minWidth: "1ch" },
|
|
307
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_framer_motion4.AnimatePresence, { mode: "popLayout", initial: false, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
308
|
+
import_framer_motion4.motion.span,
|
|
309
|
+
{
|
|
310
|
+
initial: { y: "100%", opacity: 0 },
|
|
311
|
+
animate: { y: 0, opacity: 1 },
|
|
312
|
+
exit: { y: "-100%", opacity: 0 },
|
|
313
|
+
transition: { duration: 0.55, ease: SPRING },
|
|
314
|
+
className: cn("inline-block", phraseClassName),
|
|
315
|
+
children: phrases[index]
|
|
316
|
+
},
|
|
317
|
+
phrases[index]
|
|
318
|
+
) })
|
|
319
|
+
}
|
|
320
|
+
)
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// src/avatar-group/index.tsx
|
|
325
|
+
var import_jsx_runtime7 = (
|
|
326
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
327
|
+
require("react/jsx-runtime")
|
|
328
|
+
);
|
|
329
|
+
var sizePx = {
|
|
330
|
+
sm: "h-7 w-7 text-[10px]",
|
|
331
|
+
md: "h-9 w-9 text-xs",
|
|
332
|
+
lg: "h-11 w-11 text-sm"
|
|
333
|
+
};
|
|
334
|
+
var overlapPx = {
|
|
335
|
+
sm: "-ml-2",
|
|
336
|
+
md: "-ml-2.5",
|
|
337
|
+
lg: "-ml-3"
|
|
338
|
+
};
|
|
339
|
+
function AvatarGroup({
|
|
340
|
+
avatars,
|
|
341
|
+
max = 5,
|
|
342
|
+
label,
|
|
343
|
+
size = "md",
|
|
344
|
+
className
|
|
345
|
+
}) {
|
|
346
|
+
const shown = avatars.slice(0, max);
|
|
347
|
+
const overflow = avatars.length - max;
|
|
348
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: cn("flex items-center gap-3", className), children: [
|
|
349
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center", children: [
|
|
350
|
+
shown.map((av, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
351
|
+
"div",
|
|
352
|
+
{
|
|
353
|
+
title: av.name,
|
|
354
|
+
className: cn(
|
|
355
|
+
"relative rounded-full ring-2 ring-background overflow-hidden shrink-0",
|
|
356
|
+
sizePx[size],
|
|
357
|
+
i > 0 && overlapPx[size]
|
|
358
|
+
),
|
|
359
|
+
children: av.src ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
360
|
+
"img",
|
|
361
|
+
{
|
|
362
|
+
src: av.src,
|
|
363
|
+
alt: av.name,
|
|
364
|
+
className: "h-full w-full object-cover"
|
|
365
|
+
}
|
|
366
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
367
|
+
"span",
|
|
368
|
+
{
|
|
369
|
+
className: "flex h-full w-full items-center justify-center font-semibold bg-primary/20 text-primary",
|
|
370
|
+
children: av.initials ?? av.name.slice(0, 2).toUpperCase()
|
|
371
|
+
}
|
|
372
|
+
)
|
|
373
|
+
},
|
|
374
|
+
i
|
|
375
|
+
)),
|
|
376
|
+
overflow > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
377
|
+
"div",
|
|
378
|
+
{
|
|
379
|
+
className: cn(
|
|
380
|
+
"relative rounded-full ring-2 ring-background shrink-0",
|
|
381
|
+
"flex items-center justify-center font-semibold",
|
|
382
|
+
"bg-muted text-muted-foreground",
|
|
383
|
+
sizePx[size],
|
|
384
|
+
overlapPx[size]
|
|
385
|
+
),
|
|
386
|
+
children: [
|
|
387
|
+
"+",
|
|
388
|
+
overflow
|
|
389
|
+
]
|
|
390
|
+
}
|
|
391
|
+
)
|
|
392
|
+
] }),
|
|
393
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-sm text-muted-foreground", children: label })
|
|
394
|
+
] });
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// src/marquee/index.tsx
|
|
398
|
+
var React3 = __toESM(require("react"));
|
|
399
|
+
var import_framer_motion5 = require("framer-motion");
|
|
400
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
401
|
+
function Marquee({
|
|
402
|
+
children,
|
|
403
|
+
reverse = false,
|
|
404
|
+
speed = 30,
|
|
405
|
+
gap = "2rem",
|
|
406
|
+
pauseOnHover = true,
|
|
407
|
+
fadeWidth = "6rem",
|
|
408
|
+
className
|
|
409
|
+
}) {
|
|
410
|
+
const [paused, setPaused] = React3.useState(false);
|
|
411
|
+
const doubled = [...children, ...children];
|
|
412
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
413
|
+
"div",
|
|
414
|
+
{
|
|
415
|
+
className: cn("relative overflow-hidden", className),
|
|
416
|
+
onMouseEnter: () => pauseOnHover && setPaused(true),
|
|
417
|
+
onMouseLeave: () => pauseOnHover && setPaused(false),
|
|
418
|
+
children: [
|
|
419
|
+
fadeWidth !== "0" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
420
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
421
|
+
"div",
|
|
422
|
+
{
|
|
423
|
+
"aria-hidden": true,
|
|
424
|
+
className: "pointer-events-none absolute inset-y-0 left-0 z-10",
|
|
425
|
+
style: {
|
|
426
|
+
width: fadeWidth,
|
|
427
|
+
background: "linear-gradient(to right, var(--background), transparent)"
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
),
|
|
431
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
432
|
+
"div",
|
|
433
|
+
{
|
|
434
|
+
"aria-hidden": true,
|
|
435
|
+
className: "pointer-events-none absolute inset-y-0 right-0 z-10",
|
|
436
|
+
style: {
|
|
437
|
+
width: fadeWidth,
|
|
438
|
+
background: "linear-gradient(to left, var(--background), transparent)"
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
)
|
|
442
|
+
] }),
|
|
443
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
444
|
+
import_framer_motion5.motion.div,
|
|
445
|
+
{
|
|
446
|
+
className: "flex",
|
|
447
|
+
style: { gap },
|
|
448
|
+
animate: { x: reverse ? ["-50%", "0%"] : ["0%", "-50%"] },
|
|
449
|
+
transition: {
|
|
450
|
+
duration: speed,
|
|
451
|
+
ease: "linear",
|
|
452
|
+
repeat: Infinity
|
|
453
|
+
},
|
|
454
|
+
...paused && { animate: { x: reverse ? "-50%" : "0%" } },
|
|
455
|
+
children: doubled.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "shrink-0", children: child }, i))
|
|
456
|
+
}
|
|
457
|
+
)
|
|
458
|
+
]
|
|
459
|
+
}
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// src/layered-button/index.tsx
|
|
464
|
+
var import_framer_motion6 = require("framer-motion");
|
|
465
|
+
var import_lucide_react = require("lucide-react");
|
|
466
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
467
|
+
function LayeredButton({
|
|
468
|
+
href,
|
|
469
|
+
children,
|
|
470
|
+
variant = "solid",
|
|
471
|
+
className,
|
|
472
|
+
disabled = false,
|
|
473
|
+
icon,
|
|
474
|
+
onClick,
|
|
475
|
+
type = "button"
|
|
476
|
+
}) {
|
|
477
|
+
const innerClassName = variant === "solid" ? "bg-cta-gradient text-white shadow-glow" : "bg-white/[0.06] text-white/88";
|
|
478
|
+
const iconNode = icon ?? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react.ArrowRight, { className: "h-4 w-4 transition-transform duration-300 group-hover:translate-x-1" });
|
|
479
|
+
const wrapperClassName = cn(
|
|
480
|
+
"group relative inline-flex translate-gpu disabled:pointer-events-none disabled:opacity-60",
|
|
481
|
+
disabled && "pointer-events-none opacity-60",
|
|
482
|
+
className
|
|
483
|
+
);
|
|
484
|
+
const buttonChrome = /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
485
|
+
variant === "solid" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "absolute -inset-1 animate-pulse rounded-full bg-cta-gradient opacity-50 blur-xl transition duration-500 group-hover:opacity-80" }),
|
|
486
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
487
|
+
"div",
|
|
488
|
+
{
|
|
489
|
+
className: cn(
|
|
490
|
+
"relative w-full rounded-full p-px",
|
|
491
|
+
variant === "solid" ? "border border-white/60" : "border border-white/20"
|
|
492
|
+
),
|
|
493
|
+
children: [
|
|
494
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "absolute left-1/4 top-0 h-3 w-1/2 rounded-full bg-white/40 blur-md" }),
|
|
495
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
496
|
+
"div",
|
|
497
|
+
{
|
|
498
|
+
className: cn(
|
|
499
|
+
"relative flex w-full items-center justify-center gap-2 overflow-hidden rounded-full px-7 py-3 text-sm font-medium transition duration-300 group-hover:shadow-glow-strong",
|
|
500
|
+
innerClassName
|
|
501
|
+
),
|
|
502
|
+
children: [
|
|
503
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "pointer-events-none absolute inset-y-0 -left-1/3 w-1/3 -skew-x-12 bg-[linear-gradient(90deg,transparent,rgba(255,255,255,0.24),transparent)] opacity-0 transition-all duration-700 group-hover:left-[120%] group-hover:opacity-100" }),
|
|
504
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children }),
|
|
505
|
+
iconNode
|
|
506
|
+
]
|
|
507
|
+
}
|
|
508
|
+
)
|
|
509
|
+
]
|
|
510
|
+
}
|
|
511
|
+
)
|
|
512
|
+
] });
|
|
513
|
+
if (href) {
|
|
514
|
+
const handleClick = (event) => {
|
|
515
|
+
onClick?.(event);
|
|
516
|
+
if (event.defaultPrevented || disabled) return;
|
|
517
|
+
};
|
|
518
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
519
|
+
import_framer_motion6.motion.a,
|
|
520
|
+
{
|
|
521
|
+
href,
|
|
522
|
+
onClick: handleClick,
|
|
523
|
+
whileHover: disabled ? void 0 : { scale: 1.02, y: -2 },
|
|
524
|
+
whileTap: disabled ? void 0 : { scale: 0.99 },
|
|
525
|
+
className: wrapperClassName,
|
|
526
|
+
style: { willChange: "transform" },
|
|
527
|
+
"aria-disabled": disabled,
|
|
528
|
+
children: buttonChrome
|
|
529
|
+
}
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
533
|
+
import_framer_motion6.motion.button,
|
|
534
|
+
{
|
|
535
|
+
type,
|
|
536
|
+
onClick,
|
|
537
|
+
whileHover: disabled ? void 0 : { scale: 1.02, y: -2 },
|
|
538
|
+
whileTap: disabled ? void 0 : { scale: 0.99 },
|
|
539
|
+
className: wrapperClassName,
|
|
540
|
+
style: { willChange: "transform" },
|
|
541
|
+
disabled,
|
|
542
|
+
children: buttonChrome
|
|
543
|
+
}
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// src/nav-bar/index.tsx
|
|
548
|
+
var React4 = __toESM(require("react"));
|
|
549
|
+
var import_framer_motion7 = require("framer-motion");
|
|
550
|
+
var import_lucide_react2 = require("lucide-react");
|
|
551
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
552
|
+
function NavBar({ data, logo, className }) {
|
|
553
|
+
const [open, setOpen] = React4.useState(false);
|
|
554
|
+
const [scrolled, setScrolled] = React4.useState(false);
|
|
555
|
+
React4.useEffect(() => {
|
|
556
|
+
const update = () => setScrolled(window.scrollY > 12);
|
|
557
|
+
window.addEventListener("scroll", update, { passive: true });
|
|
558
|
+
update();
|
|
559
|
+
return () => window.removeEventListener("scroll", update);
|
|
560
|
+
}, []);
|
|
561
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
562
|
+
"header",
|
|
563
|
+
{
|
|
564
|
+
className: cn(
|
|
565
|
+
"fixed inset-x-0 top-0 z-50 transition-all duration-300",
|
|
566
|
+
scrolled ? "border-b border-border/60 backdrop-blur-xl" : "border-b border-transparent",
|
|
567
|
+
className
|
|
568
|
+
),
|
|
569
|
+
style: scrolled ? { background: "var(--glass-bg-strong, rgba(255,255,255,0.08))" } : void 0,
|
|
570
|
+
children: [
|
|
571
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("nav", { className: "container mx-auto flex h-16 items-center justify-between px-4 md:px-6", children: [
|
|
572
|
+
logo && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("a", { href: "/", "aria-label": "Home", className: "inline-flex shrink-0 items-center", children: logo }),
|
|
573
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ul", { className: "hidden md:flex items-center gap-7", children: data.links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
574
|
+
"a",
|
|
575
|
+
{
|
|
576
|
+
href: link.href,
|
|
577
|
+
className: "text-sm text-muted-foreground transition-colors hover:text-foreground",
|
|
578
|
+
children: link.label
|
|
579
|
+
}
|
|
580
|
+
) }, link.href)) }),
|
|
581
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
582
|
+
data.cta && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
583
|
+
"a",
|
|
584
|
+
{
|
|
585
|
+
href: data.cta.href,
|
|
586
|
+
className: "hidden md:inline-flex items-center justify-center rounded-full px-5 py-2 text-sm font-semibold bg-primary text-primary-foreground transition-all hover:opacity-90 active:scale-[0.97]",
|
|
587
|
+
children: data.cta.label
|
|
588
|
+
}
|
|
589
|
+
),
|
|
590
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
591
|
+
"button",
|
|
592
|
+
{
|
|
593
|
+
"aria-label": open ? "Close menu" : "Open menu",
|
|
594
|
+
onClick: () => setOpen((v) => !v),
|
|
595
|
+
className: "md:hidden rounded-lg p-2 text-muted-foreground hover:text-foreground hover:bg-accent transition-colors",
|
|
596
|
+
children: open ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react2.X, { size: 20 }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react2.Menu, { size: 20 })
|
|
597
|
+
}
|
|
598
|
+
)
|
|
599
|
+
] })
|
|
600
|
+
] }),
|
|
601
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_framer_motion7.AnimatePresence, { children: open && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
602
|
+
import_framer_motion7.motion.div,
|
|
603
|
+
{
|
|
604
|
+
initial: { opacity: 0, height: 0 },
|
|
605
|
+
animate: { opacity: 1, height: "auto" },
|
|
606
|
+
exit: { opacity: 0, height: 0 },
|
|
607
|
+
transition: { duration: 0.22, ease: "easeInOut" },
|
|
608
|
+
className: "md:hidden overflow-hidden border-b border-border backdrop-blur-xl",
|
|
609
|
+
style: { background: "var(--glass-bg-strong, var(--background))" },
|
|
610
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("ul", { className: "container mx-auto flex flex-col px-4 pb-5 pt-1 gap-0.5", children: [
|
|
611
|
+
data.links.map((link) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
612
|
+
"a",
|
|
613
|
+
{
|
|
614
|
+
href: link.href,
|
|
615
|
+
onClick: () => setOpen(false),
|
|
616
|
+
className: "block rounded-lg px-3 py-2.5 text-sm text-muted-foreground hover:text-foreground hover:bg-accent transition-colors",
|
|
617
|
+
children: link.label
|
|
618
|
+
}
|
|
619
|
+
) }, link.href)),
|
|
620
|
+
data.cta && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("li", { className: "mt-3 pt-3 border-t border-border", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
621
|
+
"a",
|
|
622
|
+
{
|
|
623
|
+
href: data.cta.href,
|
|
624
|
+
onClick: () => setOpen(false),
|
|
625
|
+
className: "block rounded-full px-5 py-2.5 text-sm font-semibold text-center bg-primary text-primary-foreground hover:opacity-90 transition-opacity",
|
|
626
|
+
children: data.cta.label
|
|
627
|
+
}
|
|
628
|
+
) })
|
|
629
|
+
] })
|
|
630
|
+
},
|
|
631
|
+
"mobile-menu"
|
|
632
|
+
) })
|
|
633
|
+
]
|
|
634
|
+
}
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// src/cta-banner/index.tsx
|
|
639
|
+
var import_framer_motion8 = require("framer-motion");
|
|
640
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
641
|
+
function CTABanner({ data, className }) {
|
|
642
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
643
|
+
"section",
|
|
644
|
+
{
|
|
645
|
+
className: cn("relative w-full py-24 lg:py-36 overflow-hidden", className),
|
|
646
|
+
children: [
|
|
647
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
648
|
+
"div",
|
|
649
|
+
{
|
|
650
|
+
"aria-hidden": true,
|
|
651
|
+
className: "absolute inset-0",
|
|
652
|
+
style: {
|
|
653
|
+
background: "var(--gradient-cta, linear-gradient(135deg, var(--primary) 0%, var(--ring) 100%))"
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
),
|
|
657
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
658
|
+
"div",
|
|
659
|
+
{
|
|
660
|
+
"aria-hidden": true,
|
|
661
|
+
className: "absolute -top-32 left-1/3 w-96 h-96 rounded-full blur-3xl opacity-30 pointer-events-none",
|
|
662
|
+
style: { background: "var(--primary, #8fccb6)" }
|
|
663
|
+
}
|
|
664
|
+
),
|
|
665
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
666
|
+
"div",
|
|
667
|
+
{
|
|
668
|
+
"aria-hidden": true,
|
|
669
|
+
className: "absolute -bottom-32 right-1/4 w-96 h-96 rounded-full blur-3xl opacity-20 pointer-events-none",
|
|
670
|
+
style: { background: "var(--wmm-violet, #869ce2)" }
|
|
671
|
+
}
|
|
672
|
+
),
|
|
673
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "relative container mx-auto px-4 md:px-6 text-center max-w-3xl", children: [
|
|
674
|
+
data.badge && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
675
|
+
import_framer_motion8.motion.div,
|
|
676
|
+
{
|
|
677
|
+
initial: { opacity: 0, y: 12 },
|
|
678
|
+
whileInView: { opacity: 1, y: 0 },
|
|
679
|
+
viewport: { once: true },
|
|
680
|
+
transition: { duration: 0.5 },
|
|
681
|
+
className: "flex justify-center mb-5",
|
|
682
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SectionLabel, { className: "border-white/20 text-white/90", children: data.badge })
|
|
683
|
+
}
|
|
684
|
+
),
|
|
685
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
686
|
+
import_framer_motion8.motion.h2,
|
|
687
|
+
{
|
|
688
|
+
initial: { opacity: 0, y: 24 },
|
|
689
|
+
whileInView: { opacity: 1, y: 0 },
|
|
690
|
+
viewport: { once: true },
|
|
691
|
+
transition: { duration: 0.6, delay: data.badge ? 0.08 : 0 },
|
|
692
|
+
className: "text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight text-white mb-5",
|
|
693
|
+
children: data.heading
|
|
694
|
+
}
|
|
695
|
+
),
|
|
696
|
+
data.subheading && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
697
|
+
import_framer_motion8.motion.p,
|
|
698
|
+
{
|
|
699
|
+
initial: { opacity: 0, y: 16 },
|
|
700
|
+
whileInView: { opacity: 1, y: 0 },
|
|
701
|
+
viewport: { once: true },
|
|
702
|
+
transition: { duration: 0.6, delay: 0.12 },
|
|
703
|
+
className: "text-lg md:text-xl text-white/75 max-w-xl mx-auto mb-10",
|
|
704
|
+
children: data.subheading
|
|
705
|
+
}
|
|
706
|
+
),
|
|
707
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
708
|
+
import_framer_motion8.motion.div,
|
|
709
|
+
{
|
|
710
|
+
initial: { opacity: 0, y: 16 },
|
|
711
|
+
whileInView: { opacity: 1, y: 0 },
|
|
712
|
+
viewport: { once: true },
|
|
713
|
+
transition: { duration: 0.5, delay: 0.2 },
|
|
714
|
+
className: "flex flex-col sm:flex-row items-center justify-center gap-3",
|
|
715
|
+
children: [
|
|
716
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
717
|
+
"a",
|
|
718
|
+
{
|
|
719
|
+
href: data.primaryCta.href,
|
|
720
|
+
className: "inline-flex items-center justify-center rounded-full px-8 py-3.5 text-sm font-semibold bg-white text-foreground shadow-lg hover:bg-white/92 transition-all active:scale-[0.97]",
|
|
721
|
+
children: data.primaryCta.label
|
|
722
|
+
}
|
|
723
|
+
),
|
|
724
|
+
data.secondaryCta && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
725
|
+
"a",
|
|
726
|
+
{
|
|
727
|
+
href: data.secondaryCta.href,
|
|
728
|
+
className: "inline-flex items-center justify-center rounded-full px-8 py-3.5 text-sm font-semibold text-white border border-white/30 hover:bg-white/10 transition-all",
|
|
729
|
+
children: data.secondaryCta.label
|
|
730
|
+
}
|
|
731
|
+
)
|
|
732
|
+
]
|
|
733
|
+
}
|
|
734
|
+
)
|
|
735
|
+
] })
|
|
736
|
+
]
|
|
737
|
+
}
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// src/process-steps/index.tsx
|
|
742
|
+
var import_framer_motion9 = require("framer-motion");
|
|
743
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
744
|
+
function ProcessSteps({
|
|
745
|
+
label,
|
|
746
|
+
heading,
|
|
747
|
+
subheading,
|
|
748
|
+
steps,
|
|
749
|
+
layout = "horizontal",
|
|
750
|
+
className
|
|
751
|
+
}) {
|
|
752
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("section", { className: cn("w-full py-16 lg:py-28", className), children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "container px-4 md:px-6 max-w-5xl mx-auto", children: [
|
|
753
|
+
(label || heading || subheading) && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "text-center mb-14 space-y-4", children: [
|
|
754
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SectionLabel, { children: label }) }),
|
|
755
|
+
heading && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { className: "text-3xl md:text-4xl font-bold tracking-tight text-foreground", children: heading }),
|
|
756
|
+
subheading && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-muted-foreground max-w-xl mx-auto", children: subheading })
|
|
757
|
+
] }),
|
|
758
|
+
layout === "horizontal" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
759
|
+
"div",
|
|
760
|
+
{
|
|
761
|
+
className: cn(
|
|
762
|
+
"grid gap-8",
|
|
763
|
+
steps.length <= 3 ? "md:grid-cols-3" : "md:grid-cols-2 lg:grid-cols-4"
|
|
764
|
+
),
|
|
765
|
+
children: steps.map((step, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
766
|
+
import_framer_motion9.motion.div,
|
|
767
|
+
{
|
|
768
|
+
initial: { opacity: 0, y: 20 },
|
|
769
|
+
whileInView: { opacity: 1, y: 0 },
|
|
770
|
+
viewport: { once: true },
|
|
771
|
+
transition: { duration: 0.5, delay: i * 0.1 },
|
|
772
|
+
className: "relative flex flex-col gap-4",
|
|
773
|
+
children: [
|
|
774
|
+
i < steps.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
775
|
+
"div",
|
|
776
|
+
{
|
|
777
|
+
"aria-hidden": true,
|
|
778
|
+
className: "hidden md:block absolute top-5 left-[calc(50%+24px)] right-0 h-px",
|
|
779
|
+
style: { background: "var(--gradient-primary, var(--primary))", opacity: 0.25 }
|
|
780
|
+
}
|
|
781
|
+
),
|
|
782
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
783
|
+
"div",
|
|
784
|
+
{
|
|
785
|
+
className: "flex h-10 w-10 items-center justify-center rounded-xl border border-primary/30 bg-primary/10 shrink-0",
|
|
786
|
+
children: step.icon ?? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-sm font-bold text-primary", children: String(i + 1).padStart(2, "0") })
|
|
787
|
+
}
|
|
788
|
+
),
|
|
789
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
|
|
790
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm font-semibold text-foreground mb-1", children: step.title }),
|
|
791
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground", children: step.description })
|
|
792
|
+
] })
|
|
793
|
+
]
|
|
794
|
+
},
|
|
795
|
+
i
|
|
796
|
+
))
|
|
797
|
+
}
|
|
798
|
+
) : (
|
|
799
|
+
/* Vertical layout */
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "max-w-2xl mx-auto space-y-0", children: steps.map((step, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
801
|
+
import_framer_motion9.motion.div,
|
|
802
|
+
{
|
|
803
|
+
initial: { opacity: 0, x: -16 },
|
|
804
|
+
whileInView: { opacity: 1, x: 0 },
|
|
805
|
+
viewport: { once: true },
|
|
806
|
+
transition: { duration: 0.5, delay: i * 0.08 },
|
|
807
|
+
className: "relative flex gap-6 pb-10 last:pb-0",
|
|
808
|
+
children: [
|
|
809
|
+
i < steps.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
810
|
+
"div",
|
|
811
|
+
{
|
|
812
|
+
"aria-hidden": true,
|
|
813
|
+
className: "absolute left-5 top-10 bottom-0 w-px",
|
|
814
|
+
style: { background: "var(--border)" }
|
|
815
|
+
}
|
|
816
|
+
),
|
|
817
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "shrink-0 flex h-10 w-10 items-center justify-center rounded-xl border border-primary/30 bg-primary/10 z-10", children: step.icon ?? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-sm font-bold text-primary", children: String(i + 1).padStart(2, "0") }) }),
|
|
818
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "pt-1.5", children: [
|
|
819
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm font-semibold text-foreground mb-1", children: step.title }),
|
|
820
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm text-muted-foreground", children: step.description })
|
|
821
|
+
] })
|
|
822
|
+
]
|
|
823
|
+
},
|
|
824
|
+
i
|
|
825
|
+
)) })
|
|
826
|
+
)
|
|
827
|
+
] }) });
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// src/contact-form/index.tsx
|
|
831
|
+
var React5 = __toESM(require("react"));
|
|
832
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
833
|
+
function ContactForm({ data, onSubmit, className }) {
|
|
834
|
+
const [values, setValues] = React5.useState({});
|
|
835
|
+
const [loading, setLoading] = React5.useState(false);
|
|
836
|
+
const [sent, setSent] = React5.useState(false);
|
|
837
|
+
const set = (name, val) => setValues((prev) => ({ ...prev, [name]: val }));
|
|
838
|
+
const handleSubmit = async (e) => {
|
|
839
|
+
e.preventDefault();
|
|
840
|
+
if (!onSubmit) {
|
|
841
|
+
setSent(true);
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
setLoading(true);
|
|
845
|
+
try {
|
|
846
|
+
await onSubmit(values);
|
|
847
|
+
setSent(true);
|
|
848
|
+
} finally {
|
|
849
|
+
setLoading(false);
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
const inputBase = "w-full rounded-lg border border-input bg-background px-3.5 py-2.5 text-sm text-foreground placeholder:text-muted-foreground/60 transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:border-transparent disabled:opacity-50";
|
|
853
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("section", { className: cn("w-full py-16 lg:py-28", className), children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "container px-4 md:px-6 max-w-5xl mx-auto", children: [
|
|
854
|
+
(data.label || data.heading || data.subheading) && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "text-center mb-12 space-y-4", children: [
|
|
855
|
+
data.label && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SectionLabel, { children: data.label }) }),
|
|
856
|
+
data.heading && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { className: "text-3xl md:text-4xl font-bold tracking-tight text-foreground", children: data.heading }),
|
|
857
|
+
data.subheading && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-muted-foreground max-w-xl mx-auto", children: data.subheading })
|
|
858
|
+
] }),
|
|
859
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: cn("grid gap-12", data.aside ? "md:grid-cols-[1fr_2fr]" : "max-w-2xl mx-auto"), children: [
|
|
860
|
+
data.aside && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { children: data.aside }),
|
|
861
|
+
sent ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col items-center justify-center text-center gap-4 rounded-2xl border border-border bg-card p-12", children: [
|
|
862
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex h-14 w-14 items-center justify-center rounded-full bg-primary/10 text-primary", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M20 6 9 17l-5-5" }) }) }),
|
|
863
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-lg font-semibold text-foreground", children: "Message sent!" }),
|
|
864
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm text-muted-foreground", children: "We'll be in touch shortly." })
|
|
865
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
866
|
+
"form",
|
|
867
|
+
{
|
|
868
|
+
onSubmit: handleSubmit,
|
|
869
|
+
className: "grid grid-cols-2 gap-5 rounded-2xl border border-border bg-card p-6 md:p-8",
|
|
870
|
+
style: { boxShadow: "var(--shadow-card)" },
|
|
871
|
+
children: [
|
|
872
|
+
data.fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
873
|
+
"div",
|
|
874
|
+
{
|
|
875
|
+
className: cn(
|
|
876
|
+
"flex flex-col gap-1.5",
|
|
877
|
+
field.colSpan === 2 || field.type === "textarea" ? "col-span-2" : "col-span-2 sm:col-span-1"
|
|
878
|
+
),
|
|
879
|
+
children: [
|
|
880
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
881
|
+
"label",
|
|
882
|
+
{
|
|
883
|
+
htmlFor: field.name,
|
|
884
|
+
className: "text-xs font-medium text-foreground",
|
|
885
|
+
children: [
|
|
886
|
+
field.label,
|
|
887
|
+
field.required && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-primary ml-0.5", children: "*" })
|
|
888
|
+
]
|
|
889
|
+
}
|
|
890
|
+
),
|
|
891
|
+
field.type === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
892
|
+
"textarea",
|
|
893
|
+
{
|
|
894
|
+
id: field.name,
|
|
895
|
+
name: field.name,
|
|
896
|
+
rows: 5,
|
|
897
|
+
required: field.required,
|
|
898
|
+
placeholder: field.placeholder,
|
|
899
|
+
value: values[field.name] ?? "",
|
|
900
|
+
onChange: (e) => set(field.name, e.target.value),
|
|
901
|
+
className: cn(inputBase, "resize-none")
|
|
902
|
+
}
|
|
903
|
+
) : field.type === "select" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
904
|
+
"select",
|
|
905
|
+
{
|
|
906
|
+
id: field.name,
|
|
907
|
+
name: field.name,
|
|
908
|
+
required: field.required,
|
|
909
|
+
value: values[field.name] ?? "",
|
|
910
|
+
onChange: (e) => set(field.name, e.target.value),
|
|
911
|
+
className: inputBase,
|
|
912
|
+
children: [
|
|
913
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "", children: field.placeholder ?? "Select\u2026" }),
|
|
914
|
+
field.options?.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: opt, children: opt }, opt))
|
|
915
|
+
]
|
|
916
|
+
}
|
|
917
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
918
|
+
"input",
|
|
919
|
+
{
|
|
920
|
+
id: field.name,
|
|
921
|
+
name: field.name,
|
|
922
|
+
type: field.type ?? "text",
|
|
923
|
+
required: field.required,
|
|
924
|
+
placeholder: field.placeholder,
|
|
925
|
+
value: values[field.name] ?? "",
|
|
926
|
+
onChange: (e) => set(field.name, e.target.value),
|
|
927
|
+
className: inputBase
|
|
928
|
+
}
|
|
929
|
+
)
|
|
930
|
+
]
|
|
931
|
+
},
|
|
932
|
+
field.name
|
|
933
|
+
)),
|
|
934
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "col-span-2 mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
935
|
+
"button",
|
|
936
|
+
{
|
|
937
|
+
type: "submit",
|
|
938
|
+
disabled: loading,
|
|
939
|
+
className: "w-full flex items-center justify-center rounded-full px-6 py-3 text-sm font-semibold bg-primary text-primary-foreground hover:opacity-90 disabled:opacity-60 transition-all active:scale-[0.98]",
|
|
940
|
+
children: loading ? "Sending\u2026" : data.submitLabel ?? "Send Message"
|
|
941
|
+
}
|
|
942
|
+
) })
|
|
943
|
+
]
|
|
944
|
+
}
|
|
945
|
+
)
|
|
946
|
+
] })
|
|
947
|
+
] }) });
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// src/case-studies-section/index.tsx
|
|
951
|
+
var import_framer_motion10 = require("framer-motion");
|
|
952
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
953
|
+
function CaseStudiesSection({
|
|
954
|
+
label,
|
|
955
|
+
heading,
|
|
956
|
+
subheading,
|
|
957
|
+
items,
|
|
958
|
+
className
|
|
959
|
+
}) {
|
|
960
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("section", { className: cn("w-full py-16 lg:py-28", className), children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "container px-4 md:px-6 max-w-6xl mx-auto", children: [
|
|
961
|
+
(label || heading || subheading) && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "text-center mb-14 space-y-4", children: [
|
|
962
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SectionLabel, { children: label }) }),
|
|
963
|
+
heading && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h2", { className: "text-3xl md:text-4xl font-bold tracking-tight text-foreground", children: heading }),
|
|
964
|
+
subheading && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-muted-foreground max-w-xl mx-auto", children: subheading })
|
|
965
|
+
] }),
|
|
966
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "grid gap-6 md:grid-cols-2", children: items.map((cs, i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
967
|
+
import_framer_motion10.motion.article,
|
|
968
|
+
{
|
|
969
|
+
initial: { opacity: 0, y: 24 },
|
|
970
|
+
whileInView: { opacity: 1, y: 0 },
|
|
971
|
+
whileHover: { y: -4 },
|
|
972
|
+
viewport: { once: true },
|
|
973
|
+
transition: { duration: 0.5, delay: i * 0.08 },
|
|
974
|
+
className: cn(
|
|
975
|
+
"relative flex flex-col rounded-2xl border border-border bg-card overflow-hidden"
|
|
976
|
+
),
|
|
977
|
+
style: { boxShadow: "var(--shadow-card)" },
|
|
978
|
+
children: [
|
|
979
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
980
|
+
"div",
|
|
981
|
+
{
|
|
982
|
+
"aria-hidden": true,
|
|
983
|
+
className: "absolute inset-x-8 top-0 h-px",
|
|
984
|
+
style: { background: "var(--gradient-primary, var(--primary))", opacity: 0.4 }
|
|
985
|
+
}
|
|
986
|
+
),
|
|
987
|
+
cs.image && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "w-full border-b border-border overflow-hidden max-h-48", children: cs.image }),
|
|
988
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col flex-1 p-6 gap-5", children: [
|
|
989
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
990
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "inline-flex items-center rounded-full px-2.5 py-1 text-xs font-semibold bg-primary/12 text-primary", children: cs.client }),
|
|
991
|
+
cs.vertical && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "inline-flex items-center rounded-full px-2.5 py-1 text-xs font-medium bg-muted text-muted-foreground", children: cs.vertical })
|
|
992
|
+
] }),
|
|
993
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("dl", { className: "space-y-3", children: [
|
|
994
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex gap-2 items-start", children: [
|
|
995
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dt", { className: "shrink-0 text-xs font-semibold text-muted-foreground uppercase tracking-widest w-16 pt-0.5", children: "Before" }),
|
|
996
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dd", { className: "text-sm text-muted-foreground", children: cs.before })
|
|
997
|
+
] }),
|
|
998
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex gap-2 items-start", children: [
|
|
999
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dt", { className: "shrink-0 text-xs font-semibold text-primary uppercase tracking-widest w-16 pt-0.5", children: "Built" }),
|
|
1000
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dd", { className: "text-sm text-foreground", children: cs.built })
|
|
1001
|
+
] }),
|
|
1002
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex gap-2 items-start", children: [
|
|
1003
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dt", { className: "shrink-0 text-xs font-semibold text-emerald-500 uppercase tracking-widest w-16 pt-0.5", children: "Result" }),
|
|
1004
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("dd", { className: "text-sm font-medium text-foreground", children: cs.result })
|
|
1005
|
+
] })
|
|
1006
|
+
] }),
|
|
1007
|
+
cs.stats && cs.stats.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex gap-4 flex-wrap border-t border-border pt-4", children: cs.stats.map((s, j) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
|
|
1008
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-xl font-bold text-foreground", children: s.value }),
|
|
1009
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-xs text-muted-foreground", children: s.label })
|
|
1010
|
+
] }, j)) }),
|
|
1011
|
+
cs.quote && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("blockquote", { className: "border-l-2 border-primary/40 pl-4 mt-auto", children: [
|
|
1012
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("p", { className: "text-sm italic text-muted-foreground", children: [
|
|
1013
|
+
'"',
|
|
1014
|
+
cs.quote,
|
|
1015
|
+
'"'
|
|
1016
|
+
] }),
|
|
1017
|
+
cs.quoteAuthor && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("cite", { className: "text-xs text-muted-foreground/70 not-italic mt-1 block", children: [
|
|
1018
|
+
"\u2014 ",
|
|
1019
|
+
cs.quoteAuthor
|
|
1020
|
+
] })
|
|
1021
|
+
] }),
|
|
1022
|
+
cs.href && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1023
|
+
"a",
|
|
1024
|
+
{
|
|
1025
|
+
href: cs.href,
|
|
1026
|
+
className: "mt-auto self-start text-xs font-semibold text-primary hover:text-primary/80 underline-offset-2 hover:underline transition-colors",
|
|
1027
|
+
children: "Read full case study \u2192"
|
|
1028
|
+
}
|
|
1029
|
+
)
|
|
1030
|
+
] })
|
|
1031
|
+
]
|
|
1032
|
+
},
|
|
1033
|
+
i
|
|
1034
|
+
)) })
|
|
1035
|
+
] }) });
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// src/bento-grid/index.tsx
|
|
1039
|
+
var import_framer_motion11 = require("framer-motion");
|
|
1040
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1041
|
+
var spanCols = {
|
|
1042
|
+
1: "md:col-span-1",
|
|
1043
|
+
2: "md:col-span-2",
|
|
1044
|
+
3: "md:col-span-3"
|
|
1045
|
+
};
|
|
1046
|
+
var spanRows = {
|
|
1047
|
+
1: "",
|
|
1048
|
+
2: "md:row-span-2"
|
|
1049
|
+
};
|
|
1050
|
+
function BentoGrid({
|
|
1051
|
+
label,
|
|
1052
|
+
heading,
|
|
1053
|
+
subheading,
|
|
1054
|
+
cells,
|
|
1055
|
+
className
|
|
1056
|
+
}) {
|
|
1057
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("section", { className: cn("w-full py-16 lg:py-28", className), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "container px-4 md:px-6 max-w-6xl mx-auto", children: [
|
|
1058
|
+
(label || heading || subheading) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "text-center mb-12 space-y-4", children: [
|
|
1059
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SectionLabel, { children: label }) }),
|
|
1060
|
+
heading && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h2", { className: "text-3xl md:text-4xl font-bold tracking-tight text-foreground", children: heading }),
|
|
1061
|
+
subheading && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-muted-foreground max-w-xl mx-auto", children: subheading })
|
|
1062
|
+
] }),
|
|
1063
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4 auto-rows-fr", children: cells.map((cell, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1064
|
+
import_framer_motion11.motion.div,
|
|
1065
|
+
{
|
|
1066
|
+
initial: { opacity: 0, y: 20 },
|
|
1067
|
+
whileInView: { opacity: 1, y: 0 },
|
|
1068
|
+
viewport: { once: true },
|
|
1069
|
+
transition: { duration: 0.5, delay: i * 0.07 },
|
|
1070
|
+
className: cn(
|
|
1071
|
+
"relative flex flex-col rounded-2xl border overflow-hidden p-6 min-h-[180px]",
|
|
1072
|
+
spanCols[cell.colSpan ?? 1],
|
|
1073
|
+
spanRows[cell.rowSpan ?? 1],
|
|
1074
|
+
cell.highlight ? "border-primary/50 bg-card" : "border-border bg-card",
|
|
1075
|
+
cell.className
|
|
1076
|
+
),
|
|
1077
|
+
style: cell.highlight ? { boxShadow: "var(--shadow-glow, none)" } : { boxShadow: "var(--shadow-card)" },
|
|
1078
|
+
children: [
|
|
1079
|
+
cell.highlight && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1080
|
+
"div",
|
|
1081
|
+
{
|
|
1082
|
+
"aria-hidden": true,
|
|
1083
|
+
className: "absolute inset-x-0 top-0 h-px",
|
|
1084
|
+
style: { background: "var(--gradient-primary, var(--primary))" }
|
|
1085
|
+
}
|
|
1086
|
+
),
|
|
1087
|
+
cell.tag && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1088
|
+
"span",
|
|
1089
|
+
{
|
|
1090
|
+
className: cn(
|
|
1091
|
+
"self-start inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium mb-4",
|
|
1092
|
+
cell.highlight ? "bg-primary/15 text-primary" : "bg-muted text-muted-foreground"
|
|
1093
|
+
),
|
|
1094
|
+
children: cell.tag
|
|
1095
|
+
}
|
|
1096
|
+
),
|
|
1097
|
+
cell.visual && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "mb-4 flex-1 flex items-start", children: cell.visual }),
|
|
1098
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "mt-auto", children: [
|
|
1099
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-base font-semibold text-foreground mb-1", children: cell.title }),
|
|
1100
|
+
cell.description && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground", children: cell.description })
|
|
1101
|
+
] })
|
|
1102
|
+
]
|
|
1103
|
+
},
|
|
1104
|
+
i
|
|
1105
|
+
)) })
|
|
1106
|
+
] }) });
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
// src/stats-section/index.tsx
|
|
1110
|
+
var React6 = __toESM(require("react"));
|
|
1111
|
+
var import_framer_motion12 = require("framer-motion");
|
|
1112
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1113
|
+
function CountUp({ value, animate: shouldAnimate = true }) {
|
|
1114
|
+
const ref = React6.useRef(null);
|
|
1115
|
+
const inView = (0, import_framer_motion12.useInView)(ref, { once: true, margin: "-80px" });
|
|
1116
|
+
const motionVal = (0, import_framer_motion12.useMotionValue)(0);
|
|
1117
|
+
const rounded = (0, import_framer_motion12.useTransform)(motionVal, (v) => Math.round(v));
|
|
1118
|
+
const [display, setDisplay] = React6.useState(shouldAnimate ? 0 : value);
|
|
1119
|
+
React6.useEffect(() => {
|
|
1120
|
+
if (!shouldAnimate) {
|
|
1121
|
+
setDisplay(value);
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
if (!inView) return;
|
|
1125
|
+
const controls = (0, import_framer_motion12.animate)(motionVal, value, { duration: 1.8, ease: "easeOut" });
|
|
1126
|
+
const unsub = rounded.on("change", (v) => setDisplay(v));
|
|
1127
|
+
return () => {
|
|
1128
|
+
controls.stop();
|
|
1129
|
+
unsub();
|
|
1130
|
+
};
|
|
1131
|
+
}, [inView, value, shouldAnimate]);
|
|
1132
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { ref, children: display.toLocaleString() });
|
|
1133
|
+
}
|
|
1134
|
+
function StatsSection({
|
|
1135
|
+
label,
|
|
1136
|
+
heading,
|
|
1137
|
+
subheading,
|
|
1138
|
+
stats,
|
|
1139
|
+
animate: shouldAnimate = true,
|
|
1140
|
+
className
|
|
1141
|
+
}) {
|
|
1142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
1143
|
+
"section",
|
|
1144
|
+
{
|
|
1145
|
+
className: cn("w-full py-16 lg:py-24 relative overflow-hidden", className),
|
|
1146
|
+
children: [
|
|
1147
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1148
|
+
"div",
|
|
1149
|
+
{
|
|
1150
|
+
"aria-hidden": true,
|
|
1151
|
+
className: "absolute inset-0 pointer-events-none",
|
|
1152
|
+
style: { background: "var(--gradient-teal-glow, none)" }
|
|
1153
|
+
}
|
|
1154
|
+
),
|
|
1155
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "relative container px-4 md:px-6 max-w-5xl mx-auto", children: [
|
|
1156
|
+
(label || heading || subheading) && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "text-center mb-14 space-y-4", children: [
|
|
1157
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SectionLabel, { children: label }) }),
|
|
1158
|
+
heading && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h2", { className: "text-3xl md:text-4xl font-bold tracking-tight text-foreground", children: heading }),
|
|
1159
|
+
subheading && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-muted-foreground max-w-xl mx-auto", children: subheading })
|
|
1160
|
+
] }),
|
|
1161
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1162
|
+
"div",
|
|
1163
|
+
{
|
|
1164
|
+
className: cn(
|
|
1165
|
+
"grid gap-8 sm:gap-12",
|
|
1166
|
+
stats.length === 2 && "sm:grid-cols-2",
|
|
1167
|
+
stats.length === 3 && "sm:grid-cols-3",
|
|
1168
|
+
stats.length >= 4 && "sm:grid-cols-2 lg:grid-cols-4"
|
|
1169
|
+
),
|
|
1170
|
+
children: stats.map((stat, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
1171
|
+
import_framer_motion12.motion.div,
|
|
1172
|
+
{
|
|
1173
|
+
initial: { opacity: 0, y: 24 },
|
|
1174
|
+
whileInView: { opacity: 1, y: 0 },
|
|
1175
|
+
viewport: { once: true },
|
|
1176
|
+
transition: { duration: 0.5, delay: i * 0.1 },
|
|
1177
|
+
className: "flex flex-col items-center text-center gap-2",
|
|
1178
|
+
children: [
|
|
1179
|
+
i > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1180
|
+
"div",
|
|
1181
|
+
{
|
|
1182
|
+
"aria-hidden": true,
|
|
1183
|
+
className: "hidden sm:block absolute h-16 w-px bg-border/60 left-0 top-1/2 -translate-y-1/2"
|
|
1184
|
+
}
|
|
1185
|
+
),
|
|
1186
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("p", { className: "text-5xl md:text-6xl font-black tracking-tight text-foreground tabular-nums", children: [
|
|
1187
|
+
stat.prefix && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-primary", children: stat.prefix }),
|
|
1188
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CountUp, { value: stat.value, animate: shouldAnimate }),
|
|
1189
|
+
stat.suffix && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-primary", children: stat.suffix })
|
|
1190
|
+
] }),
|
|
1191
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-sm font-semibold text-foreground", children: stat.label }),
|
|
1192
|
+
stat.description && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-xs text-muted-foreground max-w-[140px]", children: stat.description })
|
|
1193
|
+
]
|
|
1194
|
+
},
|
|
1195
|
+
i
|
|
1196
|
+
))
|
|
1197
|
+
}
|
|
1198
|
+
)
|
|
1199
|
+
] })
|
|
1200
|
+
]
|
|
1201
|
+
}
|
|
1202
|
+
);
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// src/logo-cloud/index.tsx
|
|
1206
|
+
var import_framer_motion13 = require("framer-motion");
|
|
1207
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1208
|
+
function LogoCloud({
|
|
1209
|
+
eyebrow,
|
|
1210
|
+
items,
|
|
1211
|
+
variant = "marquee",
|
|
1212
|
+
speed = 32,
|
|
1213
|
+
className
|
|
1214
|
+
}) {
|
|
1215
|
+
const doubled = [...items, ...items];
|
|
1216
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("section", { className: cn("w-full py-10 lg:py-16", className), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "container px-4 md:px-6 max-w-6xl mx-auto", children: [
|
|
1217
|
+
eyebrow && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-center text-xs font-medium uppercase tracking-widest text-muted-foreground mb-8", children: eyebrow }),
|
|
1218
|
+
variant === "static" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex flex-wrap items-center justify-center gap-8 md:gap-12", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1219
|
+
import_framer_motion13.motion.div,
|
|
1220
|
+
{
|
|
1221
|
+
initial: { opacity: 0 },
|
|
1222
|
+
whileInView: { opacity: 1 },
|
|
1223
|
+
viewport: { once: true },
|
|
1224
|
+
transition: { duration: 0.4, delay: i * 0.06 },
|
|
1225
|
+
title: item.name,
|
|
1226
|
+
className: "opacity-50 hover:opacity-80 transition-opacity grayscale hover:grayscale-0",
|
|
1227
|
+
children: item.logo
|
|
1228
|
+
},
|
|
1229
|
+
i
|
|
1230
|
+
)) }) : (
|
|
1231
|
+
/* Marquee */
|
|
1232
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "relative overflow-hidden", children: [
|
|
1233
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1234
|
+
"div",
|
|
1235
|
+
{
|
|
1236
|
+
"aria-hidden": true,
|
|
1237
|
+
className: "pointer-events-none absolute inset-y-0 left-0 w-20 z-10",
|
|
1238
|
+
style: { background: "linear-gradient(to right, var(--background), transparent)" }
|
|
1239
|
+
}
|
|
1240
|
+
),
|
|
1241
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1242
|
+
"div",
|
|
1243
|
+
{
|
|
1244
|
+
"aria-hidden": true,
|
|
1245
|
+
className: "pointer-events-none absolute inset-y-0 right-0 w-20 z-10",
|
|
1246
|
+
style: { background: "linear-gradient(to left, var(--background), transparent)" }
|
|
1247
|
+
}
|
|
1248
|
+
),
|
|
1249
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1250
|
+
import_framer_motion13.motion.div,
|
|
1251
|
+
{
|
|
1252
|
+
className: "flex gap-12 items-center",
|
|
1253
|
+
animate: { x: ["0%", "-50%"] },
|
|
1254
|
+
transition: { duration: speed, ease: "linear", repeat: Infinity },
|
|
1255
|
+
children: doubled.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1256
|
+
"div",
|
|
1257
|
+
{
|
|
1258
|
+
title: item.name,
|
|
1259
|
+
className: "shrink-0 opacity-40 hover:opacity-75 transition-opacity grayscale hover:grayscale-0",
|
|
1260
|
+
children: item.logo
|
|
1261
|
+
},
|
|
1262
|
+
i
|
|
1263
|
+
))
|
|
1264
|
+
}
|
|
1265
|
+
)
|
|
1266
|
+
] })
|
|
1267
|
+
)
|
|
1268
|
+
] }) });
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
// src/hero-section/index.tsx
|
|
1272
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1273
|
+
function HeroSection({
|
|
1274
|
+
headline,
|
|
1275
|
+
subheadline,
|
|
1276
|
+
primaryCta,
|
|
1277
|
+
secondaryCta,
|
|
1278
|
+
className,
|
|
1279
|
+
children
|
|
1280
|
+
}) {
|
|
1281
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1282
|
+
"section",
|
|
1283
|
+
{
|
|
1284
|
+
className: cn(
|
|
1285
|
+
"w-full py-12 md:py-24 lg:py-32 xl:py-48 bg-muted/50 border-b",
|
|
1286
|
+
className
|
|
1287
|
+
),
|
|
1288
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "container px-4 md:px-6", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col items-center space-y-4 text-center", children: [
|
|
1289
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "space-y-2", children: [
|
|
1290
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h1", { className: "text-3xl font-bold tracking-tighter sm:text-4xl md:text-5xl lg:text-6xl/none", children: headline }),
|
|
1291
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "mx-auto max-w-[700px] text-muted-foreground md:text-xl", children: subheadline })
|
|
1292
|
+
] }),
|
|
1293
|
+
(primaryCta || secondaryCta) && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex gap-4", children: [
|
|
1294
|
+
primaryCta,
|
|
1295
|
+
secondaryCta
|
|
1296
|
+
] }),
|
|
1297
|
+
children
|
|
1298
|
+
] }) })
|
|
1299
|
+
}
|
|
1300
|
+
);
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// src/feature-grid/index.tsx
|
|
1304
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1305
|
+
function FeatureGrid({
|
|
1306
|
+
sectionTitle,
|
|
1307
|
+
features,
|
|
1308
|
+
columns = 3,
|
|
1309
|
+
className
|
|
1310
|
+
}) {
|
|
1311
|
+
const gridCols = {
|
|
1312
|
+
2: "md:grid-cols-2",
|
|
1313
|
+
3: "md:grid-cols-3",
|
|
1314
|
+
4: "md:grid-cols-2 lg:grid-cols-4"
|
|
1315
|
+
};
|
|
1316
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("section", { className: cn("w-full py-12 lg:py-24", className), children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "container px-4 md:px-6", children: [
|
|
1317
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h2", { className: "text-3xl font-bold tracking-tighter text-center mb-8", children: sectionTitle }),
|
|
1318
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: cn("grid grid-cols-1 gap-6", gridCols[columns]), children: features.map((feature, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1319
|
+
"div",
|
|
1320
|
+
{
|
|
1321
|
+
className: "flex flex-col items-center p-6 border rounded-lg bg-card text-card-foreground shadow-sm",
|
|
1322
|
+
children: [
|
|
1323
|
+
feature.icon ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "mb-4", children: feature.icon }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "h-12 w-12 rounded-full bg-muted mb-4" }),
|
|
1324
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { className: "text-xl font-bold mb-2", children: feature.title }),
|
|
1325
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-muted-foreground text-center", children: feature.description })
|
|
1326
|
+
]
|
|
1327
|
+
},
|
|
1328
|
+
i
|
|
1329
|
+
)) })
|
|
1330
|
+
] }) });
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
// src/pricing-table/index.tsx
|
|
1334
|
+
var React7 = __toESM(require("react"));
|
|
1335
|
+
var import_framer_motion14 = require("framer-motion");
|
|
1336
|
+
var import_lucide_react3 = require("lucide-react");
|
|
1337
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1338
|
+
function formatPrice(p, billing, annualPrice) {
|
|
1339
|
+
if (typeof p === "string") return p;
|
|
1340
|
+
if (billing === "annual" && annualPrice !== void 0) {
|
|
1341
|
+
return typeof annualPrice === "number" ? String(annualPrice) : annualPrice;
|
|
1342
|
+
}
|
|
1343
|
+
return String(p);
|
|
1344
|
+
}
|
|
1345
|
+
function PricingTable({
|
|
1346
|
+
sectionTitle,
|
|
1347
|
+
label,
|
|
1348
|
+
heading,
|
|
1349
|
+
subheading,
|
|
1350
|
+
plans,
|
|
1351
|
+
priceSuffix = "/mo",
|
|
1352
|
+
showToggle = true,
|
|
1353
|
+
annualSavingsLabel = "Save 20%",
|
|
1354
|
+
className
|
|
1355
|
+
}) {
|
|
1356
|
+
const [billing, setBilling] = React7.useState("monthly");
|
|
1357
|
+
const hasAnnual = plans.some((p) => p.annualPrice !== void 0);
|
|
1358
|
+
const title = heading ?? sectionTitle ?? "";
|
|
1359
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("section", { className: cn("w-full py-16 lg:py-28", className), children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "container px-4 md:px-6 max-w-6xl mx-auto", children: [
|
|
1360
|
+
(label || title || subheading) && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "text-center mb-10 space-y-4", children: [
|
|
1361
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SectionLabel, { children: label }) }),
|
|
1362
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h2", { className: "text-3xl md:text-4xl font-bold tracking-tight text-foreground", children: title }),
|
|
1363
|
+
subheading && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-muted-foreground max-w-xl mx-auto", children: subheading })
|
|
1364
|
+
] }),
|
|
1365
|
+
showToggle && hasAnnual && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center justify-center gap-3 mb-10", children: [
|
|
1366
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1367
|
+
"span",
|
|
1368
|
+
{
|
|
1369
|
+
className: cn(
|
|
1370
|
+
"text-sm font-medium transition-colors",
|
|
1371
|
+
billing === "monthly" ? "text-foreground" : "text-muted-foreground"
|
|
1372
|
+
),
|
|
1373
|
+
children: "Monthly"
|
|
1374
|
+
}
|
|
1375
|
+
),
|
|
1376
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1377
|
+
"button",
|
|
1378
|
+
{
|
|
1379
|
+
role: "switch",
|
|
1380
|
+
"aria-checked": billing === "annual",
|
|
1381
|
+
onClick: () => setBilling((b) => b === "monthly" ? "annual" : "monthly"),
|
|
1382
|
+
className: cn(
|
|
1383
|
+
"relative inline-flex h-6 w-11 cursor-pointer rounded-full border-2 border-transparent transition-colors",
|
|
1384
|
+
billing === "annual" ? "bg-primary" : "bg-muted-foreground/30"
|
|
1385
|
+
),
|
|
1386
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1387
|
+
"span",
|
|
1388
|
+
{
|
|
1389
|
+
className: cn(
|
|
1390
|
+
"pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow-sm transition-transform",
|
|
1391
|
+
billing === "annual" ? "translate-x-5" : "translate-x-0"
|
|
1392
|
+
)
|
|
1393
|
+
}
|
|
1394
|
+
)
|
|
1395
|
+
}
|
|
1396
|
+
),
|
|
1397
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1398
|
+
"span",
|
|
1399
|
+
{
|
|
1400
|
+
className: cn(
|
|
1401
|
+
"text-sm font-medium transition-colors",
|
|
1402
|
+
billing === "annual" ? "text-foreground" : "text-muted-foreground"
|
|
1403
|
+
),
|
|
1404
|
+
children: [
|
|
1405
|
+
"Annual",
|
|
1406
|
+
annualSavingsLabel && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "ml-1.5 inline-flex items-center rounded-full px-2 py-0.5 text-xs font-semibold bg-primary/15 text-primary", children: annualSavingsLabel })
|
|
1407
|
+
]
|
|
1408
|
+
}
|
|
1409
|
+
)
|
|
1410
|
+
] }),
|
|
1411
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1412
|
+
"div",
|
|
1413
|
+
{
|
|
1414
|
+
className: cn(
|
|
1415
|
+
"grid gap-6",
|
|
1416
|
+
plans.length === 2 && "md:grid-cols-2 max-w-3xl mx-auto",
|
|
1417
|
+
plans.length === 3 && "md:grid-cols-2 lg:grid-cols-3",
|
|
1418
|
+
plans.length >= 4 && "md:grid-cols-2 lg:grid-cols-4"
|
|
1419
|
+
),
|
|
1420
|
+
children: plans.map((plan, i) => {
|
|
1421
|
+
const isFeatured = plan.isPrimary ?? plan.featured ?? false;
|
|
1422
|
+
const displayPrice = formatPrice(plan.price, billing, plan.annualPrice);
|
|
1423
|
+
const suffix = plan.priceSuffix ?? priceSuffix;
|
|
1424
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1425
|
+
import_framer_motion14.motion.div,
|
|
1426
|
+
{
|
|
1427
|
+
initial: { opacity: 0, y: 24 },
|
|
1428
|
+
whileInView: { opacity: 1, y: 0 },
|
|
1429
|
+
viewport: { once: true },
|
|
1430
|
+
transition: { duration: 0.5, delay: i * 0.08 },
|
|
1431
|
+
className: cn(
|
|
1432
|
+
"relative flex flex-col rounded-2xl border overflow-hidden transition-shadow",
|
|
1433
|
+
isFeatured ? "border-primary/60 bg-card" : "border-border bg-card"
|
|
1434
|
+
),
|
|
1435
|
+
style: isFeatured ? { boxShadow: "var(--shadow-glow, 0 4px 24px oklch(0.58 0.15 175 / 22%))" } : { boxShadow: "var(--shadow-card)" },
|
|
1436
|
+
children: [
|
|
1437
|
+
isFeatured && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1438
|
+
"div",
|
|
1439
|
+
{
|
|
1440
|
+
"aria-hidden": true,
|
|
1441
|
+
className: "absolute inset-x-0 top-0 h-px",
|
|
1442
|
+
style: { background: "var(--gradient-primary, var(--primary))" }
|
|
1443
|
+
}
|
|
1444
|
+
),
|
|
1445
|
+
plan.badge && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "absolute top-4 right-4", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "inline-flex items-center rounded-full px-2.5 py-1 text-xs font-semibold bg-primary text-primary-foreground", children: plan.badge }) }),
|
|
1446
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "p-6 pb-0", children: [
|
|
1447
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-sm font-medium text-muted-foreground mb-1", children: plan.name }),
|
|
1448
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-xs text-muted-foreground/70 mb-5", children: plan.target }),
|
|
1449
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-end gap-1 mb-6", children: [
|
|
1450
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-4xl font-bold text-foreground tracking-tight", children: typeof displayPrice === "number" ? `$${displayPrice}` : displayPrice }),
|
|
1451
|
+
typeof plan.price === "number" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-sm text-muted-foreground mb-1.5", children: suffix })
|
|
1452
|
+
] })
|
|
1453
|
+
] }),
|
|
1454
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex-1 px-6 pb-6", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ul", { className: "space-y-3", children: plan.features.map((feature, j) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("li", { className: "flex items-start gap-2.5 text-sm text-muted-foreground", children: [
|
|
1455
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1456
|
+
import_lucide_react3.Check,
|
|
1457
|
+
{
|
|
1458
|
+
size: 15,
|
|
1459
|
+
className: "shrink-0 mt-0.5 text-primary",
|
|
1460
|
+
strokeWidth: 2.5
|
|
1461
|
+
}
|
|
1462
|
+
),
|
|
1463
|
+
feature
|
|
1464
|
+
] }, j)) }) }),
|
|
1465
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "px-6 pb-6", children: plan.cta ?? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1466
|
+
"a",
|
|
1467
|
+
{
|
|
1468
|
+
href: plan.ctaHref ?? "#",
|
|
1469
|
+
className: cn(
|
|
1470
|
+
"flex w-full items-center justify-center rounded-full px-4 py-2.5 text-sm font-semibold transition-all active:scale-[0.97]",
|
|
1471
|
+
isFeatured ? "bg-primary text-primary-foreground hover:opacity-90" : "border border-border bg-background text-foreground hover:bg-accent"
|
|
1472
|
+
),
|
|
1473
|
+
children: plan.ctaText
|
|
1474
|
+
}
|
|
1475
|
+
) })
|
|
1476
|
+
]
|
|
1477
|
+
},
|
|
1478
|
+
i
|
|
1479
|
+
);
|
|
1480
|
+
})
|
|
1481
|
+
}
|
|
1482
|
+
)
|
|
1483
|
+
] }) });
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
// src/testimonial-carousel/index.tsx
|
|
1487
|
+
var import_react = require("react");
|
|
1488
|
+
var import_framer_motion15 = require("framer-motion");
|
|
1489
|
+
var import_lucide_react4 = require("lucide-react");
|
|
1490
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1491
|
+
var SPRING_EASE2 = [0.22, 1, 0.36, 1];
|
|
1492
|
+
function isPlaceholderCompany(company) {
|
|
1493
|
+
return /^TBD\b/i.test(company.trim());
|
|
1494
|
+
}
|
|
1495
|
+
function TestimonialsCarousel({
|
|
1496
|
+
data,
|
|
1497
|
+
filterByVertical,
|
|
1498
|
+
className
|
|
1499
|
+
}) {
|
|
1500
|
+
const reviews = (0, import_react.useMemo)(() => {
|
|
1501
|
+
const visible = data.reviews.filter((r) => !r.hidden);
|
|
1502
|
+
if (!filterByVertical) return visible;
|
|
1503
|
+
const filtered = visible.filter((r) => r.vertical === filterByVertical);
|
|
1504
|
+
return filtered.length > 0 ? filtered : visible;
|
|
1505
|
+
}, [data.reviews, filterByVertical]);
|
|
1506
|
+
const verticalLabels = data.vertical_labels ?? {};
|
|
1507
|
+
const [{ index, direction }, setCarouselState] = (0, import_react.useState)({ index: 0, direction: 1 });
|
|
1508
|
+
const [isPaused, setIsPaused] = (0, import_react.useState)(false);
|
|
1509
|
+
(0, import_react.useEffect)(() => {
|
|
1510
|
+
if (isPaused || reviews.length === 0) return;
|
|
1511
|
+
const id = window.setInterval(() => {
|
|
1512
|
+
setCarouselState((s) => ({ index: (s.index + 1) % reviews.length, direction: 1 }));
|
|
1513
|
+
}, 5e3);
|
|
1514
|
+
return () => window.clearInterval(id);
|
|
1515
|
+
}, [isPaused, reviews.length]);
|
|
1516
|
+
const paginate = (dir) => {
|
|
1517
|
+
if (reviews.length === 0) return;
|
|
1518
|
+
setCarouselState((s) => ({
|
|
1519
|
+
index: (s.index + dir + reviews.length) % reviews.length,
|
|
1520
|
+
direction: dir
|
|
1521
|
+
}));
|
|
1522
|
+
};
|
|
1523
|
+
if (reviews.length === 0) return null;
|
|
1524
|
+
const safeIndex = Math.min(index, reviews.length - 1);
|
|
1525
|
+
const active = reviews[safeIndex];
|
|
1526
|
+
const hasMedia = Boolean(active.video);
|
|
1527
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: cn("mt-14", className), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
1528
|
+
"div",
|
|
1529
|
+
{
|
|
1530
|
+
className: "relative overflow-hidden rounded-[36px] border border-border bg-[linear-gradient(180deg,color-mix(in_srgb,var(--foreground)_6%,transparent),color-mix(in_srgb,var(--foreground)_2%,transparent))] p-4 shadow-panel md:p-6",
|
|
1531
|
+
onMouseEnter: () => setIsPaused(true),
|
|
1532
|
+
onMouseLeave: () => setIsPaused(false),
|
|
1533
|
+
children: [
|
|
1534
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "pointer-events-none absolute inset-0 opacity-[0.05]" }),
|
|
1535
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "pointer-events-none absolute left-[8%] top-0 h-24 w-1/3 rounded-full bg-primary/12 blur-3xl" }),
|
|
1536
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "pointer-events-none absolute bottom-0 right-[8%] h-28 w-1/3 rounded-full bg-secondary/10 blur-3xl" }),
|
|
1537
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "pointer-events-none absolute inset-x-10 bottom-0 h-px bg-gradient-to-r from-transparent via-foreground/15 to-transparent" }),
|
|
1538
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "relative z-10 overflow-hidden rounded-[30px]", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_framer_motion15.AnimatePresence, { initial: false, mode: "wait", custom: direction, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
1539
|
+
import_framer_motion15.motion.div,
|
|
1540
|
+
{
|
|
1541
|
+
custom: direction,
|
|
1542
|
+
initial: { opacity: 0, x: direction > 0 ? 72 : -72, scale: 0.98 },
|
|
1543
|
+
animate: { opacity: 1, x: 0, scale: 1 },
|
|
1544
|
+
exit: { opacity: 0, x: direction > 0 ? -72 : 72, scale: 0.98 },
|
|
1545
|
+
transition: { duration: 0.45, ease: SPRING_EASE2 },
|
|
1546
|
+
className: cn(
|
|
1547
|
+
"glass-panel rounded-[30px] p-6 md:p-8",
|
|
1548
|
+
hasMedia ? "grid gap-8 lg:grid-cols-[0.95fr_1.05fr] lg:items-center lg:gap-10" : "relative overflow-hidden md:p-12"
|
|
1549
|
+
),
|
|
1550
|
+
style: { willChange: "transform, opacity" },
|
|
1551
|
+
children: [
|
|
1552
|
+
hasMedia && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "relative overflow-hidden rounded-[28px] border border-border bg-[radial-gradient(circle_at_top,color-mix(in_srgb,var(--foreground)_10%,transparent),transparent_40%),linear-gradient(180deg,color-mix(in_srgb,var(--foreground)_5%,transparent),rgba(8,11,20,0.6))]", children: [
|
|
1553
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "aspect-[9/16] w-full" }),
|
|
1554
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1555
|
+
"video",
|
|
1556
|
+
{
|
|
1557
|
+
src: active.thumbnail ? active.video : `${active.video}#t=0.1`,
|
|
1558
|
+
poster: active.thumbnail,
|
|
1559
|
+
preload: "metadata",
|
|
1560
|
+
playsInline: true,
|
|
1561
|
+
controls: true,
|
|
1562
|
+
className: "absolute inset-0 h-full w-full object-cover"
|
|
1563
|
+
}
|
|
1564
|
+
)
|
|
1565
|
+
] }),
|
|
1566
|
+
hasMedia ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { children: [
|
|
1567
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex items-center gap-1.5 text-[color:var(--rating-star,#F5C451)]", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react4.Star, { className: "h-4 w-4 fill-current" }, i)) }),
|
|
1568
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react4.Quote, { className: "mt-6 h-8 w-8 text-primary" }),
|
|
1569
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "mt-6 text-xl leading-9 text-foreground md:text-[1.75rem] md:leading-[1.65] lg:max-w-[18ch]", children: active.quote }),
|
|
1570
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "mt-8 border-t border-border pt-6", children: [
|
|
1571
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-sm font-semibold uppercase tracking-[0.12em] text-foreground", children: active.author }),
|
|
1572
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1573
|
+
"p",
|
|
1574
|
+
{
|
|
1575
|
+
className: cn(
|
|
1576
|
+
"mt-2 text-sm",
|
|
1577
|
+
isPlaceholderCompany(active.company) ? "text-amber-300/80" : "text-muted-foreground"
|
|
1578
|
+
),
|
|
1579
|
+
children: isPlaceholderCompany(active.company) ? "Company TBD" : active.company
|
|
1580
|
+
}
|
|
1581
|
+
),
|
|
1582
|
+
active.vertical && verticalLabels[active.vertical] && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "mt-2 inline-block rounded-full border border-border bg-foreground/[0.05] px-2.5 py-0.5 text-[10px] font-semibold uppercase tracking-[0.14em] text-primary/90", children: verticalLabels[active.vertical] })
|
|
1583
|
+
] })
|
|
1584
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "relative mx-auto max-w-3xl text-center", children: [
|
|
1585
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "pointer-events-none absolute left-1/2 top-0 h-40 w-40 -translate-x-1/2 -translate-y-1/2 rounded-full bg-primary/12 blur-3xl" }),
|
|
1586
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "relative flex flex-col items-center gap-4", children: [
|
|
1587
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react4.Quote, { className: "h-10 w-10 text-primary" }),
|
|
1588
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex items-center gap-1.5 text-[color:var(--rating-star,#F5C451)]", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react4.Star, { className: "h-4 w-4 fill-current" }, i)) })
|
|
1589
|
+
] }),
|
|
1590
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("p", { className: "relative mt-6 font-display text-2xl font-black leading-[1.35] tracking-[-0.02em] text-foreground md:text-3xl md:leading-[1.4]", children: [
|
|
1591
|
+
"\u201C",
|
|
1592
|
+
active.quote,
|
|
1593
|
+
"\u201D"
|
|
1594
|
+
] }),
|
|
1595
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "relative mx-auto mt-8 h-px w-24 bg-gradient-to-r from-transparent via-primary/50 to-transparent" }),
|
|
1596
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "relative mt-6", children: [
|
|
1597
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-sm font-semibold uppercase tracking-[0.16em] text-foreground", children: active.author }),
|
|
1598
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1599
|
+
"p",
|
|
1600
|
+
{
|
|
1601
|
+
className: cn(
|
|
1602
|
+
"mt-2 text-sm",
|
|
1603
|
+
isPlaceholderCompany(active.company) ? "text-amber-300/80" : "text-muted-foreground"
|
|
1604
|
+
),
|
|
1605
|
+
children: isPlaceholderCompany(active.company) ? "Company TBD" : active.company
|
|
1606
|
+
}
|
|
1607
|
+
),
|
|
1608
|
+
active.vertical && verticalLabels[active.vertical] && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "mt-3 inline-block rounded-full border border-border bg-foreground/[0.05] px-2.5 py-0.5 text-[10px] font-semibold uppercase tracking-[0.14em] text-primary/90", children: verticalLabels[active.vertical] })
|
|
1609
|
+
] })
|
|
1610
|
+
] })
|
|
1611
|
+
]
|
|
1612
|
+
},
|
|
1613
|
+
`${active.author}-${active.company}`
|
|
1614
|
+
) }) }),
|
|
1615
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "relative z-10 mt-5 flex items-center justify-between gap-4", children: [
|
|
1616
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1617
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1618
|
+
"button",
|
|
1619
|
+
{
|
|
1620
|
+
type: "button",
|
|
1621
|
+
onClick: () => paginate(-1),
|
|
1622
|
+
className: "inline-flex h-11 w-11 items-center justify-center rounded-full border border-border bg-foreground/[0.05] text-foreground transition-colors hover:border-border hover:bg-foreground/[0.08]",
|
|
1623
|
+
"aria-label": "Previous testimonial",
|
|
1624
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react4.ChevronLeft, { className: "h-5 w-5" })
|
|
1625
|
+
}
|
|
1626
|
+
),
|
|
1627
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1628
|
+
"button",
|
|
1629
|
+
{
|
|
1630
|
+
type: "button",
|
|
1631
|
+
onClick: () => paginate(1),
|
|
1632
|
+
className: "inline-flex h-11 w-11 items-center justify-center rounded-full border border-border bg-foreground/[0.05] text-foreground transition-colors hover:border-border hover:bg-foreground/[0.08]",
|
|
1633
|
+
"aria-label": "Next testimonial",
|
|
1634
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react4.ChevronRight, { className: "h-5 w-5" })
|
|
1635
|
+
}
|
|
1636
|
+
)
|
|
1637
|
+
] }),
|
|
1638
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
1639
|
+
"div",
|
|
1640
|
+
{
|
|
1641
|
+
className: "font-label text-sm tabular-nums text-muted-foreground",
|
|
1642
|
+
"aria-live": "polite",
|
|
1643
|
+
"aria-label": `Testimonial ${safeIndex + 1} of ${reviews.length}`,
|
|
1644
|
+
children: [
|
|
1645
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-foreground", children: safeIndex + 1 }),
|
|
1646
|
+
" / ",
|
|
1647
|
+
reviews.length
|
|
1648
|
+
]
|
|
1649
|
+
}
|
|
1650
|
+
)
|
|
1651
|
+
] })
|
|
1652
|
+
]
|
|
1653
|
+
}
|
|
1654
|
+
) });
|
|
1655
|
+
}
|
|
1656
|
+
function TestimonialsSection({ data, filterByVertical }) {
|
|
1657
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("section", { id: "testimonials", className: "section-shell", children: [
|
|
1658
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SectionGlow, { variant: "primary" }),
|
|
1659
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "pointer-events-none absolute inset-x-0 top-0 h-24 bg-gradient-to-b from-foreground/[0.05] to-transparent" }),
|
|
1660
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "container", children: [
|
|
1661
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(FadeUp, { className: "max-w-3xl", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SectionIntro, { label: data.label, title: data.title, body: data.description }) }),
|
|
1662
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TestimonialsCarousel, { data, filterByVertical })
|
|
1663
|
+
] })
|
|
1664
|
+
] });
|
|
1665
|
+
}
|
|
1666
|
+
var TestimonialCarousel = TestimonialsCarousel;
|
|
1667
|
+
|
|
1668
|
+
// src/use-cases/index.tsx
|
|
1669
|
+
var import_lucide_react5 = require("lucide-react");
|
|
1670
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1671
|
+
var DEFAULT_ICONS = {
|
|
1672
|
+
Settings: import_lucide_react5.Settings,
|
|
1673
|
+
ShoppingBag: import_lucide_react5.ShoppingBag,
|
|
1674
|
+
PhoneCall: import_lucide_react5.PhoneCall,
|
|
1675
|
+
Lightbulb: import_lucide_react5.Lightbulb,
|
|
1676
|
+
Store: import_lucide_react5.Store
|
|
1677
|
+
};
|
|
1678
|
+
function UseCasesSection({ data, iconMap }) {
|
|
1679
|
+
const icons = { ...DEFAULT_ICONS, ...iconMap };
|
|
1680
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("section", { id: "use-cases", className: "section-shell overflow-x-clip pb-12 md:pb-24", children: [
|
|
1681
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SectionGlow, { variant: "primary" }),
|
|
1682
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "pointer-events-none absolute inset-0 opacity-[0.03]" }),
|
|
1683
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "pointer-events-none absolute left-[-10%] top-1/4 h-96 w-96 rounded-full bg-secondary/[0.18] blur-[100px]" }),
|
|
1684
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "pointer-events-none absolute right-[-10%] top-2/3 h-96 w-96 rounded-full bg-accent/10 blur-[100px]" }),
|
|
1685
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "container relative z-10", children: [
|
|
1686
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FadeUp, { className: "mx-auto max-w-3xl text-center", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SectionIntro, { label: data.label, title: data.title, centered: true }) }),
|
|
1687
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(FadeUp, { className: "mt-11 md:mt-14", delay: 0.2, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "relative mx-auto grid max-w-6xl grid-cols-2 gap-px lg:grid-cols-6", children: data.cards.map((card, idx) => {
|
|
1688
|
+
const Icon = icons[card.icon] ?? import_lucide_react5.Settings;
|
|
1689
|
+
const colClass = data.cards.length === 5 ? idx < 2 ? "lg:col-span-2" : idx === 2 ? "col-span-2 lg:col-span-2" : "col-span-2 lg:col-span-3" : "";
|
|
1690
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
1691
|
+
"div",
|
|
1692
|
+
{
|
|
1693
|
+
className: cn(
|
|
1694
|
+
"group relative flex flex-col border border-border bg-foreground/[0.04] p-4 transition-colors duration-500 hover:border-border hover:bg-foreground/[0.05] md:p-7",
|
|
1695
|
+
colClass
|
|
1696
|
+
),
|
|
1697
|
+
children: [
|
|
1698
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "pointer-events-none absolute -right-4 -top-4 h-24 w-24 rounded-full bg-foreground/[0.05] blur-2xl transition-all duration-500 group-hover:bg-foreground/10" }),
|
|
1699
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex h-10 w-10 items-center justify-center rounded-xl border border-border bg-foreground/[0.05] text-primary shadow-sm transition-transform duration-500 group-hover:scale-110 group-hover:border-border group-hover:bg-foreground/[0.07] md:h-12 md:w-12", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Icon, { className: "h-4 w-4 md:h-5 md:w-5" }) }),
|
|
1700
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "mt-4 flex flex-1 flex-col md:mt-6", children: [
|
|
1701
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { className: "font-display text-lg font-bold leading-tight tracking-tight text-foreground md:text-2xl", children: card.title }),
|
|
1702
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "mt-2 text-xs font-medium text-muted-foreground md:text-sm", children: card.subtitle }),
|
|
1703
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "mt-auto pt-4 md:pt-6", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "text-[10px] leading-relaxed text-muted-foreground md:text-xs", children: card.tracking }) })
|
|
1704
|
+
] })
|
|
1705
|
+
]
|
|
1706
|
+
},
|
|
1707
|
+
card.title
|
|
1708
|
+
);
|
|
1709
|
+
}) }) })
|
|
1710
|
+
] })
|
|
1711
|
+
] });
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
// src/value-stack/index.tsx
|
|
1715
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1716
|
+
function StackRows({ rows }) {
|
|
1717
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("ul", { className: "divide-y divide-border", children: rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
1718
|
+
"li",
|
|
1719
|
+
{
|
|
1720
|
+
className: "grid grid-cols-[1fr_auto] items-baseline gap-4 py-2 md:gap-6 md:py-3",
|
|
1721
|
+
children: [
|
|
1722
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "min-w-0", children: [
|
|
1723
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-sm text-foreground/90 md:text-base", children: row.deliverable }),
|
|
1724
|
+
row.note && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "mt-0.5 text-[11px] leading-snug text-muted-foreground", children: row.note })
|
|
1725
|
+
] }),
|
|
1726
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "shrink-0 font-display text-sm font-black tracking-[-0.02em] text-foreground md:text-base", children: row.value })
|
|
1727
|
+
]
|
|
1728
|
+
},
|
|
1729
|
+
row.deliverable
|
|
1730
|
+
)) });
|
|
1731
|
+
}
|
|
1732
|
+
function ValueStackSection({ data }) {
|
|
1733
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("section", { id: "value-stack", className: "section-shell relative overflow-x-clip", children: [
|
|
1734
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SectionGlow, { variant: "primary" }),
|
|
1735
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "pointer-events-none absolute -left-20 top-1/3 h-72 w-72 rounded-full bg-accent/10 blur-3xl" }),
|
|
1736
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "pointer-events-none absolute -right-20 bottom-0 h-80 w-80 rounded-full bg-secondary/[0.08] blur-3xl" }),
|
|
1737
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "container", children: [
|
|
1738
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(FadeUp, { className: "max-w-3xl", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SectionIntro, { label: data.label, title: data.title, body: data.body }) }),
|
|
1739
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(FadeUp, { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "mt-12 overflow-hidden rounded-[28px] border border-border bg-[linear-gradient(180deg,color-mix(in_srgb,var(--foreground)_5%,transparent),color-mix(in_srgb,var(--foreground)_2%,transparent))] shadow-panel", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "grid divide-border lg:grid-cols-2 lg:divide-x", children: ["setup_block", "ongoing_block"].map((blockKey, i) => {
|
|
1740
|
+
const block = data[blockKey];
|
|
1741
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
1742
|
+
"div",
|
|
1743
|
+
{
|
|
1744
|
+
className: cn(
|
|
1745
|
+
"relative p-6 md:p-8",
|
|
1746
|
+
i === 1 && "border-t border-border lg:border-t-0"
|
|
1747
|
+
),
|
|
1748
|
+
children: [
|
|
1749
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { className: "text-xs uppercase tracking-[0.18em] text-primary", children: block.title }),
|
|
1750
|
+
block.subtitle && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "mt-1 text-sm text-muted-foreground", children: block.subtitle }),
|
|
1751
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "mt-5", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(StackRows, { rows: block.rows }) })
|
|
1752
|
+
]
|
|
1753
|
+
},
|
|
1754
|
+
blockKey
|
|
1755
|
+
);
|
|
1756
|
+
}) }) }) }),
|
|
1757
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(FadeUp, { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "mt-8 mx-auto max-w-3xl rounded-[28px] border border-accent/30 bg-[radial-gradient(circle_at_top,rgba(115,136,207,0.14),transparent_55%),linear-gradient(180deg,color-mix(in_srgb,var(--foreground)_5%,transparent),color-mix(in_srgb,var(--foreground)_2%,transparent))] p-6 shadow-panel md:p-8", children: [
|
|
1758
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "mb-2 text-[10px] uppercase tracking-[0.22em] text-muted-foreground", children: "If you hire it out" }),
|
|
1759
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "grid gap-3 md:grid-cols-[1fr_auto] md:items-center md:gap-6", children: [
|
|
1760
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "text-sm text-muted-foreground md:text-base", children: data.totals.monthly_label }),
|
|
1761
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "font-display text-xl font-black tracking-[-0.02em] text-foreground/80 md:text-2xl", children: data.totals.monthly_value })
|
|
1762
|
+
] }),
|
|
1763
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "mt-2 grid gap-3 md:grid-cols-[1fr_auto] md:items-center md:gap-6", children: [
|
|
1764
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "text-sm text-muted-foreground md:text-base", children: data.totals.setup_label }),
|
|
1765
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "font-display text-xl font-black tracking-[-0.02em] text-foreground/80 md:text-2xl", children: data.totals.setup_value })
|
|
1766
|
+
] }),
|
|
1767
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "my-6 h-px bg-gradient-to-r from-transparent via-primary/40 to-transparent" }),
|
|
1768
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "grid gap-4 md:grid-cols-[1fr_auto] md:items-center md:gap-6", children: [
|
|
1769
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { children: [
|
|
1770
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "text-[11px] uppercase tracking-[0.22em] text-accent", children: data.investment.label }),
|
|
1771
|
+
data.investment.note && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "mt-2 text-xs leading-relaxed text-muted-foreground", children: data.investment.note })
|
|
1772
|
+
] }),
|
|
1773
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "font-display text-xl font-black leading-tight tracking-[-0.03em] text-foreground md:text-2xl", children: data.investment.value })
|
|
1774
|
+
] })
|
|
1775
|
+
] }) })
|
|
1776
|
+
] })
|
|
1777
|
+
] });
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
// src/tech-carousel/index.tsx
|
|
1781
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1782
|
+
function TechCarousel({
|
|
1783
|
+
items,
|
|
1784
|
+
className,
|
|
1785
|
+
speed = "normal",
|
|
1786
|
+
reverse = false,
|
|
1787
|
+
hoverColor = "text-teal"
|
|
1788
|
+
}) {
|
|
1789
|
+
const doubled = [...items, ...items];
|
|
1790
|
+
const animClass = reverse ? speed === "slow" ? "animate-marquee-reverse" : "animate-marquee-reverse" : speed === "slow" ? "animate-marquee-slow" : "animate-marquee";
|
|
1791
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1792
|
+
"div",
|
|
1793
|
+
{
|
|
1794
|
+
className: cn(
|
|
1795
|
+
"relative overflow-hidden mask-fade-horizontal",
|
|
1796
|
+
className
|
|
1797
|
+
),
|
|
1798
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cn("flex w-max gap-10 py-4 translate-gpu", animClass), children: doubled.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
1799
|
+
"div",
|
|
1800
|
+
{
|
|
1801
|
+
className: cn(
|
|
1802
|
+
"flex shrink-0 items-center gap-2 text-muted transition-colors duration-300",
|
|
1803
|
+
`hover:${hoverColor}`
|
|
1804
|
+
),
|
|
1805
|
+
children: [
|
|
1806
|
+
item.icon,
|
|
1807
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "text-sm font-medium whitespace-nowrap", children: item.name })
|
|
1808
|
+
]
|
|
1809
|
+
},
|
|
1810
|
+
i
|
|
1811
|
+
)) })
|
|
1812
|
+
}
|
|
1813
|
+
);
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
// src/footer/index.tsx
|
|
1817
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1818
|
+
function Footer({
|
|
1819
|
+
copyrightText,
|
|
1820
|
+
links,
|
|
1821
|
+
className,
|
|
1822
|
+
children
|
|
1823
|
+
}) {
|
|
1824
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("footer", { className: cn("w-full py-6 bg-background border-t", className), children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "container px-4 md:px-6 flex flex-col md:flex-row items-center justify-between", children: [
|
|
1825
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "text-sm text-muted-foreground", children: copyrightText }),
|
|
1826
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("nav", { className: "flex gap-4 sm:gap-6 mt-4 md:mt-0", children: links.map((link, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1827
|
+
"a",
|
|
1828
|
+
{
|
|
1829
|
+
href: link.href,
|
|
1830
|
+
className: "text-sm hover:underline cursor-pointer",
|
|
1831
|
+
children: link.label
|
|
1832
|
+
},
|
|
1833
|
+
i
|
|
1834
|
+
)) }),
|
|
1835
|
+
children
|
|
1836
|
+
] }) });
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
// src/social-proof/index.tsx
|
|
1840
|
+
var import_framer_motion16 = require("framer-motion");
|
|
1841
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1842
|
+
function SocialProof({ items, logos, className }) {
|
|
1843
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("section", { className: cn("w-full py-8 border-y bg-muted/20", className), children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "container px-4 md:px-6", children: [
|
|
1844
|
+
logos && logos.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex flex-wrap items-center justify-center gap-8 mb-8 opacity-60", children: logos.map((logo, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { children: logo }, i)) }),
|
|
1845
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-6 text-center", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
1846
|
+
import_framer_motion16.motion.div,
|
|
1847
|
+
{
|
|
1848
|
+
initial: { opacity: 0, y: 20 },
|
|
1849
|
+
whileInView: { opacity: 1, y: 0 },
|
|
1850
|
+
viewport: { once: true },
|
|
1851
|
+
transition: { delay: i * 0.1 },
|
|
1852
|
+
children: [
|
|
1853
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "text-3xl font-bold", children: item.value }),
|
|
1854
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "text-sm text-muted-foreground", children: item.label })
|
|
1855
|
+
]
|
|
1856
|
+
},
|
|
1857
|
+
i
|
|
1858
|
+
)) })
|
|
1859
|
+
] }) });
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
// src/faq/index.tsx
|
|
1863
|
+
var React8 = __toESM(require("react"));
|
|
1864
|
+
var import_framer_motion17 = require("framer-motion");
|
|
1865
|
+
var import_lucide_react6 = require("lucide-react");
|
|
1866
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1867
|
+
function Faq({
|
|
1868
|
+
sectionTitle,
|
|
1869
|
+
label,
|
|
1870
|
+
heading,
|
|
1871
|
+
subheading,
|
|
1872
|
+
items,
|
|
1873
|
+
mode = "single",
|
|
1874
|
+
className
|
|
1875
|
+
}) {
|
|
1876
|
+
const [openSet, setOpenSet] = React8.useState(/* @__PURE__ */ new Set());
|
|
1877
|
+
const title = heading ?? sectionTitle ?? "";
|
|
1878
|
+
const toggle = (i) => {
|
|
1879
|
+
setOpenSet((prev) => {
|
|
1880
|
+
const next = new Set(mode === "multi" ? prev : /* @__PURE__ */ new Set());
|
|
1881
|
+
if (prev.has(i)) next.delete(i);
|
|
1882
|
+
else next.add(i);
|
|
1883
|
+
return next;
|
|
1884
|
+
});
|
|
1885
|
+
};
|
|
1886
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("section", { className: cn("w-full py-16 lg:py-28", className), children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "container px-4 md:px-6 max-w-3xl mx-auto", children: [
|
|
1887
|
+
(label || title || subheading) && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "text-center mb-12 space-y-4", children: [
|
|
1888
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SectionLabel, { children: label }) }),
|
|
1889
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { className: "text-3xl md:text-4xl font-bold tracking-tight text-foreground", children: title }),
|
|
1890
|
+
subheading && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-muted-foreground max-w-xl mx-auto", children: subheading })
|
|
1891
|
+
] }),
|
|
1892
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "space-y-2", children: items.map((item, i) => {
|
|
1893
|
+
const isOpen = openSet.has(i);
|
|
1894
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1895
|
+
import_framer_motion17.motion.div,
|
|
1896
|
+
{
|
|
1897
|
+
initial: false,
|
|
1898
|
+
className: cn(
|
|
1899
|
+
"rounded-xl border overflow-hidden transition-colors",
|
|
1900
|
+
isOpen ? "border-primary/40 bg-card" : "border-border bg-card/50"
|
|
1901
|
+
),
|
|
1902
|
+
style: isOpen ? { boxShadow: "var(--glow-primary-sm, none)" } : void 0,
|
|
1903
|
+
children: [
|
|
1904
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
1905
|
+
"button",
|
|
1906
|
+
{
|
|
1907
|
+
className: "flex w-full items-center justify-between gap-4 px-5 py-4 text-left",
|
|
1908
|
+
onClick: () => toggle(i),
|
|
1909
|
+
"aria-expanded": isOpen,
|
|
1910
|
+
children: [
|
|
1911
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1912
|
+
"span",
|
|
1913
|
+
{
|
|
1914
|
+
className: cn(
|
|
1915
|
+
"text-sm font-medium transition-colors",
|
|
1916
|
+
isOpen ? "text-foreground" : "text-foreground/80"
|
|
1917
|
+
),
|
|
1918
|
+
children: item.question
|
|
1919
|
+
}
|
|
1920
|
+
),
|
|
1921
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1922
|
+
"span",
|
|
1923
|
+
{
|
|
1924
|
+
className: cn(
|
|
1925
|
+
"shrink-0 rounded-full p-0.5 border transition-all",
|
|
1926
|
+
isOpen ? "border-primary/50 text-primary" : "border-border text-muted-foreground"
|
|
1927
|
+
),
|
|
1928
|
+
children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react6.Minus, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react6.Plus, { size: 14 })
|
|
1929
|
+
}
|
|
1930
|
+
)
|
|
1931
|
+
]
|
|
1932
|
+
}
|
|
1933
|
+
),
|
|
1934
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_framer_motion17.AnimatePresence, { initial: false, children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1935
|
+
import_framer_motion17.motion.div,
|
|
1936
|
+
{
|
|
1937
|
+
initial: { height: 0, opacity: 0 },
|
|
1938
|
+
animate: { height: "auto", opacity: 1 },
|
|
1939
|
+
exit: { height: 0, opacity: 0 },
|
|
1940
|
+
transition: { duration: 0.25, ease: "easeInOut" },
|
|
1941
|
+
className: "overflow-hidden",
|
|
1942
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "px-5 pb-5 text-sm text-muted-foreground leading-relaxed", children: item.answer })
|
|
1943
|
+
},
|
|
1944
|
+
"answer"
|
|
1945
|
+
) })
|
|
1946
|
+
]
|
|
1947
|
+
},
|
|
1948
|
+
i
|
|
1949
|
+
);
|
|
1950
|
+
}) })
|
|
1951
|
+
] }) });
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
// src/comparison-table/index.tsx
|
|
1955
|
+
var import_lucide_react7 = require("lucide-react");
|
|
1956
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1957
|
+
function ComparisonTable({
|
|
1958
|
+
columns,
|
|
1959
|
+
rows,
|
|
1960
|
+
highlightColumn,
|
|
1961
|
+
className
|
|
1962
|
+
}) {
|
|
1963
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: cn("w-full overflow-x-auto", className), children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("table", { className: "w-full text-sm", children: [
|
|
1964
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("tr", { className: "border-b", children: [
|
|
1965
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("th", { className: "p-4 text-left font-medium text-muted-foreground", children: "Feature" }),
|
|
1966
|
+
columns.map((col, i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1967
|
+
"th",
|
|
1968
|
+
{
|
|
1969
|
+
className: cn(
|
|
1970
|
+
"p-4 text-center font-bold",
|
|
1971
|
+
highlightColumn === i && "bg-primary/5 text-primary"
|
|
1972
|
+
),
|
|
1973
|
+
children: col
|
|
1974
|
+
},
|
|
1975
|
+
i
|
|
1976
|
+
))
|
|
1977
|
+
] }) }),
|
|
1978
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("tbody", { children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("tr", { className: "border-b last:border-0", children: [
|
|
1979
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("td", { className: "p-4 font-medium", children: row.feature }),
|
|
1980
|
+
row.values.map((val, j) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1981
|
+
"td",
|
|
1982
|
+
{
|
|
1983
|
+
className: cn(
|
|
1984
|
+
"p-4 text-center",
|
|
1985
|
+
highlightColumn === j && "bg-primary/5"
|
|
1986
|
+
),
|
|
1987
|
+
children: typeof val === "boolean" ? val ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react7.CheckIcon, { className: "mx-auto h-4 w-4 text-primary" }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react7.XIcon, { className: "mx-auto h-4 w-4 text-muted-foreground/40" }) : val
|
|
1988
|
+
},
|
|
1989
|
+
j
|
|
1990
|
+
))
|
|
1991
|
+
] }, i)) })
|
|
1992
|
+
] }) });
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
// src/hero-canvas/index.tsx
|
|
1996
|
+
var import_fiber = require("@react-three/fiber");
|
|
1997
|
+
var import_simplex_noise = require("simplex-noise");
|
|
1998
|
+
var import_three = require("three");
|
|
1999
|
+
var import_react2 = require("react");
|
|
2000
|
+
var import_framer_motion18 = require("framer-motion");
|
|
2001
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
2002
|
+
function buildNodes(count) {
|
|
2003
|
+
const accentEvery = Math.max(1, Math.floor(count / 15));
|
|
2004
|
+
const nodes = [];
|
|
2005
|
+
for (let index = 0; index < count; index += 1) {
|
|
2006
|
+
const angle = Math.random() * Math.PI * 2;
|
|
2007
|
+
const radius = 1.5 + Math.random() * 5.75;
|
|
2008
|
+
const spread = Math.random() * 1.2;
|
|
2009
|
+
nodes.push({
|
|
2010
|
+
accent: index % accentEvery === 0,
|
|
2011
|
+
baseX: Math.cos(angle) * radius * 1.5,
|
|
2012
|
+
baseY: (Math.random() - 0.5) * 16 + spread,
|
|
2013
|
+
baseZ: (Math.random() - 0.5) * 6,
|
|
2014
|
+
driftX: Math.random() * 100,
|
|
2015
|
+
driftY: Math.random() * 100,
|
|
2016
|
+
driftZ: Math.random() * 100
|
|
2017
|
+
});
|
|
2018
|
+
}
|
|
2019
|
+
return nodes;
|
|
2020
|
+
}
|
|
2021
|
+
function ParticleNetwork({
|
|
2022
|
+
count,
|
|
2023
|
+
accentColor,
|
|
2024
|
+
baseColor
|
|
2025
|
+
}) {
|
|
2026
|
+
const groupRef = (0, import_react2.useRef)(null);
|
|
2027
|
+
const pointsRef = (0, import_react2.useRef)(null);
|
|
2028
|
+
const linesRef = (0, import_react2.useRef)(null);
|
|
2029
|
+
const cursorRef = (0, import_react2.useRef)({ x: 0, y: 0 });
|
|
2030
|
+
const nodes = (0, import_react2.useMemo)(() => buildNodes(count), [count]);
|
|
2031
|
+
const noise3D = (0, import_react2.useMemo)(() => (0, import_simplex_noise.createNoise3D)(), []);
|
|
2032
|
+
const pointPositions = (0, import_react2.useMemo)(() => new Float32Array(count * 3), [count]);
|
|
2033
|
+
const pointColors = (0, import_react2.useMemo)(() => new Float32Array(count * 3), [count]);
|
|
2034
|
+
const cursorOffsetsX = (0, import_react2.useMemo)(() => new Float32Array(count), [count]);
|
|
2035
|
+
const cursorOffsetsY = (0, import_react2.useMemo)(() => new Float32Array(count), [count]);
|
|
2036
|
+
const accent = (0, import_react2.useMemo)(() => new import_three.Color(accentColor), [accentColor]);
|
|
2037
|
+
const base = (0, import_react2.useMemo)(() => new import_three.Color(baseColor), [baseColor]);
|
|
2038
|
+
(0, import_react2.useEffect)(() => {
|
|
2039
|
+
const handleMouseMove = (event) => {
|
|
2040
|
+
cursorRef.current.x = event.clientX / window.innerWidth * 2 - 1;
|
|
2041
|
+
cursorRef.current.y = -(event.clientY / window.innerHeight * 2 - 1);
|
|
2042
|
+
};
|
|
2043
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
2044
|
+
return () => window.removeEventListener("mousemove", handleMouseMove);
|
|
2045
|
+
}, []);
|
|
2046
|
+
(0, import_react2.useEffect)(() => {
|
|
2047
|
+
nodes.forEach((node, index) => {
|
|
2048
|
+
const pointIndex = index * 3;
|
|
2049
|
+
pointPositions[pointIndex] = node.baseX;
|
|
2050
|
+
pointPositions[pointIndex + 1] = node.baseY;
|
|
2051
|
+
pointPositions[pointIndex + 2] = node.baseZ;
|
|
2052
|
+
const color = node.accent ? accent : base;
|
|
2053
|
+
pointColors[pointIndex] = color.r;
|
|
2054
|
+
pointColors[pointIndex + 1] = color.g;
|
|
2055
|
+
pointColors[pointIndex + 2] = color.b;
|
|
2056
|
+
});
|
|
2057
|
+
const geometry = pointsRef.current?.geometry;
|
|
2058
|
+
if (!geometry) return;
|
|
2059
|
+
geometry.setAttribute("position", new import_three.BufferAttribute(pointPositions, 3));
|
|
2060
|
+
geometry.setAttribute("color", new import_three.BufferAttribute(pointColors, 3));
|
|
2061
|
+
}, [nodes, pointColors, pointPositions, accent, base]);
|
|
2062
|
+
(0, import_fiber.useFrame)(({ clock, pointer }) => {
|
|
2063
|
+
const time = clock.elapsedTime * 0.16;
|
|
2064
|
+
const cursorWorldX = cursorRef.current.x * 9;
|
|
2065
|
+
const cursorWorldY = cursorRef.current.y * 5.5;
|
|
2066
|
+
const attractRadius = 3.2;
|
|
2067
|
+
const attractStrength = 1.4;
|
|
2068
|
+
const lerpFactor = 0.06;
|
|
2069
|
+
for (let index = 0; index < nodes.length; index += 1) {
|
|
2070
|
+
const node = nodes[index];
|
|
2071
|
+
const positionIndex = index * 3;
|
|
2072
|
+
pointPositions[positionIndex] = node.baseX + noise3D(node.driftX, time, node.driftZ) * 0.85;
|
|
2073
|
+
pointPositions[positionIndex + 1] = node.baseY + noise3D(node.driftY, node.driftX, time) * 0.7;
|
|
2074
|
+
pointPositions[positionIndex + 2] = node.baseZ + noise3D(time, node.driftZ, node.driftY) * 0.55;
|
|
2075
|
+
}
|
|
2076
|
+
for (let index = 0; index < nodes.length; index += 1) {
|
|
2077
|
+
const positionIndex = index * 3;
|
|
2078
|
+
const dx = cursorWorldX - pointPositions[positionIndex];
|
|
2079
|
+
const dy = cursorWorldY - pointPositions[positionIndex + 1];
|
|
2080
|
+
const distance = Math.hypot(dx, dy);
|
|
2081
|
+
let targetOffsetX = 0;
|
|
2082
|
+
let targetOffsetY = 0;
|
|
2083
|
+
if (distance < attractRadius) {
|
|
2084
|
+
const influence = 1 - distance / attractRadius;
|
|
2085
|
+
targetOffsetX = dx * influence * attractStrength;
|
|
2086
|
+
targetOffsetY = dy * influence * attractStrength;
|
|
2087
|
+
}
|
|
2088
|
+
cursorOffsetsX[index] += (targetOffsetX - cursorOffsetsX[index]) * lerpFactor;
|
|
2089
|
+
cursorOffsetsY[index] += (targetOffsetY - cursorOffsetsY[index]) * lerpFactor;
|
|
2090
|
+
pointPositions[positionIndex] += cursorOffsetsX[index];
|
|
2091
|
+
pointPositions[positionIndex + 1] += cursorOffsetsY[index];
|
|
2092
|
+
}
|
|
2093
|
+
const pointGeometry = pointsRef.current?.geometry;
|
|
2094
|
+
const lineGeometry = linesRef.current?.geometry;
|
|
2095
|
+
if (pointGeometry?.attributes.position) {
|
|
2096
|
+
pointGeometry.attributes.position.needsUpdate = true;
|
|
2097
|
+
}
|
|
2098
|
+
if (lineGeometry) {
|
|
2099
|
+
const segments = [];
|
|
2100
|
+
const maxSegments = count < 400 ? 540 : 1200;
|
|
2101
|
+
const threshold = count < 400 ? 2.3 : 2.5;
|
|
2102
|
+
const thresholdSq = threshold * threshold;
|
|
2103
|
+
for (let index = 0; index < nodes.length; index += 1) {
|
|
2104
|
+
for (let nextIndex = index + 1; nextIndex < nodes.length; nextIndex += 1) {
|
|
2105
|
+
const offsetA = index * 3;
|
|
2106
|
+
const offsetB = nextIndex * 3;
|
|
2107
|
+
const dx = pointPositions[offsetA] - pointPositions[offsetB];
|
|
2108
|
+
const dy = pointPositions[offsetA + 1] - pointPositions[offsetB + 1];
|
|
2109
|
+
const dz = pointPositions[offsetA + 2] - pointPositions[offsetB + 2];
|
|
2110
|
+
if (dx * dx + dy * dy + dz * dz > thresholdSq) continue;
|
|
2111
|
+
segments.push(
|
|
2112
|
+
pointPositions[offsetA],
|
|
2113
|
+
pointPositions[offsetA + 1],
|
|
2114
|
+
pointPositions[offsetA + 2],
|
|
2115
|
+
pointPositions[offsetB],
|
|
2116
|
+
pointPositions[offsetB + 1],
|
|
2117
|
+
pointPositions[offsetB + 2]
|
|
2118
|
+
);
|
|
2119
|
+
if (segments.length / 6 >= maxSegments) break;
|
|
2120
|
+
}
|
|
2121
|
+
if (segments.length / 6 >= maxSegments) break;
|
|
2122
|
+
}
|
|
2123
|
+
lineGeometry.setAttribute("position", new import_three.BufferAttribute(new Float32Array(segments), 3));
|
|
2124
|
+
}
|
|
2125
|
+
if (groupRef.current) {
|
|
2126
|
+
const baseOffsetX = count < 300 ? 2.1 : 2.75;
|
|
2127
|
+
const baseOffsetY = count < 300 ? 0.1 : -0.15;
|
|
2128
|
+
groupRef.current.position.x += (baseOffsetX + pointer.x * 0.45 - groupRef.current.position.x) * 0.045;
|
|
2129
|
+
groupRef.current.position.y += (baseOffsetY + pointer.y * 0.32 - groupRef.current.position.y) * 0.045;
|
|
2130
|
+
groupRef.current.rotation.y += (pointer.x * 0.06 - groupRef.current.rotation.y) * 0.035;
|
|
2131
|
+
groupRef.current.rotation.x += (-pointer.y * 0.04 - groupRef.current.rotation.x) * 0.035;
|
|
2132
|
+
}
|
|
2133
|
+
});
|
|
2134
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("group", { ref: groupRef, children: [
|
|
2135
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("points", { ref: pointsRef, children: [
|
|
2136
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("bufferGeometry", {}),
|
|
2137
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2138
|
+
"pointsMaterial",
|
|
2139
|
+
{
|
|
2140
|
+
size: count < 400 ? 0.048 : 0.045,
|
|
2141
|
+
sizeAttenuation: true,
|
|
2142
|
+
transparent: true,
|
|
2143
|
+
opacity: 0.92,
|
|
2144
|
+
depthWrite: false,
|
|
2145
|
+
vertexColors: true,
|
|
2146
|
+
blending: import_three.AdditiveBlending
|
|
2147
|
+
}
|
|
2148
|
+
)
|
|
2149
|
+
] }),
|
|
2150
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("lineSegments", { ref: linesRef, children: [
|
|
2151
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("bufferGeometry", {}),
|
|
2152
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2153
|
+
"lineBasicMaterial",
|
|
2154
|
+
{
|
|
2155
|
+
color: baseColor,
|
|
2156
|
+
transparent: true,
|
|
2157
|
+
opacity: count < 400 ? 0.25 : 0.2,
|
|
2158
|
+
depthWrite: false,
|
|
2159
|
+
blending: import_three.AdditiveBlending
|
|
2160
|
+
}
|
|
2161
|
+
)
|
|
2162
|
+
] })
|
|
2163
|
+
] });
|
|
2164
|
+
}
|
|
2165
|
+
function HeroCanvas({
|
|
2166
|
+
accentColor = "#8fccb6",
|
|
2167
|
+
baseColor = "#7388cf",
|
|
2168
|
+
density,
|
|
2169
|
+
className = "pointer-events-none absolute inset-0 z-[2] translate-gpu opacity-60 md:opacity-100"
|
|
2170
|
+
}) {
|
|
2171
|
+
const [count, setCount] = (0, import_react2.useState)(density ?? 400);
|
|
2172
|
+
const containerRef = (0, import_react2.useRef)(null);
|
|
2173
|
+
const isInView = (0, import_framer_motion18.useInView)(containerRef);
|
|
2174
|
+
(0, import_react2.useEffect)(() => {
|
|
2175
|
+
if (density != null) {
|
|
2176
|
+
setCount(density);
|
|
2177
|
+
return;
|
|
2178
|
+
}
|
|
2179
|
+
const media = window.matchMedia("(max-width: 767px)");
|
|
2180
|
+
const updateCount = () => setCount(media.matches ? 350 : 800);
|
|
2181
|
+
updateCount();
|
|
2182
|
+
media.addEventListener("change", updateCount);
|
|
2183
|
+
return () => media.removeEventListener("change", updateCount);
|
|
2184
|
+
}, [density]);
|
|
2185
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { ref: containerRef, className, style: { willChange: "transform" }, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2186
|
+
import_fiber.Canvas,
|
|
2187
|
+
{
|
|
2188
|
+
frameloop: isInView ? "always" : "demand",
|
|
2189
|
+
camera: { fov: 50, position: [0, 0, 12] },
|
|
2190
|
+
dpr: [1, 1.5],
|
|
2191
|
+
gl: { alpha: true, antialias: false, powerPreference: "high-performance" },
|
|
2192
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ParticleNetwork, { count, accentColor, baseColor })
|
|
2193
|
+
}
|
|
2194
|
+
) });
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
// src/wave-canvas/index.tsx
|
|
2198
|
+
var import_fiber2 = require("@react-three/fiber");
|
|
2199
|
+
var import_simplex_noise2 = require("simplex-noise");
|
|
2200
|
+
var import_three2 = require("three");
|
|
2201
|
+
var import_react3 = require("react");
|
|
2202
|
+
var import_framer_motion19 = require("framer-motion");
|
|
2203
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
2204
|
+
var DEFAULT_WAVES = [
|
|
2205
|
+
{ yOffset: 0.55, amplitude: 0.26, freq: 1.4, speed: 0.38, color: "#8fccb6", opacity: 0.9 },
|
|
2206
|
+
{ yOffset: 0.18, amplitude: 0.2, freq: 2.1, speed: 0.55, color: "#5aaa94", opacity: 0.72 },
|
|
2207
|
+
{ yOffset: -0.18, amplitude: 0.28, freq: 1.7, speed: 0.44, color: "#4F72D8", opacity: 0.55 },
|
|
2208
|
+
{ yOffset: -0.55, amplitude: 0.16, freq: 2.6, speed: 0.62, color: "#1f2d56", opacity: 0.42 }
|
|
2209
|
+
];
|
|
2210
|
+
var SEGMENTS = 220;
|
|
2211
|
+
function SineWave({ yOffset, amplitude, freq, speed, color, opacity }) {
|
|
2212
|
+
const noise2D = (0, import_react3.useMemo)(() => (0, import_simplex_noise2.createNoise2D)(), []);
|
|
2213
|
+
const geo = (0, import_react3.useMemo)(() => {
|
|
2214
|
+
const g = new import_three2.BufferGeometry();
|
|
2215
|
+
g.setAttribute("position", new import_three2.BufferAttribute(new Float32Array((SEGMENTS + 1) * 3), 3));
|
|
2216
|
+
return g;
|
|
2217
|
+
}, []);
|
|
2218
|
+
const mat = (0, import_react3.useMemo)(
|
|
2219
|
+
() => new import_three2.LineBasicMaterial({
|
|
2220
|
+
color: new import_three2.Color(color),
|
|
2221
|
+
transparent: true,
|
|
2222
|
+
opacity,
|
|
2223
|
+
blending: import_three2.AdditiveBlending,
|
|
2224
|
+
depthWrite: false
|
|
2225
|
+
}),
|
|
2226
|
+
[color, opacity]
|
|
2227
|
+
);
|
|
2228
|
+
const lineRef = (0, import_react3.useRef)(new import_three2.Line(geo, mat));
|
|
2229
|
+
(0, import_fiber2.useFrame)(({ clock }) => {
|
|
2230
|
+
const t = clock.getElapsedTime() * speed;
|
|
2231
|
+
const pos = geo.attributes.position.array;
|
|
2232
|
+
for (let i = 0; i <= SEGMENTS; i++) {
|
|
2233
|
+
const x = i / SEGMENTS * 4 - 2;
|
|
2234
|
+
const n = noise2D(x * freq * 0.4, t);
|
|
2235
|
+
pos[i * 3] = x;
|
|
2236
|
+
pos[i * 3 + 1] = yOffset + n * amplitude;
|
|
2237
|
+
pos[i * 3 + 2] = 0;
|
|
2238
|
+
}
|
|
2239
|
+
geo.attributes.position.needsUpdate = true;
|
|
2240
|
+
});
|
|
2241
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("primitive", { object: lineRef.current });
|
|
2242
|
+
}
|
|
2243
|
+
function WaveCanvas({ waves = DEFAULT_WAVES, className }) {
|
|
2244
|
+
const containerRef = (0, import_react3.useRef)(null);
|
|
2245
|
+
const isInView = (0, import_framer_motion19.useInView)(containerRef);
|
|
2246
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
2247
|
+
"div",
|
|
2248
|
+
{
|
|
2249
|
+
ref: containerRef,
|
|
2250
|
+
className,
|
|
2251
|
+
style: { width: "100%", height: "100%", position: "relative" },
|
|
2252
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
2253
|
+
import_fiber2.Canvas,
|
|
2254
|
+
{
|
|
2255
|
+
frameloop: isInView ? "always" : "demand",
|
|
2256
|
+
orthographic: true,
|
|
2257
|
+
camera: { zoom: 120, position: [0, 0, 10] },
|
|
2258
|
+
style: { width: "100%", height: "100%" },
|
|
2259
|
+
gl: { antialias: true, alpha: true },
|
|
2260
|
+
children: waves.map((w, i) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(SineWave, { ...w }, i))
|
|
2261
|
+
}
|
|
2262
|
+
)
|
|
2263
|
+
}
|
|
2264
|
+
);
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
// src/lightbox/index.tsx
|
|
2268
|
+
var React9 = __toESM(require("react"));
|
|
2269
|
+
var import_lightbox = require("@web-my-money/primitives/lightbox");
|
|
2270
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
2271
|
+
function Thumbnail({ image, onClick, className }) {
|
|
2272
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2273
|
+
"button",
|
|
2274
|
+
{
|
|
2275
|
+
type: "button",
|
|
2276
|
+
"data-slot": "thumbnail",
|
|
2277
|
+
onClick,
|
|
2278
|
+
className: cn(
|
|
2279
|
+
"group relative aspect-square overflow-hidden rounded-lg border border-border outline-none focus-visible:ring-3 focus-visible:ring-ring/50",
|
|
2280
|
+
className
|
|
2281
|
+
),
|
|
2282
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2283
|
+
"img",
|
|
2284
|
+
{
|
|
2285
|
+
src: image.thumbnailSrc ?? image.src,
|
|
2286
|
+
alt: image.alt ?? "",
|
|
2287
|
+
className: "size-full object-cover transition-transform duration-200 group-hover:scale-105",
|
|
2288
|
+
loading: "lazy"
|
|
2289
|
+
}
|
|
2290
|
+
)
|
|
2291
|
+
}
|
|
2292
|
+
);
|
|
2293
|
+
}
|
|
2294
|
+
function LightboxGallery({ images, className, gridClassName }) {
|
|
2295
|
+
const [openIndex, setOpenIndex] = React9.useState(null);
|
|
2296
|
+
const hasImages = images.length > 0;
|
|
2297
|
+
const active = openIndex !== null ? images[openIndex] : null;
|
|
2298
|
+
const goTo = (dir) => {
|
|
2299
|
+
setOpenIndex((i) => {
|
|
2300
|
+
if (i === null) return i;
|
|
2301
|
+
return (i + dir + images.length) % images.length;
|
|
2302
|
+
});
|
|
2303
|
+
};
|
|
2304
|
+
if (!hasImages) return null;
|
|
2305
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { "data-slot": "lightbox-gallery", className, children: [
|
|
2306
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: cn("grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4", gridClassName), children: images.map((image, i) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Thumbnail, { image, onClick: () => setOpenIndex(i) }, image.src)) }),
|
|
2307
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lightbox.Lightbox, { open: openIndex !== null, onOpenChange: (open) => !open && setOpenIndex(null), children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lightbox.LightboxContent, { children: active && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
|
|
2308
|
+
images.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
|
|
2309
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lightbox.LightboxNavButton, { direction: "prev", onClick: () => goTo(-1) }),
|
|
2310
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lightbox.LightboxNavButton, { direction: "next", onClick: () => goTo(1) })
|
|
2311
|
+
] }),
|
|
2312
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lightbox.LightboxImage, { src: active.src, alt: active.alt ?? "" }),
|
|
2313
|
+
active.caption && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_lightbox.LightboxCaption, { children: active.caption }),
|
|
2314
|
+
images.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("p", { className: "text-xs text-white/60", "aria-live": "polite", children: [
|
|
2315
|
+
(openIndex ?? 0) + 1,
|
|
2316
|
+
" / ",
|
|
2317
|
+
images.length
|
|
2318
|
+
] })
|
|
2319
|
+
] }) }) })
|
|
2320
|
+
] });
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
// src/notification-banner/index.tsx
|
|
2324
|
+
var React10 = __toESM(require("react"));
|
|
2325
|
+
var import_framer_motion20 = require("framer-motion");
|
|
2326
|
+
var import_lucide_react8 = require("lucide-react");
|
|
2327
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
2328
|
+
var variantConfig = {
|
|
2329
|
+
info: { icon: import_lucide_react8.Info, classes: "bg-primary/10 border-primary/20", iconClass: "text-primary" },
|
|
2330
|
+
success: { icon: import_lucide_react8.CheckCircle2, classes: "bg-emerald-500/10 border-emerald-500/20", iconClass: "text-emerald-500" },
|
|
2331
|
+
warning: { icon: import_lucide_react8.AlertTriangle, classes: "bg-amber-500/10 border-amber-500/20", iconClass: "text-amber-500" },
|
|
2332
|
+
danger: { icon: import_lucide_react8.AlertCircle, classes: "bg-destructive/10 border-destructive/20", iconClass: "text-destructive" },
|
|
2333
|
+
brand: { icon: import_lucide_react8.Info, classes: "border-0", iconClass: "text-white" }
|
|
2334
|
+
};
|
|
2335
|
+
function NotificationBanner({
|
|
2336
|
+
variant = "info",
|
|
2337
|
+
message,
|
|
2338
|
+
action,
|
|
2339
|
+
dismissible = true,
|
|
2340
|
+
onDismiss,
|
|
2341
|
+
visible = true,
|
|
2342
|
+
className
|
|
2343
|
+
}) {
|
|
2344
|
+
const [open, setOpen] = React10.useState(true);
|
|
2345
|
+
const show = visible && open;
|
|
2346
|
+
const dismiss = () => {
|
|
2347
|
+
setOpen(false);
|
|
2348
|
+
onDismiss?.();
|
|
2349
|
+
};
|
|
2350
|
+
const cfg = variantConfig[variant];
|
|
2351
|
+
const Icon = cfg.icon;
|
|
2352
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_framer_motion20.AnimatePresence, { children: show && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
2353
|
+
import_framer_motion20.motion.div,
|
|
2354
|
+
{
|
|
2355
|
+
initial: { height: 0, opacity: 0 },
|
|
2356
|
+
animate: { height: "auto", opacity: 1 },
|
|
2357
|
+
exit: { height: 0, opacity: 0 },
|
|
2358
|
+
transition: { duration: 0.2, ease: "easeInOut" },
|
|
2359
|
+
className: "overflow-hidden",
|
|
2360
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
2361
|
+
"div",
|
|
2362
|
+
{
|
|
2363
|
+
className: cn(
|
|
2364
|
+
"relative flex items-center justify-center gap-3 px-4 py-2.5 text-sm border-b",
|
|
2365
|
+
variant === "brand" ? "text-white" : "text-foreground",
|
|
2366
|
+
cfg.classes,
|
|
2367
|
+
className
|
|
2368
|
+
),
|
|
2369
|
+
style: variant === "brand" ? { background: "var(--gradient-primary, var(--primary))" } : void 0,
|
|
2370
|
+
children: [
|
|
2371
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Icon, { size: 15, className: cn("shrink-0", cfg.iconClass) }),
|
|
2372
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("p", { className: cn("text-center", variant === "brand" ? "text-white" : "text-foreground/90"), children: [
|
|
2373
|
+
message,
|
|
2374
|
+
action && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
|
|
2375
|
+
" ",
|
|
2376
|
+
action.href ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
2377
|
+
"a",
|
|
2378
|
+
{
|
|
2379
|
+
href: action.href,
|
|
2380
|
+
className: cn(
|
|
2381
|
+
"underline underline-offset-2 font-medium ml-1",
|
|
2382
|
+
variant === "brand" ? "text-white/90 hover:text-white" : "text-primary hover:text-primary/80"
|
|
2383
|
+
),
|
|
2384
|
+
children: action.label
|
|
2385
|
+
}
|
|
2386
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
2387
|
+
"button",
|
|
2388
|
+
{
|
|
2389
|
+
onClick: action.onClick,
|
|
2390
|
+
className: cn(
|
|
2391
|
+
"underline underline-offset-2 font-medium ml-1",
|
|
2392
|
+
variant === "brand" ? "text-white/90 hover:text-white" : "text-primary hover:text-primary/80"
|
|
2393
|
+
),
|
|
2394
|
+
children: action.label
|
|
2395
|
+
}
|
|
2396
|
+
)
|
|
2397
|
+
] })
|
|
2398
|
+
] }),
|
|
2399
|
+
dismissible && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
2400
|
+
"button",
|
|
2401
|
+
{
|
|
2402
|
+
onClick: dismiss,
|
|
2403
|
+
"aria-label": "Dismiss",
|
|
2404
|
+
className: cn(
|
|
2405
|
+
"absolute right-3 rounded p-1 transition-colors",
|
|
2406
|
+
variant === "brand" ? "text-white/70 hover:text-white hover:bg-white/10" : "text-muted-foreground hover:text-foreground hover:bg-accent"
|
|
2407
|
+
),
|
|
2408
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_lucide_react8.X, { size: 14 })
|
|
2409
|
+
}
|
|
2410
|
+
)
|
|
2411
|
+
]
|
|
2412
|
+
}
|
|
2413
|
+
)
|
|
2414
|
+
},
|
|
2415
|
+
"banner"
|
|
2416
|
+
) });
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2419
|
+
// src/stat-card/index.tsx
|
|
2420
|
+
var import_lucide_react9 = require("lucide-react");
|
|
2421
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
2422
|
+
function inferStatus(delta) {
|
|
2423
|
+
if (!delta) return "flat";
|
|
2424
|
+
if (delta.startsWith("+") || !delta.startsWith("-") && parseFloat(delta) > 0) return "up";
|
|
2425
|
+
if (delta.startsWith("-") || parseFloat(delta) < 0) return "down";
|
|
2426
|
+
return "flat";
|
|
2427
|
+
}
|
|
2428
|
+
var statusColors = {
|
|
2429
|
+
success: "text-emerald-500",
|
|
2430
|
+
warning: "text-amber-500",
|
|
2431
|
+
danger: "text-red-500",
|
|
2432
|
+
info: "text-primary"
|
|
2433
|
+
};
|
|
2434
|
+
function StatCard({
|
|
2435
|
+
title,
|
|
2436
|
+
value,
|
|
2437
|
+
delta,
|
|
2438
|
+
deltaLabel,
|
|
2439
|
+
icon,
|
|
2440
|
+
chart,
|
|
2441
|
+
status,
|
|
2442
|
+
className
|
|
2443
|
+
}) {
|
|
2444
|
+
const trend = inferStatus(delta);
|
|
2445
|
+
const deltaColor = status ? statusColors[status] : trend === "up" ? "text-emerald-500" : trend === "down" ? "text-red-500" : "text-muted-foreground";
|
|
2446
|
+
const TrendIcon = trend === "up" ? import_lucide_react9.TrendingUp : trend === "down" ? import_lucide_react9.TrendingDown : import_lucide_react9.Minus;
|
|
2447
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
|
|
2448
|
+
"div",
|
|
2449
|
+
{
|
|
2450
|
+
className: cn(
|
|
2451
|
+
"relative flex flex-col gap-3 rounded-xl border bg-card p-5 overflow-hidden",
|
|
2452
|
+
"border-border",
|
|
2453
|
+
className
|
|
2454
|
+
),
|
|
2455
|
+
style: { boxShadow: "var(--shadow-card)" },
|
|
2456
|
+
children: [
|
|
2457
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
2458
|
+
"div",
|
|
2459
|
+
{
|
|
2460
|
+
"aria-hidden": true,
|
|
2461
|
+
className: "absolute inset-x-0 top-0 h-px opacity-60",
|
|
2462
|
+
style: { background: "var(--gradient-primary, var(--primary))" }
|
|
2463
|
+
}
|
|
2464
|
+
),
|
|
2465
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [
|
|
2466
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider truncate", children: title }),
|
|
2467
|
+
icon && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "shrink-0 text-muted-foreground/60", children: icon })
|
|
2468
|
+
] }),
|
|
2469
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: "text-3xl font-bold text-foreground tracking-tight tabular-nums", children: typeof value === "number" ? value.toLocaleString() : value }),
|
|
2470
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "flex items-end justify-between gap-2 mt-auto", children: [
|
|
2471
|
+
delta ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: cn("flex items-center gap-1 text-xs font-medium", deltaColor), children: [
|
|
2472
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(TrendIcon, { size: 13, strokeWidth: 2.5 }),
|
|
2473
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { children: delta }),
|
|
2474
|
+
deltaLabel && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("span", { className: "text-muted-foreground font-normal", children: deltaLabel })
|
|
2475
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", {}),
|
|
2476
|
+
chart && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "shrink-0", children: chart })
|
|
2477
|
+
] })
|
|
2478
|
+
]
|
|
2479
|
+
}
|
|
2480
|
+
);
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
// src/page-header/index.tsx
|
|
2484
|
+
var import_lucide_react10 = require("lucide-react");
|
|
2485
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
2486
|
+
function PageHeader({
|
|
2487
|
+
title,
|
|
2488
|
+
description,
|
|
2489
|
+
breadcrumb,
|
|
2490
|
+
actions,
|
|
2491
|
+
below,
|
|
2492
|
+
className
|
|
2493
|
+
}) {
|
|
2494
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2495
|
+
"header",
|
|
2496
|
+
{
|
|
2497
|
+
className: cn(
|
|
2498
|
+
"flex flex-col gap-4 pb-6 border-b border-border",
|
|
2499
|
+
className
|
|
2500
|
+
),
|
|
2501
|
+
children: [
|
|
2502
|
+
breadcrumb && breadcrumb.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("nav", { "aria-label": "Breadcrumb", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("ol", { className: "flex items-center gap-1 flex-wrap", children: breadcrumb.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("li", { className: "flex items-center gap-1", children: [
|
|
2503
|
+
i > 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_lucide_react10.ChevronRight, { size: 12, className: "text-muted-foreground/50" }),
|
|
2504
|
+
item.href ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
2505
|
+
"a",
|
|
2506
|
+
{
|
|
2507
|
+
href: item.href,
|
|
2508
|
+
className: "text-xs text-muted-foreground hover:text-foreground transition-colors",
|
|
2509
|
+
children: item.label
|
|
2510
|
+
}
|
|
2511
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-xs text-muted-foreground", children: item.label })
|
|
2512
|
+
] }, i)) }) }),
|
|
2513
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "flex items-start justify-between gap-4 flex-wrap", children: [
|
|
2514
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "space-y-1", children: [
|
|
2515
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h1", { className: "text-2xl font-bold tracking-tight text-foreground", children: title }),
|
|
2516
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { className: "text-sm text-muted-foreground max-w-xl", children: description })
|
|
2517
|
+
] }),
|
|
2518
|
+
actions && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "flex items-center gap-2 flex-wrap", children: actions })
|
|
2519
|
+
] }),
|
|
2520
|
+
below && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { children: below })
|
|
2521
|
+
]
|
|
2522
|
+
}
|
|
2523
|
+
);
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2526
|
+
// src/empty-state/index.tsx
|
|
2527
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
2528
|
+
function EmptyState({
|
|
2529
|
+
icon,
|
|
2530
|
+
title,
|
|
2531
|
+
description,
|
|
2532
|
+
action,
|
|
2533
|
+
secondaryAction,
|
|
2534
|
+
variant = "page",
|
|
2535
|
+
className
|
|
2536
|
+
}) {
|
|
2537
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
2538
|
+
"div",
|
|
2539
|
+
{
|
|
2540
|
+
className: cn(
|
|
2541
|
+
"flex flex-col items-center text-center",
|
|
2542
|
+
variant === "page" ? "min-h-[360px] justify-center px-6 py-20" : "rounded-xl border border-border border-dashed bg-card/50 px-6 py-12",
|
|
2543
|
+
className
|
|
2544
|
+
),
|
|
2545
|
+
children: [
|
|
2546
|
+
icon && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
2547
|
+
"div",
|
|
2548
|
+
{
|
|
2549
|
+
className: "mb-5 flex h-14 w-14 items-center justify-center rounded-xl border border-border bg-muted/40 text-muted-foreground",
|
|
2550
|
+
children: icon
|
|
2551
|
+
}
|
|
2552
|
+
),
|
|
2553
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-base font-semibold text-foreground mb-2", children: title }),
|
|
2554
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "text-sm text-muted-foreground max-w-xs mb-6", children: description }),
|
|
2555
|
+
(action || secondaryAction) && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "flex flex-col sm:flex-row items-center gap-3", children: [
|
|
2556
|
+
action,
|
|
2557
|
+
secondaryAction
|
|
2558
|
+
] })
|
|
2559
|
+
]
|
|
2560
|
+
}
|
|
2561
|
+
);
|
|
2562
|
+
}
|
|
2563
|
+
|
|
2564
|
+
// src/dashboard-header/index.tsx
|
|
2565
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
2566
|
+
function DashboardHeader({
|
|
2567
|
+
pageTitle,
|
|
2568
|
+
notificationsCount = 0,
|
|
2569
|
+
actions,
|
|
2570
|
+
className
|
|
2571
|
+
}) {
|
|
2572
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
2573
|
+
"header",
|
|
2574
|
+
{
|
|
2575
|
+
className: cn(
|
|
2576
|
+
"flex h-14 lg:h-[60px] items-center gap-4 border-b bg-muted/20 px-6 justify-between",
|
|
2577
|
+
className
|
|
2578
|
+
),
|
|
2579
|
+
children: [
|
|
2580
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "font-semibold text-lg", children: pageTitle }),
|
|
2581
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "flex items-center gap-4", children: [
|
|
2582
|
+
notificationsCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "relative", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "h-5 w-5 rounded-full bg-primary/20 aspect-square text-[10px] font-bold flex items-center justify-center", children: notificationsCount }) }),
|
|
2583
|
+
actions
|
|
2584
|
+
] })
|
|
2585
|
+
]
|
|
2586
|
+
}
|
|
2587
|
+
);
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
// src/data-summary-cards/index.tsx
|
|
2591
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
2592
|
+
function DataSummaryCards({
|
|
2593
|
+
metrics,
|
|
2594
|
+
columns = 4,
|
|
2595
|
+
className
|
|
2596
|
+
}) {
|
|
2597
|
+
const gridCols = {
|
|
2598
|
+
2: "md:grid-cols-2",
|
|
2599
|
+
3: "md:grid-cols-3",
|
|
2600
|
+
4: "md:grid-cols-2 lg:grid-cols-4"
|
|
2601
|
+
};
|
|
2602
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: cn("grid gap-4", gridCols[columns], className), children: metrics.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
2603
|
+
"div",
|
|
2604
|
+
{
|
|
2605
|
+
className: "rounded-xl bg-card p-4 text-card-foreground ring-1 ring-foreground/10",
|
|
2606
|
+
children: [
|
|
2607
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
|
|
2608
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "text-sm font-medium text-muted-foreground", children: item.title }),
|
|
2609
|
+
item.icon ?? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "h-4 w-4 rounded bg-muted-foreground/20" })
|
|
2610
|
+
] }),
|
|
2611
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "text-2xl font-bold", children: item.value }),
|
|
2612
|
+
item.description && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "text-xs text-muted-foreground mt-1", children: item.description })
|
|
2613
|
+
]
|
|
2614
|
+
},
|
|
2615
|
+
i
|
|
2616
|
+
)) });
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
// src/data-table/index.tsx
|
|
2620
|
+
var React11 = __toESM(require("react"));
|
|
2621
|
+
var import_pagination = require("@web-my-money/primitives/pagination");
|
|
2622
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
2623
|
+
function DataTable({
|
|
2624
|
+
title,
|
|
2625
|
+
columns,
|
|
2626
|
+
rows,
|
|
2627
|
+
activeBadgeLabel = "Active",
|
|
2628
|
+
className,
|
|
2629
|
+
pageSize,
|
|
2630
|
+
page: controlledPage,
|
|
2631
|
+
onPageChange
|
|
2632
|
+
}) {
|
|
2633
|
+
const [uncontrolledPage, setUncontrolledPage] = React11.useState(1);
|
|
2634
|
+
const page = controlledPage ?? uncontrolledPage;
|
|
2635
|
+
const pageCount = pageSize ? Math.max(1, Math.ceil(rows.length / pageSize)) : 1;
|
|
2636
|
+
const visibleRows = pageSize ? rows.slice((page - 1) * pageSize, page * pageSize) : rows;
|
|
2637
|
+
const setPage = (next) => {
|
|
2638
|
+
setUncontrolledPage(next);
|
|
2639
|
+
onPageChange?.(next);
|
|
2640
|
+
};
|
|
2641
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: cn("rounded-md border", className), children: [
|
|
2642
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "p-4 border-b bg-muted/10 font-medium text-lg", children: title }),
|
|
2643
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("table", { className: "w-full text-sm", children: [
|
|
2644
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("thead", { className: "border-b bg-muted/20", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("tr", { children: columns.map((col, i) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
2645
|
+
"th",
|
|
2646
|
+
{
|
|
2647
|
+
className: cn(
|
|
2648
|
+
"font-medium p-4",
|
|
2649
|
+
i === 0 ? "text-left" : i === columns.length - 1 ? "text-right" : "text-left"
|
|
2650
|
+
),
|
|
2651
|
+
children: col
|
|
2652
|
+
},
|
|
2653
|
+
col
|
|
2654
|
+
)) }) }),
|
|
2655
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("tbody", { children: visibleRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
2656
|
+
"tr",
|
|
2657
|
+
{
|
|
2658
|
+
className: "border-b last:border-0 hover:bg-muted/10 transition-colors",
|
|
2659
|
+
children: row.cells.map((cell, i) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
2660
|
+
"td",
|
|
2661
|
+
{
|
|
2662
|
+
className: cn(
|
|
2663
|
+
"p-4",
|
|
2664
|
+
i === 0 ? "font-medium" : i === columns.length - 1 ? "text-right font-medium" : "text-muted-foreground"
|
|
2665
|
+
),
|
|
2666
|
+
children: i === 1 && row.isActive ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold bg-primary/10 text-primary", children: activeBadgeLabel }) : cell
|
|
2667
|
+
},
|
|
2668
|
+
i
|
|
2669
|
+
))
|
|
2670
|
+
},
|
|
2671
|
+
row.id
|
|
2672
|
+
)) })
|
|
2673
|
+
] }) }),
|
|
2674
|
+
pageSize && pageCount > 1 && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "flex justify-center border-t p-3", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_pagination.PaginationBar, { page, pageCount, onPageChange: setPage }) })
|
|
2675
|
+
] });
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2678
|
+
// src/sidebar-navigation/index.tsx
|
|
2679
|
+
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
2680
|
+
function SidebarNavigation({
|
|
2681
|
+
appName,
|
|
2682
|
+
userName,
|
|
2683
|
+
menuItems,
|
|
2684
|
+
footer,
|
|
2685
|
+
className
|
|
2686
|
+
}) {
|
|
2687
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
2688
|
+
"aside",
|
|
2689
|
+
{
|
|
2690
|
+
className: cn(
|
|
2691
|
+
"w-64 border-r bg-muted/20 h-screen hidden md:flex flex-col",
|
|
2692
|
+
className
|
|
2693
|
+
),
|
|
2694
|
+
children: [
|
|
2695
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "h-14 border-b flex items-center px-4 font-bold text-lg", children: appName }),
|
|
2696
|
+
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("nav", { className: "flex-1 overflow-auto py-4 px-2 space-y-2", children: menuItems.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(
|
|
2697
|
+
"a",
|
|
2698
|
+
{
|
|
2699
|
+
href: item.href ?? "#",
|
|
2700
|
+
className: cn(
|
|
2701
|
+
"flex items-center px-3 py-2 text-sm font-medium rounded-md cursor-pointer transition-colors",
|
|
2702
|
+
item.active ? "bg-primary/10 text-primary" : "hover:bg-muted text-muted-foreground"
|
|
2703
|
+
),
|
|
2704
|
+
children: [
|
|
2705
|
+
item.icon ?? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2706
|
+
"span",
|
|
2707
|
+
{
|
|
2708
|
+
className: cn(
|
|
2709
|
+
"h-4 w-4 mr-3 rounded",
|
|
2710
|
+
item.active ? "bg-primary/50" : "bg-muted-foreground/30"
|
|
2711
|
+
)
|
|
2712
|
+
}
|
|
2713
|
+
),
|
|
2714
|
+
item.label
|
|
2715
|
+
]
|
|
2716
|
+
},
|
|
2717
|
+
i
|
|
2718
|
+
)) }),
|
|
2719
|
+
(userName || footer) && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "p-4 border-t text-sm font-medium", children: footer ?? userName })
|
|
2720
|
+
]
|
|
2721
|
+
}
|
|
2722
|
+
);
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2725
|
+
// src/kpi-row/index.tsx
|
|
2726
|
+
var import_lucide_react11 = require("lucide-react");
|
|
2727
|
+
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
2728
|
+
function inferTrend(delta) {
|
|
2729
|
+
if (!delta) return "flat";
|
|
2730
|
+
if (delta.startsWith("+") || parseFloat(delta) > 0) return "up";
|
|
2731
|
+
if (delta.startsWith("-") || parseFloat(delta) < 0) return "down";
|
|
2732
|
+
return "flat";
|
|
2733
|
+
}
|
|
2734
|
+
var deltaColorMap = {
|
|
2735
|
+
up: "text-emerald-500",
|
|
2736
|
+
down: "text-red-500",
|
|
2737
|
+
flat: "text-muted-foreground"
|
|
2738
|
+
};
|
|
2739
|
+
var statusColorMap = {
|
|
2740
|
+
success: "text-emerald-500",
|
|
2741
|
+
warning: "text-amber-500",
|
|
2742
|
+
danger: "text-red-500",
|
|
2743
|
+
neutral: "text-muted-foreground"
|
|
2744
|
+
};
|
|
2745
|
+
function KPIRow({ items, dividers = true, className }) {
|
|
2746
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2747
|
+
"div",
|
|
2748
|
+
{
|
|
2749
|
+
className: cn(
|
|
2750
|
+
"grid w-full rounded-xl border border-border bg-card",
|
|
2751
|
+
`grid-cols-${Math.min(items.length, 4)} sm:grid-cols-${items.length}`,
|
|
2752
|
+
className
|
|
2753
|
+
),
|
|
2754
|
+
style: { gridTemplateColumns: `repeat(${items.length}, minmax(0, 1fr))` },
|
|
2755
|
+
children: items.map((item, i) => {
|
|
2756
|
+
const trend = inferTrend(item.delta);
|
|
2757
|
+
const deltaColor = item.status ? statusColorMap[item.status] : deltaColorMap[trend];
|
|
2758
|
+
const TrendIcon = trend === "up" ? import_lucide_react11.TrendingUp : trend === "down" ? import_lucide_react11.TrendingDown : import_lucide_react11.Minus;
|
|
2759
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
2760
|
+
"div",
|
|
2761
|
+
{
|
|
2762
|
+
className: cn(
|
|
2763
|
+
"flex flex-col gap-1 px-5 py-4",
|
|
2764
|
+
dividers && i < items.length - 1 && "border-r border-border"
|
|
2765
|
+
),
|
|
2766
|
+
children: [
|
|
2767
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { className: "text-xs font-medium uppercase tracking-wider text-muted-foreground truncate", children: item.label }),
|
|
2768
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("p", { className: "text-2xl font-bold tabular-nums text-foreground", children: [
|
|
2769
|
+
item.prefix && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-lg font-medium text-muted-foreground", children: item.prefix }),
|
|
2770
|
+
typeof item.value === "number" ? item.value.toLocaleString() : item.value,
|
|
2771
|
+
item.suffix && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-lg font-medium text-muted-foreground ml-0.5", children: item.suffix })
|
|
2772
|
+
] }),
|
|
2773
|
+
item.delta && /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: cn("flex items-center gap-1 text-xs font-medium", deltaColor), children: [
|
|
2774
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(TrendIcon, { size: 11, strokeWidth: 2.5, "aria-hidden": true }),
|
|
2775
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { children: item.delta }),
|
|
2776
|
+
item.deltaLabel && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "font-normal text-muted-foreground", children: item.deltaLabel })
|
|
2777
|
+
] })
|
|
2778
|
+
]
|
|
2779
|
+
},
|
|
2780
|
+
i
|
|
2781
|
+
);
|
|
2782
|
+
})
|
|
2783
|
+
}
|
|
2784
|
+
);
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
// src/activity-feed/index.tsx
|
|
2788
|
+
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
2789
|
+
var typeDot = {
|
|
2790
|
+
task: "bg-primary",
|
|
2791
|
+
comment: "bg-sky-500",
|
|
2792
|
+
alert: "bg-amber-500",
|
|
2793
|
+
success: "bg-emerald-500",
|
|
2794
|
+
info: "bg-muted-foreground",
|
|
2795
|
+
user: "bg-violet-500"
|
|
2796
|
+
};
|
|
2797
|
+
function getInitials(text) {
|
|
2798
|
+
if (!text) return "?";
|
|
2799
|
+
const w = text.trim().split(/\s+/);
|
|
2800
|
+
return w.length === 1 ? w[0].slice(0, 2).toUpperCase() : (w[0][0] + w[w.length - 1][0]).toUpperCase();
|
|
2801
|
+
}
|
|
2802
|
+
function ActivityFeed({
|
|
2803
|
+
items,
|
|
2804
|
+
timeline = true,
|
|
2805
|
+
compact = false,
|
|
2806
|
+
className,
|
|
2807
|
+
emptyMessage = "No activity yet."
|
|
2808
|
+
}) {
|
|
2809
|
+
if (!items.length) {
|
|
2810
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: cn("py-10 text-center text-sm text-muted-foreground", className), children: emptyMessage });
|
|
2811
|
+
}
|
|
2812
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("ul", { className: cn("flex flex-col", compact ? "gap-1" : "gap-0", className), children: items.map((item, i) => {
|
|
2813
|
+
const dotColor = item.dotColor ?? typeDot[item.type ?? "info"];
|
|
2814
|
+
const isLast = i === items.length - 1;
|
|
2815
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("li", { className: cn("relative flex gap-4", compact ? "py-2 px-1" : "py-3 px-1"), children: [
|
|
2816
|
+
timeline && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex flex-col items-center shrink-0", style: { width: 28 }, children: [
|
|
2817
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: cn("mt-0.5 size-2.5 rounded-full ring-2 ring-background shrink-0", dotColor) }),
|
|
2818
|
+
!isLast && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "mt-1 w-px flex-1 bg-border", style: { minHeight: compact ? 16 : 24 } })
|
|
2819
|
+
] }),
|
|
2820
|
+
!timeline && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "mt-0.5 shrink-0 inline-flex size-8 items-center justify-center rounded-full bg-muted text-xs font-medium text-muted-foreground overflow-hidden", children: item.icon ?? (item.avatar ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("img", { src: item.avatar, alt: item.initials ?? "", className: "size-full object-cover" }) : getInitials(item.initials ?? item.title)) }),
|
|
2821
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
2822
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [
|
|
2823
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: cn("text-sm font-medium text-foreground leading-snug", compact && "text-xs"), children: item.title }),
|
|
2824
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground whitespace-nowrap", children: item.timestamp })
|
|
2825
|
+
] }),
|
|
2826
|
+
item.description && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "mt-0.5 text-xs text-muted-foreground line-clamp-2", children: item.description }),
|
|
2827
|
+
item.meta && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "mt-1 text-[11px] text-muted-foreground/70", children: item.meta })
|
|
2828
|
+
] })
|
|
2829
|
+
] }, item.id);
|
|
2830
|
+
}) });
|
|
2831
|
+
}
|
|
2832
|
+
|
|
2833
|
+
// src/app-shell/index.tsx
|
|
2834
|
+
var React12 = __toESM(require("react"));
|
|
2835
|
+
var import_lucide_react12 = require("lucide-react");
|
|
2836
|
+
var import_dropdown_menu = require("@web-my-money/primitives/dropdown-menu");
|
|
2837
|
+
|
|
2838
|
+
// src/app-brand/index.tsx
|
|
2839
|
+
var import_jsx_runtime42 = (
|
|
2840
|
+
// Mini-logo placeholder — first letter on a primary chip.
|
|
2841
|
+
require("react/jsx-runtime")
|
|
2842
|
+
);
|
|
2843
|
+
var MARK_SIZE = { sm: "size-6 text-xs", md: "size-7 text-sm" };
|
|
2844
|
+
var TITLE_SIZE = { sm: "text-[13px]", md: "text-sm" };
|
|
2845
|
+
function AppBrand({
|
|
2846
|
+
appName,
|
|
2847
|
+
prefix = "WMM",
|
|
2848
|
+
logo,
|
|
2849
|
+
subtitle,
|
|
2850
|
+
badge,
|
|
2851
|
+
href,
|
|
2852
|
+
collapsed = false,
|
|
2853
|
+
size = "md",
|
|
2854
|
+
renderLink,
|
|
2855
|
+
className
|
|
2856
|
+
}) {
|
|
2857
|
+
const mark = logo ?? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
2858
|
+
"span",
|
|
2859
|
+
{
|
|
2860
|
+
className: cn(
|
|
2861
|
+
"grid shrink-0 place-items-center rounded-lg bg-primary font-bold text-primary-foreground",
|
|
2862
|
+
MARK_SIZE[size]
|
|
2863
|
+
),
|
|
2864
|
+
"aria-hidden": true,
|
|
2865
|
+
children: appName.slice(0, 1)
|
|
2866
|
+
}
|
|
2867
|
+
);
|
|
2868
|
+
const inner = /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "flex items-center gap-2.5", children: [
|
|
2869
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "grid shrink-0 place-items-center [&_svg]:h-auto", children: mark }),
|
|
2870
|
+
!collapsed && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
2871
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "flex min-w-0 flex-col leading-tight", children: [
|
|
2872
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: cn("truncate font-semibold tracking-tight", TITLE_SIZE[size]), children: [
|
|
2873
|
+
prefix && /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "text-muted-foreground", children: [
|
|
2874
|
+
prefix,
|
|
2875
|
+
" "
|
|
2876
|
+
] }),
|
|
2877
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "text-primary", children: appName })
|
|
2878
|
+
] }),
|
|
2879
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "truncate text-[11px] text-muted-foreground", children: subtitle })
|
|
2880
|
+
] }),
|
|
2881
|
+
badge != null && /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "border-l border-border pl-2 text-sm font-semibold text-muted-foreground", children: badge })
|
|
2882
|
+
] })
|
|
2883
|
+
] });
|
|
2884
|
+
const cls = cn("inline-flex items-center", className);
|
|
2885
|
+
if (href && renderLink) return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_jsx_runtime42.Fragment, { children: renderLink({ href, className: cls, children: inner }) });
|
|
2886
|
+
if (href)
|
|
2887
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("a", { href, className: cls, children: inner });
|
|
2888
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: cls, children: inner });
|
|
2889
|
+
}
|
|
2890
|
+
|
|
2891
|
+
// src/app-shell/index.tsx
|
|
2892
|
+
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
2893
|
+
var railW = "w-14";
|
|
2894
|
+
var openW = "w-56";
|
|
2895
|
+
var LAYOUT_KEY = "wmm-app-layout";
|
|
2896
|
+
function isGroup(n) {
|
|
2897
|
+
return Array.isArray(n.items) && !("href" in n) && !("onClick" in n) && !("icon" in n) && !("badge" in n) && !("shortLabel" in n) && !("external" in n);
|
|
2898
|
+
}
|
|
2899
|
+
function toGroups(nav) {
|
|
2900
|
+
if (!nav.length) return [];
|
|
2901
|
+
return isGroup(nav[0]) ? nav : [{ items: nav }];
|
|
2902
|
+
}
|
|
2903
|
+
function allItems(groups) {
|
|
2904
|
+
return groups.flatMap((g) => g.items);
|
|
2905
|
+
}
|
|
2906
|
+
function withActive(item, pathname) {
|
|
2907
|
+
if (item.active !== void 0 || !pathname || !item.href) return item;
|
|
2908
|
+
const active = item.href === "/" ? pathname === "/" : pathname.startsWith(item.href);
|
|
2909
|
+
return active ? { ...item, active } : item;
|
|
2910
|
+
}
|
|
2911
|
+
var LayoutContext = React12.createContext(null);
|
|
2912
|
+
function useLayoutPreference(defaultLayout = "sidebar") {
|
|
2913
|
+
const [layout, setLayoutState] = React12.useState(defaultLayout);
|
|
2914
|
+
React12.useEffect(() => {
|
|
2915
|
+
try {
|
|
2916
|
+
const saved = window.localStorage.getItem(LAYOUT_KEY);
|
|
2917
|
+
if (saved === "sidebar" || saved === "top") setLayoutState(saved);
|
|
2918
|
+
} catch {
|
|
2919
|
+
}
|
|
2920
|
+
}, []);
|
|
2921
|
+
const setLayout = React12.useCallback((l) => {
|
|
2922
|
+
setLayoutState(l);
|
|
2923
|
+
try {
|
|
2924
|
+
window.localStorage.setItem(LAYOUT_KEY, l);
|
|
2925
|
+
} catch {
|
|
2926
|
+
}
|
|
2927
|
+
}, []);
|
|
2928
|
+
return [layout, setLayout];
|
|
2929
|
+
}
|
|
2930
|
+
function LayoutToggle({ className }) {
|
|
2931
|
+
const ctx = React12.useContext(LayoutContext);
|
|
2932
|
+
if (!ctx) return null;
|
|
2933
|
+
const next = ctx.layout === "sidebar" ? "top" : "sidebar";
|
|
2934
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
2935
|
+
"button",
|
|
2936
|
+
{
|
|
2937
|
+
type: "button",
|
|
2938
|
+
onClick: () => ctx.setLayout(next),
|
|
2939
|
+
className: cn(
|
|
2940
|
+
"inline-flex items-center justify-center rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
2941
|
+
className
|
|
2942
|
+
),
|
|
2943
|
+
"aria-label": `Switch to ${next} layout`,
|
|
2944
|
+
title: `Switch to ${next} layout`,
|
|
2945
|
+
children: ctx.layout === "sidebar" ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.PanelTop, { className: "size-4" }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.PanelLeft, { className: "size-4" })
|
|
2946
|
+
}
|
|
2947
|
+
);
|
|
2948
|
+
}
|
|
2949
|
+
function SidebarNavRow({
|
|
2950
|
+
item,
|
|
2951
|
+
collapsed,
|
|
2952
|
+
renderLink,
|
|
2953
|
+
onNavigate,
|
|
2954
|
+
nested
|
|
2955
|
+
}) {
|
|
2956
|
+
const inner = /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
2957
|
+
"span",
|
|
2958
|
+
{
|
|
2959
|
+
className: cn(
|
|
2960
|
+
"flex items-center gap-2.5 rounded-md px-2.5 py-2 text-[13px] font-medium transition-colors",
|
|
2961
|
+
item.active ? "bg-primary/15 text-primary" : "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
2962
|
+
collapsed && "justify-center px-0",
|
|
2963
|
+
nested && !collapsed && "ml-3.5 py-1.5"
|
|
2964
|
+
),
|
|
2965
|
+
children: [
|
|
2966
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "grid size-[15px] shrink-0 place-items-center [&_svg]:size-[15px]", children: item.icon }),
|
|
2967
|
+
!collapsed && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "flex-1 truncate", children: [
|
|
2968
|
+
item.label,
|
|
2969
|
+
item.external && " \u2197"
|
|
2970
|
+
] }),
|
|
2971
|
+
!collapsed && item.badge != null && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "rounded bg-danger/20 px-1.5 py-px text-[10px] font-semibold text-danger", children: item.badge })
|
|
2972
|
+
]
|
|
2973
|
+
}
|
|
2974
|
+
);
|
|
2975
|
+
const cls = "block";
|
|
2976
|
+
if (item.href && item.external)
|
|
2977
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", { href: item.href, target: "_blank", rel: "noopener noreferrer", className: cls, onClick: onNavigate, children: inner });
|
|
2978
|
+
if (item.href && renderLink) return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_jsx_runtime43.Fragment, { children: renderLink({ href: item.href, className: cls, children: inner }) });
|
|
2979
|
+
if (item.href)
|
|
2980
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", { href: item.href, className: cls, onClick: onNavigate, children: inner });
|
|
2981
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", className: cn(cls, "w-full text-left"), onClick: () => {
|
|
2982
|
+
item.onClick?.();
|
|
2983
|
+
onNavigate?.();
|
|
2984
|
+
}, children: inner });
|
|
2985
|
+
}
|
|
2986
|
+
function SectionHeader({
|
|
2987
|
+
group,
|
|
2988
|
+
open,
|
|
2989
|
+
onToggle
|
|
2990
|
+
}) {
|
|
2991
|
+
if (!group.collapsible) {
|
|
2992
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "px-2.5 pb-1 pt-3 text-[10px] font-semibold uppercase tracking-widest text-muted-foreground", children: group.label });
|
|
2993
|
+
}
|
|
2994
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
2995
|
+
"button",
|
|
2996
|
+
{
|
|
2997
|
+
type: "button",
|
|
2998
|
+
onClick: onToggle,
|
|
2999
|
+
className: "flex w-full items-center gap-1 px-2.5 pb-1 pt-3 text-[10px] font-semibold uppercase tracking-widest text-muted-foreground transition-colors hover:text-foreground",
|
|
3000
|
+
children: [
|
|
3001
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.ChevronDown, { className: "size-3" }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.ChevronRight, { className: "size-3" }),
|
|
3002
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "flex-1 text-left", children: group.label })
|
|
3003
|
+
]
|
|
3004
|
+
}
|
|
3005
|
+
);
|
|
3006
|
+
}
|
|
3007
|
+
function TopLink({
|
|
3008
|
+
item,
|
|
3009
|
+
renderLink
|
|
3010
|
+
}) {
|
|
3011
|
+
const inner = /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
3012
|
+
"span",
|
|
3013
|
+
{
|
|
3014
|
+
className: cn(
|
|
3015
|
+
"inline-flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-[13px] font-medium transition-colors [&_svg]:size-4",
|
|
3016
|
+
item.active ? "bg-primary/10 text-primary" : "text-muted-foreground hover:bg-muted hover:text-foreground"
|
|
3017
|
+
),
|
|
3018
|
+
children: [
|
|
3019
|
+
item.icon,
|
|
3020
|
+
item.label,
|
|
3021
|
+
item.external && " \u2197",
|
|
3022
|
+
item.badge != null && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "rounded bg-danger/20 px-1.5 text-[10px] font-semibold text-danger", children: item.badge })
|
|
3023
|
+
]
|
|
3024
|
+
}
|
|
3025
|
+
);
|
|
3026
|
+
if (item.href && item.external)
|
|
3027
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", { href: item.href, target: "_blank", rel: "noopener noreferrer", children: inner });
|
|
3028
|
+
if (item.href && renderLink) return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_jsx_runtime43.Fragment, { children: renderLink({ href: item.href, children: inner }) });
|
|
3029
|
+
if (item.href) return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", { href: item.href, children: inner });
|
|
3030
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", onClick: item.onClick, children: inner });
|
|
3031
|
+
}
|
|
3032
|
+
function TopDropdown({
|
|
3033
|
+
label,
|
|
3034
|
+
items,
|
|
3035
|
+
renderLink
|
|
3036
|
+
}) {
|
|
3037
|
+
const hasBadge = items.some((i) => i.badge != null && i.badge !== 0);
|
|
3038
|
+
const anyActive = items.some((i) => i.active);
|
|
3039
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_dropdown_menu.DropdownMenu, { children: [
|
|
3040
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
3041
|
+
import_dropdown_menu.DropdownMenuTrigger,
|
|
3042
|
+
{
|
|
3043
|
+
className: cn(
|
|
3044
|
+
"inline-flex items-center gap-1 rounded-md px-2.5 py-1.5 text-[13px] font-medium transition-colors hover:bg-muted hover:text-foreground",
|
|
3045
|
+
anyActive ? "text-foreground" : "text-muted-foreground"
|
|
3046
|
+
),
|
|
3047
|
+
children: [
|
|
3048
|
+
label,
|
|
3049
|
+
hasBadge && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "size-1.5 rounded-full bg-primary", "aria-hidden": true }),
|
|
3050
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.ChevronDown, { className: "size-3.5 opacity-50" })
|
|
3051
|
+
]
|
|
3052
|
+
}
|
|
3053
|
+
),
|
|
3054
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_dropdown_menu.DropdownMenuContent, { align: "start", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
|
|
3055
|
+
import_dropdown_menu.DropdownMenuItem,
|
|
3056
|
+
{
|
|
3057
|
+
className: cn(item.active && "text-primary"),
|
|
3058
|
+
onClick: item.onClick,
|
|
3059
|
+
render: item.href ? item.external ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", { href: item.href, target: "_blank", rel: "noopener noreferrer" }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", { href: item.href }) : void 0,
|
|
3060
|
+
children: [
|
|
3061
|
+
item.icon,
|
|
3062
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "flex-1", children: [
|
|
3063
|
+
item.label,
|
|
3064
|
+
item.external && " \u2197"
|
|
3065
|
+
] }),
|
|
3066
|
+
item.badge != null && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "rounded bg-danger/20 px-1.5 text-[10px] font-semibold text-danger", children: item.badge })
|
|
3067
|
+
]
|
|
3068
|
+
},
|
|
3069
|
+
i
|
|
3070
|
+
)) })
|
|
3071
|
+
] });
|
|
3072
|
+
}
|
|
3073
|
+
function AppShell({
|
|
3074
|
+
appName,
|
|
3075
|
+
brandPrefix,
|
|
3076
|
+
logo,
|
|
3077
|
+
brandSubtitle,
|
|
3078
|
+
brandBadge,
|
|
3079
|
+
nav,
|
|
3080
|
+
mobileTabs,
|
|
3081
|
+
user,
|
|
3082
|
+
headerActions,
|
|
3083
|
+
sidebarFooter,
|
|
3084
|
+
layout: layoutProp,
|
|
3085
|
+
defaultLayout = "sidebar",
|
|
3086
|
+
onLayoutChange,
|
|
3087
|
+
pathname,
|
|
3088
|
+
contained = false,
|
|
3089
|
+
defaultCollapsed = false,
|
|
3090
|
+
renderLink,
|
|
3091
|
+
children,
|
|
3092
|
+
className
|
|
3093
|
+
}) {
|
|
3094
|
+
const [uncontrolled, setUncontrolled] = useLayoutPreference(defaultLayout);
|
|
3095
|
+
const layout = layoutProp ?? uncontrolled;
|
|
3096
|
+
const setLayout = React12.useCallback(
|
|
3097
|
+
(l) => {
|
|
3098
|
+
onLayoutChange?.(l);
|
|
3099
|
+
if (layoutProp === void 0) setUncontrolled(l);
|
|
3100
|
+
},
|
|
3101
|
+
[onLayoutChange, layoutProp, setUncontrolled]
|
|
3102
|
+
);
|
|
3103
|
+
const layoutCtx = React12.useMemo(() => ({ layout, setLayout }), [layout, setLayout]);
|
|
3104
|
+
const [collapsed, setCollapsed] = React12.useState(defaultCollapsed);
|
|
3105
|
+
const [drawer, setDrawer] = React12.useState(false);
|
|
3106
|
+
const [open, setOpen] = React12.useState({});
|
|
3107
|
+
const groups = React12.useMemo(() => {
|
|
3108
|
+
const gs = toGroups(nav);
|
|
3109
|
+
return gs.map((g) => ({ ...g, items: g.items.map((it) => withActive(it, pathname)) }));
|
|
3110
|
+
}, [nav, pathname]);
|
|
3111
|
+
const flat = React12.useMemo(() => allItems(groups), [groups]);
|
|
3112
|
+
const tabs = (mobileTabs ?? flat).slice(0, 5);
|
|
3113
|
+
const brand = /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
3114
|
+
AppBrand,
|
|
3115
|
+
{
|
|
3116
|
+
appName,
|
|
3117
|
+
prefix: brandPrefix,
|
|
3118
|
+
logo,
|
|
3119
|
+
subtitle: brandSubtitle,
|
|
3120
|
+
badge: brandBadge,
|
|
3121
|
+
renderLink
|
|
3122
|
+
}
|
|
3123
|
+
);
|
|
3124
|
+
const isOpen = (g, i) => !g.collapsible || (open[g.label ?? String(i)] ?? g.defaultOpen ?? true);
|
|
3125
|
+
const SidebarBody = ({ isCollapsed, onNavigate }) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex h-full flex-col", children: [
|
|
3126
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: cn("flex h-12 items-center gap-2 border-b border-border px-3", isCollapsed && "justify-center px-0"), children: [
|
|
3127
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(AppBrand, { appName, prefix: brandPrefix, logo, subtitle: brandSubtitle, collapsed: isCollapsed, renderLink, href: "/" }),
|
|
3128
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
3129
|
+
"button",
|
|
3130
|
+
{
|
|
3131
|
+
type: "button",
|
|
3132
|
+
onClick: () => setCollapsed((c) => !c),
|
|
3133
|
+
className: "ml-auto hidden rounded-md p-1 text-muted-foreground hover:bg-muted hover:text-foreground md:inline-flex",
|
|
3134
|
+
"aria-label": "Toggle sidebar",
|
|
3135
|
+
children: isCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.PanelLeft, { className: "size-4" }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.PanelLeftClose, { className: "size-4" })
|
|
3136
|
+
}
|
|
3137
|
+
)
|
|
3138
|
+
] }),
|
|
3139
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("nav", { className: "flex-1 space-y-0.5 overflow-y-auto p-2", children: groups.map((g, gi) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: cn(gi > 0 && !g.label && "mt-1"), children: [
|
|
3140
|
+
g.label && !isCollapsed && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
3141
|
+
SectionHeader,
|
|
3142
|
+
{
|
|
3143
|
+
group: g,
|
|
3144
|
+
open: isOpen(g, gi),
|
|
3145
|
+
onToggle: () => setOpen((o) => ({ ...o, [g.label ?? String(gi)]: !isOpen(g, gi) }))
|
|
3146
|
+
}
|
|
3147
|
+
),
|
|
3148
|
+
isOpen(g, gi) && g.items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(React12.Fragment, { children: [
|
|
3149
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(SidebarNavRow, { item, collapsed: isCollapsed, renderLink, onNavigate }),
|
|
3150
|
+
!isCollapsed && item.items?.map((sub, si) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(SidebarNavRow, { item: withActive(sub, pathname), renderLink, onNavigate, nested: true }, si))
|
|
3151
|
+
] }, i))
|
|
3152
|
+
] }, g.label ?? gi)) }),
|
|
3153
|
+
(sidebarFooter || user) && /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "border-t border-border p-2", children: [
|
|
3154
|
+
sidebarFooter,
|
|
3155
|
+
user && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: cn("mt-1", isCollapsed && "flex justify-center"), children: user })
|
|
3156
|
+
] })
|
|
3157
|
+
] });
|
|
3158
|
+
const MobileDrawer = () => drawer ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "fixed inset-0 z-50 md:hidden", role: "dialog", "aria-modal": true, children: [
|
|
3159
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "absolute inset-0 bg-black/50", onClick: () => setDrawer(false) }),
|
|
3160
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "absolute inset-y-0 left-0 w-[80vw] max-w-xs border-r border-border bg-card", children: [
|
|
3161
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
3162
|
+
"button",
|
|
3163
|
+
{
|
|
3164
|
+
type: "button",
|
|
3165
|
+
onClick: () => setDrawer(false),
|
|
3166
|
+
className: "absolute right-2 top-2 rounded-md p-1.5 text-muted-foreground hover:bg-muted",
|
|
3167
|
+
"aria-label": "Close menu",
|
|
3168
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.X, { className: "size-4" })
|
|
3169
|
+
}
|
|
3170
|
+
),
|
|
3171
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(SidebarBody, { isCollapsed: false, onNavigate: () => setDrawer(false) })
|
|
3172
|
+
] })
|
|
3173
|
+
] }) : null;
|
|
3174
|
+
const BottomTabs = () => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
3175
|
+
"nav",
|
|
3176
|
+
{
|
|
3177
|
+
className: "fixed inset-x-0 bottom-0 z-40 flex h-14 items-stretch border-t border-border bg-card md:hidden",
|
|
3178
|
+
style: { paddingBottom: "env(safe-area-inset-bottom)" },
|
|
3179
|
+
children: tabs.map((item, i) => {
|
|
3180
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: cn("flex h-full flex-1 flex-col items-center justify-center gap-0.5", item.active ? "text-primary" : "text-muted-foreground"), children: [
|
|
3181
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "grid size-5 place-items-center [&_svg]:size-5", children: item.icon }),
|
|
3182
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "text-[10px] font-medium leading-none", children: item.shortLabel ?? item.label })
|
|
3183
|
+
] });
|
|
3184
|
+
return item.href && item.external ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", { href: item.href, target: "_blank", rel: "noopener noreferrer", className: "flex-1", children: content }, i) : item.href && renderLink ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(React12.Fragment, { children: renderLink({ href: item.href, className: "flex-1", children: content }) }, i) : item.href ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("a", { href: item.href, className: "flex-1", children: content }, i) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", className: "flex-1", onClick: item.onClick, children: content }, i);
|
|
3185
|
+
})
|
|
3186
|
+
}
|
|
3187
|
+
);
|
|
3188
|
+
const MobileTopBar = () => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("header", { className: "flex h-12 shrink-0 items-center gap-2 border-b border-border px-3 md:hidden", children: [
|
|
3189
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("button", { type: "button", onClick: () => setDrawer(true), className: "rounded-md p-1.5 text-muted-foreground hover:bg-muted", "aria-label": "Open menu", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_lucide_react12.Menu, { className: "size-5" }) }),
|
|
3190
|
+
brand,
|
|
3191
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "ml-auto flex items-center gap-1", children: headerActions })
|
|
3192
|
+
] });
|
|
3193
|
+
if (layout === "top") {
|
|
3194
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(LayoutContext.Provider, { value: layoutCtx, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: cn("flex min-h-screen flex-col bg-background text-foreground", className), children: [
|
|
3195
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("header", { className: "sticky top-0 z-40 hidden h-14 shrink-0 items-center gap-1 border-b border-border bg-card/95 px-4 backdrop-blur md:flex", children: [
|
|
3196
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "shrink-0", children: brand }),
|
|
3197
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("nav", { className: "ml-4 flex items-center gap-0.5", children: groups.map(
|
|
3198
|
+
(g, gi) => g.label ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(TopDropdown, { label: g.label, items: g.items, renderLink }, gi) : g.items.map(
|
|
3199
|
+
(item, i) => item.items ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(TopDropdown, { label: item.label, items: item.items, renderLink }, `${gi}-${i}`) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(TopLink, { item, renderLink }, `${gi}-${i}`)
|
|
3200
|
+
)
|
|
3201
|
+
) }),
|
|
3202
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "ml-auto flex items-center gap-2", children: [
|
|
3203
|
+
headerActions,
|
|
3204
|
+
user
|
|
3205
|
+
] })
|
|
3206
|
+
] }),
|
|
3207
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(MobileTopBar, {}),
|
|
3208
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(MobileDrawer, {}),
|
|
3209
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("main", { className: "flex-1 overflow-y-auto pb-20 md:pb-0", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: cn(contained ? "mx-auto max-w-7xl px-4 py-6 sm:px-6 sm:py-8" : "p-4 sm:p-6"), children }) }),
|
|
3210
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(BottomTabs, {})
|
|
3211
|
+
] }) });
|
|
3212
|
+
}
|
|
3213
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(LayoutContext.Provider, { value: layoutCtx, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: cn("flex h-screen overflow-hidden bg-background text-foreground", className), children: [
|
|
3214
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("aside", { className: cn("hidden shrink-0 border-r border-border transition-[width] duration-200 md:block", collapsed ? railW : openW), children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(SidebarBody, { isCollapsed: collapsed }) }),
|
|
3215
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(MobileDrawer, {}),
|
|
3216
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
3217
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(MobileTopBar, {}),
|
|
3218
|
+
headerActions && /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("header", { className: "hidden h-12 shrink-0 items-center border-b border-border px-4 md:flex", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "ml-auto flex items-center gap-2", children: headerActions }) }),
|
|
3219
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("main", { className: "flex-1 overflow-y-auto pb-20 md:pb-0", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: cn(contained ? "mx-auto max-w-7xl px-4 py-6 sm:px-6 sm:py-8" : "p-4 sm:p-6"), children }) }),
|
|
3220
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(BottomTabs, {})
|
|
3221
|
+
] })
|
|
3222
|
+
] }) });
|
|
3223
|
+
}
|
|
3224
|
+
|
|
3225
|
+
// src/sub-tabs/index.tsx
|
|
3226
|
+
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
3227
|
+
function SubTabs({
|
|
3228
|
+
items,
|
|
3229
|
+
value,
|
|
3230
|
+
onChange,
|
|
3231
|
+
className,
|
|
3232
|
+
"aria-label": ariaLabel
|
|
3233
|
+
}) {
|
|
3234
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
3235
|
+
"div",
|
|
3236
|
+
{
|
|
3237
|
+
role: "tablist",
|
|
3238
|
+
"aria-label": ariaLabel,
|
|
3239
|
+
className: cn("inline-flex rounded-lg border border-border bg-card p-0.5", className),
|
|
3240
|
+
children: items.map((it) => {
|
|
3241
|
+
const selected = value === it.id;
|
|
3242
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
3243
|
+
"button",
|
|
3244
|
+
{
|
|
3245
|
+
type: "button",
|
|
3246
|
+
role: "tab",
|
|
3247
|
+
"aria-selected": selected,
|
|
3248
|
+
onClick: () => onChange(it.id),
|
|
3249
|
+
className: cn(
|
|
3250
|
+
"inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm transition-colors [&_svg]:size-4",
|
|
3251
|
+
selected ? "bg-primary/10 text-primary" : "text-muted-foreground hover:text-foreground"
|
|
3252
|
+
),
|
|
3253
|
+
children: [
|
|
3254
|
+
it.icon,
|
|
3255
|
+
it.label
|
|
3256
|
+
]
|
|
3257
|
+
},
|
|
3258
|
+
it.id
|
|
3259
|
+
);
|
|
3260
|
+
})
|
|
3261
|
+
}
|
|
3262
|
+
);
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3265
|
+
// src/page-header-banner/index.tsx
|
|
3266
|
+
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
3267
|
+
function PageHeaderBanner({
|
|
3268
|
+
title,
|
|
3269
|
+
subtitle,
|
|
3270
|
+
actions,
|
|
3271
|
+
gradient = true,
|
|
3272
|
+
icon,
|
|
3273
|
+
className
|
|
3274
|
+
}) {
|
|
3275
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3276
|
+
"div",
|
|
3277
|
+
{
|
|
3278
|
+
className: cn(
|
|
3279
|
+
"mb-6 flex flex-col gap-4 rounded-xl border border-border p-6 sm:mb-8 sm:flex-row sm:items-center sm:p-8",
|
|
3280
|
+
className
|
|
3281
|
+
),
|
|
3282
|
+
style: gradient ? {
|
|
3283
|
+
background: "linear-gradient(135deg, color-mix(in srgb, var(--primary) 10%, transparent), color-mix(in srgb, var(--accent) 5%, transparent))"
|
|
3284
|
+
} : { background: "var(--card)" },
|
|
3285
|
+
children: [
|
|
3286
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex min-w-0 items-center gap-4", children: [
|
|
3287
|
+
icon && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "grid size-12 shrink-0 place-items-center rounded-xl bg-primary/15 text-primary [&_svg]:size-6", children: icon }),
|
|
3288
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "min-w-0", children: [
|
|
3289
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h1", { className: "font-heading text-2xl font-bold tracking-tight text-foreground sm:text-3xl", children: title }),
|
|
3290
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "mt-1 text-sm text-muted-foreground", children: subtitle })
|
|
3291
|
+
] })
|
|
3292
|
+
] }),
|
|
3293
|
+
actions && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "flex shrink-0 items-center gap-2 sm:ml-auto", children: actions })
|
|
3294
|
+
]
|
|
3295
|
+
}
|
|
3296
|
+
);
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
// src/glass-panel/index.tsx
|
|
3300
|
+
var import_jsx_runtime46 = require("react/jsx-runtime");
|
|
3301
|
+
function GlassPanel({ strong, glow, className, style, ...props }) {
|
|
3302
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
3303
|
+
"div",
|
|
3304
|
+
{
|
|
3305
|
+
className: cn("rounded-2xl border", className),
|
|
3306
|
+
style: {
|
|
3307
|
+
background: strong ? "var(--glass-bg-strong, rgba(255,255,255,0.08))" : "var(--glass-bg, rgba(255,255,255,0.04))",
|
|
3308
|
+
borderColor: "var(--glass-border, var(--border))",
|
|
3309
|
+
backdropFilter: "var(--glass-blur, blur(20px))",
|
|
3310
|
+
WebkitBackdropFilter: "var(--glass-blur, blur(20px))",
|
|
3311
|
+
boxShadow: glow ? "var(--shadow-glow)" : "var(--shadow-elevated, 0 8px 32px rgba(0,0,0,0.2))",
|
|
3312
|
+
...style
|
|
3313
|
+
},
|
|
3314
|
+
...props
|
|
3315
|
+
}
|
|
3316
|
+
);
|
|
3317
|
+
}
|
|
3318
|
+
|
|
3319
|
+
// src/brand-frame/index.tsx
|
|
3320
|
+
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
3321
|
+
var POS = {
|
|
3322
|
+
"top-right": "top-4 right-4",
|
|
3323
|
+
"bottom-right": "bottom-4 right-4",
|
|
3324
|
+
center: "inset-0 flex items-center justify-center"
|
|
3325
|
+
};
|
|
3326
|
+
function BrandFrame({
|
|
3327
|
+
watermark,
|
|
3328
|
+
watermarkPosition = "top-right",
|
|
3329
|
+
watermarkOpacity = 0.06,
|
|
3330
|
+
glow = false,
|
|
3331
|
+
glass = false,
|
|
3332
|
+
animated = false,
|
|
3333
|
+
header,
|
|
3334
|
+
backdrop,
|
|
3335
|
+
className,
|
|
3336
|
+
children,
|
|
3337
|
+
style,
|
|
3338
|
+
...props
|
|
3339
|
+
}) {
|
|
3340
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
3341
|
+
"div",
|
|
3342
|
+
{
|
|
3343
|
+
className: cn(
|
|
3344
|
+
"relative overflow-hidden rounded-2xl border border-border",
|
|
3345
|
+
glass ? "backdrop-blur-xl" : "bg-card",
|
|
3346
|
+
className
|
|
3347
|
+
),
|
|
3348
|
+
style: {
|
|
3349
|
+
...glass ? { background: "var(--glass-bg, color-mix(in srgb, var(--card) 70%, transparent))" } : null,
|
|
3350
|
+
...glow ? { boxShadow: "var(--shadow-glow, 0 4px 24px color-mix(in srgb, var(--primary) 28%, transparent))" } : null,
|
|
3351
|
+
...style
|
|
3352
|
+
},
|
|
3353
|
+
...props,
|
|
3354
|
+
children: [
|
|
3355
|
+
animated && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3356
|
+
"span",
|
|
3357
|
+
{
|
|
3358
|
+
"aria-hidden": true,
|
|
3359
|
+
"data-wmm-fx": true,
|
|
3360
|
+
className: "pointer-events-none absolute inset-x-0 top-0 h-px",
|
|
3361
|
+
style: {
|
|
3362
|
+
background: "var(--gradient-primary, linear-gradient(90deg, var(--primary), var(--accent)))",
|
|
3363
|
+
backgroundSize: "200% 100%",
|
|
3364
|
+
animation: "wmm-shimmer 3s linear infinite"
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
),
|
|
3368
|
+
backdrop && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "pointer-events-none absolute inset-0", children: backdrop }),
|
|
3369
|
+
watermark && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3370
|
+
"div",
|
|
3371
|
+
{
|
|
3372
|
+
"aria-hidden": true,
|
|
3373
|
+
className: cn("pointer-events-none absolute", POS[watermarkPosition]),
|
|
3374
|
+
style: { opacity: watermarkOpacity },
|
|
3375
|
+
children: watermark
|
|
3376
|
+
}
|
|
3377
|
+
),
|
|
3378
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "relative", children: [
|
|
3379
|
+
header && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "flex items-center justify-between gap-3 border-b border-border px-5 py-3", children: header }),
|
|
3380
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "p-5", children })
|
|
3381
|
+
] })
|
|
3382
|
+
]
|
|
3383
|
+
}
|
|
3384
|
+
);
|
|
3385
|
+
}
|
|
3386
|
+
|
|
3387
|
+
// src/use-action-runner.ts
|
|
3388
|
+
var React13 = __toESM(require("react"));
|
|
3389
|
+
var import_toast = require("@web-my-money/primitives/toast");
|
|
3390
|
+
function useActionRunner() {
|
|
3391
|
+
const toast = (0, import_toast.useToast)();
|
|
3392
|
+
const [pending, setPending] = React13.useState(false);
|
|
3393
|
+
const run = React13.useCallback(
|
|
3394
|
+
async (action, options = {}) => {
|
|
3395
|
+
setPending(true);
|
|
3396
|
+
try {
|
|
3397
|
+
const result = await action();
|
|
3398
|
+
if (result.ok) {
|
|
3399
|
+
if (options.successMessage) {
|
|
3400
|
+
const title = typeof options.successMessage === "function" ? options.successMessage(result.data) : options.successMessage;
|
|
3401
|
+
toast.add({
|
|
3402
|
+
title,
|
|
3403
|
+
actionProps: options.undo ? {
|
|
3404
|
+
children: options.undo.label ?? "Undo",
|
|
3405
|
+
onClick: () => {
|
|
3406
|
+
void options.undo.action();
|
|
3407
|
+
}
|
|
3408
|
+
} : void 0
|
|
3409
|
+
});
|
|
3410
|
+
}
|
|
3411
|
+
options.onSuccess?.(result.data);
|
|
3412
|
+
} else {
|
|
3413
|
+
const title = typeof options.errorMessage === "function" ? options.errorMessage(result.error) : options.errorMessage ?? result.error;
|
|
3414
|
+
toast.add({ title, type: "error" });
|
|
3415
|
+
options.onError?.(result.error);
|
|
3416
|
+
}
|
|
3417
|
+
return result;
|
|
3418
|
+
} finally {
|
|
3419
|
+
setPending(false);
|
|
3420
|
+
options.onSettled?.();
|
|
3421
|
+
}
|
|
3422
|
+
},
|
|
3423
|
+
[toast]
|
|
3424
|
+
);
|
|
3425
|
+
return { run, pending };
|
|
3426
|
+
}
|
|
3427
|
+
|
|
3428
|
+
// src/use-optimistic-action.ts
|
|
3429
|
+
var React14 = __toESM(require("react"));
|
|
3430
|
+
function useOptimisticAction(state, reducer) {
|
|
3431
|
+
const [optimisticState, setOptimistic] = React14.useOptimistic(state, reducer);
|
|
3432
|
+
const [isPending, startTransition] = React14.useTransition();
|
|
3433
|
+
const apply = React14.useCallback(
|
|
3434
|
+
(optimisticValue, action, onResult) => {
|
|
3435
|
+
startTransition(async () => {
|
|
3436
|
+
setOptimistic(optimisticValue);
|
|
3437
|
+
const result = await action();
|
|
3438
|
+
onResult?.(result);
|
|
3439
|
+
});
|
|
3440
|
+
},
|
|
3441
|
+
[setOptimistic]
|
|
3442
|
+
);
|
|
3443
|
+
return [optimisticState, apply, isPending];
|
|
3444
|
+
}
|
|
3445
|
+
|
|
3446
|
+
// src/appearance-settings/index.tsx
|
|
3447
|
+
var import_react4 = require("@web-my-money/tokens/react");
|
|
3448
|
+
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
3449
|
+
function AppearanceSettings({ className }) {
|
|
3450
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: cn("space-y-6", className), "data-slot": "appearance-settings", children: [
|
|
3451
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center justify-between gap-4", "data-slot": "appearance-settings-row", children: [
|
|
3452
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { children: [
|
|
3453
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "text-sm font-medium text-foreground", children: "Theme" }),
|
|
3454
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "text-xs text-muted-foreground", children: "Light, dark, or the WMM brand theme." })
|
|
3455
|
+
] }),
|
|
3456
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_react4.ThemeToggle, {})
|
|
3457
|
+
] }),
|
|
3458
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center justify-between gap-4", "data-slot": "appearance-settings-row", children: [
|
|
3459
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { children: [
|
|
3460
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "text-sm font-medium text-foreground", children: "Text size" }),
|
|
3461
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "text-xs text-muted-foreground", children: "Scales the whole interface." })
|
|
3462
|
+
] }),
|
|
3463
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_react4.FontSizeToggle, {})
|
|
3464
|
+
] })
|
|
3465
|
+
] });
|
|
3466
|
+
}
|
|
3467
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
3468
|
+
0 && (module.exports = {
|
|
3469
|
+
ActivityFeed,
|
|
3470
|
+
AppBrand,
|
|
3471
|
+
AppShell,
|
|
3472
|
+
AppearanceSettings,
|
|
3473
|
+
AvatarGroup,
|
|
3474
|
+
BentoGrid,
|
|
3475
|
+
BrandFrame,
|
|
3476
|
+
CTABanner,
|
|
3477
|
+
CaseStudiesSection,
|
|
3478
|
+
ComparisonTable,
|
|
3479
|
+
ContactForm,
|
|
3480
|
+
DEFAULT_WAVES,
|
|
3481
|
+
DashboardHeader,
|
|
3482
|
+
DataSummaryCards,
|
|
3483
|
+
DataTable,
|
|
3484
|
+
EmptyState,
|
|
3485
|
+
FadeUp,
|
|
3486
|
+
Faq,
|
|
3487
|
+
FeatureGrid,
|
|
3488
|
+
Footer,
|
|
3489
|
+
GlassPanel,
|
|
3490
|
+
HeroCanvas,
|
|
3491
|
+
HeroSection,
|
|
3492
|
+
KPIRow,
|
|
3493
|
+
LayeredButton,
|
|
3494
|
+
LayoutToggle,
|
|
3495
|
+
LightboxGallery,
|
|
3496
|
+
LogoCloud,
|
|
3497
|
+
Marquee,
|
|
3498
|
+
NavBar,
|
|
3499
|
+
NotificationBanner,
|
|
3500
|
+
PageHeader,
|
|
3501
|
+
PageHeaderBanner,
|
|
3502
|
+
PricingTable,
|
|
3503
|
+
ProcessSteps,
|
|
3504
|
+
ScrollReveal,
|
|
3505
|
+
SectionGlow,
|
|
3506
|
+
SectionIntro,
|
|
3507
|
+
SectionLabel,
|
|
3508
|
+
SidebarNavigation,
|
|
3509
|
+
SocialProof,
|
|
3510
|
+
StatCard,
|
|
3511
|
+
StatsSection,
|
|
3512
|
+
SubTabs,
|
|
3513
|
+
TechCarousel,
|
|
3514
|
+
TestimonialCarousel,
|
|
3515
|
+
TestimonialsCarousel,
|
|
3516
|
+
TestimonialsSection,
|
|
3517
|
+
TextRotator,
|
|
3518
|
+
Thumbnail,
|
|
3519
|
+
UseCasesSection,
|
|
3520
|
+
ValueStackSection,
|
|
3521
|
+
WaveCanvas,
|
|
3522
|
+
useActionRunner,
|
|
3523
|
+
useLayoutPreference,
|
|
3524
|
+
useOptimisticAction
|
|
3525
|
+
});
|