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,777 @@
1
+ 'use client'
2
+
3
+ import React, { useCallback, useEffect, useRef, useState } from 'react'
4
+ import Image from 'next/image'
5
+ import Link from 'next/link'
6
+ import { gsap } from 'gsap'
7
+
8
+ export interface BentoCardMedia {
9
+ url?: string | null
10
+ alt?: string | null
11
+ width?: number | null
12
+ height?: number | null
13
+ }
14
+
15
+ export interface BentoCardLink {
16
+ type?: 'internal' | 'external' | null
17
+ url?: string | null
18
+ reference?: { slug?: string | null; value?: { slug?: string | null } } | string | null
19
+ newTab?: boolean | null
20
+ }
21
+
22
+ export interface BentoCardData {
23
+ color?: string | null
24
+ title?: string | null
25
+ description?: string | null
26
+ label?: string | null
27
+ id?: string | null
28
+ media?: BentoCardMedia | string | null
29
+ link?: BentoCardLink | null
30
+ }
31
+
32
+ export interface MagicBentoBlockProps {
33
+ blockType?: 'magicBentoBlock'
34
+ blockName?: string
35
+ textAutoHide?: boolean
36
+ enableStars?: boolean
37
+ enableSpotlight?: boolean
38
+ enableBorderGlow?: boolean
39
+ disableAnimations?: boolean
40
+ enableTilt?: boolean
41
+ clickEffect?: boolean
42
+ enableMagnetism?: boolean
43
+ spotlightRadius?: number
44
+ particleCount?: number
45
+ glowColor?: string
46
+ cards?: BentoCardData[]
47
+ sectionId?: string
48
+ customCSS?: string
49
+ }
50
+
51
+ const DEFAULT_PARTICLE_COUNT = 12
52
+ const DEFAULT_SPOTLIGHT_RADIUS = 300
53
+ const DEFAULT_GLOW_COLOR = '132, 0, 255'
54
+ const MOBILE_BREAKPOINT = 768
55
+
56
+ const FALLBACK_CARDS: BentoCardData[] = [
57
+ { color: '#120F17', title: 'Analytics', description: 'Track user behavior', label: 'Insights' },
58
+ { color: '#120F17', title: 'Dashboard', description: 'Centralized data view', label: 'Overview' },
59
+ {
60
+ color: '#120F17',
61
+ title: 'Collaboration',
62
+ description: 'Work together seamlessly',
63
+ label: 'Teamwork'
64
+ },
65
+ {
66
+ color: '#120F17',
67
+ title: 'Automation',
68
+ description: 'Streamline workflows',
69
+ label: 'Efficiency'
70
+ },
71
+ {
72
+ color: '#120F17',
73
+ title: 'Integration',
74
+ description: 'Connect favorite tools',
75
+ label: 'Connectivity'
76
+ },
77
+ {
78
+ color: '#120F17',
79
+ title: 'Security',
80
+ description: 'Enterprise-grade protection',
81
+ label: 'Protection'
82
+ }
83
+ ]
84
+
85
+ const resolveCardHref = (link?: BentoCardLink | null): string | null => {
86
+ if (!link) return null
87
+
88
+ if (link.type === 'internal') {
89
+ if (typeof link.reference === 'object') {
90
+ const slug = link.reference?.slug || link.reference?.value?.slug
91
+ return slug ? `/${slug}` : null
92
+ }
93
+
94
+ return typeof link.reference === 'string' ? `/${link.reference}` : null
95
+ }
96
+
97
+ return link.url || null
98
+ }
99
+
100
+ const createParticleElement = (x: number, y: number, color: string): HTMLDivElement => {
101
+ const el = document.createElement('div')
102
+ el.className = 'magic-bento-particle'
103
+
104
+ Object.assign(el.style, {
105
+ position: 'absolute',
106
+ width: '4px',
107
+ height: '4px',
108
+ borderRadius: '50%',
109
+ background: `rgba(${color}, 1)`,
110
+ boxShadow: `0 0 6px rgba(${color}, 0.6)`,
111
+ pointerEvents: 'none',
112
+ zIndex: '100',
113
+ left: `${x}px`,
114
+ top: `${y}px`
115
+ })
116
+
117
+ return el
118
+ }
119
+
120
+ const calculateSpotlightValues = (radius: number) => ({
121
+ proximity: radius * 0.5,
122
+ fadeDistance: radius * 0.75
123
+ })
124
+
125
+ const updateCardGlowProperties = (
126
+ card: HTMLElement,
127
+ mouseX: number,
128
+ mouseY: number,
129
+ glow: number,
130
+ radius: number
131
+ ) => {
132
+ const rect = card.getBoundingClientRect()
133
+
134
+ card.style.setProperty('--glow-x', `${((mouseX - rect.left) / rect.width) * 100}%`)
135
+ card.style.setProperty('--glow-y', `${((mouseY - rect.top) / rect.height) * 100}%`)
136
+ card.style.setProperty('--glow-intensity', glow.toString())
137
+ card.style.setProperty('--glow-radius', `${radius}px`)
138
+ }
139
+
140
+ const useMobileDetection = () => {
141
+ const [isMobile, setIsMobile] = useState(false)
142
+
143
+ useEffect(() => {
144
+ const check = () => setIsMobile(window.innerWidth <= MOBILE_BREAKPOINT)
145
+
146
+ check()
147
+ window.addEventListener('resize', check)
148
+
149
+ return () => window.removeEventListener('resize', check)
150
+ }, [])
151
+
152
+ return isMobile
153
+ }
154
+
155
+ const ParticleCard: React.FC<{
156
+ children: React.ReactNode
157
+ className?: string
158
+ style?: React.CSSProperties
159
+ disableAnimations?: boolean
160
+ particleCount?: number
161
+ glowColor?: string
162
+ enableTilt?: boolean
163
+ clickEffect?: boolean
164
+ enableMagnetism?: boolean
165
+ href?: string | null
166
+ newTab?: boolean | null
167
+ }> = ({
168
+ children,
169
+ className = '',
170
+ style,
171
+ disableAnimations = false,
172
+ particleCount = DEFAULT_PARTICLE_COUNT,
173
+ glowColor = DEFAULT_GLOW_COLOR,
174
+ enableTilt = true,
175
+ clickEffect = false,
176
+ enableMagnetism = false,
177
+ href,
178
+ newTab
179
+ }) => {
180
+ const cardRef = useRef<HTMLElement | null>(null)
181
+ const particlesRef = useRef<HTMLDivElement[]>([])
182
+ const timeoutsRef = useRef<ReturnType<typeof setTimeout>[]>([])
183
+ const isHoveredRef = useRef(false)
184
+ const memoizedParticles = useRef<HTMLDivElement[]>([])
185
+ const particlesInitialized = useRef(false)
186
+ const magnetismAnimationRef = useRef<gsap.core.Tween | null>(null)
187
+
188
+ const initializeParticles = useCallback(() => {
189
+ if (particlesInitialized.current || !cardRef.current) return
190
+
191
+ const { width, height } = cardRef.current.getBoundingClientRect()
192
+
193
+ memoizedParticles.current = Array.from({ length: particleCount }, () =>
194
+ createParticleElement(Math.random() * width, Math.random() * height, glowColor)
195
+ )
196
+
197
+ particlesInitialized.current = true
198
+ }, [particleCount, glowColor])
199
+
200
+ const clearAllParticles = useCallback(() => {
201
+ timeoutsRef.current.forEach(clearTimeout)
202
+ timeoutsRef.current = []
203
+
204
+ magnetismAnimationRef.current?.kill()
205
+
206
+ particlesRef.current.forEach((particle) => {
207
+ gsap.to(particle, {
208
+ scale: 0,
209
+ opacity: 0,
210
+ duration: 0.3,
211
+ ease: 'back.in(1.7)',
212
+ onComplete: () => particle.parentNode?.removeChild(particle)
213
+ })
214
+ })
215
+
216
+ particlesRef.current = []
217
+ }, [])
218
+
219
+ const animateParticles = useCallback(() => {
220
+ if (!cardRef.current || !isHoveredRef.current) return
221
+
222
+ if (!particlesInitialized.current) initializeParticles()
223
+
224
+ memoizedParticles.current.forEach((particle, index) => {
225
+ const id = setTimeout(() => {
226
+ if (!isHoveredRef.current || !cardRef.current) return
227
+
228
+ const clone = particle.cloneNode(true) as HTMLDivElement
229
+
230
+ cardRef.current.appendChild(clone)
231
+ particlesRef.current.push(clone)
232
+
233
+ gsap.fromTo(
234
+ clone,
235
+ { scale: 0, opacity: 0 },
236
+ { scale: 1, opacity: 1, duration: 0.3, ease: 'back.out(1.7)' }
237
+ )
238
+
239
+ gsap.to(clone, {
240
+ x: (Math.random() - 0.5) * 100,
241
+ y: (Math.random() - 0.5) * 100,
242
+ rotation: Math.random() * 360,
243
+ duration: 2 + Math.random() * 2,
244
+ ease: 'none',
245
+ repeat: -1,
246
+ yoyo: true
247
+ })
248
+
249
+ gsap.to(clone, {
250
+ opacity: 0.3,
251
+ duration: 1.5,
252
+ ease: 'power2.inOut',
253
+ repeat: -1,
254
+ yoyo: true
255
+ })
256
+ }, index * 100)
257
+
258
+ timeoutsRef.current.push(id)
259
+ })
260
+ }, [initializeParticles])
261
+
262
+ useEffect(() => {
263
+ if (disableAnimations || !cardRef.current) return
264
+
265
+ const el = cardRef.current
266
+
267
+ const onEnter = () => {
268
+ isHoveredRef.current = true
269
+ animateParticles()
270
+
271
+ if (enableTilt) {
272
+ gsap.to(el, {
273
+ rotateX: 5,
274
+ rotateY: 5,
275
+ duration: 0.3,
276
+ ease: 'power2.out',
277
+ transformPerspective: 1000
278
+ })
279
+ }
280
+ }
281
+
282
+ const onLeave = () => {
283
+ isHoveredRef.current = false
284
+ clearAllParticles()
285
+
286
+ if (enableTilt) {
287
+ gsap.to(el, {
288
+ rotateX: 0,
289
+ rotateY: 0,
290
+ duration: 0.3,
291
+ ease: 'power2.out'
292
+ })
293
+ }
294
+
295
+ if (enableMagnetism) {
296
+ gsap.to(el, {
297
+ x: 0,
298
+ y: 0,
299
+ duration: 0.3,
300
+ ease: 'power2.out'
301
+ })
302
+ }
303
+ }
304
+
305
+ const onMove = (e: MouseEvent) => {
306
+ if (!enableTilt && !enableMagnetism) return
307
+
308
+ const rect = el.getBoundingClientRect()
309
+ const x = e.clientX - rect.left
310
+ const y = e.clientY - rect.top
311
+ const cx = rect.width / 2
312
+ const cy = rect.height / 2
313
+
314
+ if (enableTilt) {
315
+ gsap.to(el, {
316
+ rotateX: ((y - cy) / cy) * -10,
317
+ rotateY: ((x - cx) / cx) * 10,
318
+ duration: 0.1,
319
+ ease: 'power2.out',
320
+ transformPerspective: 1000
321
+ })
322
+ }
323
+
324
+ if (enableMagnetism) {
325
+ magnetismAnimationRef.current = gsap.to(el, {
326
+ x: (x - cx) * 0.05,
327
+ y: (y - cy) * 0.05,
328
+ duration: 0.3,
329
+ ease: 'power2.out'
330
+ })
331
+ }
332
+ }
333
+
334
+ const onClick = (e: MouseEvent) => {
335
+ if (!clickEffect) return
336
+
337
+ const rect = el.getBoundingClientRect()
338
+ const x = e.clientX - rect.left
339
+ const y = e.clientY - rect.top
340
+
341
+ const maxDist = Math.max(
342
+ Math.hypot(x, y),
343
+ Math.hypot(x - rect.width, y),
344
+ Math.hypot(x, y - rect.height),
345
+ Math.hypot(x - rect.width, y - rect.height)
346
+ )
347
+
348
+ const ripple = document.createElement('div')
349
+
350
+ Object.assign(ripple.style, {
351
+ position: 'absolute',
352
+ width: `${maxDist * 2}px`,
353
+ height: `${maxDist * 2}px`,
354
+ borderRadius: '50%',
355
+ background: `radial-gradient(circle, rgba(${glowColor}, 0.4) 0%, rgba(${glowColor}, 0.2) 30%, transparent 70%)`,
356
+ left: `${x - maxDist}px`,
357
+ top: `${y - maxDist}px`,
358
+ pointerEvents: 'none',
359
+ zIndex: '1000'
360
+ })
361
+
362
+ el.appendChild(ripple)
363
+
364
+ gsap.fromTo(
365
+ ripple,
366
+ { scale: 0, opacity: 1 },
367
+ {
368
+ scale: 1,
369
+ opacity: 0,
370
+ duration: 0.8,
371
+ ease: 'power2.out',
372
+ onComplete: () => ripple.remove()
373
+ }
374
+ )
375
+ }
376
+
377
+ el.addEventListener('mouseenter', onEnter)
378
+ el.addEventListener('mouseleave', onLeave)
379
+ el.addEventListener('mousemove', onMove)
380
+ el.addEventListener('click', onClick)
381
+
382
+ return () => {
383
+ isHoveredRef.current = false
384
+ el.removeEventListener('mouseenter', onEnter)
385
+ el.removeEventListener('mouseleave', onLeave)
386
+ el.removeEventListener('mousemove', onMove)
387
+ el.removeEventListener('click', onClick)
388
+ clearAllParticles()
389
+ }
390
+ }, [
391
+ animateParticles,
392
+ clearAllParticles,
393
+ disableAnimations,
394
+ enableTilt,
395
+ enableMagnetism,
396
+ clickEffect,
397
+ glowColor
398
+ ])
399
+
400
+ const sharedClassName = `${className} relative block overflow-hidden`
401
+ const sharedStyle = { ...style, position: 'relative', overflow: 'hidden' } as React.CSSProperties
402
+
403
+ if (href) {
404
+ return (
405
+ <Link
406
+ ref={(node) => {
407
+ cardRef.current = node
408
+ }}
409
+ href={href}
410
+ target={newTab ? '_blank' : undefined}
411
+ rel={newTab ? 'noopener noreferrer' : undefined}
412
+ className={sharedClassName}
413
+ style={sharedStyle}
414
+ >
415
+ {children}
416
+ </Link>
417
+ )
418
+ }
419
+
420
+ return (
421
+ <div
422
+ ref={(node) => {
423
+ cardRef.current = node
424
+ }}
425
+ className={sharedClassName}
426
+ style={sharedStyle}
427
+ >
428
+ {children}
429
+ </div>
430
+ )
431
+ }
432
+
433
+ const GlobalSpotlight: React.FC<{
434
+ gridRef: React.RefObject<HTMLDivElement | null>
435
+ disableAnimations?: boolean
436
+ enabled?: boolean
437
+ spotlightRadius?: number
438
+ glowColor?: string
439
+ }> = ({
440
+ gridRef,
441
+ disableAnimations = false,
442
+ enabled = true,
443
+ spotlightRadius = DEFAULT_SPOTLIGHT_RADIUS,
444
+ glowColor = DEFAULT_GLOW_COLOR
445
+ }) => {
446
+ const spotlightRef = useRef<HTMLDivElement | null>(null)
447
+
448
+ useEffect(() => {
449
+ if (disableAnimations || !gridRef?.current || !enabled) return
450
+
451
+ const spotlight = document.createElement('div')
452
+ spotlight.className = 'magic-bento-spotlight'
453
+
454
+ Object.assign(spotlight.style, {
455
+ position: 'fixed',
456
+ width: '800px',
457
+ height: '800px',
458
+ borderRadius: '50%',
459
+ pointerEvents: 'none',
460
+ background: `radial-gradient(circle,
461
+ rgba(${glowColor}, 0.15) 0%,
462
+ rgba(${glowColor}, 0.08) 15%,
463
+ rgba(${glowColor}, 0.04) 25%,
464
+ rgba(${glowColor}, 0.02) 40%,
465
+ rgba(${glowColor}, 0.01) 65%,
466
+ transparent 70%)`,
467
+ zIndex: '200',
468
+ opacity: '0',
469
+ transform: 'translate(-50%, -50%)',
470
+ // @ts-ignore - styles
471
+ mixBlendMode: 'screen'
472
+ })
473
+
474
+ document.body.appendChild(spotlight)
475
+ spotlightRef.current = spotlight
476
+
477
+ const onMove = (e: MouseEvent) => {
478
+ if (!spotlightRef.current || !gridRef.current) return
479
+
480
+ const section = gridRef.current.closest('.magic-bento-section')
481
+ const rect = section?.getBoundingClientRect()
482
+
483
+ const inside =
484
+ rect &&
485
+ e.clientX >= rect.left &&
486
+ e.clientX <= rect.right &&
487
+ e.clientY >= rect.top &&
488
+ e.clientY <= rect.bottom
489
+
490
+ const cards = gridRef.current.querySelectorAll('.magic-bento-card')
491
+
492
+ if (!inside) {
493
+ gsap.to(spotlightRef.current, {
494
+ opacity: 0,
495
+ duration: 0.3,
496
+ ease: 'power2.out'
497
+ })
498
+
499
+ cards.forEach((card) => {
500
+ ;(card as HTMLElement).style.setProperty('--glow-intensity', '0')
501
+ })
502
+
503
+ return
504
+ }
505
+
506
+ const { proximity, fadeDistance } = calculateSpotlightValues(spotlightRadius)
507
+ let minDistance = Infinity
508
+
509
+ cards.forEach((card) => {
510
+ const el = card as HTMLElement
511
+ const cr = el.getBoundingClientRect()
512
+ const cx = cr.left + cr.width / 2
513
+ const cy = cr.top + cr.height / 2
514
+
515
+ const dist = Math.max(
516
+ 0,
517
+ Math.hypot(e.clientX - cx, e.clientY - cy) - Math.max(cr.width, cr.height) / 2
518
+ )
519
+
520
+ minDistance = Math.min(minDistance, dist)
521
+
522
+ const intensity =
523
+ dist <= proximity
524
+ ? 1
525
+ : dist <= fadeDistance
526
+ ? (fadeDistance - dist) / (fadeDistance - proximity)
527
+ : 0
528
+
529
+ updateCardGlowProperties(el, e.clientX, e.clientY, intensity, spotlightRadius)
530
+ })
531
+
532
+ gsap.to(spotlightRef.current, {
533
+ left: e.clientX,
534
+ top: e.clientY,
535
+ duration: 0.1,
536
+ ease: 'power2.out'
537
+ })
538
+
539
+ const targetOpacity =
540
+ minDistance <= proximity
541
+ ? 0.8
542
+ : minDistance <= fadeDistance
543
+ ? ((fadeDistance - minDistance) / (fadeDistance - proximity)) * 0.8
544
+ : 0
545
+
546
+ gsap.to(spotlightRef.current, {
547
+ opacity: targetOpacity,
548
+ duration: targetOpacity > 0 ? 0.2 : 0.5,
549
+ ease: 'power2.out'
550
+ })
551
+ }
552
+
553
+ const onLeave = () => {
554
+ gridRef.current?.querySelectorAll('.magic-bento-card').forEach((card) => {
555
+ ;(card as HTMLElement).style.setProperty('--glow-intensity', '0')
556
+ })
557
+
558
+ if (spotlightRef.current) {
559
+ gsap.to(spotlightRef.current, {
560
+ opacity: 0,
561
+ duration: 0.3,
562
+ ease: 'power2.out'
563
+ })
564
+ }
565
+ }
566
+
567
+ document.addEventListener('mousemove', onMove)
568
+ document.addEventListener('mouseleave', onLeave)
569
+
570
+ return () => {
571
+ document.removeEventListener('mousemove', onMove)
572
+ document.removeEventListener('mouseleave', onLeave)
573
+ spotlightRef.current?.parentNode?.removeChild(spotlightRef.current)
574
+ }
575
+ }, [gridRef, disableAnimations, enabled, spotlightRadius, glowColor])
576
+
577
+ return null
578
+ }
579
+
580
+ export const DDMagicBento: React.FC<MagicBentoBlockProps> = ({
581
+ textAutoHide = true,
582
+ enableStars = true,
583
+ enableSpotlight = true,
584
+ enableBorderGlow = true,
585
+ disableAnimations = false,
586
+ spotlightRadius = DEFAULT_SPOTLIGHT_RADIUS,
587
+ particleCount = DEFAULT_PARTICLE_COUNT,
588
+ enableTilt = false,
589
+ glowColor = DEFAULT_GLOW_COLOR,
590
+ clickEffect = true,
591
+ enableMagnetism = true,
592
+ cards,
593
+ sectionId,
594
+ customCSS
595
+ }) => {
596
+ const gridRef = useRef<HTMLDivElement>(null)
597
+ const isMobile = useMobileDetection()
598
+ const shouldDisableAnimations = disableAnimations || isMobile
599
+ const cardData = cards && cards.length > 0 ? cards : FALLBACK_CARDS
600
+
601
+ const baseCardCls = [
602
+ 'magic-bento-card group',
603
+ 'flex flex-col justify-between relative aspect-[4/3] min-h-[240px] max-h-[240px] w-full max-w-full p-5 rounded-[20px]',
604
+ 'border border-solid font-light overflow-hidden no-underline',
605
+ 'transition-all duration-300 ease-in-out',
606
+ 'hover:-translate-y-0.5 hover:shadow-[0_8px_25px_rgba(0,0,0,0.15)]',
607
+ enableBorderGlow ? 'magic-bento-card--border-glow' : ''
608
+ ]
609
+ .filter(Boolean)
610
+ .join(' ')
611
+
612
+ return (
613
+ <>
614
+ <style>{`
615
+ ${customCSS ?? ''}
616
+
617
+ .magic-bento-section {
618
+ --glow-x: 50%;
619
+ --glow-y: 50%;
620
+ --glow-intensity: 0;
621
+ --glow-radius: 200px;
622
+ --glow-color: ${glowColor};
623
+ --border-color: #2F293A;
624
+ --background-dark: #120F17;
625
+ --white: hsl(0, 0%, 100%);
626
+ }
627
+
628
+ .magic-bento-card--border-glow::after {
629
+ content: '';
630
+ position: absolute;
631
+ inset: 0;
632
+ padding: 6px;
633
+ background: radial-gradient(
634
+ var(--glow-radius) circle at var(--glow-x) var(--glow-y),
635
+ rgba(${glowColor}, calc(var(--glow-intensity) * 0.8)) 0%,
636
+ rgba(${glowColor}, calc(var(--glow-intensity) * 0.4)) 30%,
637
+ transparent 60%
638
+ );
639
+ border-radius: inherit;
640
+ -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
641
+ -webkit-mask-composite: xor;
642
+ mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
643
+ mask-composite: exclude;
644
+ pointer-events: none;
645
+ z-index: 1;
646
+ }
647
+
648
+ .magic-bento-card--border-glow:hover {
649
+ box-shadow: 0 4px 20px rgba(46, 24, 78, 0.4), 0 0 30px rgba(${glowColor}, 0.2);
650
+ }
651
+
652
+ .magic-bento-particle::before {
653
+ content: '';
654
+ position: absolute;
655
+ inset: -2px;
656
+ background: rgba(${glowColor}, 0.2);
657
+ border-radius: 50%;
658
+ z-index: -1;
659
+ }
660
+ `}</style>
661
+
662
+ {enableSpotlight && (
663
+ <GlobalSpotlight
664
+ gridRef={gridRef}
665
+ disableAnimations={shouldDisableAnimations}
666
+ enabled={enableSpotlight}
667
+ spotlightRadius={spotlightRadius}
668
+ glowColor={glowColor}
669
+ />
670
+ )}
671
+
672
+ <div
673
+ id={sectionId || undefined}
674
+ className="magic-bento-section container relative w-full max-w-[54rem] select-none px-3 !py-8"
675
+ style={{ fontSize: 'clamp(1rem, 0.9rem + 0.5vw, 1.5rem)' }}
676
+ >
677
+ <div
678
+ ref={gridRef}
679
+ className="magic-bento-grid mx-auto grid w-[100%] grid-cols-1 gap-4 p-2 sm:grid-cols-2 md:gap-4 lg:grid-cols-4 [&>.magic-bento-card:nth-child(3)]:lg:col-span-2 [&>.magic-bento-card:nth-child(3)]:lg:row-span-2 [&>.magic-bento-card:nth-child(4)]:lg:col-span-2 [&>.magic-bento-card:nth-child(6)]:lg:col-start-4 [&>.magic-bento-card:nth-child(6)]:lg:row-start-3"
680
+ >
681
+ {cardData.map((card, index) => {
682
+ const cardStyle = {
683
+ backgroundColor: card.color || 'var(--background-dark)',
684
+ borderColor: 'var(--border-color)',
685
+ color: 'var(--white)',
686
+ '--glow-x': '50%',
687
+ '--glow-y': '50%',
688
+ '--glow-intensity': '0',
689
+ '--glow-radius': '200px',
690
+ outline: '4px solid #181818db'
691
+ } as React.CSSProperties
692
+
693
+ const mediaObj = typeof card.media === 'object' ? card.media : null
694
+ const mediaUrl = mediaObj?.url ?? null
695
+ const mediaAlt = mediaObj?.alt ?? card.title ?? ''
696
+ const cardHref = resolveCardHref(card.link)
697
+
698
+ const cardInner = (
699
+ <>
700
+ {mediaUrl && (
701
+ <div className="pointer-events-none absolute inset-0 z-0 rounded-[inherit] opacity-0 transition-opacity duration-500 ease-in-out group-hover:opacity-100">
702
+ <Image
703
+ src={mediaUrl}
704
+ alt={mediaAlt}
705
+ fill
706
+ className="rounded-[inherit] object-cover"
707
+ sizes="(max-width: 640px) 90vw, (max-width: 1024px) 45vw, 300px"
708
+ />
709
+ <div className="absolute inset-0 z-[1] rounded-[inherit] bg-[linear-gradient(to_top,rgba(0,0,0,0.85)_0%,rgba(0,0,0,0.35)_50%,rgba(0,0,0,0.1)_100%),radial-gradient(ellipse_at_center,transparent_40%,rgba(0,0,0,0.5)_100%)]" />
710
+ </div>
711
+ )}
712
+
713
+ <div className="card__header relative z-10 flex justify-between gap-3 text-stone-300">
714
+ {card.label && <span className="card__label text-sm">{card.label}</span>}
715
+ </div>
716
+
717
+ <div className="card__content relative z-10 flex flex-col text-stone-300">
718
+ {card.title && (
719
+ <h3
720
+ className={`card__title m-0 mb-1 text-3d font-semibold ${
721
+ textAutoHide
722
+ ? 'overflow-hidden text-ellipsis [-webkit-line-clamp:2] [display:-webkit-box] [-webkit-box-orient:vertical]'
723
+ : ''
724
+ }`}
725
+ >
726
+ {card.title}
727
+ </h3>
728
+ )}
729
+
730
+ {card.description && (
731
+ <p
732
+ className={`card__description text-sm leading-5 text-stone-300 ${
733
+ textAutoHide
734
+ ? 'overflow-hidden text-ellipsis [-webkit-line-clamp:2] [display:-webkit-box] [-webkit-box-orient:vertical]'
735
+ : ''
736
+ }`}
737
+ >
738
+ {card.description}
739
+ </p>
740
+ )}
741
+ </div>
742
+ </>
743
+ )
744
+
745
+ if (enableStars) {
746
+ return (
747
+ <ParticleCard
748
+ key={card.id || index}
749
+ className={baseCardCls}
750
+ style={cardStyle}
751
+ disableAnimations={shouldDisableAnimations}
752
+ particleCount={particleCount}
753
+ glowColor={glowColor}
754
+ enableTilt={enableTilt}
755
+ clickEffect={clickEffect}
756
+ enableMagnetism={enableMagnetism}
757
+ href={cardHref}
758
+ newTab={card.link?.newTab}
759
+ >
760
+ {cardInner}
761
+ </ParticleCard>
762
+ )
763
+ }
764
+
765
+ return (
766
+ <div key={card.id || index} className={baseCardCls} style={cardStyle}>
767
+ {cardInner}
768
+ </div>
769
+ )
770
+ })}
771
+ </div>
772
+ </div>
773
+ </>
774
+ )
775
+ }
776
+
777
+ export default DDMagicBento