@caqophony/ui 0.3.1 → 0.5.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/README.md +58 -5
- package/dist/chunk-44GEHNZP.js +126 -0
- package/dist/chunk-DP5WQAPO.js +23 -0
- package/dist/chunk-I5DQCG6D.js +378 -0
- package/dist/chunk-ID7VBGJA.js +233 -0
- package/dist/{chunk-4YA6BZDJ.js → chunk-ODRGJV46.js} +3 -10
- package/dist/icon.d-DQqyySj2.d.mts +82 -0
- package/dist/index.d.mts +14 -82
- package/dist/index.js +803 -1351
- package/dist/markdown.js +2 -1
- package/dist/marketing.d.mts +444 -0
- package/dist/marketing.js +1439 -0
- package/dist/material-art.d.mts +137 -0
- package/dist/material-art.js +210 -0
- package/dist/material-tones.d.mts +23 -0
- package/dist/material-tones.js +66 -0
- package/dist/material.d.mts +615 -0
- package/dist/material.js +1066 -0
- package/package.json +19 -2
- package/styles.css +358 -3
|
@@ -0,0 +1,1439 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
Container,
|
|
5
|
+
NavbarMenu
|
|
6
|
+
} from "./chunk-I5DQCG6D.js";
|
|
7
|
+
import {
|
|
8
|
+
ScrollHintXMark
|
|
9
|
+
} from "./chunk-ID7VBGJA.js";
|
|
10
|
+
import {
|
|
11
|
+
cn
|
|
12
|
+
} from "./chunk-DP5WQAPO.js";
|
|
13
|
+
|
|
14
|
+
// src/marketing/marketing-header.tsx
|
|
15
|
+
import * as React from "react";
|
|
16
|
+
import { createPortal } from "react-dom";
|
|
17
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
18
|
+
var NIGHT_GROUND = "-mb-16 justify-between border-b border-border bg-night-0/80 backdrop-blur-md";
|
|
19
|
+
var ON_DARK_GROUND = "text-background dark:text-foreground";
|
|
20
|
+
var DARK_MENU_BUTTON = cn(
|
|
21
|
+
ON_DARK_GROUND,
|
|
22
|
+
"hover:bg-background/10 hover:text-background dark:hover:bg-foreground/10 dark:hover:text-foreground"
|
|
23
|
+
);
|
|
24
|
+
var NIGHT_MENU_BUTTON = "size-11";
|
|
25
|
+
var FOLDED_AWAY = "md:invisible md:absolute md:w-0 md:overflow-hidden";
|
|
26
|
+
var px = (value) => parseFloat(value) || 0;
|
|
27
|
+
function useFold(refs, actionsHost, hasLinks) {
|
|
28
|
+
const [folded, setFolded] = React.useState(false);
|
|
29
|
+
React.useLayoutEffect(() => {
|
|
30
|
+
const { bar, brand, brandText, nav, links, actionsRow, actionsHome } = refs;
|
|
31
|
+
if (!bar.current || !brand.current || !brandText.current) return;
|
|
32
|
+
let actionsWidth = 0;
|
|
33
|
+
const measure = () => {
|
|
34
|
+
const row = bar.current;
|
|
35
|
+
const mark = brand.current;
|
|
36
|
+
const text = brandText.current;
|
|
37
|
+
if (!row || !mark || !text) return;
|
|
38
|
+
const shown = nav.current ?? actionsRow.current;
|
|
39
|
+
if (!shown || getComputedStyle(shown).display === "none") return;
|
|
40
|
+
const home = actionsHome.current;
|
|
41
|
+
if (home && (!actionsHost || home.contains(actionsHost)))
|
|
42
|
+
actionsWidth = home.getBoundingClientRect().width;
|
|
43
|
+
const barStyle = getComputedStyle(row);
|
|
44
|
+
const room = row.clientWidth - px(barStyle.paddingLeft) - px(barStyle.paddingRight);
|
|
45
|
+
const brandWidth = mark.getBoundingClientRect().width - text.getBoundingClientRect().width + text.scrollWidth;
|
|
46
|
+
const linksWidth = nav.current ? px(getComputedStyle(nav.current).marginLeft) + (links.current?.getBoundingClientRect().width ?? 0) : 0;
|
|
47
|
+
const actionsSpace = actionsRow.current ? nav.current ? px(getComputedStyle(actionsRow.current).marginLeft) : px(getComputedStyle(actionsRow.current).paddingLeft) : 0;
|
|
48
|
+
setFolded(
|
|
49
|
+
Math.ceil(brandWidth + linksWidth + actionsSpace + actionsWidth) > room
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
measure();
|
|
53
|
+
const observer = new ResizeObserver(measure);
|
|
54
|
+
for (const el of [
|
|
55
|
+
bar.current,
|
|
56
|
+
brandText.current,
|
|
57
|
+
links.current,
|
|
58
|
+
actionsHome.current
|
|
59
|
+
])
|
|
60
|
+
if (el) observer.observe(el);
|
|
61
|
+
return () => observer.disconnect();
|
|
62
|
+
}, [refs, actionsHost, hasLinks]);
|
|
63
|
+
return folded;
|
|
64
|
+
}
|
|
65
|
+
function MarketingHeader({
|
|
66
|
+
brandName,
|
|
67
|
+
brandInitials,
|
|
68
|
+
navItems = [],
|
|
69
|
+
actions,
|
|
70
|
+
className,
|
|
71
|
+
variant = "light"
|
|
72
|
+
}) {
|
|
73
|
+
const isDark = variant === "dark";
|
|
74
|
+
const isNight = variant === "night";
|
|
75
|
+
const isGlass = isDark || isNight;
|
|
76
|
+
const hasLinks = navItems.length > 0;
|
|
77
|
+
const bar = React.useRef(null);
|
|
78
|
+
const brand = React.useRef(null);
|
|
79
|
+
const brandText = React.useRef(null);
|
|
80
|
+
const nav = React.useRef(null);
|
|
81
|
+
const links = React.useRef(null);
|
|
82
|
+
const actionsRow = React.useRef(null);
|
|
83
|
+
const actionsHome = React.useRef(null);
|
|
84
|
+
const refs = React.useMemo(
|
|
85
|
+
() => ({ bar, brand, brandText, nav, links, actionsRow, actionsHome }),
|
|
86
|
+
[]
|
|
87
|
+
);
|
|
88
|
+
const [actionsHost, setActionsHost] = React.useState(
|
|
89
|
+
null
|
|
90
|
+
);
|
|
91
|
+
const hasActions = Boolean(actions);
|
|
92
|
+
React.useLayoutEffect(() => {
|
|
93
|
+
if (!hasActions) return;
|
|
94
|
+
const host = document.createElement("div");
|
|
95
|
+
host.className = "contents";
|
|
96
|
+
actionsHome.current?.appendChild(host);
|
|
97
|
+
setActionsHost(host);
|
|
98
|
+
return () => {
|
|
99
|
+
host.remove();
|
|
100
|
+
setActionsHost(null);
|
|
101
|
+
};
|
|
102
|
+
}, [hasActions]);
|
|
103
|
+
const drawerActions = React.useCallback(
|
|
104
|
+
(slot) => {
|
|
105
|
+
if (actionsHost) (slot ?? actionsHome.current)?.appendChild(actionsHost);
|
|
106
|
+
},
|
|
107
|
+
[actionsHost]
|
|
108
|
+
);
|
|
109
|
+
const folded = useFold(refs, actionsHost, hasLinks);
|
|
110
|
+
return /* @__PURE__ */ jsxs(
|
|
111
|
+
"header",
|
|
112
|
+
{
|
|
113
|
+
ref: bar,
|
|
114
|
+
"data-testid": "marketing-header",
|
|
115
|
+
"data-folded": folded ? "" : void 0,
|
|
116
|
+
"data-surface": isNight ? "night" : void 0,
|
|
117
|
+
"data-marketing-header": isNight ? "night" : void 0,
|
|
118
|
+
className: cn(
|
|
119
|
+
"sticky top-0 z-50 flex h-16 items-center px-6 lg:px-12",
|
|
120
|
+
isNight ? NIGHT_GROUND : isDark ? "justify-between border-b border-primary-foreground/[0.06] bg-foreground/85 backdrop-blur-md dark:bg-background/85" : "border-b border-border bg-card dark:border-border dark:bg-card",
|
|
121
|
+
className
|
|
122
|
+
),
|
|
123
|
+
children: [
|
|
124
|
+
/* @__PURE__ */ jsxs(
|
|
125
|
+
"a",
|
|
126
|
+
{
|
|
127
|
+
ref: brand,
|
|
128
|
+
href: "/",
|
|
129
|
+
className: cn(
|
|
130
|
+
"flex min-w-0 items-center gap-2.5 text-base font-bold no-underline",
|
|
131
|
+
isDark ? ON_DARK_GROUND : "text-foreground dark:text-foreground"
|
|
132
|
+
),
|
|
133
|
+
children: [
|
|
134
|
+
/* @__PURE__ */ jsx("div", { className: "bg-primary-solid flex size-8 shrink-0 items-center justify-center rounded-lg text-xs font-extrabold text-primary-foreground", children: brandInitials }),
|
|
135
|
+
/* @__PURE__ */ jsx("span", { ref: brandText, className: "truncate", children: brandName })
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
),
|
|
139
|
+
hasLinks && /* @__PURE__ */ jsx(
|
|
140
|
+
"nav",
|
|
141
|
+
{
|
|
142
|
+
ref: nav,
|
|
143
|
+
className: cn(
|
|
144
|
+
"hidden min-w-0 flex-1 overflow-x-clip md:flex",
|
|
145
|
+
isGlass ? "ml-6" : "ml-6 lg:ml-12",
|
|
146
|
+
folded && FOLDED_AWAY
|
|
147
|
+
),
|
|
148
|
+
children: /* @__PURE__ */ jsx(
|
|
149
|
+
"div",
|
|
150
|
+
{
|
|
151
|
+
ref: links,
|
|
152
|
+
className: cn(
|
|
153
|
+
"flex w-max items-center gap-4 lg:gap-8",
|
|
154
|
+
isGlass && "mx-auto"
|
|
155
|
+
),
|
|
156
|
+
children: navItems.map((item) => /* @__PURE__ */ jsx(
|
|
157
|
+
"a",
|
|
158
|
+
{
|
|
159
|
+
href: item.href,
|
|
160
|
+
className: cn(
|
|
161
|
+
"whitespace-nowrap text-sm font-medium no-underline transition-colors",
|
|
162
|
+
isNight ? cn(
|
|
163
|
+
"flex min-h-[44px] items-center hover:text-foreground",
|
|
164
|
+
item.active ? "font-semibold text-foreground" : "text-muted-foreground"
|
|
165
|
+
) : isDark ? "flex min-h-[44px] items-center text-background/70 hover:text-background dark:text-foreground/70 dark:hover:text-foreground" : item.active ? "text-primary-text font-semibold" : "text-muted-foreground hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground"
|
|
166
|
+
),
|
|
167
|
+
children: item.label
|
|
168
|
+
},
|
|
169
|
+
item.label
|
|
170
|
+
))
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
),
|
|
175
|
+
actions && /* @__PURE__ */ jsx(
|
|
176
|
+
"div",
|
|
177
|
+
{
|
|
178
|
+
ref: actionsRow,
|
|
179
|
+
className: cn(
|
|
180
|
+
"hidden shrink-0 md:flex",
|
|
181
|
+
hasLinks ? "ml-6" : "ml-auto pl-6",
|
|
182
|
+
folded && FOLDED_AWAY
|
|
183
|
+
),
|
|
184
|
+
children: /* @__PURE__ */ jsx(
|
|
185
|
+
"div",
|
|
186
|
+
{
|
|
187
|
+
ref: actionsHome,
|
|
188
|
+
className: "flex w-max items-center gap-3 whitespace-nowrap",
|
|
189
|
+
children: actionsHost ? createPortal(actions, actionsHost) : actions
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
),
|
|
194
|
+
(hasLinks || actions) && /* @__PURE__ */ jsx(
|
|
195
|
+
NavbarMenu,
|
|
196
|
+
{
|
|
197
|
+
folded,
|
|
198
|
+
triggerClassName: isDark ? DARK_MENU_BUTTON : isNight ? NIGHT_MENU_BUTTON : void 0,
|
|
199
|
+
surface: isNight ? variant : void 0,
|
|
200
|
+
links: hasLinks ? navItems.map((item) => /* @__PURE__ */ jsx(
|
|
201
|
+
"a",
|
|
202
|
+
{
|
|
203
|
+
href: item.href,
|
|
204
|
+
className: cn(
|
|
205
|
+
"text-sm font-medium no-underline",
|
|
206
|
+
item.active ? "text-primary-text" : "text-foreground"
|
|
207
|
+
),
|
|
208
|
+
children: item.label
|
|
209
|
+
},
|
|
210
|
+
item.label
|
|
211
|
+
)) : void 0,
|
|
212
|
+
actions: actions ? /* @__PURE__ */ jsx(
|
|
213
|
+
"div",
|
|
214
|
+
{
|
|
215
|
+
ref: drawerActions,
|
|
216
|
+
className: "flex flex-col gap-2 [&>*>*]:w-full"
|
|
217
|
+
}
|
|
218
|
+
) : void 0
|
|
219
|
+
}
|
|
220
|
+
)
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// src/marketing/marketing-hero.tsx
|
|
227
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
228
|
+
function MarketingHero({
|
|
229
|
+
headline,
|
|
230
|
+
subtitle,
|
|
231
|
+
actions,
|
|
232
|
+
visual,
|
|
233
|
+
layout = "centered",
|
|
234
|
+
className
|
|
235
|
+
}) {
|
|
236
|
+
if (layout === "split") {
|
|
237
|
+
return /* @__PURE__ */ jsx2(
|
|
238
|
+
"section",
|
|
239
|
+
{
|
|
240
|
+
"data-testid": "marketing-hero",
|
|
241
|
+
className: cn("bg-primary-solid px-6 py-20 lg:px-12", className),
|
|
242
|
+
children: /* @__PURE__ */ jsxs2("div", { className: "mx-auto grid max-w-[1200px] grid-cols-1 items-center gap-16 md:grid-cols-2", children: [
|
|
243
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-5", children: [
|
|
244
|
+
/* @__PURE__ */ jsx2("h1", { className: "text-4xl font-black leading-tight text-primary-foreground md:text-5xl", children: headline }),
|
|
245
|
+
/* @__PURE__ */ jsx2("p", { className: "text-lg font-normal leading-relaxed text-primary-foreground", children: subtitle }),
|
|
246
|
+
actions && /* @__PURE__ */ jsx2("div", { className: "flex flex-wrap gap-4", children: actions })
|
|
247
|
+
] }),
|
|
248
|
+
visual && /* @__PURE__ */ jsx2("div", { className: "flex items-end justify-end", children: visual })
|
|
249
|
+
] })
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
return /* @__PURE__ */ jsxs2(
|
|
254
|
+
"section",
|
|
255
|
+
{
|
|
256
|
+
"data-testid": "marketing-hero",
|
|
257
|
+
className: cn(
|
|
258
|
+
"bg-primary-solid px-6 pb-20 pt-24 text-center lg:px-12",
|
|
259
|
+
className
|
|
260
|
+
),
|
|
261
|
+
children: [
|
|
262
|
+
/* @__PURE__ */ jsx2("h1", { className: "mx-auto mb-6 max-w-[800px] text-4xl font-black leading-tight text-primary-foreground md:text-6xl", children: headline }),
|
|
263
|
+
/* @__PURE__ */ jsx2("p", { className: "mx-auto mb-10 max-w-[640px] text-xl font-normal leading-relaxed text-primary-foreground", children: subtitle }),
|
|
264
|
+
actions && /* @__PURE__ */ jsx2("div", { className: "flex flex-wrap justify-center gap-4", children: actions })
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// src/marketing/feature-card.tsx
|
|
271
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
272
|
+
function FeatureCard({
|
|
273
|
+
icon,
|
|
274
|
+
title,
|
|
275
|
+
description,
|
|
276
|
+
className
|
|
277
|
+
}) {
|
|
278
|
+
return /* @__PURE__ */ jsxs3(
|
|
279
|
+
"div",
|
|
280
|
+
{
|
|
281
|
+
"data-testid": "feature-card",
|
|
282
|
+
className: cn(
|
|
283
|
+
"rounded-xl border border-border bg-card p-6 shadow-sm dark:border-border dark:bg-card",
|
|
284
|
+
className
|
|
285
|
+
),
|
|
286
|
+
children: [
|
|
287
|
+
/* @__PURE__ */ jsx3("div", { className: "mb-4 flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10 dark:bg-primary/10", children: /* @__PURE__ */ jsx3("div", { className: "text-primary-text dark:text-primary-text h-6 w-6", children: icon }) }),
|
|
288
|
+
/* @__PURE__ */ jsx3("h3", { className: "mb-2 text-base font-bold text-foreground dark:text-foreground", children: title }),
|
|
289
|
+
/* @__PURE__ */ jsx3("p", { className: "text-sm leading-relaxed text-muted-foreground dark:text-muted-foreground", children: description })
|
|
290
|
+
]
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/marketing/pricing-tier.tsx
|
|
296
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
297
|
+
function PricingTier({
|
|
298
|
+
name,
|
|
299
|
+
price,
|
|
300
|
+
period,
|
|
301
|
+
features,
|
|
302
|
+
highlighted = false,
|
|
303
|
+
action,
|
|
304
|
+
className
|
|
305
|
+
}) {
|
|
306
|
+
return /* @__PURE__ */ jsxs4(
|
|
307
|
+
"div",
|
|
308
|
+
{
|
|
309
|
+
"data-testid": "pricing-tier",
|
|
310
|
+
className: cn(
|
|
311
|
+
"relative rounded-xl border bg-card p-8 text-center dark:bg-card",
|
|
312
|
+
highlighted ? "border-primary shadow-lg ring-2 ring-primary/10 dark:border-primary dark:ring-primary/10" : "border-border dark:border-border",
|
|
313
|
+
className
|
|
314
|
+
),
|
|
315
|
+
children: [
|
|
316
|
+
/* @__PURE__ */ jsx4("div", { className: "mb-2 text-lg font-bold text-foreground dark:text-foreground", children: name }),
|
|
317
|
+
/* @__PURE__ */ jsx4("div", { className: "text-primary-text dark:text-primary-text text-4xl font-black", children: price }),
|
|
318
|
+
/* @__PURE__ */ jsx4("div", { className: "mb-6 text-sm text-muted-foreground dark:text-muted-foreground", children: period }),
|
|
319
|
+
/* @__PURE__ */ jsx4("ul", { className: "mb-6 space-y-1.5 text-left", children: features.map((feature) => /* @__PURE__ */ jsxs4(
|
|
320
|
+
"li",
|
|
321
|
+
{
|
|
322
|
+
className: "relative pl-6 text-sm text-foreground dark:text-foreground",
|
|
323
|
+
children: [
|
|
324
|
+
/* @__PURE__ */ jsx4("span", { className: "bg-intent-success dark:bg-intent-success absolute left-0 top-[7px] h-2 w-2 rounded-full" }),
|
|
325
|
+
feature
|
|
326
|
+
]
|
|
327
|
+
},
|
|
328
|
+
feature
|
|
329
|
+
)) }),
|
|
330
|
+
action && /* @__PURE__ */ jsx4("div", { className: "w-full", children: action })
|
|
331
|
+
]
|
|
332
|
+
}
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// src/marketing/faq-item.tsx
|
|
337
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
338
|
+
function MarketingFAQItem({
|
|
339
|
+
question,
|
|
340
|
+
answer,
|
|
341
|
+
dark = false,
|
|
342
|
+
className
|
|
343
|
+
}) {
|
|
344
|
+
return /* @__PURE__ */ jsxs5(
|
|
345
|
+
"div",
|
|
346
|
+
{
|
|
347
|
+
"data-testid": "marketing-faq-item",
|
|
348
|
+
className: cn(
|
|
349
|
+
"border-b py-6",
|
|
350
|
+
dark ? "border-muted-foreground/20 dark:border-muted-foreground/20" : "border-border dark:border-border",
|
|
351
|
+
className
|
|
352
|
+
),
|
|
353
|
+
children: [
|
|
354
|
+
/* @__PURE__ */ jsx5(
|
|
355
|
+
"h3",
|
|
356
|
+
{
|
|
357
|
+
className: cn(
|
|
358
|
+
"mb-3 text-base font-semibold",
|
|
359
|
+
dark ? "text-primary-foreground dark:text-foreground" : "text-foreground dark:text-foreground"
|
|
360
|
+
),
|
|
361
|
+
children: question
|
|
362
|
+
}
|
|
363
|
+
),
|
|
364
|
+
/* @__PURE__ */ jsx5(
|
|
365
|
+
"p",
|
|
366
|
+
{
|
|
367
|
+
className: cn(
|
|
368
|
+
"text-sm leading-[1.7]",
|
|
369
|
+
dark ? "text-primary-foreground/70 dark:text-muted-foreground" : "text-muted-foreground dark:text-muted-foreground"
|
|
370
|
+
),
|
|
371
|
+
children: answer
|
|
372
|
+
}
|
|
373
|
+
)
|
|
374
|
+
]
|
|
375
|
+
}
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// src/marketing/cta-banner.tsx
|
|
380
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
381
|
+
function CTABanner({
|
|
382
|
+
headline,
|
|
383
|
+
description,
|
|
384
|
+
actions,
|
|
385
|
+
className
|
|
386
|
+
}) {
|
|
387
|
+
return /* @__PURE__ */ jsxs6(
|
|
388
|
+
"section",
|
|
389
|
+
{
|
|
390
|
+
"data-testid": "cta-banner",
|
|
391
|
+
className: cn(
|
|
392
|
+
"bg-primary-solid px-6 py-20 text-center lg:px-12",
|
|
393
|
+
className
|
|
394
|
+
),
|
|
395
|
+
children: [
|
|
396
|
+
/* @__PURE__ */ jsx6("h2", { className: "mb-4 text-4xl font-extrabold text-primary-foreground", children: headline }),
|
|
397
|
+
/* @__PURE__ */ jsx6("p", { className: "mb-8 text-lg text-primary-foreground", children: description }),
|
|
398
|
+
actions && /* @__PURE__ */ jsx6("div", { className: "flex flex-wrap justify-center gap-4", children: actions })
|
|
399
|
+
]
|
|
400
|
+
}
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// src/marketing/marketing-cta.tsx
|
|
405
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
406
|
+
var TREATMENT = {
|
|
407
|
+
light: {
|
|
408
|
+
// the edge is `primary-text`, which reads on the page in either scheme: a
|
|
409
|
+
// dark primary's fill alone sinks into a dark page
|
|
410
|
+
primary: "border-primary-text bg-primary-solid text-primary-foreground hover:opacity-hover",
|
|
411
|
+
secondary: "border-primary-text text-primary-text hover:bg-muted"
|
|
412
|
+
},
|
|
413
|
+
brand: {
|
|
414
|
+
primary: "bg-brand-fill text-brand-fill-foreground hover:opacity-hover",
|
|
415
|
+
secondary: "border-brand-fill text-brand-fill hover:bg-brand-fill hover:text-brand-fill-foreground"
|
|
416
|
+
},
|
|
417
|
+
dark: {
|
|
418
|
+
primary: "bg-night-accent text-night-accent-foreground hover:opacity-hover",
|
|
419
|
+
secondary: "border-night-muted-foreground text-night-foreground hover:bg-night-muted"
|
|
420
|
+
},
|
|
421
|
+
image: {
|
|
422
|
+
primary: "bg-night-accent text-night-accent-foreground shadow-lg hover:opacity-hover",
|
|
423
|
+
secondary: "border-night-muted-foreground bg-night-0 text-night-foreground shadow-lg hover:bg-night-muted"
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
var FOCUS = {
|
|
427
|
+
light: "focus-visible:outline-primary-text",
|
|
428
|
+
brand: "focus-visible:outline-brand-fill",
|
|
429
|
+
dark: "focus-visible:outline-night-foreground",
|
|
430
|
+
image: "focus-visible:outline-night-foreground"
|
|
431
|
+
};
|
|
432
|
+
function MarketingCta({
|
|
433
|
+
href,
|
|
434
|
+
ground,
|
|
435
|
+
emphasis,
|
|
436
|
+
className,
|
|
437
|
+
children,
|
|
438
|
+
...anchor
|
|
439
|
+
}) {
|
|
440
|
+
return /* @__PURE__ */ jsx7(
|
|
441
|
+
"a",
|
|
442
|
+
{
|
|
443
|
+
...anchor,
|
|
444
|
+
href,
|
|
445
|
+
"data-cta-ground": ground,
|
|
446
|
+
"data-cta-emphasis": emphasis,
|
|
447
|
+
"data-border-current": emphasis === "secondary" ? "" : void 0,
|
|
448
|
+
className: cn(
|
|
449
|
+
"inline-flex min-h-12 items-center justify-center rounded-lg border-2 border-transparent px-6 py-2.5 text-center text-base font-semibold",
|
|
450
|
+
"motion-safe:duration-fast motion-safe:transition-colors",
|
|
451
|
+
"focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2",
|
|
452
|
+
TREATMENT[ground][emphasis],
|
|
453
|
+
FOCUS[ground],
|
|
454
|
+
className
|
|
455
|
+
),
|
|
456
|
+
children
|
|
457
|
+
}
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// src/marketing/how-it-works-step.tsx
|
|
462
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
463
|
+
function HowItWorksStep({
|
|
464
|
+
stepNumber,
|
|
465
|
+
title,
|
|
466
|
+
description,
|
|
467
|
+
className
|
|
468
|
+
}) {
|
|
469
|
+
return /* @__PURE__ */ jsxs7(
|
|
470
|
+
"div",
|
|
471
|
+
{
|
|
472
|
+
"data-testid": "how-it-works-step",
|
|
473
|
+
className: cn("text-center", className),
|
|
474
|
+
children: [
|
|
475
|
+
/* @__PURE__ */ jsx8("div", { className: "bg-primary-solid mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full text-xl font-bold text-primary-foreground", children: stepNumber }),
|
|
476
|
+
/* @__PURE__ */ jsx8("h3", { className: "mb-2 text-base font-bold text-foreground dark:text-foreground", children: title }),
|
|
477
|
+
/* @__PURE__ */ jsx8("p", { className: "text-sm leading-relaxed text-muted-foreground dark:text-muted-foreground", children: description })
|
|
478
|
+
]
|
|
479
|
+
}
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/marketing/use-case-card.tsx
|
|
484
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
485
|
+
function UseCaseCard({
|
|
486
|
+
persona,
|
|
487
|
+
scenario,
|
|
488
|
+
outcome,
|
|
489
|
+
className
|
|
490
|
+
}) {
|
|
491
|
+
return /* @__PURE__ */ jsxs8(
|
|
492
|
+
"div",
|
|
493
|
+
{
|
|
494
|
+
"data-testid": "use-case-card",
|
|
495
|
+
className: cn(
|
|
496
|
+
"rounded-xl border border-border bg-card p-8 dark:border-border dark:bg-card",
|
|
497
|
+
className
|
|
498
|
+
),
|
|
499
|
+
children: [
|
|
500
|
+
/* @__PURE__ */ jsx9("h3", { className: "mb-3 text-lg font-bold text-foreground dark:text-foreground", children: persona }),
|
|
501
|
+
/* @__PURE__ */ jsx9("p", { className: "mb-4 text-sm leading-relaxed text-muted-foreground dark:text-muted-foreground", children: scenario }),
|
|
502
|
+
/* @__PURE__ */ jsx9("p", { className: "text-intent-success-foreground text-sm font-medium leading-normal", children: outcome })
|
|
503
|
+
]
|
|
504
|
+
}
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// src/marketing/blog-grid.tsx
|
|
509
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
510
|
+
function PostCard({
|
|
511
|
+
post,
|
|
512
|
+
featured = false
|
|
513
|
+
}) {
|
|
514
|
+
const Wrapper = post.href ? "a" : "div";
|
|
515
|
+
const wrapperProps = post.href ? { href: post.href } : {};
|
|
516
|
+
return /* @__PURE__ */ jsxs9(
|
|
517
|
+
Wrapper,
|
|
518
|
+
{
|
|
519
|
+
...wrapperProps,
|
|
520
|
+
className: cn(
|
|
521
|
+
"group flex flex-col overflow-hidden rounded-xl border border-border bg-card shadow-sm transition-shadow hover:shadow-md",
|
|
522
|
+
featured && "sm:flex-row"
|
|
523
|
+
),
|
|
524
|
+
children: [
|
|
525
|
+
post.thumbnail && /* @__PURE__ */ jsx10(
|
|
526
|
+
"div",
|
|
527
|
+
{
|
|
528
|
+
className: cn(
|
|
529
|
+
"overflow-hidden bg-muted",
|
|
530
|
+
featured ? "aspect-video sm:w-1/2" : "aspect-video w-full"
|
|
531
|
+
),
|
|
532
|
+
children: /* @__PURE__ */ jsx10(
|
|
533
|
+
"img",
|
|
534
|
+
{
|
|
535
|
+
src: post.thumbnail,
|
|
536
|
+
alt: post.title,
|
|
537
|
+
className: "h-full w-full object-cover transition-transform group-hover:scale-105"
|
|
538
|
+
}
|
|
539
|
+
)
|
|
540
|
+
}
|
|
541
|
+
),
|
|
542
|
+
/* @__PURE__ */ jsxs9(
|
|
543
|
+
"div",
|
|
544
|
+
{
|
|
545
|
+
className: cn("flex flex-1 flex-col gap-2 p-4", featured && "sm:p-6"),
|
|
546
|
+
children: [
|
|
547
|
+
post.category && /* @__PURE__ */ jsx10("span", { className: "bg-primary-solid w-fit rounded-full px-2.5 py-0.5 text-xs font-medium text-primary-foreground", children: post.category }),
|
|
548
|
+
/* @__PURE__ */ jsx10(
|
|
549
|
+
"h3",
|
|
550
|
+
{
|
|
551
|
+
className: cn(
|
|
552
|
+
"line-clamp-2 font-semibold text-foreground",
|
|
553
|
+
featured ? "text-lg" : "text-sm"
|
|
554
|
+
),
|
|
555
|
+
children: post.title
|
|
556
|
+
}
|
|
557
|
+
),
|
|
558
|
+
post.excerpt && /* @__PURE__ */ jsx10("p", { className: "line-clamp-2 text-xs text-muted-foreground", children: post.excerpt }),
|
|
559
|
+
/* @__PURE__ */ jsxs9("div", { className: "mt-auto flex items-center gap-2 pt-2", children: [
|
|
560
|
+
post.authorAvatar && /* @__PURE__ */ jsx10(
|
|
561
|
+
"img",
|
|
562
|
+
{
|
|
563
|
+
src: post.authorAvatar,
|
|
564
|
+
alt: post.author ?? "",
|
|
565
|
+
className: "h-6 w-6 rounded-full object-cover"
|
|
566
|
+
}
|
|
567
|
+
),
|
|
568
|
+
post.author && /* @__PURE__ */ jsx10("span", { className: "text-xs font-medium text-foreground", children: post.author }),
|
|
569
|
+
/* @__PURE__ */ jsx10("span", { className: "text-xs text-muted-foreground", children: post.date })
|
|
570
|
+
] })
|
|
571
|
+
]
|
|
572
|
+
}
|
|
573
|
+
)
|
|
574
|
+
]
|
|
575
|
+
}
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
function PostRow({ post }) {
|
|
579
|
+
const Wrapper = post.href ? "a" : "div";
|
|
580
|
+
const wrapperProps = post.href ? { href: post.href } : {};
|
|
581
|
+
return /* @__PURE__ */ jsxs9(
|
|
582
|
+
Wrapper,
|
|
583
|
+
{
|
|
584
|
+
...wrapperProps,
|
|
585
|
+
className: "group flex gap-4 border-b border-border py-4 last:border-b-0",
|
|
586
|
+
children: [
|
|
587
|
+
post.thumbnail && /* @__PURE__ */ jsx10("div", { className: "h-20 w-28 flex-shrink-0 overflow-hidden rounded-lg bg-muted", children: /* @__PURE__ */ jsx10(
|
|
588
|
+
"img",
|
|
589
|
+
{
|
|
590
|
+
src: post.thumbnail,
|
|
591
|
+
alt: post.title,
|
|
592
|
+
className: "h-full w-full object-cover"
|
|
593
|
+
}
|
|
594
|
+
) }),
|
|
595
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-1 flex-col gap-1", children: [
|
|
596
|
+
post.category && /* @__PURE__ */ jsx10("span", { className: "bg-primary-solid w-fit rounded-full px-2 py-0.5 text-xs font-medium text-primary-foreground", children: post.category }),
|
|
597
|
+
/* @__PURE__ */ jsx10("h3", { className: "line-clamp-1 text-sm font-semibold text-foreground group-hover:underline", children: post.title }),
|
|
598
|
+
post.excerpt && /* @__PURE__ */ jsx10("p", { className: "line-clamp-1 text-xs text-muted-foreground", children: post.excerpt }),
|
|
599
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
600
|
+
post.author && /* @__PURE__ */ jsx10("span", { className: "text-xs text-muted-foreground", children: post.author }),
|
|
601
|
+
/* @__PURE__ */ jsx10("span", { className: "text-xs text-muted-foreground", children: post.date })
|
|
602
|
+
] })
|
|
603
|
+
] })
|
|
604
|
+
]
|
|
605
|
+
}
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
function BlogGrid({
|
|
609
|
+
variant = "threeColumn",
|
|
610
|
+
posts,
|
|
611
|
+
heading,
|
|
612
|
+
description,
|
|
613
|
+
className,
|
|
614
|
+
...props
|
|
615
|
+
}) {
|
|
616
|
+
return /* @__PURE__ */ jsxs9(
|
|
617
|
+
"section",
|
|
618
|
+
{
|
|
619
|
+
className: cn("w-full px-4 py-16 sm:px-6 lg:px-8", className),
|
|
620
|
+
...props,
|
|
621
|
+
children: [
|
|
622
|
+
(heading || description) && /* @__PURE__ */ jsxs9("div", { className: "mx-auto mb-10 max-w-2xl text-center", children: [
|
|
623
|
+
heading && /* @__PURE__ */ jsx10("h2", { className: "text-2xl font-bold text-foreground sm:text-3xl", children: heading }),
|
|
624
|
+
description && /* @__PURE__ */ jsx10("p", { className: "mt-3 text-sm text-muted-foreground", children: description })
|
|
625
|
+
] }),
|
|
626
|
+
variant === "threeColumn" && /* @__PURE__ */ jsx10("div", { className: "mx-auto grid max-w-5xl grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: posts.map((p) => /* @__PURE__ */ jsx10(PostCard, { post: p }, p.id)) }),
|
|
627
|
+
variant === "featured" && posts.length > 0 && /* @__PURE__ */ jsxs9("div", { className: "mx-auto max-w-5xl space-y-6", children: [
|
|
628
|
+
/* @__PURE__ */ jsx10(PostCard, { post: posts[0], featured: true }),
|
|
629
|
+
posts.length > 1 && /* @__PURE__ */ jsx10("div", { className: "grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3", children: posts.slice(1).map((p) => /* @__PURE__ */ jsx10(PostCard, { post: p }, p.id)) })
|
|
630
|
+
] }),
|
|
631
|
+
variant === "list" && /* @__PURE__ */ jsx10("div", { className: "mx-auto max-w-3xl", children: posts.map((p) => /* @__PURE__ */ jsx10(PostRow, { post: p }, p.id)) })
|
|
632
|
+
]
|
|
633
|
+
}
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// src/marketing/comparison-table.tsx
|
|
638
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
639
|
+
function ComparisonTable({
|
|
640
|
+
variant = "simple",
|
|
641
|
+
plans,
|
|
642
|
+
features,
|
|
643
|
+
heading,
|
|
644
|
+
className,
|
|
645
|
+
...props
|
|
646
|
+
}) {
|
|
647
|
+
const featuredPlan = variant === "featured" ? plans.find((p) => p.featured) : null;
|
|
648
|
+
return /* @__PURE__ */ jsxs10("div", { className: cn("w-full", className), ...props, children: [
|
|
649
|
+
heading && /* @__PURE__ */ jsx11("h2", { className: "mb-8 text-center text-2xl font-bold text-foreground sm:text-3xl", children: heading }),
|
|
650
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex w-full overflow-x-auto", children: [
|
|
651
|
+
/* @__PURE__ */ jsxs10("table", { className: "w-full border-collapse", children: [
|
|
652
|
+
/* @__PURE__ */ jsx11("thead", { children: /* @__PURE__ */ jsxs10("tr", { children: [
|
|
653
|
+
/* @__PURE__ */ jsx11("td", { className: "min-w-[180px] border-b border-border p-4" }),
|
|
654
|
+
plans.map((plan) => /* @__PURE__ */ jsxs10(
|
|
655
|
+
"th",
|
|
656
|
+
{
|
|
657
|
+
className: cn(
|
|
658
|
+
"min-w-[140px] border-b border-l border-border p-4 text-center",
|
|
659
|
+
featuredPlan?.id === plan.id && "bg-primary/5"
|
|
660
|
+
),
|
|
661
|
+
children: [
|
|
662
|
+
featuredPlan?.id === plan.id && plan.badge && /* @__PURE__ */ jsx11("span", { className: "bg-primary-solid mb-2 inline-block rounded-full px-2.5 py-0.5 text-xs font-medium text-primary-foreground", children: plan.badge }),
|
|
663
|
+
/* @__PURE__ */ jsx11("div", { className: "text-sm font-semibold text-foreground", children: plan.name }),
|
|
664
|
+
plan.description && /* @__PURE__ */ jsx11("div", { className: "mt-0.5 text-xs text-muted-foreground", children: plan.description })
|
|
665
|
+
]
|
|
666
|
+
},
|
|
667
|
+
plan.id
|
|
668
|
+
))
|
|
669
|
+
] }) }),
|
|
670
|
+
/* @__PURE__ */ jsx11("tbody", { children: features.map((feature, i) => /* @__PURE__ */ jsxs10(
|
|
671
|
+
"tr",
|
|
672
|
+
{
|
|
673
|
+
className: i % 2 === 1 ? "bg-muted/50" : "",
|
|
674
|
+
children: [
|
|
675
|
+
/* @__PURE__ */ jsx11("td", { className: "border-b border-border p-3 text-sm text-foreground", children: feature.label }),
|
|
676
|
+
plans.map((plan) => {
|
|
677
|
+
const val = feature.values[plan.id];
|
|
678
|
+
return /* @__PURE__ */ jsx11(
|
|
679
|
+
"td",
|
|
680
|
+
{
|
|
681
|
+
className: cn(
|
|
682
|
+
"border-b border-l border-border p-3 text-center text-sm",
|
|
683
|
+
featuredPlan?.id === plan.id && "bg-primary/5"
|
|
684
|
+
),
|
|
685
|
+
children: val === true ? /* @__PURE__ */ jsx11("span", { className: "text-intent-success-foreground", children: "\u2713" }) : val === false ? /* @__PURE__ */ jsx11("span", { className: "text-muted-foreground", children: "\u2014" }) : /* @__PURE__ */ jsx11("span", { className: "text-foreground", children: val })
|
|
686
|
+
},
|
|
687
|
+
plan.id
|
|
688
|
+
);
|
|
689
|
+
})
|
|
690
|
+
]
|
|
691
|
+
},
|
|
692
|
+
feature.key
|
|
693
|
+
)) })
|
|
694
|
+
] }),
|
|
695
|
+
/* @__PURE__ */ jsx11(ScrollHintXMark, {})
|
|
696
|
+
] })
|
|
697
|
+
] });
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// src/marketing/logo-cloud.tsx
|
|
701
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
702
|
+
function LogoCloud({
|
|
703
|
+
variant = "simple",
|
|
704
|
+
logos,
|
|
705
|
+
heading,
|
|
706
|
+
className,
|
|
707
|
+
...props
|
|
708
|
+
}) {
|
|
709
|
+
const logoElement = (logo, idx) => /* @__PURE__ */ jsx12(
|
|
710
|
+
"div",
|
|
711
|
+
{
|
|
712
|
+
className: "flex items-center justify-center px-4 py-2 text-muted-foreground",
|
|
713
|
+
children: logo.icon ? logo.icon : logo.src ? /* @__PURE__ */ jsx12(
|
|
714
|
+
"img",
|
|
715
|
+
{
|
|
716
|
+
src: logo.src,
|
|
717
|
+
alt: logo.name,
|
|
718
|
+
className: "h-8 max-w-[120px] object-contain opacity-60 grayscale transition-opacity hover:opacity-100"
|
|
719
|
+
}
|
|
720
|
+
) : /* @__PURE__ */ jsx12("span", { className: "text-sm font-semibold", children: logo.name })
|
|
721
|
+
},
|
|
722
|
+
idx
|
|
723
|
+
);
|
|
724
|
+
if (variant === "scrolling") {
|
|
725
|
+
return /* @__PURE__ */ jsxs11(
|
|
726
|
+
"section",
|
|
727
|
+
{
|
|
728
|
+
className: cn("w-full overflow-hidden px-4 py-10 sm:px-6", className),
|
|
729
|
+
...props,
|
|
730
|
+
children: [
|
|
731
|
+
heading && /* @__PURE__ */ jsx12("p", { className: "mb-6 text-center text-sm text-muted-foreground", children: heading }),
|
|
732
|
+
/* @__PURE__ */ jsxs11("div", { className: "relative flex gap-12 overflow-hidden", children: [
|
|
733
|
+
/* @__PURE__ */ jsx12("div", { className: "animate-scroll flex shrink-0 gap-12", children: logos.map((l, i) => logoElement(l, i)) }),
|
|
734
|
+
/* @__PURE__ */ jsx12("div", { className: "animate-scroll flex shrink-0 gap-12", "aria-hidden": true, children: logos.map((l, i) => logoElement(l, i + logos.length)) })
|
|
735
|
+
] }),
|
|
736
|
+
/* @__PURE__ */ jsx12("style", { children: `
|
|
737
|
+
@keyframes scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
|
|
738
|
+
.animate-scroll { animation: scroll 20s linear infinite; }
|
|
739
|
+
` })
|
|
740
|
+
]
|
|
741
|
+
}
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
if (variant === "branded") {
|
|
745
|
+
return /* @__PURE__ */ jsxs11(
|
|
746
|
+
"section",
|
|
747
|
+
{
|
|
748
|
+
className: cn(
|
|
749
|
+
"w-full border-y border-border px-4 py-10 sm:px-6",
|
|
750
|
+
className
|
|
751
|
+
),
|
|
752
|
+
...props,
|
|
753
|
+
children: [
|
|
754
|
+
heading && /* @__PURE__ */ jsx12("p", { className: "mb-6 text-center text-sm font-medium text-foreground", children: heading }),
|
|
755
|
+
/* @__PURE__ */ jsx12("div", { className: "mx-auto flex max-w-4xl flex-wrap items-center justify-center gap-x-10 gap-y-6", children: logos.map((l, i) => logoElement(l, i)) })
|
|
756
|
+
]
|
|
757
|
+
}
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
return /* @__PURE__ */ jsxs11("section", { className: cn("w-full px-4 py-10 sm:px-6", className), ...props, children: [
|
|
761
|
+
heading && /* @__PURE__ */ jsx12("p", { className: "mb-6 text-center text-sm text-muted-foreground", children: heading }),
|
|
762
|
+
/* @__PURE__ */ jsx12("div", { className: "mx-auto flex max-w-4xl flex-wrap items-center justify-center gap-x-10 gap-y-6", children: logos.map((l, i) => logoElement(l, i)) })
|
|
763
|
+
] });
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// src/marketing/team-section.tsx
|
|
767
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
768
|
+
function MemberAvatar({
|
|
769
|
+
member,
|
|
770
|
+
size
|
|
771
|
+
}) {
|
|
772
|
+
const sizeClass = size === "sm" ? "h-12 w-12" : size === "md" ? "h-16 w-16" : "h-24 w-24";
|
|
773
|
+
return member.avatar ? /* @__PURE__ */ jsx13(
|
|
774
|
+
"img",
|
|
775
|
+
{
|
|
776
|
+
src: member.avatar,
|
|
777
|
+
alt: member.name,
|
|
778
|
+
className: cn("rounded-full object-cover", sizeClass)
|
|
779
|
+
}
|
|
780
|
+
) : /* @__PURE__ */ jsx13(
|
|
781
|
+
"div",
|
|
782
|
+
{
|
|
783
|
+
className: cn(
|
|
784
|
+
"flex items-center justify-center rounded-full bg-muted text-lg font-semibold text-muted-foreground",
|
|
785
|
+
sizeClass
|
|
786
|
+
),
|
|
787
|
+
children: member.name.split(" ").map((n) => n[0]).join("").slice(0, 2)
|
|
788
|
+
}
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
function TeamSection({
|
|
792
|
+
variant = "grid",
|
|
793
|
+
members,
|
|
794
|
+
heading,
|
|
795
|
+
description,
|
|
796
|
+
columns = 3,
|
|
797
|
+
className,
|
|
798
|
+
...props
|
|
799
|
+
}) {
|
|
800
|
+
const colsClass = columns === 2 ? "sm:grid-cols-2" : columns === 4 ? "sm:grid-cols-2 lg:grid-cols-4" : "sm:grid-cols-2 lg:grid-cols-3";
|
|
801
|
+
return /* @__PURE__ */ jsxs12(
|
|
802
|
+
"section",
|
|
803
|
+
{
|
|
804
|
+
className: cn("w-full px-4 py-16 sm:px-6 lg:px-8", className),
|
|
805
|
+
...props,
|
|
806
|
+
children: [
|
|
807
|
+
(heading || description) && /* @__PURE__ */ jsxs12("div", { className: "mx-auto mb-12 max-w-2xl text-center", children: [
|
|
808
|
+
heading && /* @__PURE__ */ jsx13("h2", { className: "text-2xl font-bold text-foreground sm:text-3xl", children: heading }),
|
|
809
|
+
description && /* @__PURE__ */ jsx13("p", { className: "mt-3 text-sm text-muted-foreground sm:text-base", children: description })
|
|
810
|
+
] }),
|
|
811
|
+
variant === "grid" && /* @__PURE__ */ jsx13(
|
|
812
|
+
"div",
|
|
813
|
+
{
|
|
814
|
+
className: cn("mx-auto grid max-w-5xl grid-cols-1 gap-10", colsClass),
|
|
815
|
+
children: members.map((m) => /* @__PURE__ */ jsxs12("div", { className: "flex flex-col items-center text-center", children: [
|
|
816
|
+
/* @__PURE__ */ jsx13(MemberAvatar, { member: m, size: "lg" }),
|
|
817
|
+
/* @__PURE__ */ jsx13("h3", { className: "mt-4 text-sm font-semibold text-foreground", children: m.name }),
|
|
818
|
+
/* @__PURE__ */ jsx13("p", { className: "text-xs text-muted-foreground", children: m.role }),
|
|
819
|
+
m.bio && /* @__PURE__ */ jsx13("p", { className: "mt-2 line-clamp-3 text-xs text-muted-foreground", children: m.bio })
|
|
820
|
+
] }, m.id))
|
|
821
|
+
}
|
|
822
|
+
),
|
|
823
|
+
variant === "list" && /* @__PURE__ */ jsx13("div", { className: "mx-auto max-w-3xl divide-y divide-border", children: members.map((m) => /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-4 py-4", children: [
|
|
824
|
+
/* @__PURE__ */ jsx13(MemberAvatar, { member: m, size: "md" }),
|
|
825
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex-1", children: [
|
|
826
|
+
/* @__PURE__ */ jsx13("h3", { className: "text-sm font-semibold text-foreground", children: m.name }),
|
|
827
|
+
/* @__PURE__ */ jsx13("p", { className: "text-xs text-muted-foreground", children: m.role }),
|
|
828
|
+
m.bio && /* @__PURE__ */ jsx13("p", { className: "mt-1 line-clamp-2 text-xs text-muted-foreground", children: m.bio })
|
|
829
|
+
] }),
|
|
830
|
+
m.socialLinks && m.socialLinks.length > 0 && /* @__PURE__ */ jsx13("div", { className: "flex gap-2", children: m.socialLinks.map((s) => /* @__PURE__ */ jsx13(
|
|
831
|
+
"a",
|
|
832
|
+
{
|
|
833
|
+
href: s.href,
|
|
834
|
+
"aria-label": s.label,
|
|
835
|
+
className: "text-muted-foreground hover:text-foreground",
|
|
836
|
+
children: s.icon ?? s.label
|
|
837
|
+
},
|
|
838
|
+
s.label
|
|
839
|
+
)) })
|
|
840
|
+
] }, m.id)) }),
|
|
841
|
+
variant === "cards" && /* @__PURE__ */ jsx13(
|
|
842
|
+
"div",
|
|
843
|
+
{
|
|
844
|
+
className: cn("mx-auto grid max-w-5xl grid-cols-1 gap-6", colsClass),
|
|
845
|
+
children: members.map((m) => /* @__PURE__ */ jsxs12(
|
|
846
|
+
"div",
|
|
847
|
+
{
|
|
848
|
+
className: "flex flex-col items-center rounded-xl border border-border bg-card p-6 text-center shadow-sm",
|
|
849
|
+
children: [
|
|
850
|
+
/* @__PURE__ */ jsx13(MemberAvatar, { member: m, size: "lg" }),
|
|
851
|
+
/* @__PURE__ */ jsx13("h3", { className: "mt-4 text-sm font-semibold text-foreground", children: m.name }),
|
|
852
|
+
/* @__PURE__ */ jsx13("p", { className: "text-xs text-muted-foreground", children: m.role }),
|
|
853
|
+
m.bio && /* @__PURE__ */ jsx13("p", { className: "mt-2 line-clamp-3 text-xs text-muted-foreground", children: m.bio }),
|
|
854
|
+
m.socialLinks && m.socialLinks.length > 0 && /* @__PURE__ */ jsx13("div", { className: "mt-3 flex gap-3", children: m.socialLinks.map((s) => /* @__PURE__ */ jsx13(
|
|
855
|
+
"a",
|
|
856
|
+
{
|
|
857
|
+
href: s.href,
|
|
858
|
+
"aria-label": s.label,
|
|
859
|
+
className: "text-muted-foreground hover:text-foreground",
|
|
860
|
+
children: s.icon ?? s.label
|
|
861
|
+
},
|
|
862
|
+
s.label
|
|
863
|
+
)) })
|
|
864
|
+
]
|
|
865
|
+
},
|
|
866
|
+
m.id
|
|
867
|
+
))
|
|
868
|
+
}
|
|
869
|
+
)
|
|
870
|
+
]
|
|
871
|
+
}
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// src/marketing/newsletter-section.tsx
|
|
876
|
+
import * as React2 from "react";
|
|
877
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
878
|
+
function NewsletterSection({
|
|
879
|
+
variant = "centered",
|
|
880
|
+
heading,
|
|
881
|
+
description,
|
|
882
|
+
ctaLabel,
|
|
883
|
+
placeholder,
|
|
884
|
+
onSubscribe,
|
|
885
|
+
className,
|
|
886
|
+
...props
|
|
887
|
+
}) {
|
|
888
|
+
const [email, setEmail] = React2.useState("");
|
|
889
|
+
if (onSubscribe && !ctaLabel)
|
|
890
|
+
throw new Error(
|
|
891
|
+
"NewsletterSection: `onSubscribe` needs `ctaLabel`; with no label the form is not drawn"
|
|
892
|
+
);
|
|
893
|
+
const handleSubmit = (e) => {
|
|
894
|
+
e.preventDefault();
|
|
895
|
+
if (email.trim()) onSubscribe?.(email.trim());
|
|
896
|
+
};
|
|
897
|
+
const inputField = /* @__PURE__ */ jsx14(
|
|
898
|
+
"input",
|
|
899
|
+
{
|
|
900
|
+
type: "email",
|
|
901
|
+
value: email,
|
|
902
|
+
onChange: (e) => setEmail(e.target.value),
|
|
903
|
+
placeholder,
|
|
904
|
+
"aria-label": placeholder ?? ctaLabel,
|
|
905
|
+
className: "h-10 min-w-40 flex-1 rounded-md border border-border bg-card px-3 text-sm text-foreground outline-none placeholder:text-muted-foreground focus:ring-2 focus:ring-ring"
|
|
906
|
+
}
|
|
907
|
+
);
|
|
908
|
+
const submitBtn = /* @__PURE__ */ jsx14(Button, { type: "submit", children: ctaLabel });
|
|
909
|
+
if (variant === "inline") {
|
|
910
|
+
return /* @__PURE__ */ jsx14("section", { className: cn("w-full px-4 py-8 sm:px-6", className), ...props, children: /* @__PURE__ */ jsxs13("div", { className: "mx-auto flex max-w-xl flex-wrap items-center gap-3", children: [
|
|
911
|
+
heading && /* @__PURE__ */ jsx14("span", { className: "text-sm font-medium text-foreground", children: heading }),
|
|
912
|
+
ctaLabel && /* @__PURE__ */ jsxs13(
|
|
913
|
+
"form",
|
|
914
|
+
{
|
|
915
|
+
onSubmit: handleSubmit,
|
|
916
|
+
className: "flex min-w-0 flex-1 flex-wrap gap-3",
|
|
917
|
+
children: [
|
|
918
|
+
inputField,
|
|
919
|
+
submitBtn
|
|
920
|
+
]
|
|
921
|
+
}
|
|
922
|
+
)
|
|
923
|
+
] }) });
|
|
924
|
+
}
|
|
925
|
+
if (variant === "split") {
|
|
926
|
+
return /* @__PURE__ */ jsx14(
|
|
927
|
+
"section",
|
|
928
|
+
{
|
|
929
|
+
className: cn("w-full px-4 py-12 sm:px-6 lg:px-8", className),
|
|
930
|
+
...props,
|
|
931
|
+
children: /* @__PURE__ */ jsxs13("div", { className: "mx-auto flex max-w-4xl flex-col items-start gap-6 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
932
|
+
/* @__PURE__ */ jsxs13("div", { className: "max-w-md", children: [
|
|
933
|
+
heading && /* @__PURE__ */ jsx14("h2", { className: "text-xl font-bold text-foreground sm:text-2xl", children: heading }),
|
|
934
|
+
description && /* @__PURE__ */ jsx14("p", { className: "mt-2 text-sm text-muted-foreground", children: description })
|
|
935
|
+
] }),
|
|
936
|
+
ctaLabel && /* @__PURE__ */ jsxs13(
|
|
937
|
+
"form",
|
|
938
|
+
{
|
|
939
|
+
onSubmit: handleSubmit,
|
|
940
|
+
className: "flex w-full flex-wrap gap-3 sm:w-auto",
|
|
941
|
+
children: [
|
|
942
|
+
inputField,
|
|
943
|
+
submitBtn
|
|
944
|
+
]
|
|
945
|
+
}
|
|
946
|
+
)
|
|
947
|
+
] })
|
|
948
|
+
}
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
return /* @__PURE__ */ jsx14(
|
|
952
|
+
"section",
|
|
953
|
+
{
|
|
954
|
+
className: cn("w-full px-4 py-16 sm:px-6 lg:px-8", className),
|
|
955
|
+
...props,
|
|
956
|
+
children: /* @__PURE__ */ jsxs13("div", { className: "mx-auto max-w-md text-center", children: [
|
|
957
|
+
heading && /* @__PURE__ */ jsx14("h2", { className: "text-2xl font-bold text-foreground sm:text-3xl", children: heading }),
|
|
958
|
+
description && /* @__PURE__ */ jsx14("p", { className: "mt-3 text-sm text-muted-foreground", children: description }),
|
|
959
|
+
ctaLabel && /* @__PURE__ */ jsxs13("form", { onSubmit: handleSubmit, className: "mt-6 flex flex-wrap gap-3", children: [
|
|
960
|
+
inputField,
|
|
961
|
+
submitBtn
|
|
962
|
+
] })
|
|
963
|
+
] })
|
|
964
|
+
}
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// src/marketing/contact-section.tsx
|
|
969
|
+
import * as React3 from "react";
|
|
970
|
+
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
971
|
+
function ContactForm({
|
|
972
|
+
submitLabel,
|
|
973
|
+
onSubmitForm
|
|
974
|
+
}) {
|
|
975
|
+
const id = React3.useId();
|
|
976
|
+
const [form, setForm] = React3.useState({
|
|
977
|
+
name: "",
|
|
978
|
+
email: "",
|
|
979
|
+
message: ""
|
|
980
|
+
});
|
|
981
|
+
const handleSubmit = (e) => {
|
|
982
|
+
e.preventDefault();
|
|
983
|
+
onSubmitForm?.(form);
|
|
984
|
+
};
|
|
985
|
+
const inputClass = "h-10 w-full rounded-md border border-border bg-card px-3 text-sm text-foreground outline-none placeholder:text-muted-foreground focus:ring-2 focus:ring-ring";
|
|
986
|
+
return /* @__PURE__ */ jsxs14("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [
|
|
987
|
+
/* @__PURE__ */ jsxs14("div", { children: [
|
|
988
|
+
/* @__PURE__ */ jsx15(
|
|
989
|
+
"label",
|
|
990
|
+
{
|
|
991
|
+
htmlFor: `${id}-name`,
|
|
992
|
+
className: "mb-1.5 block text-sm font-medium text-foreground",
|
|
993
|
+
children: "Name"
|
|
994
|
+
}
|
|
995
|
+
),
|
|
996
|
+
/* @__PURE__ */ jsx15(
|
|
997
|
+
"input",
|
|
998
|
+
{
|
|
999
|
+
id: `${id}-name`,
|
|
1000
|
+
type: "text",
|
|
1001
|
+
value: form.name,
|
|
1002
|
+
onChange: (e) => setForm((f) => ({ ...f, name: e.target.value })),
|
|
1003
|
+
className: inputClass
|
|
1004
|
+
}
|
|
1005
|
+
)
|
|
1006
|
+
] }),
|
|
1007
|
+
/* @__PURE__ */ jsxs14("div", { children: [
|
|
1008
|
+
/* @__PURE__ */ jsx15(
|
|
1009
|
+
"label",
|
|
1010
|
+
{
|
|
1011
|
+
htmlFor: `${id}-email`,
|
|
1012
|
+
className: "mb-1.5 block text-sm font-medium text-foreground",
|
|
1013
|
+
children: "Email"
|
|
1014
|
+
}
|
|
1015
|
+
),
|
|
1016
|
+
/* @__PURE__ */ jsx15(
|
|
1017
|
+
"input",
|
|
1018
|
+
{
|
|
1019
|
+
id: `${id}-email`,
|
|
1020
|
+
type: "email",
|
|
1021
|
+
value: form.email,
|
|
1022
|
+
onChange: (e) => setForm((f) => ({ ...f, email: e.target.value })),
|
|
1023
|
+
className: inputClass
|
|
1024
|
+
}
|
|
1025
|
+
)
|
|
1026
|
+
] }),
|
|
1027
|
+
/* @__PURE__ */ jsxs14("div", { children: [
|
|
1028
|
+
/* @__PURE__ */ jsx15(
|
|
1029
|
+
"label",
|
|
1030
|
+
{
|
|
1031
|
+
htmlFor: `${id}-message`,
|
|
1032
|
+
className: "mb-1.5 block text-sm font-medium text-foreground",
|
|
1033
|
+
children: "Message"
|
|
1034
|
+
}
|
|
1035
|
+
),
|
|
1036
|
+
/* @__PURE__ */ jsx15(
|
|
1037
|
+
"textarea",
|
|
1038
|
+
{
|
|
1039
|
+
id: `${id}-message`,
|
|
1040
|
+
value: form.message,
|
|
1041
|
+
onChange: (e) => setForm((f) => ({ ...f, message: e.target.value })),
|
|
1042
|
+
rows: 4,
|
|
1043
|
+
className: "w-full rounded-md border border-border bg-card px-3 py-2 text-sm text-foreground outline-none placeholder:text-muted-foreground focus:ring-2 focus:ring-ring"
|
|
1044
|
+
}
|
|
1045
|
+
)
|
|
1046
|
+
] }),
|
|
1047
|
+
/* @__PURE__ */ jsx15(Button, { type: "submit", children: submitLabel })
|
|
1048
|
+
] });
|
|
1049
|
+
}
|
|
1050
|
+
function ContactSection({
|
|
1051
|
+
variant = "centered",
|
|
1052
|
+
heading,
|
|
1053
|
+
description,
|
|
1054
|
+
submitLabel,
|
|
1055
|
+
onSubmitForm,
|
|
1056
|
+
mapSlot,
|
|
1057
|
+
className,
|
|
1058
|
+
...props
|
|
1059
|
+
}) {
|
|
1060
|
+
if (onSubmitForm && !submitLabel)
|
|
1061
|
+
throw new Error(
|
|
1062
|
+
"ContactSection: `onSubmitForm` needs `submitLabel`; with no label the form is not drawn"
|
|
1063
|
+
);
|
|
1064
|
+
const headerBlock = (heading || description) && /* @__PURE__ */ jsxs14("div", { children: [
|
|
1065
|
+
heading && /* @__PURE__ */ jsx15("h2", { className: "text-2xl font-bold text-foreground sm:text-3xl", children: heading }),
|
|
1066
|
+
description && /* @__PURE__ */ jsx15("p", { className: "mt-3 text-sm text-muted-foreground", children: description })
|
|
1067
|
+
] });
|
|
1068
|
+
const formCard = submitLabel && /* @__PURE__ */ jsx15("div", { className: "rounded-xl border border-border bg-card p-6 shadow-sm", children: /* @__PURE__ */ jsx15(ContactForm, { submitLabel, onSubmitForm }) });
|
|
1069
|
+
if (variant === "splitForm") {
|
|
1070
|
+
return /* @__PURE__ */ jsx15(
|
|
1071
|
+
"section",
|
|
1072
|
+
{
|
|
1073
|
+
className: cn("w-full px-4 py-16 sm:px-6 lg:px-8", className),
|
|
1074
|
+
...props,
|
|
1075
|
+
children: /* @__PURE__ */ jsxs14("div", { className: "mx-auto grid max-w-5xl gap-12 lg:grid-cols-2", children: [
|
|
1076
|
+
/* @__PURE__ */ jsx15("div", { className: "flex flex-col justify-center", children: headerBlock }),
|
|
1077
|
+
formCard
|
|
1078
|
+
] })
|
|
1079
|
+
}
|
|
1080
|
+
);
|
|
1081
|
+
}
|
|
1082
|
+
if (variant === "withMap") {
|
|
1083
|
+
return /* @__PURE__ */ jsx15(
|
|
1084
|
+
"section",
|
|
1085
|
+
{
|
|
1086
|
+
className: cn("w-full px-4 py-16 sm:px-6 lg:px-8", className),
|
|
1087
|
+
...props,
|
|
1088
|
+
children: /* @__PURE__ */ jsxs14("div", { className: "mx-auto max-w-5xl", children: [
|
|
1089
|
+
headerBlock,
|
|
1090
|
+
/* @__PURE__ */ jsxs14("div", { className: "mt-8 grid gap-8 lg:grid-cols-2", children: [
|
|
1091
|
+
formCard,
|
|
1092
|
+
mapSlot && /* @__PURE__ */ jsx15("div", { className: "overflow-hidden rounded-xl border border-border bg-muted", children: mapSlot })
|
|
1093
|
+
] })
|
|
1094
|
+
] })
|
|
1095
|
+
}
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
return /* @__PURE__ */ jsx15(
|
|
1099
|
+
"section",
|
|
1100
|
+
{
|
|
1101
|
+
className: cn("w-full px-4 py-16 sm:px-6 lg:px-8", className),
|
|
1102
|
+
...props,
|
|
1103
|
+
children: /* @__PURE__ */ jsxs14("div", { className: "mx-auto max-w-lg text-center", children: [
|
|
1104
|
+
headerBlock,
|
|
1105
|
+
/* @__PURE__ */ jsx15("div", { className: "mt-8 text-left", children: formCard })
|
|
1106
|
+
] })
|
|
1107
|
+
}
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// src/marketing/footer.tsx
|
|
1112
|
+
import * as React4 from "react";
|
|
1113
|
+
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1114
|
+
function MarketingFooter({
|
|
1115
|
+
variant = "simple",
|
|
1116
|
+
brandName,
|
|
1117
|
+
logo,
|
|
1118
|
+
linkGroups = [],
|
|
1119
|
+
links = [],
|
|
1120
|
+
socialLinks = [],
|
|
1121
|
+
legalText,
|
|
1122
|
+
newsletterHeading,
|
|
1123
|
+
newsletterDescription,
|
|
1124
|
+
onSubscribe,
|
|
1125
|
+
className,
|
|
1126
|
+
...props
|
|
1127
|
+
}) {
|
|
1128
|
+
const [email, setEmail] = React4.useState("");
|
|
1129
|
+
const newsletterTitle = React4.useId();
|
|
1130
|
+
if (onSubscribe && !newsletterHeading)
|
|
1131
|
+
throw new Error(
|
|
1132
|
+
"MarketingFooter: `onSubscribe` needs `newsletterHeading`; with no heading the newsletter is not drawn"
|
|
1133
|
+
);
|
|
1134
|
+
const logoBox = logo && /* @__PURE__ */ jsx16("span", { className: "text-primary-text block size-6 shrink-0 [&>*]:size-full", children: logo });
|
|
1135
|
+
const socialRow = socialLinks.length > 0 && /* @__PURE__ */ jsx16("div", { className: "flex gap-4", children: socialLinks.map((s) => /* @__PURE__ */ jsx16(
|
|
1136
|
+
"a",
|
|
1137
|
+
{
|
|
1138
|
+
href: s.href,
|
|
1139
|
+
"aria-label": s.label,
|
|
1140
|
+
className: "text-muted-foreground transition-colors hover:text-foreground",
|
|
1141
|
+
children: s.icon
|
|
1142
|
+
},
|
|
1143
|
+
s.label
|
|
1144
|
+
)) });
|
|
1145
|
+
if (variant === "simple") {
|
|
1146
|
+
return /* @__PURE__ */ jsx16(
|
|
1147
|
+
"footer",
|
|
1148
|
+
{
|
|
1149
|
+
className: cn("w-full border-t border-border bg-card py-8", className),
|
|
1150
|
+
...props,
|
|
1151
|
+
children: /* @__PURE__ */ jsxs15(Container, { className: "flex flex-col items-center gap-4 sm:flex-row sm:justify-between", children: [
|
|
1152
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
|
|
1153
|
+
logoBox,
|
|
1154
|
+
/* @__PURE__ */ jsx16("span", { className: "text-sm font-semibold text-foreground", children: brandName })
|
|
1155
|
+
] }),
|
|
1156
|
+
links.length > 0 && /* @__PURE__ */ jsx16("nav", { className: "flex flex-wrap gap-4", children: links.map((l) => /* @__PURE__ */ jsx16(
|
|
1157
|
+
"a",
|
|
1158
|
+
{
|
|
1159
|
+
href: l.href,
|
|
1160
|
+
className: "text-sm text-muted-foreground hover:text-foreground",
|
|
1161
|
+
children: l.label
|
|
1162
|
+
},
|
|
1163
|
+
l.label
|
|
1164
|
+
)) }),
|
|
1165
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-4", children: [
|
|
1166
|
+
socialRow,
|
|
1167
|
+
legalText && /* @__PURE__ */ jsx16("span", { className: "text-xs text-muted-foreground", children: legalText })
|
|
1168
|
+
] })
|
|
1169
|
+
] })
|
|
1170
|
+
}
|
|
1171
|
+
);
|
|
1172
|
+
}
|
|
1173
|
+
if (variant === "withNewsletter") {
|
|
1174
|
+
return /* @__PURE__ */ jsx16(
|
|
1175
|
+
"footer",
|
|
1176
|
+
{
|
|
1177
|
+
className: cn("w-full border-t border-border bg-card py-12", className),
|
|
1178
|
+
...props,
|
|
1179
|
+
children: /* @__PURE__ */ jsxs15(Container, { children: [
|
|
1180
|
+
/* @__PURE__ */ jsxs15("div", { className: "grid gap-8 lg:grid-cols-[1fr_320px]", children: [
|
|
1181
|
+
/* @__PURE__ */ jsx16("div", { className: "grid grid-cols-2 gap-8 sm:grid-cols-3", children: linkGroups.map((group) => /* @__PURE__ */ jsxs15("div", { children: [
|
|
1182
|
+
/* @__PURE__ */ jsx16("h3", { className: "mb-3 text-sm font-semibold text-foreground", children: group.title }),
|
|
1183
|
+
/* @__PURE__ */ jsx16("ul", { className: "space-y-2", children: group.links.map((l) => /* @__PURE__ */ jsx16("li", { children: /* @__PURE__ */ jsx16(
|
|
1184
|
+
"a",
|
|
1185
|
+
{
|
|
1186
|
+
href: l.href,
|
|
1187
|
+
className: "text-sm text-muted-foreground hover:text-foreground",
|
|
1188
|
+
children: l.label
|
|
1189
|
+
}
|
|
1190
|
+
) }, l.label)) })
|
|
1191
|
+
] }, group.title)) }),
|
|
1192
|
+
newsletterHeading && /* @__PURE__ */ jsxs15("div", { children: [
|
|
1193
|
+
/* @__PURE__ */ jsx16(
|
|
1194
|
+
"h3",
|
|
1195
|
+
{
|
|
1196
|
+
id: newsletterTitle,
|
|
1197
|
+
className: "mb-2 text-sm font-semibold text-foreground",
|
|
1198
|
+
children: newsletterHeading
|
|
1199
|
+
}
|
|
1200
|
+
),
|
|
1201
|
+
newsletterDescription && /* @__PURE__ */ jsx16("p", { className: "mb-3 text-xs text-muted-foreground", children: newsletterDescription }),
|
|
1202
|
+
/* @__PURE__ */ jsxs15(
|
|
1203
|
+
"form",
|
|
1204
|
+
{
|
|
1205
|
+
onSubmit: (e) => {
|
|
1206
|
+
e.preventDefault();
|
|
1207
|
+
if (email.trim()) onSubscribe?.(email.trim());
|
|
1208
|
+
},
|
|
1209
|
+
className: "flex gap-2",
|
|
1210
|
+
children: [
|
|
1211
|
+
/* @__PURE__ */ jsx16(
|
|
1212
|
+
"input",
|
|
1213
|
+
{
|
|
1214
|
+
type: "email",
|
|
1215
|
+
value: email,
|
|
1216
|
+
onChange: (e) => setEmail(e.target.value),
|
|
1217
|
+
"aria-labelledby": newsletterTitle,
|
|
1218
|
+
className: "h-9 min-w-0 flex-1 rounded-md border border-border bg-card px-3 text-sm text-foreground outline-none focus:ring-2 focus:ring-ring"
|
|
1219
|
+
}
|
|
1220
|
+
),
|
|
1221
|
+
/* @__PURE__ */ jsx16(
|
|
1222
|
+
"button",
|
|
1223
|
+
{
|
|
1224
|
+
type: "submit",
|
|
1225
|
+
className: "bg-primary-solid h-9 rounded-md px-4 text-sm font-medium text-primary-foreground hover:opacity-90",
|
|
1226
|
+
children: "Subscribe"
|
|
1227
|
+
}
|
|
1228
|
+
)
|
|
1229
|
+
]
|
|
1230
|
+
}
|
|
1231
|
+
)
|
|
1232
|
+
] })
|
|
1233
|
+
] }),
|
|
1234
|
+
/* @__PURE__ */ jsxs15("div", { className: "mt-8 flex flex-col items-center justify-between gap-4 border-t border-border pt-6 sm:flex-row", children: [
|
|
1235
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
|
|
1236
|
+
logoBox,
|
|
1237
|
+
legalText && /* @__PURE__ */ jsx16("span", { className: "text-sm text-muted-foreground", children: legalText })
|
|
1238
|
+
] }),
|
|
1239
|
+
socialRow
|
|
1240
|
+
] })
|
|
1241
|
+
] })
|
|
1242
|
+
}
|
|
1243
|
+
);
|
|
1244
|
+
}
|
|
1245
|
+
return /* @__PURE__ */ jsx16(
|
|
1246
|
+
"footer",
|
|
1247
|
+
{
|
|
1248
|
+
className: cn("w-full border-t border-border bg-card py-12", className),
|
|
1249
|
+
...props,
|
|
1250
|
+
children: /* @__PURE__ */ jsxs15(Container, { children: [
|
|
1251
|
+
/* @__PURE__ */ jsxs15("div", { className: "grid gap-8 sm:grid-cols-2 lg:grid-cols-4", children: [
|
|
1252
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
1253
|
+
/* @__PURE__ */ jsxs15("div", { className: "mb-4 flex items-center gap-2", children: [
|
|
1254
|
+
logoBox,
|
|
1255
|
+
/* @__PURE__ */ jsx16("span", { className: "text-sm font-semibold text-foreground", children: brandName })
|
|
1256
|
+
] }),
|
|
1257
|
+
socialRow
|
|
1258
|
+
] }),
|
|
1259
|
+
linkGroups.map((group) => /* @__PURE__ */ jsxs15("div", { children: [
|
|
1260
|
+
/* @__PURE__ */ jsx16("h3", { className: "mb-3 text-sm font-semibold text-foreground", children: group.title }),
|
|
1261
|
+
/* @__PURE__ */ jsx16("ul", { className: "space-y-2", children: group.links.map((l) => /* @__PURE__ */ jsx16("li", { children: /* @__PURE__ */ jsx16(
|
|
1262
|
+
"a",
|
|
1263
|
+
{
|
|
1264
|
+
href: l.href,
|
|
1265
|
+
className: "text-sm text-muted-foreground hover:text-foreground",
|
|
1266
|
+
children: l.label
|
|
1267
|
+
}
|
|
1268
|
+
) }, l.label)) })
|
|
1269
|
+
] }, group.title))
|
|
1270
|
+
] }),
|
|
1271
|
+
legalText && /* @__PURE__ */ jsx16("div", { className: "mt-8 border-t border-border pt-6 text-center text-xs text-muted-foreground", children: legalText })
|
|
1272
|
+
] })
|
|
1273
|
+
}
|
|
1274
|
+
);
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
// src/marketing/testimonial-section.tsx
|
|
1278
|
+
import * as React5 from "react";
|
|
1279
|
+
import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1280
|
+
function TestimonialCard({
|
|
1281
|
+
testimonial,
|
|
1282
|
+
className
|
|
1283
|
+
}) {
|
|
1284
|
+
return /* @__PURE__ */ jsxs16(
|
|
1285
|
+
"div",
|
|
1286
|
+
{
|
|
1287
|
+
className: cn(
|
|
1288
|
+
"flex flex-col gap-4 rounded-xl border border-border bg-card p-6 shadow-sm",
|
|
1289
|
+
className
|
|
1290
|
+
),
|
|
1291
|
+
children: [
|
|
1292
|
+
/* @__PURE__ */ jsxs16("p", { className: "flex-1 text-sm italic text-foreground", children: [
|
|
1293
|
+
"\u201C",
|
|
1294
|
+
testimonial.quote,
|
|
1295
|
+
"\u201D"
|
|
1296
|
+
] }),
|
|
1297
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-3", children: [
|
|
1298
|
+
testimonial.avatar ? /* @__PURE__ */ jsx17(
|
|
1299
|
+
"img",
|
|
1300
|
+
{
|
|
1301
|
+
src: testimonial.avatar,
|
|
1302
|
+
alt: testimonial.name,
|
|
1303
|
+
className: "h-10 w-10 rounded-full object-cover"
|
|
1304
|
+
}
|
|
1305
|
+
) : /* @__PURE__ */ jsx17("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-muted text-sm font-medium text-muted-foreground", children: testimonial.name.charAt(0) }),
|
|
1306
|
+
/* @__PURE__ */ jsxs16("div", { children: [
|
|
1307
|
+
/* @__PURE__ */ jsx17("p", { className: "text-sm font-semibold text-foreground", children: testimonial.name }),
|
|
1308
|
+
(testimonial.role || testimonial.company) && /* @__PURE__ */ jsx17("p", { className: "text-xs text-muted-foreground", children: [testimonial.role, testimonial.company].filter(Boolean).join(" \xB7 ") })
|
|
1309
|
+
] })
|
|
1310
|
+
] })
|
|
1311
|
+
]
|
|
1312
|
+
}
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
function GridLayout({
|
|
1316
|
+
testimonials,
|
|
1317
|
+
columns = 3
|
|
1318
|
+
}) {
|
|
1319
|
+
const gridCols = columns === 2 ? "sm:grid-cols-2" : "sm:grid-cols-2 lg:grid-cols-3";
|
|
1320
|
+
return /* @__PURE__ */ jsx17("div", { className: cn("grid grid-cols-1 gap-6", gridCols), children: testimonials.map((t) => /* @__PURE__ */ jsx17(TestimonialCard, { testimonial: t }, t.id)) });
|
|
1321
|
+
}
|
|
1322
|
+
function CarouselLayout({
|
|
1323
|
+
testimonials,
|
|
1324
|
+
autoPlayInterval = 5e3
|
|
1325
|
+
}) {
|
|
1326
|
+
const [activeIndex, setActiveIndex] = React5.useState(0);
|
|
1327
|
+
React5.useEffect(() => {
|
|
1328
|
+
if (autoPlayInterval <= 0 || testimonials.length <= 1) return;
|
|
1329
|
+
const timer = setInterval(() => {
|
|
1330
|
+
setActiveIndex((i) => (i + 1) % testimonials.length);
|
|
1331
|
+
}, autoPlayInterval);
|
|
1332
|
+
return () => clearInterval(timer);
|
|
1333
|
+
}, [autoPlayInterval, testimonials.length]);
|
|
1334
|
+
const current = testimonials[activeIndex];
|
|
1335
|
+
if (!current) return null;
|
|
1336
|
+
return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col items-center gap-6", children: [
|
|
1337
|
+
/* @__PURE__ */ jsx17("div", { className: "w-full max-w-2xl", children: /* @__PURE__ */ jsx17(TestimonialCard, { testimonial: current, className: "text-center" }) }),
|
|
1338
|
+
testimonials.length > 1 && /* @__PURE__ */ jsx17("div", { className: "flex gap-2", children: testimonials.map((t, i) => /* @__PURE__ */ jsx17(
|
|
1339
|
+
"button",
|
|
1340
|
+
{
|
|
1341
|
+
type: "button",
|
|
1342
|
+
onClick: () => setActiveIndex(i),
|
|
1343
|
+
"aria-label": t.name,
|
|
1344
|
+
className: cn(
|
|
1345
|
+
"h-2 rounded-full transition-all",
|
|
1346
|
+
i === activeIndex ? "w-6 bg-primary" : "w-2 bg-muted-foreground/30"
|
|
1347
|
+
)
|
|
1348
|
+
},
|
|
1349
|
+
i
|
|
1350
|
+
)) })
|
|
1351
|
+
] });
|
|
1352
|
+
}
|
|
1353
|
+
function SingleQuoteLayout({ testimonial }) {
|
|
1354
|
+
return /* @__PURE__ */ jsxs16("div", { className: "mx-auto flex max-w-3xl flex-col items-center gap-6 text-center", children: [
|
|
1355
|
+
testimonial.logo && /* @__PURE__ */ jsx17(
|
|
1356
|
+
"img",
|
|
1357
|
+
{
|
|
1358
|
+
src: testimonial.logo,
|
|
1359
|
+
alt: testimonial.company ?? "",
|
|
1360
|
+
className: "h-8 opacity-60"
|
|
1361
|
+
}
|
|
1362
|
+
),
|
|
1363
|
+
/* @__PURE__ */ jsxs16("blockquote", { className: "text-xl font-medium italic text-foreground sm:text-2xl", children: [
|
|
1364
|
+
"\u201C",
|
|
1365
|
+
testimonial.quote,
|
|
1366
|
+
"\u201D"
|
|
1367
|
+
] }),
|
|
1368
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-3", children: [
|
|
1369
|
+
testimonial.avatar ? /* @__PURE__ */ jsx17(
|
|
1370
|
+
"img",
|
|
1371
|
+
{
|
|
1372
|
+
src: testimonial.avatar,
|
|
1373
|
+
alt: testimonial.name,
|
|
1374
|
+
className: "h-12 w-12 rounded-full object-cover"
|
|
1375
|
+
}
|
|
1376
|
+
) : /* @__PURE__ */ jsx17("div", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-muted text-sm font-medium text-muted-foreground", children: testimonial.name.charAt(0) }),
|
|
1377
|
+
/* @__PURE__ */ jsxs16("div", { className: "text-left", children: [
|
|
1378
|
+
/* @__PURE__ */ jsx17("p", { className: "text-sm font-semibold text-foreground", children: testimonial.name }),
|
|
1379
|
+
(testimonial.role || testimonial.company) && /* @__PURE__ */ jsx17("p", { className: "text-xs text-muted-foreground", children: [testimonial.role, testimonial.company].filter(Boolean).join(" \xB7 ") })
|
|
1380
|
+
] })
|
|
1381
|
+
] })
|
|
1382
|
+
] });
|
|
1383
|
+
}
|
|
1384
|
+
function WallOfLoveLayout({ testimonials }) {
|
|
1385
|
+
return /* @__PURE__ */ jsx17("div", { className: "columns-1 gap-6 sm:columns-2 lg:columns-3", children: testimonials.map((t) => /* @__PURE__ */ jsx17("div", { className: "mb-6 break-inside-avoid", children: /* @__PURE__ */ jsx17(TestimonialCard, { testimonial: t }) }, t.id)) });
|
|
1386
|
+
}
|
|
1387
|
+
function TestimonialSection({
|
|
1388
|
+
variant = "grid",
|
|
1389
|
+
testimonials,
|
|
1390
|
+
heading,
|
|
1391
|
+
subheading,
|
|
1392
|
+
columns = 3,
|
|
1393
|
+
autoPlayInterval = 5e3,
|
|
1394
|
+
className,
|
|
1395
|
+
...props
|
|
1396
|
+
}) {
|
|
1397
|
+
return /* @__PURE__ */ jsxs16(
|
|
1398
|
+
"section",
|
|
1399
|
+
{
|
|
1400
|
+
className: cn("w-full px-4 py-12 sm:px-6 lg:px-8", className),
|
|
1401
|
+
...props,
|
|
1402
|
+
children: [
|
|
1403
|
+
(heading || subheading) && /* @__PURE__ */ jsxs16("div", { className: "mx-auto mb-10 max-w-2xl text-center", children: [
|
|
1404
|
+
heading && /* @__PURE__ */ jsx17("h2", { className: "text-2xl font-bold text-foreground sm:text-3xl", children: heading }),
|
|
1405
|
+
subheading && /* @__PURE__ */ jsx17("p", { className: "mt-3 text-sm text-muted-foreground sm:text-base", children: subheading })
|
|
1406
|
+
] }),
|
|
1407
|
+
variant === "grid" && /* @__PURE__ */ jsx17(GridLayout, { testimonials, columns }),
|
|
1408
|
+
variant === "carousel" && /* @__PURE__ */ jsx17(
|
|
1409
|
+
CarouselLayout,
|
|
1410
|
+
{
|
|
1411
|
+
testimonials,
|
|
1412
|
+
autoPlayInterval
|
|
1413
|
+
}
|
|
1414
|
+
),
|
|
1415
|
+
variant === "singleQuote" && testimonials[0] && /* @__PURE__ */ jsx17(SingleQuoteLayout, { testimonial: testimonials[0] }),
|
|
1416
|
+
variant === "wallOfLove" && /* @__PURE__ */ jsx17(WallOfLoveLayout, { testimonials })
|
|
1417
|
+
]
|
|
1418
|
+
}
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
export {
|
|
1422
|
+
BlogGrid,
|
|
1423
|
+
CTABanner,
|
|
1424
|
+
ComparisonTable,
|
|
1425
|
+
ContactSection,
|
|
1426
|
+
FeatureCard,
|
|
1427
|
+
LogoCloud,
|
|
1428
|
+
MarketingCta,
|
|
1429
|
+
MarketingFAQItem,
|
|
1430
|
+
MarketingFooter,
|
|
1431
|
+
MarketingHeader,
|
|
1432
|
+
MarketingHero,
|
|
1433
|
+
HowItWorksStep as MarketingHowItWorksStep,
|
|
1434
|
+
PricingTier as MarketingPricingTier,
|
|
1435
|
+
NewsletterSection,
|
|
1436
|
+
TeamSection,
|
|
1437
|
+
TestimonialSection,
|
|
1438
|
+
UseCaseCard
|
|
1439
|
+
};
|