blocks-dusted 0.1.9 → 0.1.11

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 (248) hide show
  1. package/README.md +35 -0
  2. package/package.json +1 -1
  3. package/src/utils/paths.js +13 -13
  4. package/templates/blocks/DD-Accordion/Component.tsx +229 -0
  5. package/templates/blocks/DD-Accordion/README.md +3 -0
  6. package/templates/blocks/DD-Accordion/config.ts +73 -0
  7. package/templates/blocks/DD-Accordion/manifest.json +75 -0
  8. package/templates/blocks/DD-AnimText/Component.tsx +788 -0
  9. package/templates/blocks/DD-AnimText/README.md +3 -0
  10. package/templates/blocks/DD-AnimText/config.ts +295 -0
  11. package/templates/blocks/DD-AnimText/manifest.json +85 -0
  12. package/templates/blocks/DD-AsideNav/Component.tsx +321 -0
  13. package/templates/blocks/DD-AsideNav/config.ts +204 -0
  14. package/templates/blocks/DD-AsideNav/manifest.json +80 -0
  15. package/templates/blocks/DD-Banner/Component.tsx +51 -0
  16. package/templates/blocks/DD-Banner/config.ts +57 -0
  17. package/templates/blocks/DD-Banner/manifest.json +72 -0
  18. package/templates/blocks/DD-BgLightning/Component.tsx +44 -0
  19. package/templates/blocks/DD-BgLightning/README.md +3 -0
  20. package/templates/blocks/DD-BgLightning/config.ts +97 -0
  21. package/templates/blocks/DD-BgLightning/manifest.json +79 -0
  22. package/templates/blocks/DD-BookCall/Component.tsx +10 -11
  23. package/templates/blocks/DD-BookCall/config.ts +238 -238
  24. package/templates/blocks/DD-ButtonPop/Component.tsx +117 -0
  25. package/templates/blocks/DD-ButtonPop/config.ts +105 -0
  26. package/templates/blocks/DD-ButtonPop/manifest.json +88 -0
  27. package/templates/blocks/DD-ButtonPop/svg-icons/Dust2.tsx +167 -0
  28. package/templates/blocks/DD-Card/Component.tsx +251 -0
  29. package/templates/blocks/DD-Card/README.md +4 -0
  30. package/templates/blocks/DD-Card/config.ts +154 -0
  31. package/templates/blocks/DD-Card/manifest.json +82 -0
  32. package/templates/blocks/DD-CardTemplate01/Component.tsx +5 -6
  33. package/templates/blocks/DD-CardTemplate01/config.ts +106 -106
  34. package/templates/blocks/DD-Carousel-A/Component.tsx +249 -249
  35. package/templates/blocks/DD-Carousel-B/Component.tsx +403 -403
  36. package/templates/blocks/DD-Chip/Component.tsx +250 -0
  37. package/templates/blocks/DD-Chip/EXAMPLES.md +313 -0
  38. package/templates/blocks/DD-Chip/README.md +202 -0
  39. package/templates/blocks/DD-Chip/config.ts +369 -0
  40. package/templates/blocks/DD-Chip/manifest.json +74 -0
  41. package/templates/blocks/DD-ComparisonTable/Component.tsx +256 -256
  42. package/templates/blocks/DD-Contact/Component.tsx +434 -434
  43. package/templates/blocks/DD-Contact/config.ts +22 -22
  44. package/templates/blocks/DD-Counter/Component.tsx +190 -0
  45. package/templates/blocks/DD-Counter/README.md +4 -0
  46. package/templates/blocks/DD-Counter/config.ts +291 -0
  47. package/templates/blocks/DD-Counter/manifest.json +74 -0
  48. package/templates/blocks/DD-CustomCSS/Component.tsx +8 -0
  49. package/templates/blocks/DD-CustomCSS/README.md +4 -0
  50. package/templates/blocks/DD-CustomCSS/addToLayout.md +5 -0
  51. package/templates/blocks/DD-CustomCSS/config.ts +22 -0
  52. package/templates/blocks/DD-CustomCSS/manifest.json +72 -0
  53. package/templates/blocks/DD-CustomCSS/renderCustomCSS.md +7 -0
  54. package/templates/blocks/DD-FeatCat/Component.tsx +302 -302
  55. package/templates/blocks/DD-FeatCat/config.ts +201 -201
  56. package/templates/blocks/DD-FeatStrip/Component.tsx +585 -585
  57. package/templates/blocks/DD-FeatStrip/config.ts +134 -134
  58. package/templates/blocks/DD-FluidBtn/ButtonsEyeCatching.tsx +628 -0
  59. package/templates/blocks/DD-FluidBtn/Component.tsx +43 -0
  60. package/templates/blocks/DD-FluidBtn/README.md +6 -0
  61. package/templates/blocks/DD-FluidBtn/config.ts +102 -0
  62. package/templates/blocks/DD-FluidBtn/manifest.json +86 -0
  63. package/templates/blocks/DD-GooeyInfo/Component.tsx +149 -0
  64. package/templates/blocks/DD-GooeyInfo/config.ts +135 -0
  65. package/templates/blocks/DD-GooeyInfo/manifest.json +72 -0
  66. package/templates/blocks/DD-Hero/Component.tsx +40 -17
  67. package/templates/blocks/DD-Hero/config.ts +267 -267
  68. package/templates/blocks/DD-HorizontalScroll/Component.tsx +4 -2
  69. package/templates/blocks/DD-HorizontalScroll/config.ts +231 -231
  70. package/templates/blocks/DD-Icon/Component.tsx +287 -0
  71. package/templates/blocks/DD-Icon/README.md +4 -0
  72. package/templates/blocks/DD-Icon/config.ts +258 -0
  73. package/templates/blocks/DD-Icon/hooks/revalidateBlockIds.ts +66 -0
  74. package/templates/blocks/DD-Icon/manifest.json +82 -0
  75. package/templates/blocks/DD-IconButton/Component.tsx +455 -0
  76. package/templates/blocks/DD-IconButton/README.md +326 -0
  77. package/templates/blocks/DD-IconButton/config.ts +239 -0
  78. package/templates/blocks/DD-IconButton/manifest.json +85 -0
  79. package/templates/blocks/DD-IdTag/Component.tsx +21 -0
  80. package/templates/blocks/DD-IdTag/README.md +4 -0
  81. package/templates/blocks/DD-IdTag/config.ts +41 -0
  82. package/templates/blocks/DD-IdTag/manifest.json +72 -0
  83. package/templates/blocks/DD-Iframe/Component.tsx +45 -0
  84. package/templates/blocks/DD-Iframe/README.md +4 -0
  85. package/templates/blocks/DD-Iframe/config.ts +47 -0
  86. package/templates/blocks/DD-Iframe/manifest.json +72 -0
  87. package/templates/blocks/DD-IframeMedia/Component.tsx +129 -0
  88. package/templates/blocks/DD-IframeMedia/README.md +4 -0
  89. package/templates/blocks/DD-IframeMedia/config.ts +79 -0
  90. package/templates/blocks/DD-IframeMedia/manifest.json +72 -0
  91. package/templates/blocks/DD-LineAnim/Component.tsx +36 -0
  92. package/templates/blocks/DD-LineAnim/README.md +4 -0
  93. package/templates/blocks/DD-LineAnim/config.ts +90 -0
  94. package/templates/blocks/DD-LineAnim/manifest.json +80 -0
  95. package/templates/blocks/DD-LinkGrid/Component.tsx +119 -0
  96. package/templates/blocks/DD-LinkGrid/README.md +4 -0
  97. package/templates/blocks/DD-LinkGrid/config.ts +51 -0
  98. package/templates/blocks/DD-LinkGrid/manifest.json +74 -0
  99. package/templates/blocks/DD-LogoMarq/Component.tsx +132 -0
  100. package/templates/blocks/DD-LogoMarq/README.md +4 -0
  101. package/templates/blocks/DD-LogoMarq/config.ts +264 -0
  102. package/templates/blocks/DD-LogoMarq/manifest.json +82 -0
  103. package/templates/blocks/DD-Lottie/Component.tsx +459 -0
  104. package/templates/blocks/DD-Lottie/README.md +4 -0
  105. package/templates/blocks/DD-Lottie/config.ts +379 -0
  106. package/templates/blocks/DD-Lottie/index.tsx +28 -0
  107. package/templates/blocks/DD-Lottie/manifest.json +83 -0
  108. package/templates/blocks/DD-MagicBento/Component.tsx +777 -0
  109. package/templates/blocks/DD-MagicBento/README.md +4 -0
  110. package/templates/blocks/DD-MagicBento/config.ts +264 -0
  111. package/templates/blocks/DD-MagicBento/manifest.json +74 -0
  112. package/templates/blocks/DD-MasonaryMedia/Component.tsx +547 -545
  113. package/templates/blocks/DD-MasonaryMedia/config.ts +2 -2
  114. package/templates/blocks/DD-MasonaryMedia/vendor.d.ts +2 -2
  115. package/templates/blocks/DD-Masonry/Component.tsx +645 -0
  116. package/templates/blocks/DD-Masonry/README.md +4 -0
  117. package/templates/blocks/DD-Masonry/config.ts +475 -0
  118. package/templates/blocks/DD-Masonry/manifest.json +82 -0
  119. package/templates/blocks/DD-Pricing/Component.tsx +372 -372
  120. package/templates/blocks/DD-Process/Component.tsx +149 -149
  121. package/templates/blocks/DD-Process/config.ts +150 -150
  122. package/templates/blocks/DD-Progress/Component.tsx +141 -0
  123. package/templates/blocks/DD-Progress/README.md +4 -0
  124. package/templates/blocks/DD-Progress/config.ts +175 -0
  125. package/templates/blocks/DD-Progress/manifest.json +74 -0
  126. package/templates/blocks/DD-ProjHeader/Component.tsx +91 -0
  127. package/templates/blocks/DD-ProjHeader/README.md +4 -0
  128. package/templates/blocks/DD-ProjHeader/config.ts +96 -0
  129. package/templates/blocks/DD-ProjHeader/manifest.json +72 -0
  130. package/templates/blocks/DD-ProjSlider/Component.tsx +123 -0
  131. package/templates/blocks/DD-ProjSlider/README.md +4 -0
  132. package/templates/blocks/DD-ProjSlider/config.ts +64 -0
  133. package/templates/blocks/DD-ProjSlider/manifest.json +72 -0
  134. package/templates/blocks/DD-ScrollText/Component.tsx +114 -0
  135. package/templates/blocks/DD-ScrollText/README.md +4 -0
  136. package/templates/blocks/DD-ScrollText/config.ts +58 -0
  137. package/templates/blocks/DD-ScrollText/manifest.json +72 -0
  138. package/templates/blocks/DD-Section/Component.tsx +266 -266
  139. package/templates/blocks/DD-Separator/Component.tsx +66 -0
  140. package/templates/blocks/DD-Separator/README.md +4 -0
  141. package/templates/blocks/DD-Separator/config.ts +58 -0
  142. package/templates/blocks/DD-Separator/manifest.json +72 -0
  143. package/templates/blocks/DD-Services/Component.tsx +176 -176
  144. package/templates/blocks/DD-Services/config.ts +149 -149
  145. package/templates/blocks/DD-ShowcaseGrid/Component.tsx +307 -307
  146. package/templates/blocks/DD-Slider-A/Component.tsx +237 -237
  147. package/templates/blocks/DD-StackCards/Component.tsx +473 -473
  148. package/templates/blocks/DD-StackCards/config.ts +399 -399
  149. package/templates/blocks/DD-Team/Component.tsx +247 -247
  150. package/templates/blocks/DD-Team/config.ts +173 -173
  151. package/templates/blocks/DD-TeamCards/Component.tsx +251 -0
  152. package/templates/blocks/DD-TeamCards/README.md +4 -0
  153. package/templates/blocks/DD-TeamCards/config.ts +302 -0
  154. package/templates/blocks/DD-TeamCards/manifest.json +74 -0
  155. package/templates/blocks/DD-TechStack/Component.tsx +168 -162
  156. package/templates/blocks/DD-TechStack/config.ts +153 -153
  157. package/templates/blocks/DD-TestMarq/Component.tsx +132 -0
  158. package/templates/blocks/DD-TestMarq/README.md +4 -0
  159. package/templates/blocks/DD-TestMarq/RowLabel.tsx +9 -0
  160. package/templates/blocks/DD-TestMarq/config.ts +88 -0
  161. package/templates/blocks/DD-TestMarq/manifest.json +72 -0
  162. package/templates/blocks/DD-Testim/Component.tsx +247 -0
  163. package/templates/blocks/DD-Testim/README.md +4 -0
  164. package/templates/blocks/DD-Testim/config.ts +101 -0
  165. package/templates/blocks/DD-Testim/manifest.json +75 -0
  166. package/templates/blocks/DD-Testim2/Component.tsx +256 -0
  167. package/templates/blocks/DD-Testim2/README.md +4 -0
  168. package/templates/blocks/DD-Testim2/config.ts +100 -0
  169. package/templates/blocks/DD-Testim2/manifest.json +74 -0
  170. package/templates/blocks/DD-Testimonials/Component.tsx +147 -147
  171. package/templates/blocks/DD-Testimonials/config.ts +120 -120
  172. package/templates/blocks/DD-TextMarq/Component.tsx +157 -0
  173. package/templates/blocks/DD-TextMarq/README.md +4 -0
  174. package/templates/blocks/DD-TextMarq/config.ts +237 -0
  175. package/templates/blocks/DD-TextMarq/manifest.json +82 -0
  176. package/templates/blocks/DD-Thanks/Component.tsx +500 -0
  177. package/templates/blocks/DD-Thanks/README.md +4 -0
  178. package/templates/blocks/DD-Thanks/config.ts +224 -0
  179. package/templates/blocks/DD-Thanks/manifest.json +72 -0
  180. package/templates/blocks/DD-VertMarq/Component.tsx +154 -0
  181. package/templates/blocks/DD-VertMarq/README.md +4 -0
  182. package/templates/blocks/DD-VertMarq/config.ts +236 -0
  183. package/templates/blocks/DD-VertMarq/dist/index.css +6 -0
  184. package/templates/blocks/DD-VertMarq/dist/index.min.css +1 -0
  185. package/templates/blocks/DD-VertMarq/manifest.json +74 -0
  186. package/templates/blocks/DD-Work/Component.tsx +318 -315
  187. package/templates/blocks/DD-Work/config.ts +165 -165
  188. package/templates/blocks/DD-Work-B/Component.tsx +294 -294
  189. package/templates/blocks/DDHG-CTASection2/Component.tsx +185 -0
  190. package/templates/blocks/DDHG-CTASection2/config.ts +140 -0
  191. package/templates/blocks/DDHG-CTASection2/manifest.json +45 -0
  192. package/templates/blocks/DDHG-HighlightArc/Component.tsx +243 -0
  193. package/templates/blocks/DDHG-HighlightArc/config.ts +85 -0
  194. package/templates/blocks/DDHG-HighlightArc/manifest.json +46 -0
  195. package/templates/blocks/DDHG-LogoMarquee/Component.tsx +93 -0
  196. package/templates/blocks/DDHG-LogoMarquee/config.ts +66 -0
  197. package/templates/blocks/DDHG-LogoMarquee/manifest.json +39 -0
  198. package/templates/blocks/DDHG-NavCodeGrid/Component.tsx +213 -0
  199. package/templates/blocks/DDHG-NavCodeGrid/config.ts +64 -0
  200. package/templates/blocks/DDHG-NavCodeGrid/manifest.json +45 -0
  201. package/templates/blocks/DDHG-ProcessSec/Component.tsx +575 -0
  202. package/templates/blocks/DDHG-ProcessSec/config.ts +170 -0
  203. package/templates/blocks/DDHG-ProcessSec/manifest.json +56 -0
  204. package/templates/blocks/DDHG-ServiceDetails/Component.tsx +164 -0
  205. package/templates/blocks/DDHG-ServiceDetails/ServiceDetailCard.tsx +394 -0
  206. package/templates/blocks/DDHG-ServiceDetails/config.ts +77 -0
  207. package/templates/blocks/DDHG-ServiceDetails/manifest.json +50 -0
  208. package/templates/blocks/DDHG-ServiceHero/Component.tsx +234 -0
  209. package/templates/blocks/DDHG-ServiceHero/config.ts +49 -0
  210. package/templates/blocks/DDHG-ServiceHero/manifest.json +26 -0
  211. package/templates/blocks/DDHG-ServiceOverview/Component.tsx +277 -0
  212. package/templates/blocks/DDHG-ServiceOverview/config.ts +64 -0
  213. package/templates/blocks/DDHG-ServiceOverview/manifest.json +44 -0
  214. package/templates/blocks/DDHG-StatsFAQ/Component.tsx +389 -0
  215. package/templates/blocks/DDHG-StatsFAQ/config.ts +204 -0
  216. package/templates/blocks/DDHG-StatsFAQ/manifest.json +45 -0
  217. package/templates/blocks/DDHG-TeamCards/Component.tsx +131 -0
  218. package/templates/blocks/DDHG-TeamCards/config.ts +48 -0
  219. package/templates/blocks/DDHG-TeamCards/manifest.json +29 -0
  220. package/templates/components/HeaderDD02/MobileBottomNav/index.tsx +352 -257
  221. package/templates/components/HeaderDD02/index.tsx +313 -229
  222. package/templates/shared/src/components/BgLightning/index.tsx +242 -0
  223. package/templates/shared/src/components/ui/ShareButton/index.tsx +80 -0
  224. package/templates/shared/src/components/ui/anims/FadeOnScroll.tsx +48 -0
  225. package/templates/shared/src/components/ui/anims/FadeUpOnInView.tsx +63 -0
  226. package/templates/shared/src/components/ui/anims/GlareHover.tsx +111 -0
  227. package/templates/shared/src/components/ui/anims/LineAnims.tsx +81 -0
  228. package/templates/shared/src/components/ui/anims/TitleAnims01.tsx +54 -0
  229. package/templates/shared/src/components/ui/anims/animation-container.tsx +29 -0
  230. package/templates/shared/src/components/ui/anims/blur-in.tsx +26 -0
  231. package/templates/shared/src/components/ui/anims/counter.tsx +53 -0
  232. package/templates/shared/src/components/ui/anims/fade.tsx +83 -0
  233. package/templates/shared/src/components/ui/anims/gradual-spacing.tsx +39 -0
  234. package/templates/shared/src/components/ui/anims/pull-up.tsx +93 -0
  235. package/templates/shared/src/components/ui/anims/reveal-text.tsx +76 -0
  236. package/templates/shared/src/components/ui/anims/rotate-words.tsx +43 -0
  237. package/templates/shared/src/components/ui/anims/shiny-text.tsx +58 -0
  238. package/templates/shared/src/components/ui/anims/shuffle-text.tsx +85 -0
  239. package/templates/shared/src/components/ui/anims/split-text.tsx +211 -0
  240. package/templates/shared/src/components/ui/anims/staggered-fade.tsx +133 -0
  241. package/templates/shared/src/components/ui/anims/text-scroll.tsx +111 -0
  242. package/templates/shared/src/components/ui/anims/typing-effect.tsx +112 -0
  243. package/templates/shared/src/components/ui/button-dusted-fluid/index.tsx +1521 -0
  244. package/templates/shared/src/components/ui/separator.tsx +85 -0
  245. package/templates/shared/src/hooks/useBodyScrollLock.ts +97 -0
  246. package/templates/shared/src/hooks/useClickOutside.ts +28 -0
  247. package/templates/shared/src/utilities/renderCustomCSS.ts +5 -0
  248. package/templates/shared/src/utilities/smoothScroll.ts +65 -0
@@ -0,0 +1,500 @@
1
+ 'use client'
2
+
3
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
4
+ import Link from 'next/link'
5
+ import {
6
+ Check,
7
+ DownloadCloud,
8
+ Home,
9
+ LayoutGrid,
10
+ MailCheck,
11
+ ShieldCheck,
12
+ Sparkles
13
+ } from 'lucide-react'
14
+ import { cn } from '@/utilities/ui'
15
+
16
+ type InfoPill = {
17
+ id?: string | null
18
+ label?: string | null
19
+ icon?: 'mail' | 'download' | 'shield' | null
20
+ }
21
+
22
+ type CtaLink = {
23
+ label?: string | null
24
+ href?: string | null
25
+ variant?: 'primary' | 'secondary' | null
26
+ icon?: 'home' | 'grid' | 'download' | null
27
+ }
28
+
29
+ type ThanksConfettiProps = {
30
+ sectionId?: string | null
31
+ customCSS?: string | null
32
+ headline?: string | null
33
+ description?: string | null
34
+ subDescription?: string | null
35
+ replayLabel?: string | null
36
+ brandLabel?: string | null
37
+ showBrandLabel?: boolean | null
38
+ showReplayButton?: boolean | null
39
+ autoPlayConfetti?: boolean | null
40
+ confettiDuration?: number | null
41
+ infoPills?: InfoPill[] | null
42
+ ctaLinks?: CtaLink[] | null
43
+ className?: string
44
+ disableInnerContainer?: boolean
45
+ }
46
+
47
+ type ConfettiParticle = {
48
+ x: number
49
+ y: number
50
+ vx: number
51
+ vy: number
52
+ size: number
53
+ rotation: number
54
+ rotationSpeed: number
55
+ color: string
56
+ shape: 'circle' | 'square'
57
+ life: number
58
+ maxLife: number
59
+ }
60
+
61
+ const CONFETTI_COLORS = ['#d6d3d1', '#a8a29e', '#10b981', '#6ee7b7', '#ffffff', '#f5f5f4']
62
+
63
+ const defaultInfoPills: Required<Pick<InfoPill, 'label' | 'icon'>>[] = [
64
+ { icon: 'mail', label: 'Confirmation sent' },
65
+ { icon: 'download', label: 'Files ready' },
66
+ { icon: 'shield', label: 'License activated' }
67
+ ]
68
+
69
+ const defaultCtaLinks: Required<Pick<CtaLink, 'label' | 'href' | 'variant' | 'icon'>>[] = [
70
+ { label: 'Back to Home', href: '/', variant: 'primary', icon: 'home' },
71
+ { label: 'Continue Browsing', href: '/components', variant: 'secondary', icon: 'grid' }
72
+ ]
73
+
74
+ function PillIcon({ icon }: { icon?: InfoPill['icon'] }) {
75
+ if (icon === 'download') return <DownloadCloud className="h-3.5 w-3.5" />
76
+ if (icon === 'shield') return <ShieldCheck className="h-3.5 w-3.5" />
77
+
78
+ return <MailCheck className="h-3.5 w-3.5" />
79
+ }
80
+
81
+ function CtaIcon({ icon }: { icon?: CtaLink['icon'] }) {
82
+ if (icon === 'grid') return <LayoutGrid className="h-4 w-4" />
83
+ if (icon === 'download') return <DownloadCloud className="h-4 w-4" />
84
+
85
+ return <Home className="h-4 w-4" />
86
+ }
87
+
88
+ function getSafeDuration(duration?: number | null) {
89
+ if (typeof duration !== 'number' || !Number.isFinite(duration)) return 3000
90
+ return Math.min(Math.max(duration, 1000), 8000)
91
+ }
92
+
93
+ function createParticles({
94
+ amount,
95
+ originX,
96
+ originY,
97
+ angle,
98
+ spread,
99
+ velocity,
100
+ width,
101
+ height
102
+ }: {
103
+ amount: number
104
+ originX: number
105
+ originY: number
106
+ angle?: number
107
+ spread: number
108
+ velocity: number
109
+ width: number
110
+ height: number
111
+ }): ConfettiParticle[] {
112
+ return Array.from({ length: amount }, () => {
113
+ const baseAngle = typeof angle === 'number' ? angle : Math.random() * 360
114
+ const randomAngle = (baseAngle - spread / 2 + Math.random() * spread) * (Math.PI / 180)
115
+ const speed = velocity * (0.45 + Math.random() * 0.75)
116
+
117
+ return {
118
+ x: originX * width,
119
+ y: originY * height,
120
+ vx: Math.cos(randomAngle) * speed,
121
+ vy: Math.sin(randomAngle) * speed,
122
+ size: 4 + Math.random() * 7,
123
+ rotation: Math.random() * Math.PI,
124
+ rotationSpeed: -0.22 + Math.random() * 0.44,
125
+ color: CONFETTI_COLORS[Math.floor(Math.random() * CONFETTI_COLORS.length)] ?? '#ffffff',
126
+ shape: Math.random() > 0.5 ? 'circle' : 'square',
127
+ life: 0,
128
+ maxLife: 90 + Math.random() * 70
129
+ }
130
+ })
131
+ }
132
+
133
+ export function DDThanks({
134
+ sectionId,
135
+ headline = 'Thank you! 🎉',
136
+ description = 'Your order has been confirmed and is on its way.',
137
+ subDescription = "We've sent a confirmation email with your download links and license keys. Check your inbox — and maybe your spam folder too.",
138
+ replayLabel = 'Replay confetti',
139
+ brandLabel = 'DesignsDusted',
140
+ showBrandLabel = true,
141
+ showReplayButton = true,
142
+ autoPlayConfetti = true,
143
+ confettiDuration = 3000,
144
+ infoPills,
145
+ ctaLinks,
146
+ className
147
+ }: ThanksConfettiProps) {
148
+ const hasRun = useRef(false)
149
+ const canvasRef = useRef<HTMLCanvasElement | null>(null)
150
+ const animationRef = useRef<number | null>(null)
151
+ const particlesRef = useRef<ConfettiParticle[]>([])
152
+ const [visible, setVisible] = useState(false)
153
+
154
+ const pills = useMemo(() => {
155
+ const source = infoPills?.length ? infoPills : defaultInfoPills
156
+ return source.filter((pill) => pill.label)
157
+ }, [infoPills])
158
+
159
+ const links = useMemo(() => {
160
+ const source = ctaLinks?.length ? ctaLinks : defaultCtaLinks
161
+ return source.filter((link) => link.label && link.href)
162
+ }, [ctaLinks])
163
+
164
+ const stopAnimation = useCallback(() => {
165
+ if (animationRef.current) {
166
+ cancelAnimationFrame(animationRef.current)
167
+ animationRef.current = null
168
+ }
169
+ }, [])
170
+
171
+ const fireConfetti = useCallback(() => {
172
+ const canvas = canvasRef.current
173
+ const ctx = canvas?.getContext('2d')
174
+ if (!canvas || !ctx) return
175
+
176
+ const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
177
+ if (reducedMotion) return
178
+
179
+ const pixelRatio = Math.min(window.devicePixelRatio || 1, 2)
180
+ const width = window.innerWidth
181
+ const height = window.innerHeight
182
+
183
+ canvas.width = width * pixelRatio
184
+ canvas.height = height * pixelRatio
185
+ canvas.style.width = `${width}px`
186
+ canvas.style.height = `${height}px`
187
+ ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0)
188
+
189
+ const duration = getSafeDuration(confettiDuration)
190
+ const end = performance.now() + duration
191
+
192
+ particlesRef.current = [
193
+ ...particlesRef.current,
194
+ ...createParticles({
195
+ amount: 120,
196
+ originX: 0.5,
197
+ originY: 0.5,
198
+ spread: 100,
199
+ velocity: 20,
200
+ width,
201
+ height
202
+ }),
203
+ ...createParticles({
204
+ amount: 60,
205
+ originX: 0,
206
+ originY: 0.6,
207
+ angle: -35,
208
+ spread: 70,
209
+ velocity: 18,
210
+ width,
211
+ height
212
+ }),
213
+ ...createParticles({
214
+ amount: 60,
215
+ originX: 1,
216
+ originY: 0.6,
217
+ angle: 215,
218
+ spread: 70,
219
+ velocity: 18,
220
+ width,
221
+ height
222
+ })
223
+ ]
224
+
225
+ stopAnimation()
226
+
227
+ const frame = (now: number) => {
228
+ ctx.clearRect(0, 0, width, height)
229
+
230
+ if (now < end && Math.random() > 0.35) {
231
+ particlesRef.current.push(
232
+ ...createParticles({
233
+ amount: 2,
234
+ originX: 0,
235
+ originY: 0.3,
236
+ angle: -25,
237
+ spread: 55,
238
+ velocity: 10,
239
+ width,
240
+ height
241
+ }),
242
+ ...createParticles({
243
+ amount: 2,
244
+ originX: 1,
245
+ originY: 0.3,
246
+ angle: 205,
247
+ spread: 55,
248
+ velocity: 10,
249
+ width,
250
+ height
251
+ })
252
+ )
253
+ }
254
+
255
+ particlesRef.current = particlesRef.current.filter((particle) => {
256
+ particle.life += 1
257
+ particle.x += particle.vx
258
+ particle.y += particle.vy
259
+ particle.vy += 0.28
260
+ particle.vx *= 0.992
261
+ particle.rotation += particle.rotationSpeed
262
+
263
+ const opacity = Math.max(0, 1 - particle.life / particle.maxLife)
264
+ if (opacity <= 0 || particle.y > height + 40) return false
265
+
266
+ ctx.save()
267
+ ctx.globalAlpha = opacity
268
+ ctx.translate(particle.x, particle.y)
269
+ ctx.rotate(particle.rotation)
270
+ ctx.fillStyle = particle.color
271
+
272
+ if (particle.shape === 'circle') {
273
+ ctx.beginPath()
274
+ ctx.arc(0, 0, particle.size * 0.5, 0, Math.PI * 2)
275
+ ctx.fill()
276
+ } else {
277
+ ctx.fillRect(-particle.size / 2, -particle.size / 2, particle.size, particle.size)
278
+ }
279
+
280
+ ctx.restore()
281
+ return true
282
+ })
283
+
284
+ if (particlesRef.current.length || now < end) {
285
+ animationRef.current = requestAnimationFrame(frame)
286
+ } else {
287
+ ctx.clearRect(0, 0, width, height)
288
+ animationRef.current = null
289
+ }
290
+ }
291
+
292
+ animationRef.current = requestAnimationFrame(frame)
293
+ }, [confettiDuration, stopAnimation])
294
+
295
+ useEffect(() => {
296
+ if (hasRun.current) return
297
+ hasRun.current = true
298
+
299
+ const timer = window.setTimeout(() => {
300
+ setVisible(true)
301
+ if (autoPlayConfetti !== false) fireConfetti()
302
+ }, 200)
303
+
304
+ return () => window.clearTimeout(timer)
305
+ }, [autoPlayConfetti, fireConfetti])
306
+
307
+ useEffect(() => {
308
+ return () => {
309
+ stopAnimation()
310
+ particlesRef.current = []
311
+ }
312
+ }, [stopAnimation])
313
+
314
+ return (
315
+ <section
316
+ id={sectionId ?? undefined}
317
+ className={cn(
318
+ 'thanks-confetti-section relative flex min-h-screen w-full flex-col items-center justify-center overflow-hidden bg-stone-950 px-4 py-24 text-center',
319
+ className
320
+ )}
321
+ >
322
+ <canvas
323
+ ref={canvasRef}
324
+ aria-hidden="true"
325
+ className="pointer-events-none fixed inset-0 z-[60] h-screen w-screen"
326
+ />
327
+
328
+ <div className="pointer-events-none absolute inset-0">
329
+ <div
330
+ className="absolute inset-0 opacity-20"
331
+ style={{
332
+ backgroundImage:
333
+ 'radial-gradient(circle at 20% 50%, rgba(16,185,129,0.12) 0%, transparent 50%), radial-gradient(circle at 80% 20%, rgba(255,255,255,0.05) 0%, transparent 50%)'
334
+ }}
335
+ />
336
+ <div
337
+ className="absolute inset-0 opacity-5"
338
+ style={{
339
+ backgroundImage:
340
+ 'linear-gradient(rgba(255,255,255,0.5) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.5) 1px, transparent 1px)',
341
+ backgroundSize: '60px 60px'
342
+ }}
343
+ />
344
+ </div>
345
+
346
+ <div
347
+ className="relative z-10 flex w-full max-w-lg flex-col items-center px-2"
348
+ style={{
349
+ opacity: visible ? 1 : 0,
350
+ transform: visible ? 'translateY(0) scale(1)' : 'translateY(32px) scale(0.96)',
351
+ transition:
352
+ 'opacity 0.7s cubic-bezier(0.34,1.56,0.64,1), transform 0.7s cubic-bezier(0.34,1.56,0.64,1)'
353
+ }}
354
+ >
355
+ <div className="relative mb-8">
356
+ <div
357
+ className="flex h-24 w-24 items-center justify-center rounded-full"
358
+ style={{
359
+ background: 'linear-gradient(135deg, #10b981 0%, #6ee7b7 100%)',
360
+ boxShadow: '0 0 60px rgba(16,185,129,0.35), 0 0 120px rgba(16,185,129,0.15)',
361
+ opacity: visible ? 1 : 0,
362
+ transform: visible ? 'scale(1)' : 'scale(0.5)',
363
+ transition:
364
+ 'opacity 0.5s ease 0.3s, transform 0.6s cubic-bezier(0.34,1.56,0.64,1) 0.3s'
365
+ }}
366
+ >
367
+ <Check className="h-11 w-11 stroke-[3px] text-white" />
368
+ </div>
369
+ <div
370
+ className="absolute inset-0 rounded-full bg-emerald-500/20"
371
+ style={{
372
+ animation: visible
373
+ ? 'thanks-confetti-ping 2s cubic-bezier(0,0,0.2,1) infinite 0.8s'
374
+ : 'none'
375
+ }}
376
+ />
377
+ </div>
378
+
379
+ <div
380
+ style={{
381
+ opacity: visible ? 1 : 0,
382
+ transform: visible ? 'translateY(0)' : 'translateY(20px)',
383
+ transition: 'opacity 0.6s ease 0.5s, transform 0.6s ease 0.5s'
384
+ }}
385
+ >
386
+ {headline && (
387
+ <h1 className="mb-3 text-4xl font-bold tracking-tight text-white md:text-5xl">
388
+ {headline}
389
+ </h1>
390
+ )}
391
+
392
+ {description && (
393
+ <p className="mb-2 text-lg leading-relaxed text-stone-400">{description}</p>
394
+ )}
395
+
396
+ {subDescription && (
397
+ <p className="mb-10 text-sm leading-relaxed text-stone-500">{subDescription}</p>
398
+ )}
399
+ </div>
400
+
401
+ {pills.length > 0 && (
402
+ <div
403
+ className="mb-10 flex flex-wrap items-center justify-center gap-3"
404
+ style={{
405
+ opacity: visible ? 1 : 0,
406
+ transform: visible ? 'translateY(0)' : 'translateY(16px)',
407
+ transition: 'opacity 0.6s ease 0.7s, transform 0.6s ease 0.7s'
408
+ }}
409
+ >
410
+ {pills.map((item, index) => (
411
+ <div
412
+ key={
413
+ 'id' in item ? (item.id ?? `${item.label}-${index}`) : `${item.label}-${index}`
414
+ }
415
+ className="flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-4 py-2"
416
+ >
417
+ <span className="flex h-4 w-4 items-center justify-center text-emerald-400">
418
+ <PillIcon icon={item.icon} />
419
+ </span>
420
+ <span className="whitespace-nowrap text-sm text-stone-400">{item.label}</span>
421
+ </div>
422
+ ))}
423
+ </div>
424
+ )}
425
+
426
+ {links.length > 0 && (
427
+ <div
428
+ className="flex w-full flex-col gap-3 sm:flex-row"
429
+ style={{
430
+ opacity: visible ? 1 : 0,
431
+ transform: visible ? 'translateY(0)' : 'translateY(16px)',
432
+ transition: 'opacity 0.6s ease 0.9s, transform 0.6s ease 0.9s'
433
+ }}
434
+ >
435
+ {links.map((link, index) => {
436
+ const isPrimary =
437
+ (link.variant ?? (index === 0 ? 'primary' : 'secondary')) === 'primary'
438
+
439
+ return (
440
+ <Link
441
+ key={`${link.href}-${index}`}
442
+ href={link.href ?? '#'}
443
+ className={cn(
444
+ 'inline-flex flex-1 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-lg px-6 py-3.5 text-sm font-semibold transition-colors',
445
+ isPrimary
446
+ ? 'bg-white text-stone-900 hover:bg-stone-100'
447
+ : 'border border-white/15 bg-white/10 text-white hover:bg-white/20'
448
+ )}
449
+ >
450
+ <CtaIcon icon={link.icon} />
451
+ {link.label}
452
+ </Link>
453
+ )
454
+ })}
455
+ </div>
456
+ )}
457
+
458
+ {showReplayButton !== false && replayLabel && (
459
+ <div
460
+ className="mt-8"
461
+ style={{
462
+ opacity: visible ? 1 : 0,
463
+ transition: 'opacity 0.6s ease 1.1s'
464
+ }}
465
+ >
466
+ <button
467
+ type="button"
468
+ onClick={fireConfetti}
469
+ className="flex cursor-pointer items-center gap-1.5 text-xs text-stone-600 transition-colors hover:text-stone-400"
470
+ >
471
+ <Sparkles className="h-3 w-3" />
472
+ {replayLabel}
473
+ </button>
474
+ </div>
475
+ )}
476
+ </div>
477
+
478
+ {showBrandLabel !== false && brandLabel && (
479
+ <div
480
+ className="absolute bottom-8 left-1/2 z-10 -translate-x-1/2 text-xs font-black uppercase tracking-[0.35em] text-stone-500"
481
+ style={{
482
+ opacity: visible ? 0.4 : 0,
483
+ transition: 'opacity 0.6s ease 1.2s'
484
+ }}
485
+ >
486
+ {brandLabel}
487
+ </div>
488
+ )}
489
+
490
+ <style>{`
491
+ @keyframes thanks-confetti-ping {
492
+ 75%, 100% {
493
+ transform: scale(2);
494
+ opacity: 0;
495
+ }
496
+ }
497
+ `}</style>
498
+ </section>
499
+ )
500
+ }
@@ -0,0 +1,4 @@
1
+ # DD-Thanks
2
+
3
+ Portable first-pass conversion of `ThanksConfetti` from ROUND-TWO-CONVERSION. Project-specific roots and nested unconverted block dependencies were intentionally replaced with local rendering so the template can install into a clean Payload project.
4
+