blocks-dusted 0.1.10 → 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 (246) 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/shared/src/components/BgLightning/index.tsx +242 -0
  221. package/templates/shared/src/components/ui/ShareButton/index.tsx +80 -0
  222. package/templates/shared/src/components/ui/anims/FadeOnScroll.tsx +48 -0
  223. package/templates/shared/src/components/ui/anims/FadeUpOnInView.tsx +63 -0
  224. package/templates/shared/src/components/ui/anims/GlareHover.tsx +111 -0
  225. package/templates/shared/src/components/ui/anims/LineAnims.tsx +81 -0
  226. package/templates/shared/src/components/ui/anims/TitleAnims01.tsx +54 -0
  227. package/templates/shared/src/components/ui/anims/animation-container.tsx +29 -0
  228. package/templates/shared/src/components/ui/anims/blur-in.tsx +26 -0
  229. package/templates/shared/src/components/ui/anims/counter.tsx +53 -0
  230. package/templates/shared/src/components/ui/anims/fade.tsx +83 -0
  231. package/templates/shared/src/components/ui/anims/gradual-spacing.tsx +39 -0
  232. package/templates/shared/src/components/ui/anims/pull-up.tsx +93 -0
  233. package/templates/shared/src/components/ui/anims/reveal-text.tsx +76 -0
  234. package/templates/shared/src/components/ui/anims/rotate-words.tsx +43 -0
  235. package/templates/shared/src/components/ui/anims/shiny-text.tsx +58 -0
  236. package/templates/shared/src/components/ui/anims/shuffle-text.tsx +85 -0
  237. package/templates/shared/src/components/ui/anims/split-text.tsx +211 -0
  238. package/templates/shared/src/components/ui/anims/staggered-fade.tsx +133 -0
  239. package/templates/shared/src/components/ui/anims/text-scroll.tsx +111 -0
  240. package/templates/shared/src/components/ui/anims/typing-effect.tsx +112 -0
  241. package/templates/shared/src/components/ui/button-dusted-fluid/index.tsx +1521 -0
  242. package/templates/shared/src/components/ui/separator.tsx +85 -0
  243. package/templates/shared/src/hooks/useBodyScrollLock.ts +97 -0
  244. package/templates/shared/src/hooks/useClickOutside.ts +28 -0
  245. package/templates/shared/src/utilities/renderCustomCSS.ts +5 -0
  246. package/templates/shared/src/utilities/smoothScroll.ts +65 -0
@@ -0,0 +1,131 @@
1
+ 'use client'
2
+
3
+ import { useEffect, useRef } from 'react'
4
+ import Image from 'next/image'
5
+ import Link from 'next/link'
6
+ import { Globe, Briefcase, Camera } from 'lucide-react'
7
+ import { cn } from '@/utilities/ui'
8
+ import { getMediaUrl } from '@/utilities/getMediaUrl'
9
+
10
+ type MediaDoc = {
11
+ url?: string | null
12
+ alt?: string | null
13
+ }
14
+
15
+ type TeamMember = {
16
+ name?: string | null
17
+ role?: string | null
18
+ bio?: string | null
19
+ image?: number | MediaDoc | null
20
+ priority?: boolean | null
21
+ facebookUrl?: string | null
22
+ linkedinUrl?: string | null
23
+ instagramUrl?: string | null
24
+ id?: string | null
25
+ }
26
+
27
+ export type DDHGTeamCardsProps = {
28
+ sectionId?: string | null
29
+ customClassName?: string | null
30
+ customCSS?: string | null
31
+ members?: TeamMember[] | null
32
+ }
33
+
34
+ function getMediaDoc(img?: number | MediaDoc | null): MediaDoc | null {
35
+ if (!img || typeof img === 'number') return null
36
+ return img
37
+ }
38
+
39
+ export const DDHGTeamCards: React.FC<DDHGTeamCardsProps> = ({
40
+ sectionId,
41
+ customClassName,
42
+ customCSS,
43
+ members,
44
+ }) => {
45
+ const ref = useRef<HTMLDivElement>(null)
46
+
47
+ useEffect(() => {
48
+ const observer = new IntersectionObserver(
49
+ (entries) => {
50
+ entries.forEach((entry) => {
51
+ if (entry.isIntersecting) {
52
+ entry.target.querySelectorAll<HTMLElement>('.reveal').forEach((el, i) => {
53
+ setTimeout(() => {
54
+ el.style.opacity = '1'
55
+ el.style.transform = 'translateY(0)'
56
+ }, i * 100)
57
+ })
58
+ observer.unobserve(entry.target)
59
+ }
60
+ })
61
+ },
62
+ { threshold: 0.1 },
63
+ )
64
+ if (ref.current) observer.observe(ref.current)
65
+ return () => observer.disconnect()
66
+ }, [])
67
+
68
+ return (
69
+ <div id={sectionId ?? undefined} className={cn('px-5 md:px-8 py-8', customClassName)} ref={ref}>
70
+ {customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
71
+ <div className="max-w-7xl mx-auto">
72
+ {members && members.length > 0 && (
73
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5 md:gap-6">
74
+ {members.map((member, i) => {
75
+ const imageDoc = getMediaDoc(member.image)
76
+ const imageUrl = getMediaUrl(imageDoc?.url)
77
+ const socials = [
78
+ { Icon: Globe, url: member.facebookUrl, label: 'Facebook' },
79
+ { Icon: Briefcase, url: member.linkedinUrl, label: 'LinkedIn' },
80
+ { Icon: Camera, url: member.instagramUrl, label: 'Instagram' },
81
+ ].filter((s) => !!s.url)
82
+
83
+ return (
84
+ <div
85
+ key={member.id != null ? `id-${member.id}` : `idx-${i}`}
86
+ className="reveal group relative overflow-hidden cursor-pointer bg-transparent h-[28rem] md:h-[32rem]"
87
+ style={{ opacity: 0, transform: 'translateY(20px)', transition: `opacity 0.9s ease ${i * 0.1}s, transform 0.9s ease ${i * 0.1}s` }}
88
+ >
89
+ {imageDoc && imageUrl && (
90
+ <div className="relative w-full h-full overflow-hidden brightness-100 group-hover:brightness-50">
91
+ <Image
92
+ src={imageUrl}
93
+ alt={imageDoc.alt ?? member.name ?? ''}
94
+ fill
95
+ sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
96
+ priority={Boolean(member.priority)}
97
+ className="team-member object-cover object-top brightness-100 group-hover:brightness-50 group-hover:scale-110 transition-transform duration-500 ease-out"
98
+ />
99
+ </div>
100
+ )}
101
+ <div className="pattern-overlay absolute inset-0 opacity-[0.03] pointer-events-none" style={{ backgroundImage: 'repeating-linear-gradient(90deg, #000 0px, #000 1px, transparent 1px, transparent 20px)' }} />
102
+ <div className="gradient-overlay absolute inset-0 bg-gradient-to-t from-black/80 via-black/80 to-transparent group-hover:from-black/90 transition-all duration-300 group-hover:backdrop-brightness-50" />
103
+ <div className="content-card absolute inset-0 flex flex-col justify-end p-3 text-white">
104
+ <div className="z-10 text-center mb-3">
105
+ {member.name && <h3 className="text-xl md:text-2xl font-bold mb-1 text-white drop-shadow-lg" style={{ fontFamily: 'Outfit, sans-serif', fontWeight: 700 }}>{member.name}</h3>}
106
+ {member.role && <p className="text-xs md:text-sm font-medium uppercase tracking-wider text-stone-200 dark:text-stone-200 drop-shadow-md" style={{ fontFamily: "'Inter', sans-serif", fontWeight: 500 }}>{member.role}</p>}
107
+ </div>
108
+ <div className="hover-panel transform translate-y-full group-hover:translate-y-0 transition-transform duration-300 ease-out p-4" style={{ background: 'rgba(0,0,0,0.4)', backdropFilter: 'blur(8px)' }}>
109
+ {member.bio && <p className="text-[13px] text-white/70 leading-relaxed mb-4 opacity-0 group-hover:opacity-100 transition-opacity duration-300 delay-100">{member.bio}</p>}
110
+ {socials.length > 0 && (
111
+ <div className="socials-map flex gap-3 justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-300 delay-200">
112
+ {socials.map(({ Icon, url, label }) => (
113
+ <Link key={label} href={url!} target="_blank" rel="noopener noreferrer" aria-label={`${member.name} on ${label}`} className="text-white/70 hover:text-white hover:scale-110 transition-all duration-200 p-2 rounded-full bg-white/10 hover:bg-white/20 backdrop-blur-sm">
114
+ <Icon size={14} />
115
+ </Link>
116
+ ))}
117
+ </div>
118
+ )}
119
+ </div>
120
+ </div>
121
+ </div>
122
+ )
123
+ })}
124
+ </div>
125
+ )}
126
+ </div>
127
+ </div>
128
+ )
129
+ }
130
+
131
+ export default DDHGTeamCards
@@ -0,0 +1,48 @@
1
+ import type { Block } from 'payload'
2
+
3
+ export const DDHGTeamCards: Block = {
4
+ slug: 'DDHG-TeamCards',
5
+ interfaceName: 'DDHGTeamCards',
6
+ labels: { singular: 'Team Cards', plural: 'Team Cards' },
7
+ fields: [
8
+ {
9
+ type: 'tabs',
10
+ tabs: [
11
+ {
12
+ label: 'Team Members',
13
+ fields: [
14
+ {
15
+ name: 'members',
16
+ type: 'array',
17
+ label: 'Team Members',
18
+ fields: [
19
+ { type: 'row', fields: [
20
+ { name: 'name', type: 'text', label: 'Name', required: true, admin: { width: '50%' } },
21
+ { name: 'role', type: 'text', label: 'Role / Title', admin: { width: '50%' } },
22
+ ] },
23
+ { name: 'bio', type: 'textarea', label: 'Bio (shown on hover)' },
24
+ { name: 'image', type: 'upload', relationTo: 'media', label: 'Photo' },
25
+ { name: 'priority', type: 'checkbox', label: 'High Priority', defaultValue: false, admin: { description: 'Enable for above-the-fold media.' } },
26
+ { type: 'row', fields: [
27
+ { name: 'linkedinUrl', type: 'text', label: 'LinkedIn URL', admin: { width: '33%' } },
28
+ { name: 'instagramUrl', type: 'text', label: 'Instagram URL', admin: { width: '33%' } },
29
+ { name: 'facebookUrl', type: 'text', label: 'Facebook URL', admin: { width: '33%' } },
30
+ ] },
31
+ ],
32
+ },
33
+ ],
34
+ },
35
+ {
36
+ label: 'Advanced',
37
+ fields: [
38
+ { type: 'row', fields: [
39
+ { name: 'sectionId', type: 'text', label: 'Section ID', admin: { width: '50%', description: 'Optional anchor ID' } },
40
+ { name: 'customClassName', type: 'text', label: 'Custom CSS Classes', admin: { width: '50%' } },
41
+ ] },
42
+ { name: 'customCSS', type: 'code', label: 'Custom CSS', admin: { language: 'css', description: 'Injected as a <style> tag. Use with caution.' } },
43
+ ],
44
+ },
45
+ ],
46
+ },
47
+ ],
48
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "type": "block",
3
+ "name": "DDHG-TeamCards",
4
+ "label": "Team Cards",
5
+ "sourceName": "TeamCards",
6
+ "portableName": "DDHG-TeamCards",
7
+ "slug": "DDHG-TeamCards",
8
+ "version": "0.0.1",
9
+ "source": { "repo": "Hadizainal/HeatherGrey2025", "originalPath": "src/blocks/TeamCards", "originalSlug": "teamCards", "originalConfigExport": "TeamCards", "originalComponentExport": "TeamCardsBlock", "originalInterfaceName": "TeamCardsBlockProps" },
10
+ "files": [
11
+ { "from": "Component.tsx", "to": "src/blocks/DDHG-TeamCards/Component.tsx" },
12
+ { "from": "config.ts", "to": "src/blocks/DDHG-TeamCards/config.ts" }
13
+ ],
14
+ "dependencies": [{ "name": "lucide-react" }],
15
+ "sharedFiles": [],
16
+ "requiredProjectFiles": [
17
+ { "path": "src/utilities/ui.ts", "reason": "Component uses the cn utility." },
18
+ { "path": "src/utilities/getMediaUrl.ts", "reason": "Component resolves media URLs through getMediaUrl." }
19
+ ],
20
+ "optionalProjectFiles": [],
21
+ "collectionRegistration": { "enabled": true, "collections": ["Pages", "Posts"] },
22
+ "renderBlocksRegistration": { "enabled": true },
23
+ "renderBlocksBehavior": { "wrapperless": false },
24
+ "pageRouteIntegration": { "required": false, "manualSteps": [] },
25
+ "manualSteps": ["Run payload generate:types after schema changes."],
26
+ "notes": ["Converted from HeatherGrey2025 TeamCards.", "Generated Payload media type dependency replaced with a local structural type.", "Priority loading now follows each member row's priority field.", "Installer must not overwrite existing target files."],
27
+ "exportName": "DDHGTeamCards",
28
+ "interfaceName": "DDHGTeamCards"
29
+ }
@@ -0,0 +1,242 @@
1
+ 'use client'
2
+
3
+ import React, { useRef, useEffect } from 'react'
4
+
5
+ interface BgLightningProps {
6
+ hue?: number
7
+ xOffset?: number
8
+ speed?: number
9
+ intensity?: number
10
+ size?: number
11
+ }
12
+
13
+ const BgLightning: React.FC<BgLightningProps> = ({
14
+ hue = 230,
15
+ xOffset = 0,
16
+ speed = 1,
17
+ intensity = 1,
18
+ size = 1
19
+ }) => {
20
+ const canvasRef = useRef<HTMLCanvasElement>(null)
21
+
22
+ useEffect(() => {
23
+ const canvas = canvasRef.current
24
+ if (!canvas) return
25
+
26
+ let frameId = 0
27
+ let disposed = false
28
+
29
+ const gl = canvas.getContext('webgl', {
30
+ alpha: true,
31
+ premultipliedAlpha: false
32
+ })
33
+
34
+ if (!gl) {
35
+ console.error('WebGL not supported')
36
+ return
37
+ }
38
+
39
+ const resizeCanvas = () => {
40
+ const width = canvas.clientWidth
41
+ const height = canvas.clientHeight
42
+
43
+ if (canvas.width !== width || canvas.height !== height) {
44
+ canvas.width = width
45
+ canvas.height = height
46
+ }
47
+ }
48
+
49
+ resizeCanvas()
50
+ window.addEventListener('resize', resizeCanvas)
51
+
52
+ const vertexShaderSource = `
53
+ attribute vec2 aPosition;
54
+
55
+ void main() {
56
+ gl_Position = vec4(aPosition, 0.0, 1.0);
57
+ }
58
+ `
59
+
60
+ const fragmentShaderSource = `
61
+ precision mediump float;
62
+
63
+ uniform vec2 iResolution;
64
+ uniform float iTime;
65
+ uniform float uHue;
66
+ uniform float uXOffset;
67
+ uniform float uSpeed;
68
+ uniform float uIntensity;
69
+ uniform float uSize;
70
+
71
+ #define OCTAVE_COUNT 10
72
+
73
+ vec3 hsv2rgb(vec3 c) {
74
+ vec3 rgb = clamp(abs(mod(c.x * 6.0 + vec3(0.0,4.0,2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);
75
+ return c.z * mix(vec3(1.0), rgb, c.y);
76
+ }
77
+
78
+ float hash11(float p) {
79
+ p = fract(p * .1031);
80
+ p *= p + 33.33;
81
+ p *= p + p;
82
+ return fract(p);
83
+ }
84
+
85
+ float hash12(vec2 p) {
86
+ vec3 p3 = fract(vec3(p.xyx) * .1031);
87
+ p3 += dot(p3, p3.yzx + 33.33);
88
+ return fract((p3.x + p3.y) * p3.z);
89
+ }
90
+
91
+ mat2 rotate2d(float theta) {
92
+ float c = cos(theta);
93
+ float s = sin(theta);
94
+ return mat2(c, -s, s, c);
95
+ }
96
+
97
+ float noise(vec2 p) {
98
+ vec2 ip = floor(p);
99
+ vec2 fp = fract(p);
100
+
101
+ float a = hash12(ip);
102
+ float b = hash12(ip + vec2(1.0, 0.0));
103
+ float c = hash12(ip + vec2(0.0, 1.0));
104
+ float d = hash12(ip + vec2(1.0, 1.0));
105
+
106
+ vec2 t = smoothstep(0.0, 1.0, fp);
107
+
108
+ return mix(mix(a, b, t.x), mix(c, d, t.x), t.y);
109
+ }
110
+
111
+ float fbm(vec2 p) {
112
+ float value = 0.0;
113
+ float amplitude = 0.5;
114
+
115
+ for (int i = 0; i < OCTAVE_COUNT; ++i) {
116
+ value += amplitude * noise(p);
117
+ p *= rotate2d(0.45);
118
+ p *= 2.0;
119
+ amplitude *= 0.5;
120
+ }
121
+
122
+ return value;
123
+ }
124
+
125
+ void mainImage(out vec4 fragColor, in vec2 fragCoord) {
126
+ vec2 uv = fragCoord / iResolution.xy;
127
+ uv = 2.0 * uv - 1.0;
128
+ uv.x *= iResolution.x / iResolution.y;
129
+ uv.x += uXOffset;
130
+
131
+ uv += 2.0 * fbm(uv * uSize + 0.8 * iTime * uSpeed) - 1.0;
132
+
133
+ float dist = max(abs(uv.x), 0.001);
134
+ vec3 baseColor = hsv2rgb(vec3(uHue / 360.0, 0.7, 0.8));
135
+ vec3 col = baseColor * pow(mix(0.0, 0.07, hash11(iTime * uSpeed)) / dist, 1.0) * uIntensity;
136
+
137
+ float a = clamp(max(col.r, max(col.g, col.b)), 0.0, 1.0);
138
+ fragColor = vec4(col, a);
139
+ }
140
+
141
+ void main() {
142
+ mainImage(gl_FragColor, gl_FragCoord.xy);
143
+ }
144
+ `
145
+
146
+ const compileShader = (source: string, type: number) => {
147
+ const shader = gl.createShader(type)
148
+ if (!shader) return null
149
+
150
+ gl.shaderSource(shader, source)
151
+ gl.compileShader(shader)
152
+
153
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
154
+ console.error('Shader compile error:', gl.getShaderInfoLog(shader))
155
+ gl.deleteShader(shader)
156
+ return null
157
+ }
158
+
159
+ return shader
160
+ }
161
+
162
+ const vertexShader = compileShader(vertexShaderSource, gl.VERTEX_SHADER)
163
+ const fragmentShader = compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
164
+
165
+ if (!vertexShader || !fragmentShader) return
166
+
167
+ const program = gl.createProgram()
168
+ if (!program) return
169
+
170
+ gl.attachShader(program, vertexShader)
171
+ gl.attachShader(program, fragmentShader)
172
+ gl.linkProgram(program)
173
+
174
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
175
+ console.error('Program linking error:', gl.getProgramInfoLog(program))
176
+ gl.deleteProgram(program)
177
+ return
178
+ }
179
+
180
+ const vertices = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1])
181
+
182
+ const vertexBuffer = gl.createBuffer()
183
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
184
+ gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
185
+
186
+ const aPosition = gl.getAttribLocation(program, 'aPosition')
187
+
188
+ if (aPosition >= 0) {
189
+ gl.useProgram(program)
190
+ gl.enableVertexAttribArray(aPosition)
191
+ gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0)
192
+ }
193
+
194
+ const iResolutionLocation = gl.getUniformLocation(program, 'iResolution')
195
+ const iTimeLocation = gl.getUniformLocation(program, 'iTime')
196
+ const uHueLocation = gl.getUniformLocation(program, 'uHue')
197
+ const uXOffsetLocation = gl.getUniformLocation(program, 'uXOffset')
198
+ const uSpeedLocation = gl.getUniformLocation(program, 'uSpeed')
199
+ const uIntensityLocation = gl.getUniformLocation(program, 'uIntensity')
200
+ const uSizeLocation = gl.getUniformLocation(program, 'uSize')
201
+
202
+ const startTime = performance.now()
203
+
204
+ const render = () => {
205
+ if (disposed) return
206
+
207
+ resizeCanvas()
208
+
209
+ gl.useProgram(program)
210
+ gl.viewport(0, 0, canvas.width, canvas.height)
211
+
212
+ if (iResolutionLocation) gl.uniform2f(iResolutionLocation, canvas.width, canvas.height)
213
+ if (iTimeLocation) gl.uniform1f(iTimeLocation, (performance.now() - startTime) / 1000)
214
+ if (uHueLocation) gl.uniform1f(uHueLocation, hue)
215
+ if (uXOffsetLocation) gl.uniform1f(uXOffsetLocation, xOffset)
216
+ if (uSpeedLocation) gl.uniform1f(uSpeedLocation, speed)
217
+ if (uIntensityLocation) gl.uniform1f(uIntensityLocation, intensity)
218
+ if (uSizeLocation) gl.uniform1f(uSizeLocation, size)
219
+
220
+ gl.drawArrays(gl.TRIANGLES, 0, 6)
221
+
222
+ frameId = requestAnimationFrame(render)
223
+ }
224
+
225
+ frameId = requestAnimationFrame(render)
226
+
227
+ return () => {
228
+ disposed = true
229
+ cancelAnimationFrame(frameId)
230
+ window.removeEventListener('resize', resizeCanvas)
231
+
232
+ gl.deleteBuffer(vertexBuffer)
233
+ gl.deleteShader(vertexShader)
234
+ gl.deleteShader(fragmentShader)
235
+ gl.deleteProgram(program)
236
+ }
237
+ }, [hue, xOffset, speed, intensity, size])
238
+
239
+ return <canvas ref={canvasRef} className="relative h-full w-full" />
240
+ }
241
+
242
+ export default BgLightning
@@ -0,0 +1,80 @@
1
+ 'use client'
2
+
3
+ import React, { useState } from 'react'
4
+ import { LucideIcon } from 'lucide-react'
5
+
6
+ import { cn } from '@/utilities/ui'
7
+ import { Button } from '@/components/ui/button'
8
+
9
+ interface ShareLink {
10
+ icon: LucideIcon
11
+ href?: string
12
+ onClick?: () => void
13
+ label?: string
14
+ }
15
+
16
+ interface ShareButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
17
+ links: ShareLink[]
18
+ children: React.ReactNode
19
+ }
20
+
21
+ export const ShareButton = ({ className, links, children, ...props }: ShareButtonProps) => {
22
+ const [isHovered, setIsHovered] = useState(false)
23
+
24
+ return (
25
+ <div
26
+ className="relative"
27
+ onMouseEnter={() => setIsHovered(true)}
28
+ onMouseLeave={() => setIsHovered(false)}
29
+ >
30
+ <Button
31
+ className={cn(
32
+ 'relative min-w-40 rounded-3xl ',
33
+ 'bg-white dark:bg-black',
34
+ 'hover:bg-gray-50 dark:hover:bg-gray-950',
35
+ 'text-stone-200 dark:text-stone-200',
36
+ 'border border-black/10 dark:border-white/10',
37
+ 'transition-all duration-300',
38
+ isHovered ? 'opacity-0' : 'opacity-100',
39
+ className
40
+ )}
41
+ {...props}
42
+ >
43
+ <span className="flex items-center gap-2">{children}</span>
44
+ </Button>
45
+
46
+ <div className="absolute left-0 top-0 flex h-10">
47
+ {links.map((link, index) => {
48
+ const Icon = link.icon
49
+ return (
50
+ <button
51
+ type="button"
52
+ key={index}
53
+ onClick={link.onClick}
54
+ className={cn(
55
+ 'h-10',
56
+ 'w-10',
57
+ 'flex items-center justify-center',
58
+ 'bg-black dark:bg-white',
59
+ 'text-white dark:text-black',
60
+ 'transition-all duration-300',
61
+ index === 0 && 'rounded-l-3xl',
62
+ index === links.length - 1 && 'rounded-r-3xl',
63
+ 'border-r border-white/10 last:border-r-0 dark:border-black/10',
64
+ 'hover:bg-gray-900 dark:hover:bg-gray-100',
65
+ '',
66
+ isHovered ? 'translate-x-0 opacity-100' : '-translate-x-full opacity-0',
67
+ index === 0 && 'transition-all duration-200',
68
+ index === 1 && 'delay-\\[50ms\\] transition-all duration-200',
69
+ index === 2 && 'transition-all delay-100 duration-200',
70
+ index === 3 && 'transition-all delay-150 duration-200'
71
+ )}
72
+ >
73
+ <Icon className="size-4" />
74
+ </button>
75
+ )
76
+ })}
77
+ </div>
78
+ </div>
79
+ )
80
+ }
@@ -0,0 +1,48 @@
1
+ 'use client'
2
+
3
+ import React, { useEffect, useRef, useState } from 'react'
4
+ import { motion, useScroll, useTransform } from 'framer-motion'
5
+
6
+ interface FadeOnScrollProps {
7
+ children: React.ReactNode
8
+ }
9
+
10
+ export const FadeOnScroll: React.FC<FadeOnScrollProps> = ({ children }) => {
11
+ const containerRef = useRef<HTMLDivElement>(null)
12
+ const [targetRef, setTargetRef] = useState<HTMLElement | null>(null)
13
+
14
+ // Bind scroll tracking only when ready
15
+ const scrollSetupRef = useRef(false)
16
+ const { scrollYProgress } = useScroll({
17
+ target: targetRef ? { current: targetRef } : undefined,
18
+ offset: ['start 50%', 'start 0%'],
19
+ })
20
+
21
+ const opacity = useTransform(scrollYProgress, [0, 1], [1, 0])
22
+
23
+ useEffect(() => {
24
+ if (typeof window === 'undefined') return
25
+
26
+ const container = containerRef.current
27
+ if (!container) return
28
+
29
+ const parent = container.closest('.renderblock-container')
30
+ if (!parent) return
31
+
32
+ let sibling = parent.nextElementSibling as HTMLElement | null
33
+ while (sibling && !sibling.classList.contains('renderblock-container')) {
34
+ sibling = sibling.nextElementSibling as HTMLElement | null
35
+ }
36
+
37
+ if (sibling && !scrollSetupRef.current) {
38
+ setTargetRef(sibling)
39
+ scrollSetupRef.current = true
40
+ }
41
+ }, [])
42
+
43
+ return (
44
+ <motion.div ref={containerRef} style={{ opacity }}>
45
+ {children}
46
+ </motion.div>
47
+ )
48
+ }
@@ -0,0 +1,63 @@
1
+ 'use client'
2
+ import React, { useRef, useEffect, useState, ReactNode } from 'react'
3
+ import { motion } from 'framer-motion'
4
+ import { cn } from '@/utilities/ui'
5
+
6
+ interface FadeUpOnInViewProps {
7
+ children: ReactNode
8
+ delay?: number
9
+ className?: string
10
+ }
11
+
12
+ export const FadeUpOnInView: React.FC<FadeUpOnInViewProps> = ({ children, delay, className }) => {
13
+ const ref = useRef<HTMLDivElement | null>(null)
14
+ const [isVisible, setIsVisible] = useState(false)
15
+
16
+ useEffect(() => {
17
+ if (!ref.current) return
18
+ const target = ref.current
19
+ const observer = new IntersectionObserver(
20
+ (entries) => {
21
+ if (entries && entries.length > 0 && entries[0]) {
22
+ setIsVisible(!!entries[0].isIntersecting)
23
+ }
24
+ },
25
+ {
26
+ root: null,
27
+ rootMargin: '0px',
28
+ threshold: 0.5
29
+ }
30
+ )
31
+ observer.observe(target)
32
+ return () => {
33
+ observer.disconnect()
34
+ }
35
+ }, [])
36
+
37
+ // Defensive: Only allow number and >= 0 for delay
38
+ const animationDelay = typeof delay === 'number' && !isNaN(delay) && delay >= 0 ? delay : 0
39
+
40
+ // Defensive: Only render children if defined
41
+ const safeChildren = children === undefined || children === null ? null : children
42
+
43
+ return (
44
+ <motion.div
45
+ className={cn('fadeupInView', className)}
46
+ ref={ref}
47
+ initial={{ opacity: 0, y: 40 }}
48
+ animate={{
49
+ opacity: isVisible ? 1 : 0,
50
+ y: isVisible ? 0 : 40
51
+ }}
52
+ exit={{ opacity: 0, y: 40 }}
53
+ transition={{
54
+ duration: 0.3,
55
+ delay: animationDelay
56
+ }}
57
+ >
58
+ {safeChildren}
59
+ </motion.div>
60
+ )
61
+ }
62
+
63
+ export default FadeUpOnInView