nextworks 0.2.0-alpha.16 → 0.2.0-alpha.18
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 +0 -4
- package/dist/cli_manifests/blocks_manifest.json +10 -2
- package/dist/kits/blocks/.nextworks/docs/BLOCKS_QUICKSTART.md +3 -0
- package/dist/kits/blocks/.nextworks/docs/BLOCKS_README.md +11 -1
- package/dist/kits/blocks/components/sections/CommandShowcase.tsx +517 -0
- package/dist/kits/blocks/components/sections/FeaturedProjectShowcase.tsx +687 -0
- package/dist/kits/blocks/components/sections/HeroWithVideo.tsx +495 -0
- package/dist/kits/blocks/components/sections/ProjectDeepDive.tsx +805 -0
- package/dist/kits/blocks/components/sections/SelectedWorkRail.tsx +485 -0
- package/dist/kits/blocks/package-deps.json +3 -3
- package/dist/kits/blocks/tsconfig.json +0 -2
- package/dist/kits/blocks/tsconfig.tsbuildinfo +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Link from "next/link";
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
type ButtonVariant =
|
|
7
|
+
| "default"
|
|
8
|
+
| "destructive"
|
|
9
|
+
| "outline"
|
|
10
|
+
| "secondary"
|
|
11
|
+
| "ghost"
|
|
12
|
+
| "link";
|
|
13
|
+
|
|
14
|
+
type ButtonSize = "default" | "sm" | "lg" | "icon";
|
|
15
|
+
|
|
16
|
+
export interface HeroWithVideoCta {
|
|
17
|
+
label?: string;
|
|
18
|
+
href?: string;
|
|
19
|
+
ariaLabel?: string;
|
|
20
|
+
variant?: ButtonVariant;
|
|
21
|
+
size?: ButtonSize;
|
|
22
|
+
className?: string;
|
|
23
|
+
unstyled?: boolean;
|
|
24
|
+
style?: React.CSSProperties;
|
|
25
|
+
target?: string;
|
|
26
|
+
rel?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface HeroWithVideoTextContent {
|
|
30
|
+
text?: React.ReactNode;
|
|
31
|
+
className?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface HeroWithVideoTitleContent extends HeroWithVideoTextContent {
|
|
35
|
+
highlight?: string;
|
|
36
|
+
highlightClassName?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface HeroWithVideoMedia {
|
|
40
|
+
src?: string;
|
|
41
|
+
poster?: string;
|
|
42
|
+
title?: string;
|
|
43
|
+
ariaLabel?: string;
|
|
44
|
+
className?: string;
|
|
45
|
+
autoPlay?: boolean;
|
|
46
|
+
muted?: boolean;
|
|
47
|
+
loop?: boolean;
|
|
48
|
+
playsInline?: boolean;
|
|
49
|
+
controls?: boolean;
|
|
50
|
+
preload?: "none" | "metadata" | "auto";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface HeroWithVideoClassNames {
|
|
54
|
+
section?: string;
|
|
55
|
+
backgroundGlow?: string;
|
|
56
|
+
container?: string;
|
|
57
|
+
content?: string;
|
|
58
|
+
eyebrow?: string;
|
|
59
|
+
title?: string;
|
|
60
|
+
titleHighlight?: string;
|
|
61
|
+
description?: string;
|
|
62
|
+
credibility?: string;
|
|
63
|
+
buttons?: string;
|
|
64
|
+
primaryCta?: string;
|
|
65
|
+
secondaryCta?: string;
|
|
66
|
+
command?: string;
|
|
67
|
+
videoOuter?: string;
|
|
68
|
+
videoFrame?: string;
|
|
69
|
+
videoChrome?: string;
|
|
70
|
+
video?: string;
|
|
71
|
+
videoFallback?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface HeroWithVideoProps {
|
|
75
|
+
id?: string;
|
|
76
|
+
className?: string;
|
|
77
|
+
eyebrow?: string | HeroWithVideoTextContent;
|
|
78
|
+
title?: string | HeroWithVideoTitleContent;
|
|
79
|
+
heading?: string | HeroWithVideoTitleContent;
|
|
80
|
+
description?: string | HeroWithVideoTextContent;
|
|
81
|
+
subheading?: string | HeroWithVideoTextContent;
|
|
82
|
+
credibility?: string | HeroWithVideoTextContent;
|
|
83
|
+
command?: string | HeroWithVideoTextContent;
|
|
84
|
+
primaryCta?: HeroWithVideoCta;
|
|
85
|
+
secondaryCta?: HeroWithVideoCta;
|
|
86
|
+
cta1?: HeroWithVideoCta;
|
|
87
|
+
cta2?: HeroWithVideoCta;
|
|
88
|
+
video?: HeroWithVideoMedia;
|
|
89
|
+
embed?: React.ReactNode;
|
|
90
|
+
fallback?: React.ReactNode;
|
|
91
|
+
previewId?: string;
|
|
92
|
+
ariaLabel?: string;
|
|
93
|
+
titleId?: string;
|
|
94
|
+
enableMotion?: boolean;
|
|
95
|
+
classNames?: HeroWithVideoClassNames;
|
|
96
|
+
section?: { className?: string };
|
|
97
|
+
container?: { className?: string };
|
|
98
|
+
content?: { className?: string };
|
|
99
|
+
eyebrowSlot?: { className?: string };
|
|
100
|
+
titleSlot?: { className?: string };
|
|
101
|
+
descriptionSlot?: { className?: string };
|
|
102
|
+
credibilitySlot?: { className?: string };
|
|
103
|
+
buttonsContainer?: { className?: string };
|
|
104
|
+
commandSlot?: { className?: string };
|
|
105
|
+
videoOuter?: { className?: string };
|
|
106
|
+
videoFrame?: { className?: string };
|
|
107
|
+
videoChrome?: { className?: string };
|
|
108
|
+
videoSlot?: { className?: string };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function normalizeTextContent<T extends HeroWithVideoTextContent>(
|
|
112
|
+
value: string | T | undefined,
|
|
113
|
+
defaults: Required<HeroWithVideoTextContent>,
|
|
114
|
+
): Required<HeroWithVideoTextContent> {
|
|
115
|
+
if (typeof value === "string") {
|
|
116
|
+
return { text: value, className: defaults.className };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
text: value?.text ?? defaults.text,
|
|
121
|
+
className: cn(defaults.className, value?.className),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function normalizeTitleContent(
|
|
126
|
+
value: string | HeroWithVideoTitleContent | undefined,
|
|
127
|
+
defaults: Required<HeroWithVideoTitleContent>,
|
|
128
|
+
): Required<HeroWithVideoTitleContent> {
|
|
129
|
+
if (typeof value === "string") {
|
|
130
|
+
return {
|
|
131
|
+
text: value,
|
|
132
|
+
className: defaults.className,
|
|
133
|
+
highlight: defaults.highlight,
|
|
134
|
+
highlightClassName: defaults.highlightClassName,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
text: value?.text ?? defaults.text,
|
|
140
|
+
className: cn(defaults.className, value?.className),
|
|
141
|
+
highlight: value?.highlight ?? defaults.highlight,
|
|
142
|
+
highlightClassName: cn(
|
|
143
|
+
defaults.highlightClassName,
|
|
144
|
+
value?.highlightClassName,
|
|
145
|
+
),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function renderHighlightedTitle(
|
|
150
|
+
title: Required<HeroWithVideoTitleContent>,
|
|
151
|
+
className?: string,
|
|
152
|
+
) {
|
|
153
|
+
if (!title.highlight || typeof title.text !== "string") {
|
|
154
|
+
return title.text;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const [before, ...rest] = title.text.split(title.highlight);
|
|
158
|
+
|
|
159
|
+
if (rest.length === 0) {
|
|
160
|
+
return title.text;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<>
|
|
165
|
+
{before}
|
|
166
|
+
<span className={cn(title.highlightClassName, className)}>
|
|
167
|
+
{title.highlight}
|
|
168
|
+
</span>
|
|
169
|
+
{rest.join(title.highlight)}
|
|
170
|
+
</>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function renderCta(cta: HeroWithVideoCta | undefined) {
|
|
175
|
+
if (!cta?.label) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<Button
|
|
181
|
+
asChild
|
|
182
|
+
variant={cta.variant}
|
|
183
|
+
size={cta.size}
|
|
184
|
+
className={cta.className}
|
|
185
|
+
unstyled={cta.unstyled}
|
|
186
|
+
style={cta.style}
|
|
187
|
+
>
|
|
188
|
+
<Link
|
|
189
|
+
href={cta.href || "#"}
|
|
190
|
+
aria-label={cta.ariaLabel ?? cta.label}
|
|
191
|
+
target={cta.target}
|
|
192
|
+
rel={cta.rel ?? (cta.target === "_blank" ? "noreferrer" : undefined)}
|
|
193
|
+
>
|
|
194
|
+
{cta.label}
|
|
195
|
+
</Link>
|
|
196
|
+
</Button>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function HeroWithVideo({
|
|
201
|
+
id,
|
|
202
|
+
className,
|
|
203
|
+
eyebrow,
|
|
204
|
+
title,
|
|
205
|
+
heading,
|
|
206
|
+
description,
|
|
207
|
+
subheading,
|
|
208
|
+
credibility,
|
|
209
|
+
command,
|
|
210
|
+
primaryCta,
|
|
211
|
+
secondaryCta,
|
|
212
|
+
cta1,
|
|
213
|
+
cta2,
|
|
214
|
+
video,
|
|
215
|
+
embed,
|
|
216
|
+
fallback,
|
|
217
|
+
previewId,
|
|
218
|
+
ariaLabel = "Video hero section",
|
|
219
|
+
titleId,
|
|
220
|
+
enableMotion = true,
|
|
221
|
+
classNames,
|
|
222
|
+
section,
|
|
223
|
+
container,
|
|
224
|
+
content,
|
|
225
|
+
eyebrowSlot,
|
|
226
|
+
titleSlot,
|
|
227
|
+
descriptionSlot,
|
|
228
|
+
credibilitySlot,
|
|
229
|
+
buttonsContainer,
|
|
230
|
+
commandSlot,
|
|
231
|
+
videoOuter,
|
|
232
|
+
videoFrame,
|
|
233
|
+
videoChrome,
|
|
234
|
+
videoSlot,
|
|
235
|
+
}: HeroWithVideoProps) {
|
|
236
|
+
const normalizedEyebrow = normalizeTextContent(eyebrow, {
|
|
237
|
+
text: "Product demo · Launch page · Video preview",
|
|
238
|
+
className:
|
|
239
|
+
"hidden text-xs font-medium uppercase tracking-[0.28em] text-muted-foreground sm:block sm:text-sm",
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const normalizedTitle = normalizeTitleContent(heading ?? title, {
|
|
243
|
+
text: "Show your product with a clear video-first hero.",
|
|
244
|
+
className:
|
|
245
|
+
"mx-auto max-w-5xl text-balance text-4xl font-semibold tracking-[-0.055em] text-foreground sm:text-6xl lg:text-7xl",
|
|
246
|
+
highlight: "video-first",
|
|
247
|
+
highlightClassName: "text-foreground",
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
const normalizedDescription = normalizeTextContent(subheading ?? description, {
|
|
251
|
+
text: "Introduce a product, service, or project with a focused headline, simple calls to action, and a large demo preview.",
|
|
252
|
+
className:
|
|
253
|
+
"mx-auto mt-5 max-w-2xl text-pretty text-base leading-7 text-muted-foreground sm:text-lg lg:text-xl",
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const normalizedCredibility = normalizeTextContent(credibility, {
|
|
257
|
+
text: "Designed for landing pages, launches, and product walkthroughs.",
|
|
258
|
+
className: "mt-4 text-sm text-muted-foreground",
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
const normalizedCommand = normalizeTextContent(command, {
|
|
262
|
+
text: "Add a short setup command or product note here.",
|
|
263
|
+
className:
|
|
264
|
+
"mt-6 inline-flex max-w-full items-center rounded-full border border-border bg-muted/60 px-4 py-2 font-mono text-xs text-muted-foreground shadow-[inset_0_1px_0_rgba(255,255,255,0.08)] sm:text-sm dark:shadow-[inset_0_1px_0_rgba(255,255,255,0.08)]",
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
const buttonMotion = enableMotion
|
|
268
|
+
? "transition-all duration-200 hover:-translate-y-0.5"
|
|
269
|
+
: "transition-none hover:!translate-y-0";
|
|
270
|
+
|
|
271
|
+
const resolvedPreviewId =
|
|
272
|
+
previewId ?? (id ? `${id}-preview` : "video-preview");
|
|
273
|
+
|
|
274
|
+
const resolvedPrimaryCta: HeroWithVideoCta = {
|
|
275
|
+
label: "View demo",
|
|
276
|
+
href: `#${resolvedPreviewId}`,
|
|
277
|
+
variant: "default",
|
|
278
|
+
size: "lg",
|
|
279
|
+
unstyled: true,
|
|
280
|
+
...(primaryCta ?? cta1 ?? {}),
|
|
281
|
+
className: cn(
|
|
282
|
+
"h-11 rounded-full bg-primary px-6 text-sm font-medium text-primary-foreground shadow-lg hover:bg-primary/90",
|
|
283
|
+
buttonMotion,
|
|
284
|
+
classNames?.primaryCta,
|
|
285
|
+
primaryCta?.className ?? cta1?.className,
|
|
286
|
+
),
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const secondaryInput = secondaryCta ?? cta2;
|
|
290
|
+
const resolvedSecondaryCta: HeroWithVideoCta = {
|
|
291
|
+
label: "Learn more",
|
|
292
|
+
href: "#",
|
|
293
|
+
variant: "outline",
|
|
294
|
+
size: "lg",
|
|
295
|
+
unstyled: true,
|
|
296
|
+
...(secondaryInput ?? {}),
|
|
297
|
+
className: cn(
|
|
298
|
+
"h-11 rounded-full border border-border bg-background/80 px-6 text-sm font-medium text-foreground hover:bg-muted",
|
|
299
|
+
buttonMotion,
|
|
300
|
+
classNames?.secondaryCta,
|
|
301
|
+
secondaryInput?.className,
|
|
302
|
+
),
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
const videoMotion = enableMotion
|
|
306
|
+
? "transition-transform duration-300 hover:-translate-y-1"
|
|
307
|
+
: "transition-none hover:!translate-y-0";
|
|
308
|
+
|
|
309
|
+
return (
|
|
310
|
+
<section
|
|
311
|
+
id={id}
|
|
312
|
+
className={cn(
|
|
313
|
+
"relative overflow-hidden bg-background px-4 py-20 text-foreground sm:px-6 lg:px-8 lg:py-24",
|
|
314
|
+
section?.className,
|
|
315
|
+
classNames?.section,
|
|
316
|
+
className,
|
|
317
|
+
)}
|
|
318
|
+
aria-label={ariaLabel}
|
|
319
|
+
aria-labelledby={titleId}
|
|
320
|
+
>
|
|
321
|
+
<div
|
|
322
|
+
className={cn(
|
|
323
|
+
"pointer-events-none absolute left-1/2 top-[34rem] h-[30rem] w-[72rem] -translate-x-1/2 rounded-full bg-[radial-gradient(circle_at_center,rgba(0,0,0,0.08)_0%,rgba(0,0,0,0.03)_24%,transparent_68%)] blur-3xl dark:bg-[radial-gradient(circle_at_center,rgba(255,255,255,0.16)_0%,rgba(255,255,255,0.08)_24%,transparent_68%)]",
|
|
324
|
+
classNames?.backgroundGlow,
|
|
325
|
+
)}
|
|
326
|
+
aria-hidden="true"
|
|
327
|
+
/>
|
|
328
|
+
<div
|
|
329
|
+
className="pointer-events-none absolute inset-x-0 top-0 h-40 bg-gradient-to-b from-foreground/5 to-transparent"
|
|
330
|
+
aria-hidden="true"
|
|
331
|
+
/>
|
|
332
|
+
|
|
333
|
+
<div
|
|
334
|
+
className={cn(
|
|
335
|
+
"relative z-10 mx-auto flex max-w-7xl flex-col items-center",
|
|
336
|
+
container?.className,
|
|
337
|
+
classNames?.container,
|
|
338
|
+
)}
|
|
339
|
+
>
|
|
340
|
+
<div
|
|
341
|
+
className={cn(
|
|
342
|
+
"mx-auto flex max-w-5xl flex-col items-center text-center",
|
|
343
|
+
content?.className,
|
|
344
|
+
classNames?.content,
|
|
345
|
+
)}
|
|
346
|
+
>
|
|
347
|
+
{normalizedEyebrow.text ? (
|
|
348
|
+
<p
|
|
349
|
+
className={cn(
|
|
350
|
+
normalizedEyebrow.className,
|
|
351
|
+
eyebrowSlot?.className,
|
|
352
|
+
classNames?.eyebrow,
|
|
353
|
+
)}
|
|
354
|
+
>
|
|
355
|
+
{normalizedEyebrow.text}
|
|
356
|
+
</p>
|
|
357
|
+
) : null}
|
|
358
|
+
|
|
359
|
+
<h1
|
|
360
|
+
id={titleId}
|
|
361
|
+
className={cn(
|
|
362
|
+
"mt-5",
|
|
363
|
+
normalizedTitle.className,
|
|
364
|
+
titleSlot?.className,
|
|
365
|
+
classNames?.title,
|
|
366
|
+
)}
|
|
367
|
+
>
|
|
368
|
+
{renderHighlightedTitle(normalizedTitle, classNames?.titleHighlight)}
|
|
369
|
+
</h1>
|
|
370
|
+
|
|
371
|
+
{normalizedDescription.text ? (
|
|
372
|
+
<p
|
|
373
|
+
className={cn(
|
|
374
|
+
normalizedDescription.className,
|
|
375
|
+
descriptionSlot?.className,
|
|
376
|
+
classNames?.description,
|
|
377
|
+
)}
|
|
378
|
+
>
|
|
379
|
+
{normalizedDescription.text}
|
|
380
|
+
</p>
|
|
381
|
+
) : null}
|
|
382
|
+
|
|
383
|
+
<div
|
|
384
|
+
className={cn(
|
|
385
|
+
"mt-8 flex w-full flex-col items-center justify-center gap-3 sm:w-auto sm:flex-row",
|
|
386
|
+
buttonsContainer?.className,
|
|
387
|
+
classNames?.buttons,
|
|
388
|
+
)}
|
|
389
|
+
>
|
|
390
|
+
{renderCta(resolvedPrimaryCta)}
|
|
391
|
+
{renderCta(resolvedSecondaryCta)}
|
|
392
|
+
</div>
|
|
393
|
+
|
|
394
|
+
{normalizedCredibility.text ? (
|
|
395
|
+
<p
|
|
396
|
+
className={cn(
|
|
397
|
+
normalizedCredibility.className,
|
|
398
|
+
credibilitySlot?.className,
|
|
399
|
+
classNames?.credibility,
|
|
400
|
+
)}
|
|
401
|
+
>
|
|
402
|
+
{normalizedCredibility.text}
|
|
403
|
+
</p>
|
|
404
|
+
) : null}
|
|
405
|
+
|
|
406
|
+
{normalizedCommand.text ? (
|
|
407
|
+
<code
|
|
408
|
+
className={cn(
|
|
409
|
+
normalizedCommand.className,
|
|
410
|
+
commandSlot?.className,
|
|
411
|
+
classNames?.command,
|
|
412
|
+
)}
|
|
413
|
+
>
|
|
414
|
+
<span className="mr-2 text-muted-foreground/60" aria-hidden="true">
|
|
415
|
+
$
|
|
416
|
+
</span>
|
|
417
|
+
<span className="truncate">{normalizedCommand.text}</span>
|
|
418
|
+
</code>
|
|
419
|
+
) : null}
|
|
420
|
+
</div>
|
|
421
|
+
|
|
422
|
+
<div
|
|
423
|
+
id={resolvedPreviewId}
|
|
424
|
+
className={cn(
|
|
425
|
+
"relative mt-12 w-full max-w-6xl sm:mt-14 lg:mt-16",
|
|
426
|
+
videoOuter?.className,
|
|
427
|
+
classNames?.videoOuter,
|
|
428
|
+
)}
|
|
429
|
+
>
|
|
430
|
+
<div
|
|
431
|
+
className={cn(
|
|
432
|
+
"relative overflow-hidden rounded-[1.75rem] border border-border bg-card/80 p-2 shadow-[0_28px_90px_rgba(0,0,0,0.12)] backdrop-blur dark:shadow-[0_28px_90px_rgba(0,0,0,0.72),0_0_0_1px_rgba(255,255,255,0.04)]",
|
|
433
|
+
videoMotion,
|
|
434
|
+
videoFrame?.className,
|
|
435
|
+
classNames?.videoFrame,
|
|
436
|
+
)}
|
|
437
|
+
>
|
|
438
|
+
<div
|
|
439
|
+
className={cn(
|
|
440
|
+
"flex h-10 items-center gap-2 border-b border-border px-4",
|
|
441
|
+
videoChrome?.className,
|
|
442
|
+
classNames?.videoChrome,
|
|
443
|
+
)}
|
|
444
|
+
aria-hidden="true"
|
|
445
|
+
>
|
|
446
|
+
<span className="size-2.5 rounded-full bg-foreground/24" />
|
|
447
|
+
<span className="size-2.5 rounded-full bg-foreground/16" />
|
|
448
|
+
<span className="size-2.5 rounded-full bg-foreground/10" />
|
|
449
|
+
<span className="ml-3 h-2 w-28 rounded-full bg-foreground/8" />
|
|
450
|
+
</div>
|
|
451
|
+
|
|
452
|
+
<div className="relative aspect-video overflow-hidden rounded-[1.25rem] bg-muted">
|
|
453
|
+
{embed ??
|
|
454
|
+
(video?.src ? (
|
|
455
|
+
<video
|
|
456
|
+
src={video.src}
|
|
457
|
+
poster={video.poster}
|
|
458
|
+
title={video.title ?? video.ariaLabel ?? "Hero video"}
|
|
459
|
+
aria-label={video.ariaLabel ?? video.title ?? "Hero video"}
|
|
460
|
+
className={cn(
|
|
461
|
+
"size-full object-cover",
|
|
462
|
+
video.className,
|
|
463
|
+
videoSlot?.className,
|
|
464
|
+
classNames?.video,
|
|
465
|
+
)}
|
|
466
|
+
autoPlay={video.autoPlay}
|
|
467
|
+
muted={video.muted ?? video.autoPlay ?? false}
|
|
468
|
+
loop={video.loop}
|
|
469
|
+
playsInline={video.playsInline ?? true}
|
|
470
|
+
controls={video.controls ?? true}
|
|
471
|
+
preload={video.preload ?? "metadata"}
|
|
472
|
+
/>
|
|
473
|
+
) : (
|
|
474
|
+
<div
|
|
475
|
+
className={cn(
|
|
476
|
+
"flex size-full items-center justify-center bg-[radial-gradient(circle_at_center,rgba(255,255,255,0.28),rgba(255,255,255,0.1)_38%,rgba(255,255,255,0)_72%)] px-6 text-center dark:bg-[radial-gradient(circle_at_center,rgba(255,255,255,0.11),rgba(255,255,255,0.035)_38%,rgba(0,0,0,1)_72%)]",
|
|
477
|
+
classNames?.videoFallback,
|
|
478
|
+
)}
|
|
479
|
+
>
|
|
480
|
+
{fallback ?? (
|
|
481
|
+
<p className="max-w-md text-sm leading-6 text-muted-foreground">
|
|
482
|
+
Add a demo video source to show a product walkthrough,
|
|
483
|
+
launch preview, or selected project here.
|
|
484
|
+
</p>
|
|
485
|
+
)}
|
|
486
|
+
</div>
|
|
487
|
+
))}
|
|
488
|
+
</div>
|
|
489
|
+
</div>
|
|
490
|
+
</div>
|
|
491
|
+
</div>
|
|
492
|
+
</section>
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
|