nextworks 0.2.0-alpha.2 → 0.2.0-alpha.20

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.
Files changed (145) hide show
  1. package/README.md +280 -228
  2. package/dist/cli_manifests/blocks_manifest.json +193 -194
  3. package/dist/commands/blocks.d.ts +3 -0
  4. package/dist/commands/blocks.d.ts.map +1 -1
  5. package/dist/commands/blocks.js +128 -19
  6. package/dist/commands/blocks.js.map +1 -1
  7. package/dist/commands/doctor.d.ts +136 -0
  8. package/dist/commands/doctor.d.ts.map +1 -0
  9. package/dist/commands/doctor.js +696 -0
  10. package/dist/commands/doctor.js.map +1 -0
  11. package/dist/commands/remove-blocks.d.ts +4 -1
  12. package/dist/commands/remove-blocks.d.ts.map +1 -1
  13. package/dist/commands/remove-blocks.js +24 -6
  14. package/dist/commands/remove-blocks.js.map +1 -1
  15. package/dist/index.js +125 -4
  16. package/dist/index.js.map +1 -1
  17. package/dist/kits/blocks/.nextworks/docs/BLOCKS_QUICKSTART.md +104 -194
  18. package/dist/kits/blocks/.nextworks/docs/BLOCKS_README.md +115 -75
  19. package/dist/kits/blocks/.nextworks/docs/THEME_GUIDE.md +269 -251
  20. package/dist/kits/blocks/app/templates/digitalagency/PresetThemeVars.tsx +80 -80
  21. package/dist/kits/blocks/app/templates/digitalagency/README.md +42 -36
  22. package/dist/kits/blocks/app/templates/digitalagency/components/About.tsx +71 -99
  23. package/dist/kits/blocks/app/templates/digitalagency/components/CTA.tsx +40 -74
  24. package/dist/kits/blocks/app/templates/digitalagency/components/Contact.tsx +123 -227
  25. package/dist/kits/blocks/app/templates/digitalagency/components/Footer.tsx +89 -89
  26. package/dist/kits/blocks/app/templates/digitalagency/components/Hero.tsx +83 -90
  27. package/dist/kits/blocks/app/templates/digitalagency/components/Navbar.tsx +121 -168
  28. package/dist/kits/blocks/app/templates/digitalagency/components/NetworkPattern.tsx +288 -297
  29. package/dist/kits/blocks/app/templates/digitalagency/components/Portfolio.tsx +157 -157
  30. package/dist/kits/blocks/app/templates/digitalagency/components/Pricing.tsx +114 -114
  31. package/dist/kits/blocks/app/templates/digitalagency/components/Process.tsx +59 -59
  32. package/dist/kits/blocks/app/templates/digitalagency/components/Services.tsx +55 -55
  33. package/dist/kits/blocks/app/templates/digitalagency/components/Team.tsx +28 -28
  34. package/dist/kits/blocks/app/templates/digitalagency/components/Testimonials.tsx +65 -65
  35. package/dist/kits/blocks/app/templates/digitalagency/page.tsx +38 -38
  36. package/dist/kits/blocks/app/templates/gallery/PresetThemeVars.tsx +130 -85
  37. package/dist/kits/blocks/app/templates/gallery/page.tsx +357 -303
  38. package/dist/kits/blocks/app/templates/productlaunch/PresetThemeVars.tsx +75 -74
  39. package/dist/kits/blocks/app/templates/productlaunch/README.md +62 -55
  40. package/dist/kits/blocks/app/templates/productlaunch/components/About.tsx +84 -178
  41. package/dist/kits/blocks/app/templates/productlaunch/components/CTA.tsx +50 -93
  42. package/dist/kits/blocks/app/templates/productlaunch/components/Contact.tsx +231 -231
  43. package/dist/kits/blocks/app/templates/productlaunch/components/FAQ.tsx +86 -93
  44. package/dist/kits/blocks/app/templates/productlaunch/components/Features.tsx +83 -84
  45. package/dist/kits/blocks/app/templates/productlaunch/components/Footer.tsx +132 -132
  46. package/dist/kits/blocks/app/templates/productlaunch/components/Hero.tsx +88 -89
  47. package/dist/kits/blocks/app/templates/productlaunch/components/Navbar.tsx +116 -162
  48. package/dist/kits/blocks/app/templates/productlaunch/components/Pricing.tsx +106 -106
  49. package/dist/kits/blocks/app/templates/productlaunch/components/ProcessTimeline.tsx +110 -110
  50. package/dist/kits/blocks/app/templates/productlaunch/components/ServicesGrid.tsx +68 -68
  51. package/dist/kits/blocks/app/templates/productlaunch/components/Team.tsx +104 -104
  52. package/dist/kits/blocks/app/templates/productlaunch/components/Testimonials.tsx +90 -89
  53. package/dist/kits/blocks/app/templates/productlaunch/components/TrustBadges.tsx +76 -76
  54. package/dist/kits/blocks/app/templates/productlaunch/page.tsx +43 -43
  55. package/dist/kits/blocks/app/templates/saasdashboard/PresetThemeVars.tsx +80 -80
  56. package/dist/kits/blocks/app/templates/saasdashboard/README.md +44 -38
  57. package/dist/kits/blocks/app/templates/saasdashboard/components/Contact.tsx +129 -176
  58. package/dist/kits/blocks/app/templates/saasdashboard/components/Dashboard.tsx +293 -293
  59. package/dist/kits/blocks/app/templates/saasdashboard/components/FAQ.tsx +55 -55
  60. package/dist/kits/blocks/app/templates/saasdashboard/components/Features.tsx +90 -91
  61. package/dist/kits/blocks/app/templates/saasdashboard/components/Footer.tsx +77 -77
  62. package/dist/kits/blocks/app/templates/saasdashboard/components/Hero.tsx +104 -105
  63. package/dist/kits/blocks/app/templates/saasdashboard/components/Hero_mask.tsx +126 -127
  64. package/dist/kits/blocks/app/templates/saasdashboard/components/Navbar.tsx +117 -159
  65. package/dist/kits/blocks/app/templates/saasdashboard/components/Pricing.tsx +90 -90
  66. package/dist/kits/blocks/app/templates/saasdashboard/components/SmoothScroll.tsx +96 -97
  67. package/dist/kits/blocks/app/templates/saasdashboard/components/Testimonials.tsx +72 -72
  68. package/dist/kits/blocks/app/templates/saasdashboard/components/TrustBadges.tsx +53 -53
  69. package/dist/kits/blocks/app/templates/saasdashboard/page.tsx +39 -39
  70. package/dist/kits/blocks/components/enhanced-theme-provider.tsx +195 -183
  71. package/dist/kits/blocks/components/providers/BlocksAppProviders.tsx +27 -27
  72. package/dist/kits/blocks/components/sections/About.tsx +291 -291
  73. package/dist/kits/blocks/components/sections/CTA.tsx +257 -258
  74. package/dist/kits/blocks/components/sections/CommandShowcase.tsx +517 -0
  75. package/dist/kits/blocks/components/sections/Contact.tsx +267 -267
  76. package/dist/kits/blocks/components/sections/FAQ.tsx +214 -225
  77. package/dist/kits/blocks/components/sections/FeaturedProjectShowcase.tsx +687 -0
  78. package/dist/kits/blocks/components/sections/Features.tsx +268 -270
  79. package/dist/kits/blocks/components/sections/Footer.tsx +302 -302
  80. package/dist/kits/blocks/components/sections/HeroMotion.tsx +308 -308
  81. package/dist/kits/blocks/components/sections/HeroOverlay.tsx +358 -358
  82. package/dist/kits/blocks/components/sections/HeroProductDemo.tsx +246 -0
  83. package/dist/kits/blocks/components/sections/HeroSplit.tsx +352 -352
  84. package/dist/kits/blocks/components/sections/HeroWithVideo.tsx +495 -0
  85. package/dist/kits/blocks/components/sections/Navbar.tsx +352 -353
  86. package/dist/kits/blocks/components/sections/PortfolioSimple.tsx +549 -550
  87. package/dist/kits/blocks/components/sections/Pricing.tsx +264 -264
  88. package/dist/kits/blocks/components/sections/ProcessTimeline.tsx +325 -325
  89. package/dist/kits/blocks/components/sections/ProjectDeepDive.tsx +805 -0
  90. package/dist/kits/blocks/components/sections/SelectedWorkRail.tsx +485 -0
  91. package/dist/kits/blocks/components/sections/ServicesGrid.tsx +210 -210
  92. package/dist/kits/blocks/components/sections/Team.tsx +309 -309
  93. package/dist/kits/blocks/components/sections/Testimonials.tsx +158 -158
  94. package/dist/kits/blocks/components/sections/TrustBadges.tsx +162 -162
  95. package/dist/kits/blocks/components/sections/product-demo/ApprovalInboxPanel.tsx +128 -0
  96. package/dist/kits/blocks/components/sections/product-demo/DemoStage.tsx +519 -0
  97. package/dist/kits/blocks/components/sections/product-demo/DemoWindow.tsx +140 -0
  98. package/dist/kits/blocks/components/sections/product-demo/KnowledgePanel.tsx +130 -0
  99. package/dist/kits/blocks/components/sections/product-demo/RunConsolePanel.tsx +430 -0
  100. package/dist/kits/blocks/components/sections/product-demo/TaskListPanel.tsx +302 -0
  101. package/dist/kits/blocks/components/sections/product-demo/WorkflowStudioPanel.tsx +744 -0
  102. package/dist/kits/blocks/components/sections/product-demo/types.ts +262 -0
  103. package/dist/kits/blocks/components/theme-provider.tsx +1 -34
  104. package/dist/kits/blocks/components/ui/alert-dialog.tsx +134 -134
  105. package/dist/kits/blocks/components/ui/brand-node.tsx +121 -121
  106. package/dist/kits/blocks/components/ui/button.tsx +122 -122
  107. package/dist/kits/blocks/components/ui/card.tsx +95 -95
  108. package/dist/kits/blocks/components/ui/checkbox.tsx +30 -30
  109. package/dist/kits/blocks/components/ui/cta-button.tsx +125 -125
  110. package/dist/kits/blocks/components/ui/dropdown-menu.tsx +201 -201
  111. package/dist/kits/blocks/components/ui/feature-card.tsx +91 -91
  112. package/dist/kits/blocks/components/ui/input.tsx +27 -27
  113. package/dist/kits/blocks/components/ui/label.tsx +29 -29
  114. package/dist/kits/blocks/components/ui/pricing-card.tsx +120 -120
  115. package/dist/kits/blocks/components/ui/select.tsx +25 -25
  116. package/dist/kits/blocks/components/ui/skeleton.tsx +13 -13
  117. package/dist/kits/blocks/components/ui/table.tsx +98 -98
  118. package/dist/kits/blocks/components/ui/testimonial-card.tsx +108 -108
  119. package/dist/kits/blocks/components/ui/textarea.tsx +26 -26
  120. package/dist/kits/blocks/components/ui/theme-selector.tsx +243 -247
  121. package/dist/kits/blocks/components/ui/theme-toggle.tsx +74 -74
  122. package/dist/kits/blocks/components/ui/toaster.tsx +7 -7
  123. package/dist/kits/blocks/lib/themes.ts +400 -400
  124. package/dist/kits/blocks/lib/utils.ts +6 -9
  125. package/dist/kits/blocks/package-deps.json +40 -28
  126. package/dist/kits/blocks/tsconfig.json +11 -0
  127. package/dist/kits/blocks/tsconfig.tsbuildinfo +1 -0
  128. package/dist/utils/file-operations.d.ts +3 -1
  129. package/dist/utils/file-operations.d.ts.map +1 -1
  130. package/dist/utils/file-operations.js +84 -12
  131. package/dist/utils/file-operations.js.map +1 -1
  132. package/dist/utils/installation-tracker.d.ts +2 -2
  133. package/dist/utils/installation-tracker.d.ts.map +1 -1
  134. package/dist/utils/installation-tracker.js +11 -11
  135. package/dist/utils/installation-tracker.js.map +1 -1
  136. package/dist/utils/package-manager.d.ts +6 -0
  137. package/dist/utils/package-manager.d.ts.map +1 -0
  138. package/dist/utils/package-manager.js +58 -0
  139. package/dist/utils/package-manager.js.map +1 -0
  140. package/dist/utils/yarn-pnp.d.ts +6 -0
  141. package/dist/utils/yarn-pnp.d.ts.map +1 -0
  142. package/dist/utils/yarn-pnp.js +39 -0
  143. package/dist/utils/yarn-pnp.js.map +1 -0
  144. package/package.json +5 -2
  145. package/dist/kits/blocks/notes/THEME_GUIDE.md +0 -29
@@ -0,0 +1,687 @@
1
+ import React from "react";
2
+ import Image from "next/image";
3
+ import Link from "next/link";
4
+ import { Button } from "@/components/ui/button";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ type ButtonVariant =
8
+ | "default"
9
+ | "destructive"
10
+ | "outline"
11
+ | "secondary"
12
+ | "ghost"
13
+ | "link";
14
+
15
+ type ButtonSize = "default" | "sm" | "lg" | "icon";
16
+
17
+ export interface FeaturedProjectShowcaseCta {
18
+ label?: string;
19
+ href?: string;
20
+ ariaLabel?: string;
21
+ variant?: ButtonVariant;
22
+ size?: ButtonSize;
23
+ className?: string;
24
+ unstyled?: boolean;
25
+ style?: React.CSSProperties;
26
+ target?: string;
27
+ rel?: string;
28
+ }
29
+
30
+ export interface FeaturedProjectShowcaseTag {
31
+ label: string;
32
+ className?: string;
33
+ }
34
+
35
+ export interface FeaturedProjectShowcaseFeature {
36
+ title?: string;
37
+ description: React.ReactNode;
38
+ className?: string;
39
+ }
40
+
41
+ export interface FeaturedProjectShowcaseMetaItem {
42
+ label: string;
43
+ value: React.ReactNode;
44
+ className?: string;
45
+ }
46
+
47
+ export interface FeaturedProjectShowcaseBreakdownItem {
48
+ label: string;
49
+ description: React.ReactNode;
50
+ className?: string;
51
+ }
52
+
53
+ export interface FeaturedProjectShowcaseMediaConfig {
54
+ type?: "image" | "video" | "terminal" | "custom";
55
+ src?: string;
56
+ alt?: string;
57
+ title?: string;
58
+ ariaLabel?: string;
59
+ poster?: string;
60
+ autoPlay?: boolean;
61
+ muted?: boolean;
62
+ loop?: boolean;
63
+ playsInline?: boolean;
64
+ controls?: boolean;
65
+ preload?: "none" | "metadata" | "auto";
66
+ commands?: string[];
67
+ output?: string[];
68
+ caption?: React.ReactNode;
69
+ className?: string;
70
+ content?: React.ReactNode;
71
+ }
72
+
73
+ export interface FeaturedProjectShowcaseClassNames {
74
+ section?: string;
75
+ backgroundGlow?: string;
76
+ container?: string;
77
+ contentGrid?: string;
78
+ content?: string;
79
+ eyebrow?: string;
80
+ title?: string;
81
+ description?: string;
82
+ tags?: string;
83
+ tag?: string;
84
+ features?: string;
85
+ feature?: string;
86
+ featureMarker?: string;
87
+ featureTitle?: string;
88
+ featureDescription?: string;
89
+ breakdown?: string;
90
+ breakdownItem?: string;
91
+ breakdownLabel?: string;
92
+ breakdownDescription?: string;
93
+ meta?: string;
94
+ metaItem?: string;
95
+ metaLabel?: string;
96
+ metaValue?: string;
97
+ buttons?: string;
98
+ primaryCta?: string;
99
+ secondaryCta?: string;
100
+ mediaOuter?: string;
101
+ mediaFrame?: string;
102
+ mediaChrome?: string;
103
+ mediaContent?: string;
104
+ mediaCaption?: string;
105
+ terminal?: string;
106
+ terminalLine?: string;
107
+ terminalOutput?: string;
108
+ image?: string;
109
+ video?: string;
110
+ }
111
+
112
+ export interface FeaturedProjectShowcaseProps {
113
+ id?: string;
114
+ className?: string;
115
+ eyebrow?: React.ReactNode;
116
+ title?: React.ReactNode;
117
+ description?: React.ReactNode;
118
+ tags?: Array<string | FeaturedProjectShowcaseTag>;
119
+ features?: Array<string | FeaturedProjectShowcaseFeature>;
120
+ breakdown?: FeaturedProjectShowcaseBreakdownItem[];
121
+ meta?: FeaturedProjectShowcaseMetaItem[];
122
+ primaryCta?: FeaturedProjectShowcaseCta;
123
+ secondaryCta?: FeaturedProjectShowcaseCta;
124
+ media?: React.ReactNode | FeaturedProjectShowcaseMediaConfig | false;
125
+ mediaId?: string;
126
+ detailsId?: string;
127
+ ariaLabel?: string;
128
+ titleId?: string;
129
+ enableMotion?: boolean;
130
+ classNames?: FeaturedProjectShowcaseClassNames;
131
+ section?: { className?: string };
132
+ container?: { className?: string };
133
+ content?: { className?: string };
134
+ mediaSlot?: { className?: string };
135
+ }
136
+
137
+ const defaultTags = [
138
+ "Product",
139
+ "Frontend",
140
+ "Launch",
141
+ "Case study",
142
+ "Design system",
143
+ "Workflow",
144
+ ];
145
+
146
+ const defaultFeatures: FeaturedProjectShowcaseFeature[] = [
147
+ { description: "Clear project positioning with room for technical details." },
148
+ { description: "Flexible media area for screenshots, video, terminal output, or custom content." },
149
+ { description: "Optional tags, metadata, and calls to action." },
150
+ { description: "Works for products, tools, portfolios, and case studies." },
151
+ ];
152
+
153
+ const defaultBreakdown: FeaturedProjectShowcaseBreakdownItem[] = [
154
+ {
155
+ label: "What it is",
156
+ description: "A focused project highlight with enough context to understand the work.",
157
+ },
158
+ {
159
+ label: "What it shows",
160
+ description: "Key features, implementation notes, supporting details, and proof points.",
161
+ },
162
+ {
163
+ label: "How to use it",
164
+ description: "Wrap it with project-specific copy, links, media, and metadata.",
165
+ },
166
+ ];
167
+
168
+ const defaultMeta: FeaturedProjectShowcaseMetaItem[] = [
169
+ { label: "Type", value: "Featured project" },
170
+ { label: "Focus", value: "Product story" },
171
+ { label: "Status", value: "Demo content" },
172
+ ];
173
+
174
+ const defaultMedia: FeaturedProjectShowcaseMediaConfig = {
175
+ type: "terminal",
176
+ title: "Project preview",
177
+ ariaLabel: "Terminal-style preview showing example project notes",
178
+ commands: [
179
+ "open project-brief.md",
180
+ "review design-system-notes.md",
181
+ "ship polished-preview",
182
+ ],
183
+ output: [
184
+ "✔ summary, tags, and project metadata ready",
185
+ "✔ feature bullets and implementation notes added",
186
+ "✔ media area available for screenshots or video",
187
+ ],
188
+ caption: "Use the media area for a screenshot, video, terminal preview, or custom visual.",
189
+ };
190
+
191
+ function isMediaConfig(
192
+ media: FeaturedProjectShowcaseProps["media"],
193
+ ): media is FeaturedProjectShowcaseMediaConfig {
194
+ return Boolean(
195
+ media &&
196
+ typeof media === "object" &&
197
+ !React.isValidElement(media) &&
198
+ ("type" in media || "src" in media || "content" in media),
199
+ );
200
+ }
201
+
202
+ function normalizeTag(tag: string | FeaturedProjectShowcaseTag) {
203
+ return typeof tag === "string" ? { label: tag } : tag;
204
+ }
205
+
206
+ function normalizeFeature(feature: string | FeaturedProjectShowcaseFeature) {
207
+ return typeof feature === "string" ? { description: feature } : feature;
208
+ }
209
+
210
+ function renderCta(cta: FeaturedProjectShowcaseCta | undefined) {
211
+ if (!cta?.label) {
212
+ return null;
213
+ }
214
+
215
+ return (
216
+ <Button
217
+ asChild
218
+ variant={cta.variant}
219
+ size={cta.size}
220
+ className={cta.className}
221
+ unstyled={cta.unstyled}
222
+ style={cta.style}
223
+ >
224
+ <Link
225
+ href={cta.href || "#"}
226
+ aria-label={cta.ariaLabel ?? cta.label}
227
+ target={cta.target}
228
+ rel={cta.rel ?? (cta.target === "_blank" ? "noreferrer" : undefined)}
229
+ >
230
+ {cta.label}
231
+ </Link>
232
+ </Button>
233
+ );
234
+ }
235
+
236
+ function renderMediaContent(
237
+ media: FeaturedProjectShowcaseMediaConfig,
238
+ classNames?: FeaturedProjectShowcaseClassNames,
239
+ ) {
240
+ if (media.content) {
241
+ return media.content;
242
+ }
243
+
244
+ if (media.type === "image" && media.src) {
245
+ return (
246
+ <div
247
+ className={cn(
248
+ "relative min-h-[24rem] overflow-hidden",
249
+ media.className,
250
+ classNames?.image,
251
+ )}
252
+ >
253
+ <Image
254
+ src={media.src}
255
+ alt={media.alt ?? media.title ?? "Featured project preview"}
256
+ fill
257
+ sizes="(max-width: 1024px) 100vw, 50vw"
258
+ className="object-cover"
259
+ unoptimized
260
+ />
261
+ </div>
262
+ );
263
+ }
264
+
265
+ if (media.type === "video" && media.src) {
266
+ return (
267
+ <video
268
+ src={media.src}
269
+ poster={media.poster}
270
+ title={media.title ?? media.ariaLabel ?? "Featured project video"}
271
+ aria-label={media.ariaLabel ?? media.title ?? "Featured project video"}
272
+ className={cn("size-full object-cover", media.className, classNames?.video)}
273
+ autoPlay={media.autoPlay}
274
+ muted={media.muted ?? media.autoPlay ?? false}
275
+ loop={media.loop}
276
+ playsInline={media.playsInline ?? true}
277
+ controls={media.controls ?? true}
278
+ preload={media.preload ?? "metadata"}
279
+ />
280
+ );
281
+ }
282
+
283
+ return (
284
+ <div
285
+ className={cn(
286
+ "flex min-h-[24rem] flex-col justify-between bg-muted p-5 font-mono text-xs text-muted-foreground sm:p-6",
287
+
288
+ media.className,
289
+ classNames?.terminal,
290
+ )}
291
+ role="img"
292
+ aria-label={media.ariaLabel ?? media.title ?? "Terminal preview"}
293
+ >
294
+ <div className="space-y-3">
295
+ {(media.commands ?? defaultMedia.commands ?? []).map((command) => (
296
+ <p key={command} className={cn("break-all", classNames?.terminalLine)}>
297
+ <span className="mr-2 text-muted-foreground/60" aria-hidden="true">
298
+
299
+ $
300
+ </span>
301
+ <span>{command}</span>
302
+ </p>
303
+ ))}
304
+ </div>
305
+
306
+ <div className="mt-8 space-y-2 border-t border-border pt-5">
307
+
308
+ {(media.output ?? defaultMedia.output ?? []).map((line) => (
309
+ <p key={line} className={cn("text-muted-foreground", classNames?.terminalOutput)}>
310
+
311
+ {line}
312
+ </p>
313
+ ))}
314
+ </div>
315
+ </div>
316
+ );
317
+ }
318
+
319
+ function renderMedia(
320
+ media: FeaturedProjectShowcaseProps["media"],
321
+ classNames?: FeaturedProjectShowcaseClassNames,
322
+ ) {
323
+ if (media === false) {
324
+ return null;
325
+ }
326
+
327
+ if (media !== undefined && !isMediaConfig(media)) {
328
+ return media;
329
+ }
330
+
331
+ const resolvedMedia = isMediaConfig(media) ? media : defaultMedia;
332
+
333
+ return (
334
+ <>
335
+ {renderMediaContent(resolvedMedia, classNames)}
336
+ {resolvedMedia.caption ? (
337
+ <p className={cn("px-5 py-4 text-sm text-muted-foreground", classNames?.mediaCaption)}>
338
+
339
+ {resolvedMedia.caption}
340
+ </p>
341
+ ) : null}
342
+ </>
343
+ );
344
+ }
345
+
346
+ export function FeaturedProjectShowcase({
347
+ id,
348
+ className,
349
+ eyebrow = "Featured project",
350
+ title = "Featured project",
351
+ description =
352
+ "Highlight one project with a short summary, key features, supporting details, and an optional visual preview.",
353
+ tags = defaultTags,
354
+ features = defaultFeatures,
355
+ breakdown = defaultBreakdown,
356
+ meta = defaultMeta,
357
+ primaryCta,
358
+ secondaryCta,
359
+ media,
360
+ mediaId,
361
+ detailsId,
362
+ ariaLabel = "Featured project showcase section",
363
+ titleId,
364
+ enableMotion = true,
365
+ classNames,
366
+ section,
367
+ container,
368
+ content,
369
+ mediaSlot,
370
+ }: FeaturedProjectShowcaseProps) {
371
+ const motionClasses = enableMotion
372
+ ? "transition-all duration-200 hover:-translate-y-0.5"
373
+ : "transition-none hover:!translate-y-0";
374
+
375
+ const resolvedMediaId = mediaId ?? (id ? `${id}-media` : "featured-project-media");
376
+ const resolvedDetailsId = detailsId ?? (id ? `${id}-details` : "featured-project-details");
377
+
378
+ const resolvedPrimaryCta: FeaturedProjectShowcaseCta = {
379
+ label: "View project",
380
+ href: `#${resolvedMediaId}`,
381
+ variant: "default",
382
+ size: "lg",
383
+ unstyled: true,
384
+ ...(primaryCta ?? {}),
385
+ className: cn(
386
+ "h-11 rounded-full bg-primary px-6 text-sm font-medium text-primary-foreground shadow-lg hover:bg-primary/90",
387
+
388
+ motionClasses,
389
+ classNames?.primaryCta,
390
+ primaryCta?.className,
391
+ ),
392
+ };
393
+
394
+ const resolvedSecondaryCta: FeaturedProjectShowcaseCta = {
395
+ label: "Read notes",
396
+ href: `#${resolvedDetailsId}`,
397
+ variant: "outline",
398
+ size: "lg",
399
+ unstyled: true,
400
+ ...(secondaryCta ?? {}),
401
+ className: cn(
402
+ "h-11 rounded-full border border-border bg-background/80 px-6 text-sm font-medium text-foreground hover:bg-muted",
403
+
404
+ motionClasses,
405
+ classNames?.secondaryCta,
406
+ secondaryCta?.className,
407
+ ),
408
+ };
409
+
410
+ const mediaContent = renderMedia(media, classNames);
411
+
412
+ return (
413
+ <section
414
+ id={id}
415
+ className={cn(
416
+ "relative overflow-hidden bg-background px-4 py-20 text-foreground sm:px-6 lg:px-8 lg:py-24",
417
+
418
+ section?.className,
419
+ classNames?.section,
420
+ className,
421
+ )}
422
+ aria-label={ariaLabel}
423
+ aria-labelledby={titleId}
424
+ >
425
+ <div
426
+ className={cn(
427
+ "pointer-events-none absolute right-[-18rem] top-24 h-[34rem] w-[34rem] rounded-full bg-[radial-gradient(circle_at_center,rgba(0,0,0,0.08),rgba(0,0,0,0.03)_36%,transparent_70%)] blur-3xl dark:bg-[radial-gradient(circle_at_center,rgba(255,255,255,0.12),rgba(255,255,255,0.04)_36%,transparent_70%)]",
428
+
429
+ classNames?.backgroundGlow,
430
+ )}
431
+ aria-hidden="true"
432
+ />
433
+
434
+ <div
435
+ className={cn(
436
+ "relative z-10 mx-auto max-w-7xl",
437
+ container?.className,
438
+ classNames?.container,
439
+ )}
440
+ >
441
+ <div
442
+ className={cn(
443
+ "grid gap-8 lg:grid-cols-[minmax(0,0.92fr)_minmax(26rem,1.08fr)] lg:items-stretch",
444
+ classNames?.contentGrid,
445
+ )}
446
+ >
447
+ <div
448
+ className={cn(
449
+ "flex flex-col rounded-[2rem] border border-border bg-card/80 p-6 shadow-[0_24px_90px_rgba(0,0,0,0.12)] backdrop-blur dark:shadow-[0_24px_90px_rgba(0,0,0,0.55)] sm:p-8 lg:p-10",
450
+
451
+ content?.className,
452
+ classNames?.content,
453
+ )}
454
+ >
455
+ {eyebrow ? (
456
+ <p
457
+ className={cn(
458
+ "text-xs font-medium uppercase tracking-[0.28em] text-muted-foreground",
459
+
460
+ classNames?.eyebrow,
461
+ )}
462
+ >
463
+ {eyebrow}
464
+ </p>
465
+ ) : null}
466
+
467
+ <h2
468
+ id={titleId}
469
+ className={cn(
470
+ "mt-5 text-balance text-4xl font-semibold tracking-[-0.055em] text-foreground sm:text-5xl lg:text-6xl",
471
+
472
+ classNames?.title,
473
+ )}
474
+ >
475
+ {title}
476
+ </h2>
477
+
478
+ {description ? (
479
+ <p
480
+ className={cn(
481
+ "mt-5 max-w-2xl text-pretty text-base leading-7 text-muted-foreground sm:text-lg",
482
+
483
+ classNames?.description,
484
+ )}
485
+ >
486
+ {description}
487
+ </p>
488
+ ) : null}
489
+
490
+ {tags.length > 0 ? (
491
+ <div className={cn("mt-7 flex flex-wrap gap-2", classNames?.tags)}>
492
+ {tags.map((tag) => {
493
+ const normalizedTag = normalizeTag(tag);
494
+
495
+ return (
496
+ <span
497
+ key={normalizedTag.label}
498
+ className={cn(
499
+ "rounded-full border border-border bg-muted/60 px-3 py-1 text-xs font-medium text-muted-foreground",
500
+
501
+ classNames?.tag,
502
+ normalizedTag.className,
503
+ )}
504
+ >
505
+ {normalizedTag.label}
506
+ </span>
507
+ );
508
+ })}
509
+ </div>
510
+ ) : null}
511
+
512
+ {features.length > 0 ? (
513
+ <ul className={cn("mt-8 space-y-3", classNames?.features)}>
514
+ {features.map((feature, index) => {
515
+ const normalizedFeature = normalizeFeature(feature);
516
+
517
+ return (
518
+ <li
519
+ key={`${normalizedFeature.title ?? "feature"}-${index}`}
520
+ className={cn(
521
+ "flex gap-3 text-sm leading-6 text-muted-foreground",
522
+
523
+ classNames?.feature,
524
+ normalizedFeature.className,
525
+ )}
526
+ >
527
+ <span
528
+ className={cn(
529
+ "mt-2 size-1.5 shrink-0 rounded-full bg-foreground/50",
530
+
531
+ classNames?.featureMarker,
532
+ )}
533
+ aria-hidden="true"
534
+ />
535
+ <span>
536
+ {normalizedFeature.title ? (
537
+ <span
538
+ className={cn(
539
+ "mr-1 font-medium text-foreground",
540
+
541
+ classNames?.featureTitle,
542
+ )}
543
+ >
544
+ {normalizedFeature.title}:
545
+ </span>
546
+ ) : null}
547
+ <span className={classNames?.featureDescription}>
548
+ {normalizedFeature.description}
549
+ </span>
550
+ </span>
551
+ </li>
552
+ );
553
+ })}
554
+ </ul>
555
+ ) : null}
556
+
557
+ {breakdown.length > 0 ? (
558
+ <div
559
+ id={resolvedDetailsId}
560
+ className={cn(
561
+ "mt-8 grid gap-3 border-t border-border pt-6 sm:grid-cols-3",
562
+
563
+ classNames?.breakdown,
564
+ )}
565
+ >
566
+ {breakdown.map((item) => (
567
+ <div
568
+ key={item.label}
569
+ className={cn(
570
+ "rounded-2xl border border-border bg-muted/40 p-4",
571
+
572
+ classNames?.breakdownItem,
573
+ item.className,
574
+ )}
575
+ >
576
+ <p
577
+ className={cn(
578
+ "text-sm font-medium text-foreground",
579
+
580
+ classNames?.breakdownLabel,
581
+ )}
582
+ >
583
+ {item.label}
584
+ </p>
585
+ <p
586
+ className={cn(
587
+ "mt-2 text-sm leading-6 text-muted-foreground",
588
+
589
+ classNames?.breakdownDescription,
590
+ )}
591
+ >
592
+ {item.description}
593
+ </p>
594
+ </div>
595
+ ))}
596
+ </div>
597
+ ) : null}
598
+
599
+ <div
600
+ className={cn(
601
+ "mt-8 flex flex-col gap-3 sm:flex-row",
602
+ classNames?.buttons,
603
+ )}
604
+ >
605
+ {renderCta(resolvedPrimaryCta)}
606
+ {renderCta(resolvedSecondaryCta)}
607
+ </div>
608
+
609
+ {meta.length > 0 ? (
610
+ <dl
611
+ className={cn(
612
+ "mt-auto grid gap-4 border-t border-border pt-6 sm:grid-cols-3 lg:mt-10",
613
+
614
+ classNames?.meta,
615
+ )}
616
+ >
617
+ {meta.map((item) => (
618
+ <div
619
+ key={item.label}
620
+ className={cn("min-w-0", classNames?.metaItem, item.className)}
621
+ >
622
+ <dt
623
+ className={cn(
624
+ "text-xs uppercase tracking-[0.2em] text-muted-foreground",
625
+
626
+ classNames?.metaLabel,
627
+ )}
628
+ >
629
+ {item.label}
630
+ </dt>
631
+ <dd
632
+ className={cn(
633
+ "mt-2 truncate text-sm font-medium text-foreground/80",
634
+
635
+ classNames?.metaValue,
636
+ )}
637
+ >
638
+ {item.value}
639
+ </dd>
640
+ </div>
641
+ ))}
642
+ </dl>
643
+ ) : null}
644
+ </div>
645
+
646
+ {mediaContent ? (
647
+ <div
648
+ id={resolvedMediaId}
649
+ className={cn(
650
+ "relative overflow-hidden rounded-[2rem] border border-border bg-card/80 p-2 shadow-[0_24px_90px_rgba(0,0,0,0.12)] backdrop-blur dark:shadow-[0_24px_90px_rgba(0,0,0,0.62)]",
651
+
652
+ enableMotion && "transition-transform duration-300 hover:-translate-y-1",
653
+ !enableMotion && "transition-none hover:!translate-y-0",
654
+ mediaSlot?.className,
655
+ classNames?.mediaOuter,
656
+ )}
657
+ >
658
+ <div
659
+ className={cn(
660
+ "flex h-10 items-center gap-2 border-b border-border px-4",
661
+
662
+ classNames?.mediaChrome,
663
+ )}
664
+ aria-hidden="true"
665
+ >
666
+ <span className="size-2.5 rounded-full bg-foreground/24" />
667
+ <span className="size-2.5 rounded-full bg-foreground/16" />
668
+ <span className="size-2.5 rounded-full bg-foreground/10" />
669
+ <span className="ml-3 h-2 w-28 rounded-full bg-foreground/8" />
670
+
671
+ </div>
672
+ <div
673
+ className={cn(
674
+ "overflow-hidden rounded-[1.45rem] bg-muted",
675
+
676
+ classNames?.mediaFrame,
677
+ )}
678
+ >
679
+ <div className={classNames?.mediaContent}>{mediaContent}</div>
680
+ </div>
681
+ </div>
682
+ ) : null}
683
+ </div>
684
+ </div>
685
+ </section>
686
+ );
687
+ }