blocks-dusted 0.1.10 → 0.1.12

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 (249) hide show
  1. package/README.md +35 -0
  2. package/package.json +5 -2
  3. package/src/cli.js +39 -3
  4. package/src/commands/shop.js +59 -0
  5. package/src/commands/warehouse.js +73 -0
  6. package/src/utils/paths.js +13 -13
  7. package/templates/blocks/DD-Accordion/Component.tsx +229 -0
  8. package/templates/blocks/DD-Accordion/README.md +3 -0
  9. package/templates/blocks/DD-Accordion/config.ts +73 -0
  10. package/templates/blocks/DD-Accordion/manifest.json +75 -0
  11. package/templates/blocks/DD-AnimText/Component.tsx +788 -0
  12. package/templates/blocks/DD-AnimText/README.md +3 -0
  13. package/templates/blocks/DD-AnimText/config.ts +295 -0
  14. package/templates/blocks/DD-AnimText/manifest.json +85 -0
  15. package/templates/blocks/DD-AsideNav/Component.tsx +321 -0
  16. package/templates/blocks/DD-AsideNav/config.ts +204 -0
  17. package/templates/blocks/DD-AsideNav/manifest.json +80 -0
  18. package/templates/blocks/DD-Banner/Component.tsx +51 -0
  19. package/templates/blocks/DD-Banner/config.ts +57 -0
  20. package/templates/blocks/DD-Banner/manifest.json +72 -0
  21. package/templates/blocks/DD-BgLightning/Component.tsx +44 -0
  22. package/templates/blocks/DD-BgLightning/README.md +3 -0
  23. package/templates/blocks/DD-BgLightning/config.ts +97 -0
  24. package/templates/blocks/DD-BgLightning/manifest.json +79 -0
  25. package/templates/blocks/DD-BookCall/Component.tsx +535 -535
  26. package/templates/blocks/DD-BookCall/config.ts +238 -238
  27. package/templates/blocks/DD-ButtonPop/Component.tsx +117 -0
  28. package/templates/blocks/DD-ButtonPop/config.ts +105 -0
  29. package/templates/blocks/DD-ButtonPop/manifest.json +88 -0
  30. package/templates/blocks/DD-ButtonPop/svg-icons/Dust2.tsx +167 -0
  31. package/templates/blocks/DD-Card/Component.tsx +251 -0
  32. package/templates/blocks/DD-Card/README.md +4 -0
  33. package/templates/blocks/DD-Card/config.ts +154 -0
  34. package/templates/blocks/DD-Card/manifest.json +82 -0
  35. package/templates/blocks/DD-CardTemplate01/Component.tsx +140 -140
  36. package/templates/blocks/DD-CardTemplate01/config.ts +106 -106
  37. package/templates/blocks/DD-Carousel-A/Component.tsx +249 -249
  38. package/templates/blocks/DD-Carousel-B/Component.tsx +403 -403
  39. package/templates/blocks/DD-Chip/Component.tsx +250 -0
  40. package/templates/blocks/DD-Chip/EXAMPLES.md +313 -0
  41. package/templates/blocks/DD-Chip/README.md +202 -0
  42. package/templates/blocks/DD-Chip/config.ts +369 -0
  43. package/templates/blocks/DD-Chip/manifest.json +74 -0
  44. package/templates/blocks/DD-ComparisonTable/Component.tsx +256 -256
  45. package/templates/blocks/DD-Contact/Component.tsx +435 -434
  46. package/templates/blocks/DD-Contact/config.ts +22 -22
  47. package/templates/blocks/DD-Counter/Component.tsx +190 -0
  48. package/templates/blocks/DD-Counter/README.md +4 -0
  49. package/templates/blocks/DD-Counter/config.ts +291 -0
  50. package/templates/blocks/DD-Counter/manifest.json +74 -0
  51. package/templates/blocks/DD-CustomCSS/Component.tsx +8 -0
  52. package/templates/blocks/DD-CustomCSS/README.md +4 -0
  53. package/templates/blocks/DD-CustomCSS/addToLayout.md +5 -0
  54. package/templates/blocks/DD-CustomCSS/config.ts +22 -0
  55. package/templates/blocks/DD-CustomCSS/manifest.json +72 -0
  56. package/templates/blocks/DD-CustomCSS/renderCustomCSS.md +7 -0
  57. package/templates/blocks/DD-FeatCat/Component.tsx +302 -302
  58. package/templates/blocks/DD-FeatCat/config.ts +201 -201
  59. package/templates/blocks/DD-FeatStrip/Component.tsx +585 -585
  60. package/templates/blocks/DD-FeatStrip/config.ts +134 -134
  61. package/templates/blocks/DD-FluidBtn/ButtonsEyeCatching.tsx +628 -0
  62. package/templates/blocks/DD-FluidBtn/Component.tsx +43 -0
  63. package/templates/blocks/DD-FluidBtn/README.md +6 -0
  64. package/templates/blocks/DD-FluidBtn/config.ts +102 -0
  65. package/templates/blocks/DD-FluidBtn/manifest.json +86 -0
  66. package/templates/blocks/DD-GooeyInfo/Component.tsx +149 -0
  67. package/templates/blocks/DD-GooeyInfo/config.ts +135 -0
  68. package/templates/blocks/DD-GooeyInfo/manifest.json +72 -0
  69. package/templates/blocks/DD-Hero/Component.tsx +297 -297
  70. package/templates/blocks/DD-Hero/config.ts +267 -267
  71. package/templates/blocks/DD-HorizontalScroll/Component.tsx +936 -936
  72. package/templates/blocks/DD-HorizontalScroll/config.ts +231 -231
  73. package/templates/blocks/DD-Icon/Component.tsx +287 -0
  74. package/templates/blocks/DD-Icon/README.md +4 -0
  75. package/templates/blocks/DD-Icon/config.ts +258 -0
  76. package/templates/blocks/DD-Icon/hooks/revalidateBlockIds.ts +66 -0
  77. package/templates/blocks/DD-Icon/manifest.json +82 -0
  78. package/templates/blocks/DD-IconButton/Component.tsx +455 -0
  79. package/templates/blocks/DD-IconButton/README.md +326 -0
  80. package/templates/blocks/DD-IconButton/config.ts +239 -0
  81. package/templates/blocks/DD-IconButton/manifest.json +85 -0
  82. package/templates/blocks/DD-IdTag/Component.tsx +21 -0
  83. package/templates/blocks/DD-IdTag/README.md +4 -0
  84. package/templates/blocks/DD-IdTag/config.ts +41 -0
  85. package/templates/blocks/DD-IdTag/manifest.json +72 -0
  86. package/templates/blocks/DD-Iframe/Component.tsx +45 -0
  87. package/templates/blocks/DD-Iframe/README.md +4 -0
  88. package/templates/blocks/DD-Iframe/config.ts +47 -0
  89. package/templates/blocks/DD-Iframe/manifest.json +72 -0
  90. package/templates/blocks/DD-IframeMedia/Component.tsx +133 -0
  91. package/templates/blocks/DD-IframeMedia/README.md +4 -0
  92. package/templates/blocks/DD-IframeMedia/config.ts +79 -0
  93. package/templates/blocks/DD-IframeMedia/manifest.json +72 -0
  94. package/templates/blocks/DD-LineAnim/Component.tsx +36 -0
  95. package/templates/blocks/DD-LineAnim/README.md +4 -0
  96. package/templates/blocks/DD-LineAnim/config.ts +90 -0
  97. package/templates/blocks/DD-LineAnim/manifest.json +80 -0
  98. package/templates/blocks/DD-LinkGrid/Component.tsx +119 -0
  99. package/templates/blocks/DD-LinkGrid/README.md +4 -0
  100. package/templates/blocks/DD-LinkGrid/config.ts +51 -0
  101. package/templates/blocks/DD-LinkGrid/manifest.json +74 -0
  102. package/templates/blocks/DD-LogoMarq/Component.tsx +132 -0
  103. package/templates/blocks/DD-LogoMarq/README.md +4 -0
  104. package/templates/blocks/DD-LogoMarq/config.ts +264 -0
  105. package/templates/blocks/DD-LogoMarq/manifest.json +82 -0
  106. package/templates/blocks/DD-Lottie/Component.tsx +459 -0
  107. package/templates/blocks/DD-Lottie/README.md +4 -0
  108. package/templates/blocks/DD-Lottie/config.ts +379 -0
  109. package/templates/blocks/DD-Lottie/index.tsx +28 -0
  110. package/templates/blocks/DD-Lottie/manifest.json +83 -0
  111. package/templates/blocks/DD-MagicBento/Component.tsx +777 -0
  112. package/templates/blocks/DD-MagicBento/README.md +4 -0
  113. package/templates/blocks/DD-MagicBento/config.ts +264 -0
  114. package/templates/blocks/DD-MagicBento/manifest.json +74 -0
  115. package/templates/blocks/DD-MasonaryMedia/Component.tsx +545 -545
  116. package/templates/blocks/DD-MasonaryMedia/config.ts +2 -2
  117. package/templates/blocks/DD-MasonaryMedia/vendor.d.ts +2 -2
  118. package/templates/blocks/DD-Masonry/Component.tsx +645 -0
  119. package/templates/blocks/DD-Masonry/README.md +4 -0
  120. package/templates/blocks/DD-Masonry/config.ts +475 -0
  121. package/templates/blocks/DD-Masonry/manifest.json +82 -0
  122. package/templates/blocks/DD-Pricing/Component.tsx +2 -5
  123. package/templates/blocks/DD-Process/Component.tsx +2 -4
  124. package/templates/blocks/DD-Process/config.ts +150 -150
  125. package/templates/blocks/DD-Progress/Component.tsx +156 -0
  126. package/templates/blocks/DD-Progress/README.md +4 -0
  127. package/templates/blocks/DD-Progress/config.ts +175 -0
  128. package/templates/blocks/DD-Progress/manifest.json +74 -0
  129. package/templates/blocks/DD-ProjHeader/Component.tsx +91 -0
  130. package/templates/blocks/DD-ProjHeader/README.md +4 -0
  131. package/templates/blocks/DD-ProjHeader/config.ts +96 -0
  132. package/templates/blocks/DD-ProjHeader/manifest.json +72 -0
  133. package/templates/blocks/DD-ProjSlider/Component.tsx +123 -0
  134. package/templates/blocks/DD-ProjSlider/README.md +4 -0
  135. package/templates/blocks/DD-ProjSlider/config.ts +64 -0
  136. package/templates/blocks/DD-ProjSlider/manifest.json +72 -0
  137. package/templates/blocks/DD-ScrollText/Component.tsx +114 -0
  138. package/templates/blocks/DD-ScrollText/README.md +4 -0
  139. package/templates/blocks/DD-ScrollText/config.ts +58 -0
  140. package/templates/blocks/DD-ScrollText/manifest.json +72 -0
  141. package/templates/blocks/DD-Section/Component.tsx +266 -266
  142. package/templates/blocks/DD-Separator/Component.tsx +66 -0
  143. package/templates/blocks/DD-Separator/README.md +4 -0
  144. package/templates/blocks/DD-Separator/config.ts +58 -0
  145. package/templates/blocks/DD-Separator/manifest.json +72 -0
  146. package/templates/blocks/DD-Services/Component.tsx +176 -176
  147. package/templates/blocks/DD-Services/config.ts +149 -149
  148. package/templates/blocks/DD-ShowcaseGrid/Component.tsx +307 -307
  149. package/templates/blocks/DD-Slider-A/Component.tsx +1 -1
  150. package/templates/blocks/DD-StackCards/Component.tsx +1 -1
  151. package/templates/blocks/DD-StackCards/config.ts +399 -399
  152. package/templates/blocks/DD-Team/Component.tsx +247 -247
  153. package/templates/blocks/DD-Team/config.ts +173 -173
  154. package/templates/blocks/DD-TeamCards/Component.tsx +251 -0
  155. package/templates/blocks/DD-TeamCards/README.md +4 -0
  156. package/templates/blocks/DD-TeamCards/config.ts +302 -0
  157. package/templates/blocks/DD-TeamCards/manifest.json +74 -0
  158. package/templates/blocks/DD-TechStack/Component.tsx +174 -174
  159. package/templates/blocks/DD-TechStack/config.ts +153 -153
  160. package/templates/blocks/DD-TestMarq/Component.tsx +132 -0
  161. package/templates/blocks/DD-TestMarq/README.md +4 -0
  162. package/templates/blocks/DD-TestMarq/RowLabel.tsx +9 -0
  163. package/templates/blocks/DD-TestMarq/config.ts +88 -0
  164. package/templates/blocks/DD-TestMarq/manifest.json +72 -0
  165. package/templates/blocks/DD-Testim/Component.tsx +247 -0
  166. package/templates/blocks/DD-Testim/README.md +4 -0
  167. package/templates/blocks/DD-Testim/config.ts +101 -0
  168. package/templates/blocks/DD-Testim/manifest.json +75 -0
  169. package/templates/blocks/DD-Testim2/Component.tsx +256 -0
  170. package/templates/blocks/DD-Testim2/README.md +4 -0
  171. package/templates/blocks/DD-Testim2/config.ts +100 -0
  172. package/templates/blocks/DD-Testim2/manifest.json +74 -0
  173. package/templates/blocks/DD-Testimonials/Component.tsx +139 -147
  174. package/templates/blocks/DD-Testimonials/config.ts +120 -120
  175. package/templates/blocks/DD-TextMarq/Component.tsx +157 -0
  176. package/templates/blocks/DD-TextMarq/README.md +4 -0
  177. package/templates/blocks/DD-TextMarq/config.ts +237 -0
  178. package/templates/blocks/DD-TextMarq/manifest.json +82 -0
  179. package/templates/blocks/DD-Thanks/Component.tsx +501 -0
  180. package/templates/blocks/DD-Thanks/README.md +4 -0
  181. package/templates/blocks/DD-Thanks/config.ts +224 -0
  182. package/templates/blocks/DD-Thanks/manifest.json +72 -0
  183. package/templates/blocks/DD-VertMarq/Component.tsx +154 -0
  184. package/templates/blocks/DD-VertMarq/README.md +4 -0
  185. package/templates/blocks/DD-VertMarq/config.ts +236 -0
  186. package/templates/blocks/DD-VertMarq/dist/index.css +6 -0
  187. package/templates/blocks/DD-VertMarq/dist/index.min.css +1 -0
  188. package/templates/blocks/DD-VertMarq/manifest.json +74 -0
  189. package/templates/blocks/DD-Work/Component.tsx +318 -315
  190. package/templates/blocks/DD-Work/config.ts +165 -165
  191. package/templates/blocks/DD-Work-B/Component.tsx +294 -294
  192. package/templates/blocks/DDHG-CTASection2/Component.tsx +185 -0
  193. package/templates/blocks/DDHG-CTASection2/config.ts +140 -0
  194. package/templates/blocks/DDHG-CTASection2/manifest.json +45 -0
  195. package/templates/blocks/DDHG-HighlightArc/Component.tsx +243 -0
  196. package/templates/blocks/DDHG-HighlightArc/config.ts +85 -0
  197. package/templates/blocks/DDHG-HighlightArc/manifest.json +46 -0
  198. package/templates/blocks/DDHG-LogoMarquee/Component.tsx +143 -0
  199. package/templates/blocks/DDHG-LogoMarquee/config.ts +154 -0
  200. package/templates/blocks/DDHG-LogoMarquee/manifest.json +39 -0
  201. package/templates/blocks/DDHG-NavCodeGrid/Component.tsx +227 -0
  202. package/templates/blocks/DDHG-NavCodeGrid/config.ts +64 -0
  203. package/templates/blocks/DDHG-NavCodeGrid/manifest.json +45 -0
  204. package/templates/blocks/DDHG-ProcessSec/Component.tsx +574 -0
  205. package/templates/blocks/DDHG-ProcessSec/config.ts +170 -0
  206. package/templates/blocks/DDHG-ProcessSec/manifest.json +56 -0
  207. package/templates/blocks/DDHG-ServiceDetails/Component.tsx +164 -0
  208. package/templates/blocks/DDHG-ServiceDetails/ServiceDetailCard.tsx +390 -0
  209. package/templates/blocks/DDHG-ServiceDetails/config.ts +77 -0
  210. package/templates/blocks/DDHG-ServiceDetails/manifest.json +50 -0
  211. package/templates/blocks/DDHG-ServiceHero/Component.tsx +234 -0
  212. package/templates/blocks/DDHG-ServiceHero/config.ts +49 -0
  213. package/templates/blocks/DDHG-ServiceHero/manifest.json +26 -0
  214. package/templates/blocks/DDHG-ServiceOverview/Component.tsx +277 -0
  215. package/templates/blocks/DDHG-ServiceOverview/config.ts +64 -0
  216. package/templates/blocks/DDHG-ServiceOverview/manifest.json +44 -0
  217. package/templates/blocks/DDHG-StatsFAQ/Component.tsx +389 -0
  218. package/templates/blocks/DDHG-StatsFAQ/config.ts +204 -0
  219. package/templates/blocks/DDHG-StatsFAQ/manifest.json +45 -0
  220. package/templates/blocks/DDHG-TeamCards/Component.tsx +169 -0
  221. package/templates/blocks/DDHG-TeamCards/config.ts +48 -0
  222. package/templates/blocks/DDHG-TeamCards/manifest.json +29 -0
  223. package/templates/shared/src/components/BgLightning/index.tsx +242 -0
  224. package/templates/shared/src/components/ui/ShareButton/index.tsx +80 -0
  225. package/templates/shared/src/components/ui/anims/FadeOnScroll.tsx +48 -0
  226. package/templates/shared/src/components/ui/anims/FadeUpOnInView.tsx +63 -0
  227. package/templates/shared/src/components/ui/anims/GlareHover.tsx +111 -0
  228. package/templates/shared/src/components/ui/anims/LineAnims.tsx +81 -0
  229. package/templates/shared/src/components/ui/anims/TitleAnims01.tsx +54 -0
  230. package/templates/shared/src/components/ui/anims/animation-container.tsx +29 -0
  231. package/templates/shared/src/components/ui/anims/blur-in.tsx +26 -0
  232. package/templates/shared/src/components/ui/anims/counter.tsx +53 -0
  233. package/templates/shared/src/components/ui/anims/fade.tsx +83 -0
  234. package/templates/shared/src/components/ui/anims/gradual-spacing.tsx +39 -0
  235. package/templates/shared/src/components/ui/anims/pull-up.tsx +93 -0
  236. package/templates/shared/src/components/ui/anims/reveal-text.tsx +76 -0
  237. package/templates/shared/src/components/ui/anims/rotate-words.tsx +43 -0
  238. package/templates/shared/src/components/ui/anims/shiny-text.tsx +58 -0
  239. package/templates/shared/src/components/ui/anims/shuffle-text.tsx +85 -0
  240. package/templates/shared/src/components/ui/anims/split-text.tsx +211 -0
  241. package/templates/shared/src/components/ui/anims/staggered-fade.tsx +133 -0
  242. package/templates/shared/src/components/ui/anims/text-scroll.tsx +111 -0
  243. package/templates/shared/src/components/ui/anims/typing-effect.tsx +112 -0
  244. package/templates/shared/src/components/ui/button-dusted-fluid/index.tsx +1521 -0
  245. package/templates/shared/src/components/ui/separator.tsx +85 -0
  246. package/templates/shared/src/hooks/useBodyScrollLock.ts +97 -0
  247. package/templates/shared/src/hooks/useClickOutside.ts +28 -0
  248. package/templates/shared/src/utilities/renderCustomCSS.ts +5 -0
  249. package/templates/shared/src/utilities/smoothScroll.ts +65 -0
@@ -1,297 +1,297 @@
1
- 'use client'
2
-
3
- import React, { useState } from 'react'
4
- import Image from 'next/image'
5
- import { motion } from 'framer-motion'
6
- import { TextFade } from '@/components/ui/anims/fade'
7
- import * as LucideIcons from 'lucide-react'
8
-
9
- export type DDHeroProps = Record<string, any>
10
- type Media = { url?: string | null; alt?: string | null; [key: string]: any }
11
- type ButtonItem = { href?: string | null; class?: string | null; label?: string | null }
12
- type StatItem = { value?: string | null; label?: string | null }
13
-
14
- function isLocalAssetSrc(src?: string | null): src is string {
15
- return typeof src === 'string' && src.startsWith('/api/media/file/')
16
- }
17
-
18
- function HeroPlaceholder() {
19
- return (
20
- <svg
21
- aria-hidden="true"
22
- className="h-full w-full"
23
- viewBox="0 0 1600 900"
24
- preserveAspectRatio="none"
25
- >
26
- <defs>
27
- <linearGradient id="dd-hero-placeholder" x1="0" y1="0" x2="1" y2="1">
28
- <stop offset="0%" stopColor="#09090b" />
29
- <stop offset="45%" stopColor="#241244" />
30
- <stop offset="100%" stopColor="#111827" />
31
- </linearGradient>
32
- <pattern id="dd-hero-grid" width="80" height="80" patternUnits="userSpaceOnUse">
33
- <path
34
- d="M 80 0 L 0 0 0 80"
35
- fill="none"
36
- stroke="#ffffff"
37
- strokeOpacity="0.06"
38
- strokeWidth="1"
39
- />
40
- </pattern>
41
- </defs>
42
- <rect width="1600" height="900" fill="url(#dd-hero-placeholder)" />
43
- <rect width="1600" height="900" fill="url(#dd-hero-grid)" />
44
- <path
45
- d="M 1040 140 C 1260 220 1380 390 1320 570 C 1240 800 910 790 760 640 C 620 500 790 260 1040 140 Z"
46
- fill="#ffffff"
47
- fillOpacity="0.08"
48
- />
49
- <path
50
- d="M 180 620 C 360 470 570 490 690 640 C 810 790 600 900 360 840 C 210 800 90 740 180 620 Z"
51
- fill="#a3e635"
52
- fillOpacity="0.08"
53
- />
54
- </svg>
55
- )
56
- }
57
-
58
- function DynamicIcon({
59
- name,
60
- size = 16,
61
- ...props
62
- }: { name?: string | null } & Omit<LucideIcons.LucideProps, 'name'>) {
63
- if (!name) return null
64
- const Icon = (LucideIcons as unknown as Record<string, React.FC<LucideIcons.LucideProps>>)[name]
65
- if (!Icon) return null
66
- return <Icon size={size} {...props} />
67
- }
68
-
69
- export const DDHero: React.FC<DDHeroProps> = ({
70
- badge,
71
- headlineMain,
72
- headlineAccent,
73
- description,
74
- // primaryCta,
75
- // secondaryCta,
76
- stats,
77
- backgroundImage,
78
- backgroundImageFallbackUrl,
79
- sectionId,
80
- showScrollIndicator,
81
- customCSS,
82
- showButtons = true,
83
- buttons = [
84
- { variant: 'v1', icon: 'Goal', label: 'Choose Lane' },
85
- { variant: 'v1', icon: 'Feather', label: 'How it works' },
86
- ],
87
- }) => {
88
- const bgMedia =
89
- backgroundImage && typeof backgroundImage === 'object' ? (backgroundImage as Media) : null
90
- const bgUrl = bgMedia?.url ?? backgroundImageFallbackUrl ?? undefined
91
- const safeBgUrl = isLocalAssetSrc(bgUrl) ? bgUrl : null
92
- const isVideo = Boolean(safeBgUrl && (bgMedia?.mimeType?.startsWith('video/') ?? false))
93
- const buttonItems = buttons as ButtonItem[]
94
- const statItems = (stats ?? []) as StatItem[]
95
-
96
- const [bgLoaded, setBgLoaded] = useState(false)
97
-
98
- // Get dynamic icon component
99
- const ChipIcon = LucideIcons.Sparkles
100
-
101
- return (
102
- <>
103
- {customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
104
-
105
- <div
106
- id={sectionId ?? undefined}
107
- className="relative min-h-screen flex items-center overflow-hidden"
108
- >
109
- {/* Background Image */}
110
- <div className="absolute inset-0">
111
- {safeBgUrl ? (
112
- <>
113
- {!bgLoaded && <div className="absolute inset-0 bg-stone-900 animate-pulse" />}
114
- {isVideo ? (
115
- <video
116
- src={safeBgUrl}
117
- autoPlay
118
- muted
119
- loop
120
- playsInline
121
- preload="none"
122
- className="w-full h-full object-cover object-top"
123
- onLoadedData={() => setBgLoaded(true)}
124
- />
125
- ) : (
126
- <Image
127
- src={safeBgUrl}
128
- alt="Studio hero background"
129
- fill
130
- priority
131
- loading="eager"
132
- className="object-cover object-top"
133
- onLoad={() => setBgLoaded(true)}
134
- />
135
- )}
136
- </>
137
- ) : (
138
- <HeroPlaceholder />
139
- )}
140
- <div className="absolute inset-0 bg-gradient-to-r from-stone-950/95 via-stone-950/80 to-stone-950/40" />
141
- <div className="absolute inset-0 bg-linear-to-t from-stone-950/60 via-transparent to-transparent" />
142
- </div>
143
-
144
- {/* Content */}
145
- <div className="relative z-10 w-full max-w-6xl lg:max-w-7xl mx-auto px-4 md:px-6 pt-28 pb-24">
146
- #BlockName-DDHero
147
- <div className="max-w-2xl">
148
- {/* Badge */}
149
- {/* {badge?.show && badge.text && (
150
- <div className="inline-flex items-center gap-2 bg-stone-50/10 border border-white/20 rounded-full px-4 py-1.5 mb-8">
151
- <span className="w-1.5 h-1.5 rounded-full bg-lime-400 animate-pulse" />
152
- <span className="text-stone-50/80 text-xs font-medium tracking-wide">
153
- {badge.text}
154
- </span>
155
- </div>
156
- )} */}
157
-
158
- {/* Badge - to convert to dynamic */}
159
- {badge?.show && badge.text && (
160
- <motion.div
161
- variants={{
162
- hidden: { opacity: 0, y: -20, filter: 'blur(6px)' },
163
- visible: { opacity: 1, y: 0, filter: 'none' },
164
- }}
165
- transition={{ duration: 0.5, ease: 'easeOut' }}
166
- >
167
- <span className="inline-flex items-center gap-2 rounded-full border border-lime-500 bg-black/70 px-4 py-1.5 text-xs text-lime-100">
168
- {/* TODO: Reconnect Badge/AnimatedShinyText if this project provides them. */}
169
- <ChipIcon className="mr-2 h-3.5 w-3.5" />
170
- {badge.text}
171
- </span>
172
- </motion.div>
173
- )}
174
-
175
- {/* Headline */}
176
- {/* <h1 className="text-5xl md:text-6xl lg:text-7xl font-semibold text-stone-900 dark:text-stone-50 leading-[1.05] tracking-tight mb-6">
177
- {headlineMain}
178
- <br />
179
- <span className="text-stone-400">{headlineAccent}</span>
180
- </h1> */}
181
-
182
- {/* Headline */}
183
- <motion.div
184
- className="relative mt-4 z-50 headline-main"
185
- variants={{
186
- hidden: { opacity: 0, y: 40 },
187
- visible: { opacity: 1, y: 0 },
188
- }}
189
- viewport={{ once: false, amount: 0.3 }}
190
- transition={{ duration: 0.6, ease: 'easeOut' }}
191
- style={{ filter: 'drop-shadow(3px 3px 1px #151515)' }}
192
- >
193
- <span className="block text-6xl sm:text-6xl font-semibold text-left tracking-tight md:text-7xl text-purple-600 dark:text-violet-600 hyphens-auto">
194
- {/* TODO: Reconnect SplittingText animation if this project provides it. */}
195
- {headlineMain}
196
- </span>
197
- </motion.div>
198
- <motion.div
199
- className="relative z-50 headline-accent"
200
- variants={{
201
- hidden: { opacity: 0, y: 40 },
202
- visible: { opacity: 1, y: 0 },
203
- }}
204
- viewport={{ once: false, amount: 0.3 }}
205
- transition={{ duration: 0.6, ease: 'easeOut' }}
206
- style={{ filter: 'drop-shadow(3px 3px 1px #151515)' }}
207
- >
208
- <span className="block text-6xl sm:text-6xl font-semibold text-left tracking-tight md:text-7xl text-purple-900 dark:text-violet-900 hyphens-auto">
209
- {/* TODO: Reconnect SplittingText animation if this project provides it. */}
210
- {headlineAccent}
211
- </span>
212
- </motion.div>
213
-
214
- {/* Description */}
215
- <TextFade direction="down" className="mt-10" delay={0.5}>
216
- {description && (
217
- <p className="text-stone-50/65 leading-relaxed mt-4 mb-0 max-w-xl">{description}</p>
218
- )}
219
- </TextFade>
220
-
221
- {/* CTA Buttons */}
222
- {/* <div className="flex flex-col sm:flex-row gap-3 mx-4">
223
- {primaryCta?.label && (
224
- <a
225
- href={primaryCta.href ?? '#'}
226
- className="inline-flex items-center justify-center gap-2 bg-stone-50 text-stone-900 px-6 py-3 rounded-lg text-sm font-semibold hover:bg-stone-100 transition-colors cursor-pointer whitespace-nowrap"
227
- >
228
- <DynamicIcon className="shrink-0" name={primaryCta.iconName} size={16} />
229
- {primaryCta.label}
230
- </a>
231
- )}
232
- {secondaryCta?.label && (
233
- <a
234
- href={secondaryCta.href ?? '#'}
235
- className="inline-flex items-center justify-center gap-2 bg-stone-50/10 border border-white/20 text-stone-50 px-6 py-3 rounded-lg text-sm font-semibold hover:bg-stone-50/20 transition-colors cursor-pointer whitespace-nowrap"
236
- >
237
- <DynamicIcon className="shrink-0" name={secondaryCta.iconName} size={16} />
238
- {secondaryCta.label}
239
- </a>
240
- )}
241
- </div> */}
242
-
243
- {/* Dusted CTA Buttons */}
244
- {showButtons && buttonItems.length > 0 && (
245
- <motion.div
246
- className="dusted-hero-cta-col mt-8 relative flex col-start-2 col-span-2 gap-4"
247
- variants={{
248
- hidden: { opacity: 0, y: 20 },
249
- visible: { opacity: 1, y: 0 },
250
- }}
251
- transition={{ duration: 0.6, ease: 'easeOut' }}
252
- >
253
- {buttonItems.map((button, index) => (
254
- <a
255
- key={index}
256
- href={(button as any).href ?? '#'}
257
- className={
258
- button.class ??
259
- 'inline-flex items-center gap-1.5 bg-indigo-700 text-stone-50 text-xs font-semibold px-3 py-1.5 rounded-lg group-hover:bg-indigo-600 group-hover:scale-[1.05] group-hover:shadow-xl transition-all duration-150 whitespace-nowrap'
260
- }
261
- style={{ cornerShape: 'squircle' } as React.CSSProperties}
262
- >
263
- {/* TODO: Reconnect ButtonDustedFluid if this project provides it. */}
264
- {button.label || 'Button'}
265
- </a>
266
- ))}
267
- </motion.div>
268
- )}
269
-
270
- {/* Stats */}
271
- {statItems.length > 0 && (
272
- <div className="flex items-center gap-8 mt-24 pt-8 border-t border-white/10">
273
- {statItems.map((stat, index) => (
274
- <div key={stat.label ?? index}>
275
- <div className="text-4xl font-semibold text-stone-100/50 dark:text-stone-50">
276
- {stat.value}
277
- </div>
278
- <div className="text-xs text-stone-50/75 mt-0.5">{stat.label}</div>
279
- </div>
280
- ))}
281
- </div>
282
- )}
283
- </div>
284
- </div>
285
-
286
- {/* Scroll indicator */}
287
- {showScrollIndicator && (
288
- <div className="absolute bottom-8 left-1/2 -translate-x-1/2 flex flex-col items-center gap-2 animate-bounce">
289
- <div className="w-5 h-8 border border-white/30 rounded-full flex items-start justify-center pt-1.5">
290
- <div className="w-1 h-2 bg-stone-50/50 rounded-full" />
291
- </div>
292
- </div>
293
- )}
294
- </div>
295
- </>
296
- )
297
- }
1
+ 'use client'
2
+
3
+ import React, { useState } from 'react'
4
+ import Image from 'next/image'
5
+ import { motion } from 'framer-motion'
6
+ import { TextFade } from '@/components/ui/anims/fade'
7
+ import * as LucideIcons from 'lucide-react'
8
+
9
+ export type DDHeroProps = Record<string, any>
10
+ type Media = { url?: string | null; alt?: string | null; [key: string]: any }
11
+ type ButtonItem = { href?: string | null; class?: string | null; label?: string | null }
12
+ type StatItem = { value?: string | null; label?: string | null }
13
+
14
+ function isLocalAssetSrc(src?: string | null): src is string {
15
+ return typeof src === 'string' && src.startsWith('/api/media/file/')
16
+ }
17
+
18
+ function HeroPlaceholder() {
19
+ return (
20
+ <svg
21
+ aria-hidden="true"
22
+ className="h-full w-full"
23
+ viewBox="0 0 1600 900"
24
+ preserveAspectRatio="none"
25
+ >
26
+ <defs>
27
+ <linearGradient id="dd-hero-placeholder" x1="0" y1="0" x2="1" y2="1">
28
+ <stop offset="0%" stopColor="#09090b" />
29
+ <stop offset="45%" stopColor="#241244" />
30
+ <stop offset="100%" stopColor="#111827" />
31
+ </linearGradient>
32
+ <pattern id="dd-hero-grid" width="80" height="80" patternUnits="userSpaceOnUse">
33
+ <path
34
+ d="M 80 0 L 0 0 0 80"
35
+ fill="none"
36
+ stroke="#ffffff"
37
+ strokeOpacity="0.06"
38
+ strokeWidth="1"
39
+ />
40
+ </pattern>
41
+ </defs>
42
+ <rect width="1600" height="900" fill="url(#dd-hero-placeholder)" />
43
+ <rect width="1600" height="900" fill="url(#dd-hero-grid)" />
44
+ <path
45
+ d="M 1040 140 C 1260 220 1380 390 1320 570 C 1240 800 910 790 760 640 C 620 500 790 260 1040 140 Z"
46
+ fill="#ffffff"
47
+ fillOpacity="0.08"
48
+ />
49
+ <path
50
+ d="M 180 620 C 360 470 570 490 690 640 C 810 790 600 900 360 840 C 210 800 90 740 180 620 Z"
51
+ fill="#a3e635"
52
+ fillOpacity="0.08"
53
+ />
54
+ </svg>
55
+ )
56
+ }
57
+
58
+ function DynamicIcon({
59
+ name,
60
+ size = 16,
61
+ ...props
62
+ }: { name?: string | null } & Omit<LucideIcons.LucideProps, 'name'>) {
63
+ if (!name) return null
64
+ const Icon = (LucideIcons as unknown as Record<string, React.FC<LucideIcons.LucideProps>>)[name]
65
+ if (!Icon) return null
66
+ return <Icon size={size} {...props} />
67
+ }
68
+
69
+ export const DDHero: React.FC<DDHeroProps> = ({
70
+ badge,
71
+ headlineMain,
72
+ headlineAccent,
73
+ description,
74
+ // primaryCta,
75
+ // secondaryCta,
76
+ stats,
77
+ backgroundImage,
78
+ backgroundImageFallbackUrl,
79
+ sectionId,
80
+ showScrollIndicator,
81
+ customCSS,
82
+ showButtons = true,
83
+ buttons = [
84
+ { variant: 'v1', icon: 'Goal', label: 'Choose Lane' },
85
+ { variant: 'v1', icon: 'Feather', label: 'How it works' },
86
+ ],
87
+ }) => {
88
+ const bgMedia =
89
+ backgroundImage && typeof backgroundImage === 'object' ? (backgroundImage as Media) : null
90
+ const bgUrl = bgMedia?.url ?? backgroundImageFallbackUrl ?? undefined
91
+ const safeBgUrl = isLocalAssetSrc(bgUrl) ? bgUrl : null
92
+ const isVideo = Boolean(safeBgUrl && (bgMedia?.mimeType?.startsWith('video/') ?? false))
93
+ const buttonItems = buttons as ButtonItem[]
94
+ const statItems = (stats ?? []) as StatItem[]
95
+
96
+ const [bgLoaded, setBgLoaded] = useState(false)
97
+
98
+ // Get dynamic icon component
99
+ const ChipIcon = LucideIcons.Sparkles
100
+
101
+ return (
102
+ <>
103
+ {customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
104
+
105
+ <div
106
+ id={sectionId ?? undefined}
107
+ className="relative min-h-screen flex items-center overflow-hidden"
108
+ >
109
+ {/* Background Image */}
110
+ <div className="absolute inset-0">
111
+ {safeBgUrl ? (
112
+ <>
113
+ {!bgLoaded && <div className="absolute inset-0 bg-stone-900 animate-pulse" />}
114
+ {isVideo ? (
115
+ <video
116
+ src={safeBgUrl}
117
+ autoPlay
118
+ muted
119
+ loop
120
+ playsInline
121
+ preload="none"
122
+ className="w-full h-full object-cover object-top"
123
+ onLoadedData={() => setBgLoaded(true)}
124
+ />
125
+ ) : (
126
+ <Image
127
+ src={safeBgUrl}
128
+ alt="Studio hero background"
129
+ fill
130
+ priority
131
+ loading="eager"
132
+ className="object-cover object-top"
133
+ onLoad={() => setBgLoaded(true)}
134
+ />
135
+ )}
136
+ </>
137
+ ) : (
138
+ <HeroPlaceholder />
139
+ )}
140
+ <div className="absolute inset-0 bg-gradient-to-r from-stone-950/95 via-stone-950/80 to-stone-950/40" />
141
+ <div className="absolute inset-0 bg-linear-to-t from-stone-950/60 via-transparent to-transparent" />
142
+ </div>
143
+
144
+ {/* Content */}
145
+ <div className="relative z-10 w-full max-w-6xl lg:max-w-7xl mx-auto px-4 md:px-6 pt-28 pb-24">
146
+ #BlockName-DDHero
147
+ <div className="max-w-2xl">
148
+ {/* Badge */}
149
+ {/* {badge?.show && badge.text && (
150
+ <div className="inline-flex items-center gap-2 bg-stone-50/10 border border-white/20 rounded-full px-4 py-1.5 mb-8">
151
+ <span className="w-1.5 h-1.5 rounded-full bg-lime-400 animate-pulse" />
152
+ <span className="text-stone-50/80 text-xs font-medium tracking-wide">
153
+ {badge.text}
154
+ </span>
155
+ </div>
156
+ )} */}
157
+
158
+ {/* Badge - to convert to dynamic */}
159
+ {badge?.show && badge.text && (
160
+ <motion.div
161
+ variants={{
162
+ hidden: { opacity: 0, y: -20, filter: 'blur(6px)' },
163
+ visible: { opacity: 1, y: 0, filter: 'none' },
164
+ }}
165
+ transition={{ duration: 0.5, ease: 'easeOut' }}
166
+ >
167
+ <span className="inline-flex items-center gap-2 rounded-full border border-lime-500 bg-black/70 px-4 py-1.5 text-xs text-lime-100">
168
+ {/* TODO: Reconnect Badge/AnimatedShinyText if this project provides them. */}
169
+ <ChipIcon className="mr-2 h-3.5 w-3.5" />
170
+ {badge.text}
171
+ </span>
172
+ </motion.div>
173
+ )}
174
+
175
+ {/* Headline */}
176
+ {/* <h1 className="text-5xl md:text-6xl lg:text-7xl font-semibold text-stone-900 dark:text-stone-50 leading-[1.05] tracking-tight mb-6">
177
+ {headlineMain}
178
+ <br />
179
+ <span className="text-stone-400">{headlineAccent}</span>
180
+ </h1> */}
181
+
182
+ {/* Headline */}
183
+ <motion.div
184
+ className="relative mt-4 z-50 headline-main"
185
+ variants={{
186
+ hidden: { opacity: 0, y: 40 },
187
+ visible: { opacity: 1, y: 0 },
188
+ }}
189
+ viewport={{ once: false, amount: 0.3 }}
190
+ transition={{ duration: 0.6, ease: 'easeOut' }}
191
+ style={{ filter: 'drop-shadow(3px 3px 1px #151515)' }}
192
+ >
193
+ <span className="block text-6xl sm:text-6xl font-semibold text-left tracking-tight md:text-7xl text-purple-600 dark:text-violet-600 hyphens-auto">
194
+ {/* TODO: Reconnect SplittingText animation if this project provides it. */}
195
+ {headlineMain}
196
+ </span>
197
+ </motion.div>
198
+ <motion.div
199
+ className="relative z-50 headline-accent"
200
+ variants={{
201
+ hidden: { opacity: 0, y: 40 },
202
+ visible: { opacity: 1, y: 0 },
203
+ }}
204
+ viewport={{ once: false, amount: 0.3 }}
205
+ transition={{ duration: 0.6, ease: 'easeOut' }}
206
+ style={{ filter: 'drop-shadow(3px 3px 1px #151515)' }}
207
+ >
208
+ <span className="block text-6xl sm:text-6xl font-semibold text-left tracking-tight md:text-7xl text-purple-900 dark:text-violet-900 hyphens-auto">
209
+ {/* TODO: Reconnect SplittingText animation if this project provides it. */}
210
+ {headlineAccent}
211
+ </span>
212
+ </motion.div>
213
+
214
+ {/* Description */}
215
+ <TextFade direction="down" className="mt-10" delay={0.5}>
216
+ {description && (
217
+ <p className="text-stone-50/65 leading-relaxed mt-4 mb-0 max-w-xl">{description}</p>
218
+ )}
219
+ </TextFade>
220
+
221
+ {/* CTA Buttons */}
222
+ {/* <div className="flex flex-col sm:flex-row gap-3 mx-4">
223
+ {primaryCta?.label && (
224
+ <a
225
+ href={primaryCta.href ?? '#'}
226
+ className="inline-flex items-center justify-center gap-2 bg-stone-50 text-stone-900 px-6 py-3 rounded-lg text-sm font-semibold hover:bg-stone-100 transition-colors cursor-pointer whitespace-nowrap"
227
+ >
228
+ <DynamicIcon className="shrink-0" name={primaryCta.iconName} size={16} />
229
+ {primaryCta.label}
230
+ </a>
231
+ )}
232
+ {secondaryCta?.label && (
233
+ <a
234
+ href={secondaryCta.href ?? '#'}
235
+ className="inline-flex items-center justify-center gap-2 bg-stone-50/10 border border-white/20 text-stone-50 px-6 py-3 rounded-lg text-sm font-semibold hover:bg-stone-50/20 transition-colors cursor-pointer whitespace-nowrap"
236
+ >
237
+ <DynamicIcon className="shrink-0" name={secondaryCta.iconName} size={16} />
238
+ {secondaryCta.label}
239
+ </a>
240
+ )}
241
+ </div> */}
242
+
243
+ {/* Dusted CTA Buttons */}
244
+ {showButtons && buttonItems.length > 0 && (
245
+ <motion.div
246
+ className="dusted-hero-cta-col mt-8 relative flex col-start-2 col-span-2 gap-4"
247
+ variants={{
248
+ hidden: { opacity: 0, y: 20 },
249
+ visible: { opacity: 1, y: 0 },
250
+ }}
251
+ transition={{ duration: 0.6, ease: 'easeOut' }}
252
+ >
253
+ {buttonItems.map((button, index) => (
254
+ <a
255
+ key={index}
256
+ href={(button as any).href ?? '#'}
257
+ className={
258
+ button.class ??
259
+ 'inline-flex items-center gap-1.5 bg-indigo-700 text-stone-50 text-xs font-semibold px-3 py-1.5 rounded-lg group-hover:bg-indigo-600 group-hover:scale-[1.05] group-hover:shadow-xl transition-all duration-150 whitespace-nowrap'
260
+ }
261
+ style={{ cornerShape: 'squircle' } as React.CSSProperties}
262
+ >
263
+ {/* TODO: Reconnect ButtonDustedFluid if this project provides it. */}
264
+ {button.label || 'Button'}
265
+ </a>
266
+ ))}
267
+ </motion.div>
268
+ )}
269
+
270
+ {/* Stats */}
271
+ {statItems.length > 0 && (
272
+ <div className="flex items-center gap-8 mt-24 pt-8 border-t border-white/10">
273
+ {statItems.map((stat, index) => (
274
+ <div key={stat.label ?? index}>
275
+ <div className="text-4xl font-semibold text-stone-100/50 dark:text-stone-50">
276
+ {stat.value}
277
+ </div>
278
+ <div className="text-xs text-stone-50/75 mt-0.5">{stat.label}</div>
279
+ </div>
280
+ ))}
281
+ </div>
282
+ )}
283
+ </div>
284
+ </div>
285
+
286
+ {/* Scroll indicator */}
287
+ {showScrollIndicator && (
288
+ <div className="absolute bottom-8 left-1/2 -translate-x-1/2 flex flex-col items-center gap-2 animate-bounce">
289
+ <div className="w-5 h-8 border border-white/30 rounded-full flex items-start justify-center pt-1.5">
290
+ <div className="w-1 h-2 bg-stone-50/50 rounded-full" />
291
+ </div>
292
+ </div>
293
+ )}
294
+ </div>
295
+ </>
296
+ )
297
+ }