blocks-dusted 0.1.10 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/README.md +35 -0
  2. package/package.json +5 -2
  3. package/src/cli.js +39 -3
  4. package/src/commands/shop.js +59 -0
  5. package/src/commands/warehouse.js +73 -0
  6. package/src/utils/paths.js +13 -13
  7. package/templates/blocks/DD-Accordion/Component.tsx +229 -0
  8. package/templates/blocks/DD-Accordion/README.md +3 -0
  9. package/templates/blocks/DD-Accordion/config.ts +73 -0
  10. package/templates/blocks/DD-Accordion/manifest.json +75 -0
  11. package/templates/blocks/DD-AnimText/Component.tsx +788 -0
  12. package/templates/blocks/DD-AnimText/README.md +3 -0
  13. package/templates/blocks/DD-AnimText/config.ts +295 -0
  14. package/templates/blocks/DD-AnimText/manifest.json +85 -0
  15. package/templates/blocks/DD-AsideNav/Component.tsx +321 -0
  16. package/templates/blocks/DD-AsideNav/config.ts +204 -0
  17. package/templates/blocks/DD-AsideNav/manifest.json +80 -0
  18. package/templates/blocks/DD-Banner/Component.tsx +51 -0
  19. package/templates/blocks/DD-Banner/config.ts +57 -0
  20. package/templates/blocks/DD-Banner/manifest.json +72 -0
  21. package/templates/blocks/DD-BgLightning/Component.tsx +44 -0
  22. package/templates/blocks/DD-BgLightning/README.md +3 -0
  23. package/templates/blocks/DD-BgLightning/config.ts +97 -0
  24. package/templates/blocks/DD-BgLightning/manifest.json +79 -0
  25. package/templates/blocks/DD-BookCall/Component.tsx +535 -535
  26. package/templates/blocks/DD-BookCall/config.ts +238 -238
  27. package/templates/blocks/DD-ButtonPop/Component.tsx +117 -0
  28. package/templates/blocks/DD-ButtonPop/config.ts +105 -0
  29. package/templates/blocks/DD-ButtonPop/manifest.json +88 -0
  30. package/templates/blocks/DD-ButtonPop/svg-icons/Dust2.tsx +167 -0
  31. package/templates/blocks/DD-Card/Component.tsx +251 -0
  32. package/templates/blocks/DD-Card/README.md +4 -0
  33. package/templates/blocks/DD-Card/config.ts +154 -0
  34. package/templates/blocks/DD-Card/manifest.json +82 -0
  35. package/templates/blocks/DD-CardTemplate01/Component.tsx +140 -140
  36. package/templates/blocks/DD-CardTemplate01/config.ts +106 -106
  37. package/templates/blocks/DD-Carousel-A/Component.tsx +249 -249
  38. package/templates/blocks/DD-Carousel-B/Component.tsx +403 -403
  39. package/templates/blocks/DD-Chip/Component.tsx +250 -0
  40. package/templates/blocks/DD-Chip/EXAMPLES.md +313 -0
  41. package/templates/blocks/DD-Chip/README.md +202 -0
  42. package/templates/blocks/DD-Chip/config.ts +369 -0
  43. package/templates/blocks/DD-Chip/manifest.json +74 -0
  44. package/templates/blocks/DD-ComparisonTable/Component.tsx +256 -256
  45. package/templates/blocks/DD-Contact/Component.tsx +435 -434
  46. package/templates/blocks/DD-Contact/config.ts +22 -22
  47. package/templates/blocks/DD-Counter/Component.tsx +190 -0
  48. package/templates/blocks/DD-Counter/README.md +4 -0
  49. package/templates/blocks/DD-Counter/config.ts +291 -0
  50. package/templates/blocks/DD-Counter/manifest.json +74 -0
  51. package/templates/blocks/DD-CustomCSS/Component.tsx +8 -0
  52. package/templates/blocks/DD-CustomCSS/README.md +4 -0
  53. package/templates/blocks/DD-CustomCSS/addToLayout.md +5 -0
  54. package/templates/blocks/DD-CustomCSS/config.ts +22 -0
  55. package/templates/blocks/DD-CustomCSS/manifest.json +72 -0
  56. package/templates/blocks/DD-CustomCSS/renderCustomCSS.md +7 -0
  57. package/templates/blocks/DD-FeatCat/Component.tsx +302 -302
  58. package/templates/blocks/DD-FeatCat/config.ts +201 -201
  59. package/templates/blocks/DD-FeatStrip/Component.tsx +585 -585
  60. package/templates/blocks/DD-FeatStrip/config.ts +134 -134
  61. package/templates/blocks/DD-FluidBtn/ButtonsEyeCatching.tsx +628 -0
  62. package/templates/blocks/DD-FluidBtn/Component.tsx +43 -0
  63. package/templates/blocks/DD-FluidBtn/README.md +6 -0
  64. package/templates/blocks/DD-FluidBtn/config.ts +102 -0
  65. package/templates/blocks/DD-FluidBtn/manifest.json +86 -0
  66. package/templates/blocks/DD-GooeyInfo/Component.tsx +149 -0
  67. package/templates/blocks/DD-GooeyInfo/config.ts +135 -0
  68. package/templates/blocks/DD-GooeyInfo/manifest.json +72 -0
  69. package/templates/blocks/DD-Hero/Component.tsx +297 -297
  70. package/templates/blocks/DD-Hero/config.ts +267 -267
  71. package/templates/blocks/DD-HorizontalScroll/Component.tsx +936 -936
  72. package/templates/blocks/DD-HorizontalScroll/config.ts +231 -231
  73. package/templates/blocks/DD-Icon/Component.tsx +287 -0
  74. package/templates/blocks/DD-Icon/README.md +4 -0
  75. package/templates/blocks/DD-Icon/config.ts +258 -0
  76. package/templates/blocks/DD-Icon/hooks/revalidateBlockIds.ts +66 -0
  77. package/templates/blocks/DD-Icon/manifest.json +82 -0
  78. package/templates/blocks/DD-IconButton/Component.tsx +455 -0
  79. package/templates/blocks/DD-IconButton/README.md +326 -0
  80. package/templates/blocks/DD-IconButton/config.ts +239 -0
  81. package/templates/blocks/DD-IconButton/manifest.json +85 -0
  82. package/templates/blocks/DD-IdTag/Component.tsx +21 -0
  83. package/templates/blocks/DD-IdTag/README.md +4 -0
  84. package/templates/blocks/DD-IdTag/config.ts +41 -0
  85. package/templates/blocks/DD-IdTag/manifest.json +72 -0
  86. package/templates/blocks/DD-Iframe/Component.tsx +45 -0
  87. package/templates/blocks/DD-Iframe/README.md +4 -0
  88. package/templates/blocks/DD-Iframe/config.ts +47 -0
  89. package/templates/blocks/DD-Iframe/manifest.json +72 -0
  90. package/templates/blocks/DD-IframeMedia/Component.tsx +133 -0
  91. package/templates/blocks/DD-IframeMedia/README.md +4 -0
  92. package/templates/blocks/DD-IframeMedia/config.ts +79 -0
  93. package/templates/blocks/DD-IframeMedia/manifest.json +72 -0
  94. package/templates/blocks/DD-LineAnim/Component.tsx +36 -0
  95. package/templates/blocks/DD-LineAnim/README.md +4 -0
  96. package/templates/blocks/DD-LineAnim/config.ts +90 -0
  97. package/templates/blocks/DD-LineAnim/manifest.json +80 -0
  98. package/templates/blocks/DD-LinkGrid/Component.tsx +119 -0
  99. package/templates/blocks/DD-LinkGrid/README.md +4 -0
  100. package/templates/blocks/DD-LinkGrid/config.ts +51 -0
  101. package/templates/blocks/DD-LinkGrid/manifest.json +74 -0
  102. package/templates/blocks/DD-LogoMarq/Component.tsx +132 -0
  103. package/templates/blocks/DD-LogoMarq/README.md +4 -0
  104. package/templates/blocks/DD-LogoMarq/config.ts +264 -0
  105. package/templates/blocks/DD-LogoMarq/manifest.json +82 -0
  106. package/templates/blocks/DD-Lottie/Component.tsx +459 -0
  107. package/templates/blocks/DD-Lottie/README.md +4 -0
  108. package/templates/blocks/DD-Lottie/config.ts +379 -0
  109. package/templates/blocks/DD-Lottie/index.tsx +28 -0
  110. package/templates/blocks/DD-Lottie/manifest.json +83 -0
  111. package/templates/blocks/DD-MagicBento/Component.tsx +777 -0
  112. package/templates/blocks/DD-MagicBento/README.md +4 -0
  113. package/templates/blocks/DD-MagicBento/config.ts +264 -0
  114. package/templates/blocks/DD-MagicBento/manifest.json +74 -0
  115. package/templates/blocks/DD-MasonaryMedia/Component.tsx +545 -545
  116. package/templates/blocks/DD-MasonaryMedia/config.ts +2 -2
  117. package/templates/blocks/DD-MasonaryMedia/vendor.d.ts +2 -2
  118. package/templates/blocks/DD-Masonry/Component.tsx +645 -0
  119. package/templates/blocks/DD-Masonry/README.md +4 -0
  120. package/templates/blocks/DD-Masonry/config.ts +475 -0
  121. package/templates/blocks/DD-Masonry/manifest.json +82 -0
  122. package/templates/blocks/DD-Pricing/Component.tsx +2 -5
  123. package/templates/blocks/DD-Process/Component.tsx +2 -4
  124. package/templates/blocks/DD-Process/config.ts +150 -150
  125. package/templates/blocks/DD-Progress/Component.tsx +156 -0
  126. package/templates/blocks/DD-Progress/README.md +4 -0
  127. package/templates/blocks/DD-Progress/config.ts +175 -0
  128. package/templates/blocks/DD-Progress/manifest.json +74 -0
  129. package/templates/blocks/DD-ProjHeader/Component.tsx +91 -0
  130. package/templates/blocks/DD-ProjHeader/README.md +4 -0
  131. package/templates/blocks/DD-ProjHeader/config.ts +96 -0
  132. package/templates/blocks/DD-ProjHeader/manifest.json +72 -0
  133. package/templates/blocks/DD-ProjSlider/Component.tsx +123 -0
  134. package/templates/blocks/DD-ProjSlider/README.md +4 -0
  135. package/templates/blocks/DD-ProjSlider/config.ts +64 -0
  136. package/templates/blocks/DD-ProjSlider/manifest.json +72 -0
  137. package/templates/blocks/DD-ScrollText/Component.tsx +114 -0
  138. package/templates/blocks/DD-ScrollText/README.md +4 -0
  139. package/templates/blocks/DD-ScrollText/config.ts +58 -0
  140. package/templates/blocks/DD-ScrollText/manifest.json +72 -0
  141. package/templates/blocks/DD-Section/Component.tsx +266 -266
  142. package/templates/blocks/DD-Separator/Component.tsx +66 -0
  143. package/templates/blocks/DD-Separator/README.md +4 -0
  144. package/templates/blocks/DD-Separator/config.ts +58 -0
  145. package/templates/blocks/DD-Separator/manifest.json +72 -0
  146. package/templates/blocks/DD-Services/Component.tsx +176 -176
  147. package/templates/blocks/DD-Services/config.ts +149 -149
  148. package/templates/blocks/DD-ShowcaseGrid/Component.tsx +307 -307
  149. package/templates/blocks/DD-Slider-A/Component.tsx +1 -1
  150. package/templates/blocks/DD-StackCards/Component.tsx +1 -1
  151. package/templates/blocks/DD-StackCards/config.ts +399 -399
  152. package/templates/blocks/DD-Team/Component.tsx +247 -247
  153. package/templates/blocks/DD-Team/config.ts +173 -173
  154. package/templates/blocks/DD-TeamCards/Component.tsx +251 -0
  155. package/templates/blocks/DD-TeamCards/README.md +4 -0
  156. package/templates/blocks/DD-TeamCards/config.ts +302 -0
  157. package/templates/blocks/DD-TeamCards/manifest.json +74 -0
  158. package/templates/blocks/DD-TechStack/Component.tsx +174 -174
  159. package/templates/blocks/DD-TechStack/config.ts +153 -153
  160. package/templates/blocks/DD-TestMarq/Component.tsx +132 -0
  161. package/templates/blocks/DD-TestMarq/README.md +4 -0
  162. package/templates/blocks/DD-TestMarq/RowLabel.tsx +9 -0
  163. package/templates/blocks/DD-TestMarq/config.ts +88 -0
  164. package/templates/blocks/DD-TestMarq/manifest.json +72 -0
  165. package/templates/blocks/DD-Testim/Component.tsx +247 -0
  166. package/templates/blocks/DD-Testim/README.md +4 -0
  167. package/templates/blocks/DD-Testim/config.ts +101 -0
  168. package/templates/blocks/DD-Testim/manifest.json +75 -0
  169. package/templates/blocks/DD-Testim2/Component.tsx +256 -0
  170. package/templates/blocks/DD-Testim2/README.md +4 -0
  171. package/templates/blocks/DD-Testim2/config.ts +100 -0
  172. package/templates/blocks/DD-Testim2/manifest.json +74 -0
  173. package/templates/blocks/DD-Testimonials/Component.tsx +139 -147
  174. package/templates/blocks/DD-Testimonials/config.ts +120 -120
  175. package/templates/blocks/DD-TextMarq/Component.tsx +157 -0
  176. package/templates/blocks/DD-TextMarq/README.md +4 -0
  177. package/templates/blocks/DD-TextMarq/config.ts +237 -0
  178. package/templates/blocks/DD-TextMarq/manifest.json +82 -0
  179. package/templates/blocks/DD-Thanks/Component.tsx +501 -0
  180. package/templates/blocks/DD-Thanks/README.md +4 -0
  181. package/templates/blocks/DD-Thanks/config.ts +224 -0
  182. package/templates/blocks/DD-Thanks/manifest.json +72 -0
  183. package/templates/blocks/DD-VertMarq/Component.tsx +154 -0
  184. package/templates/blocks/DD-VertMarq/README.md +4 -0
  185. package/templates/blocks/DD-VertMarq/config.ts +236 -0
  186. package/templates/blocks/DD-VertMarq/dist/index.css +6 -0
  187. package/templates/blocks/DD-VertMarq/dist/index.min.css +1 -0
  188. package/templates/blocks/DD-VertMarq/manifest.json +74 -0
  189. package/templates/blocks/DD-Work/Component.tsx +318 -315
  190. package/templates/blocks/DD-Work/config.ts +165 -165
  191. package/templates/blocks/DD-Work-B/Component.tsx +294 -294
  192. package/templates/blocks/DDHG-CTASection2/Component.tsx +185 -0
  193. package/templates/blocks/DDHG-CTASection2/config.ts +140 -0
  194. package/templates/blocks/DDHG-CTASection2/manifest.json +45 -0
  195. package/templates/blocks/DDHG-HighlightArc/Component.tsx +243 -0
  196. package/templates/blocks/DDHG-HighlightArc/config.ts +85 -0
  197. package/templates/blocks/DDHG-HighlightArc/manifest.json +46 -0
  198. package/templates/blocks/DDHG-LogoMarquee/Component.tsx +143 -0
  199. package/templates/blocks/DDHG-LogoMarquee/config.ts +154 -0
  200. package/templates/blocks/DDHG-LogoMarquee/manifest.json +39 -0
  201. package/templates/blocks/DDHG-NavCodeGrid/Component.tsx +227 -0
  202. package/templates/blocks/DDHG-NavCodeGrid/config.ts +64 -0
  203. package/templates/blocks/DDHG-NavCodeGrid/manifest.json +45 -0
  204. package/templates/blocks/DDHG-ProcessSec/Component.tsx +574 -0
  205. package/templates/blocks/DDHG-ProcessSec/config.ts +170 -0
  206. package/templates/blocks/DDHG-ProcessSec/manifest.json +56 -0
  207. package/templates/blocks/DDHG-ServiceDetails/Component.tsx +164 -0
  208. package/templates/blocks/DDHG-ServiceDetails/ServiceDetailCard.tsx +390 -0
  209. package/templates/blocks/DDHG-ServiceDetails/config.ts +77 -0
  210. package/templates/blocks/DDHG-ServiceDetails/manifest.json +50 -0
  211. package/templates/blocks/DDHG-ServiceHero/Component.tsx +234 -0
  212. package/templates/blocks/DDHG-ServiceHero/config.ts +49 -0
  213. package/templates/blocks/DDHG-ServiceHero/manifest.json +26 -0
  214. package/templates/blocks/DDHG-ServiceOverview/Component.tsx +277 -0
  215. package/templates/blocks/DDHG-ServiceOverview/config.ts +64 -0
  216. package/templates/blocks/DDHG-ServiceOverview/manifest.json +44 -0
  217. package/templates/blocks/DDHG-StatsFAQ/Component.tsx +389 -0
  218. package/templates/blocks/DDHG-StatsFAQ/config.ts +204 -0
  219. package/templates/blocks/DDHG-StatsFAQ/manifest.json +45 -0
  220. package/templates/blocks/DDHG-TeamCards/Component.tsx +169 -0
  221. package/templates/blocks/DDHG-TeamCards/config.ts +48 -0
  222. package/templates/blocks/DDHG-TeamCards/manifest.json +29 -0
  223. package/templates/shared/src/components/BgLightning/index.tsx +242 -0
  224. package/templates/shared/src/components/ui/ShareButton/index.tsx +80 -0
  225. package/templates/shared/src/components/ui/anims/FadeOnScroll.tsx +48 -0
  226. package/templates/shared/src/components/ui/anims/FadeUpOnInView.tsx +63 -0
  227. package/templates/shared/src/components/ui/anims/GlareHover.tsx +111 -0
  228. package/templates/shared/src/components/ui/anims/LineAnims.tsx +81 -0
  229. package/templates/shared/src/components/ui/anims/TitleAnims01.tsx +54 -0
  230. package/templates/shared/src/components/ui/anims/animation-container.tsx +29 -0
  231. package/templates/shared/src/components/ui/anims/blur-in.tsx +26 -0
  232. package/templates/shared/src/components/ui/anims/counter.tsx +53 -0
  233. package/templates/shared/src/components/ui/anims/fade.tsx +83 -0
  234. package/templates/shared/src/components/ui/anims/gradual-spacing.tsx +39 -0
  235. package/templates/shared/src/components/ui/anims/pull-up.tsx +93 -0
  236. package/templates/shared/src/components/ui/anims/reveal-text.tsx +76 -0
  237. package/templates/shared/src/components/ui/anims/rotate-words.tsx +43 -0
  238. package/templates/shared/src/components/ui/anims/shiny-text.tsx +58 -0
  239. package/templates/shared/src/components/ui/anims/shuffle-text.tsx +85 -0
  240. package/templates/shared/src/components/ui/anims/split-text.tsx +211 -0
  241. package/templates/shared/src/components/ui/anims/staggered-fade.tsx +133 -0
  242. package/templates/shared/src/components/ui/anims/text-scroll.tsx +111 -0
  243. package/templates/shared/src/components/ui/anims/typing-effect.tsx +112 -0
  244. package/templates/shared/src/components/ui/button-dusted-fluid/index.tsx +1521 -0
  245. package/templates/shared/src/components/ui/separator.tsx +85 -0
  246. package/templates/shared/src/hooks/useBodyScrollLock.ts +97 -0
  247. package/templates/shared/src/hooks/useClickOutside.ts +28 -0
  248. package/templates/shared/src/utilities/renderCustomCSS.ts +5 -0
  249. package/templates/shared/src/utilities/smoothScroll.ts +65 -0
@@ -0,0 +1,46 @@
1
+ {
2
+ "type": "block",
3
+ "name": "DDHG-HighlightArc",
4
+ "label": "Highlight Archive Cards",
5
+ "sourceName": "HighlightArchiveCards",
6
+ "portableName": "DDHG-HighlightArc",
7
+ "slug": "DDHG-HighlightArc",
8
+ "version": "0.0.1",
9
+ "source": {
10
+ "repo": "Hadizainal/HeatherGrey2025",
11
+ "originalPath": "src/blocks/HighlightArchiveCards",
12
+ "originalSlug": "highlightArchiveCards",
13
+ "originalConfigExport": "HighlightArchiveCards",
14
+ "originalComponentExport": "HighlightArchiveCardsBlock",
15
+ "originalInterfaceName": "HighlightArchiveCardsBlock"
16
+ },
17
+ "files": [
18
+ { "from": "Component.tsx", "to": "src/blocks/DDHG-HighlightArc/Component.tsx" },
19
+ { "from": "config.ts", "to": "src/blocks/DDHG-HighlightArc/config.ts" }
20
+ ],
21
+ "dependencies": [{ "name": "lucide-react" }],
22
+ "sharedFiles": [],
23
+ "requiredProjectFiles": [
24
+ { "path": "src/fields/link.ts", "reason": "Payload config uses the shared link field." },
25
+ { "path": "src/utilities/ui.ts", "reason": "Component uses the cn utility." }
26
+ ],
27
+ "optionalProjectFiles": [
28
+ { "path": "src/components/Admin/BeforeSidebar", "reason": "Archive bundle admin UI field is currently commented out and can be restored when that bundle is imported." }
29
+ ],
30
+ "collectionRegistration": { "enabled": true, "collections": ["Pages", "Posts"] },
31
+ "renderBlocksRegistration": { "enabled": true },
32
+ "renderBlocksBehavior": { "wrapperless": false },
33
+ "pageRouteIntegration": { "required": false, "manualSteps": [] },
34
+ "manualSteps": [
35
+ "Review this block together with the future archive bundle before re-enabling the BeforeSidebar admin field.",
36
+ "Run payload generate:types after schema changes."
37
+ ],
38
+ "notes": [
39
+ "Converted from HeatherGrey2025 HighlightArchiveCards.",
40
+ "BeforeSidebar is intentionally commented out pending the archive collection bundle review.",
41
+ "Generated Payload document types were replaced with portable structural types.",
42
+ "Installer must not overwrite existing target files."
43
+ ],
44
+ "exportName": "DDHGHighlightArc",
45
+ "interfaceName": "DDHGHighlightArc"
46
+ }
@@ -0,0 +1,143 @@
1
+ 'use client'
2
+
3
+ import React, { useState } from 'react'
4
+ import { motion } from 'framer-motion'
5
+ import Image from 'next/image'
6
+ import { cn } from '@/utilities/ui'
7
+ // DDHG TODO: Re-enable after reviewing the project-specific separator/custom CSS bundle.
8
+ // import { Separator } from '@/components/ui/separator'
9
+ // import { extractCustomCSS } from '@/utilities/renderCustomCSS'
10
+
11
+ const placeholderBlur =
12
+ 'data:image/svg+xml;base64,' +
13
+ btoa(
14
+ `<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg" style="opacity:0"><rect width="100%" height="100%" fill="transparent" /></svg>`,
15
+ )
16
+
17
+ type LogoItem = {
18
+ image?: { url?: string | null; alt?: string | null } | null
19
+ imageClass?: string | null
20
+ imageStyle?: React.CSSProperties
21
+ imageAltClass?: string | null
22
+ }
23
+
24
+ export type DDHGLogoMarqueeProps = {
25
+ sectionId?: string | null
26
+ logos?: LogoItem[] | null
27
+ speed?: number | null
28
+ spacing?: number | null
29
+ priority?: boolean | null
30
+ showTopDivider?: boolean | null
31
+ showBottomDivider?: boolean | null
32
+ containerClass?: string | null
33
+ itemWidth?: number | null
34
+ enableCustomCSS?: boolean | null
35
+ customCSS?: Array<{ blockType?: string; css?: string }> | string | null
36
+ }
37
+
38
+ const LogoImage: React.FC<{
39
+ src: string
40
+ alt?: string | null
41
+ customClass?: string | null
42
+ imageStyle?: React.CSSProperties
43
+ priority?: boolean
44
+ }> = ({ src, alt, customClass, imageStyle, priority = false }) => {
45
+ const [imageError, setImageError] = useState(false)
46
+ const imageSrc = !src || imageError ? placeholderBlur : src
47
+ return (
48
+ <Image
49
+ src={imageSrc}
50
+ alt={alt || 'Logo'}
51
+ width={300}
52
+ height={300}
53
+ priority={priority}
54
+ className={customClass || ''}
55
+ style={{
56
+ objectFit: 'contain',
57
+ ...(imageStyle && typeof imageStyle === 'object' ? imageStyle : {}),
58
+ }}
59
+ onError={() => setImageError(true)}
60
+ placeholder="blur"
61
+ blurDataURL={placeholderBlur}
62
+ />
63
+ )
64
+ }
65
+
66
+ export const DDHGLogoMarquee: React.FC<DDHGLogoMarqueeProps> = ({
67
+ sectionId,
68
+ logos,
69
+ speed = 10,
70
+ spacing = 32,
71
+ priority = false,
72
+ showTopDivider = false,
73
+ showBottomDivider = false,
74
+ containerClass = 'overflow-hidden py-8 bg-transparent',
75
+ enableCustomCSS = false,
76
+ customCSS,
77
+ itemWidth,
78
+ }) => {
79
+ const validLogos = Array.isArray(logos) ? logos : []
80
+ if (validLogos.length === 0) return null
81
+ const calculatedItemWidth = itemWidth || 100
82
+ const totalWidth = validLogos.length * (calculatedItemWidth + (spacing || 0))
83
+
84
+ // DDHG TODO: Re-enable with extractCustomCSS when that bundle is reviewed.
85
+ // const extractedCSS = enableCustomCSS && Array.isArray(customCSS)
86
+ // ? extractCustomCSS(customCSS)
87
+ // : typeof customCSS === 'string'
88
+ // ? customCSS
89
+ // : ''
90
+ const extractedCSS = ''
91
+ void enableCustomCSS
92
+ void customCSS
93
+ void showTopDivider
94
+ void showBottomDivider
95
+
96
+ const renderSet = (suffix = '') =>
97
+ validLogos.map((logo, index) => (
98
+ <div
99
+ key={`logo-${index}${suffix}`}
100
+ className="marque-image-container shrink-0 flex flex-col items-center justify-center"
101
+ style={{
102
+ marginRight: `${spacing || 0}px`,
103
+ ...(itemWidth
104
+ ? { width: `${calculatedItemWidth}px` }
105
+ : { minWidth: `${calculatedItemWidth}px` }),
106
+ }}
107
+ >
108
+ <LogoImage
109
+ src={logo.image?.url || placeholderBlur}
110
+ alt={logo.image?.alt}
111
+ customClass={logo.imageClass}
112
+ imageStyle={logo.imageStyle}
113
+ priority={Boolean(priority)}
114
+ />
115
+ <p className={cn('text-base text-center', logo.imageAltClass)}>{logo.image?.alt || null}</p>
116
+ </div>
117
+ ))
118
+
119
+ return (
120
+ <>
121
+ {/* DDHG TODO: Re-enable optional Separator rendering after bundle review. */}
122
+ {/* {showTopDivider && <Separator gradient={true} className="border-seperator" />} */}
123
+ <div
124
+ id={sectionId ?? undefined}
125
+ className="logo-marquee-block relative mx-auto max-w-screen overflow-x-clip bg-stone-300/20 dark:bg-stone-900/10 top-[20vh]"
126
+ >
127
+ {extractedCSS && <style dangerouslySetInnerHTML={{ __html: extractedCSS }} />}
128
+ <motion.div
129
+ className={`${containerClass} flex py-4`}
130
+ animate={{ x: [0, -totalWidth] }}
131
+ transition={{ repeat: Infinity, duration: speed || 10, ease: 'linear' }}
132
+ style={{ width: `${totalWidth * 2}px` }}
133
+ >
134
+ {renderSet()}
135
+ {renderSet('-duplicate')}
136
+ </motion.div>
137
+ </div>
138
+ {/* {showBottomDivider && <Separator gradient={true} className="border-seperator opacity-20" />} */}
139
+ </>
140
+ )
141
+ }
142
+
143
+ export default DDHGLogoMarquee
@@ -0,0 +1,154 @@
1
+ import type { Block } from 'payload'
2
+ // DDHG TODO: Re-enable with the project-specific CustomCssBlock bundle.
3
+ // import { CustomCSSBlock } from '@/blocks/CustomCssBlock/config'
4
+
5
+ export const DDHGLogoMarquee: Block = {
6
+ slug: 'DDHG-LogoMarquee',
7
+ interfaceName: 'DDHGLogoMarquee',
8
+ labels: { singular: 'Image Marquee', plural: 'Image Marquee' },
9
+ fields: [
10
+ {
11
+ name: 'sectionId',
12
+ type: 'text',
13
+ label: 'Section ID',
14
+ required: false,
15
+ admin: { description: 'Optional anchor ID for linking and scroll targets.' },
16
+ },
17
+ {
18
+ type: 'collapsible',
19
+ label: 'Block Settings',
20
+ admin: { initCollapsed: true, className: 'custom-css-class' },
21
+ fields: [
22
+ {
23
+ type: 'collapsible',
24
+ label: 'Container Class',
25
+ admin: { initCollapsed: true, className: 'custom-css-class' },
26
+ fields: [
27
+ {
28
+ name: 'containerClass',
29
+ label: false,
30
+ type: 'text',
31
+ required: false,
32
+ admin: { description: 'Override the default container class.' },
33
+ },
34
+ ],
35
+ },
36
+ {
37
+ type: 'collapsible',
38
+ label: 'Marquee Settings',
39
+ admin: { initCollapsed: true, className: 'custom-group-class' },
40
+ fields: [
41
+ {
42
+ type: 'row',
43
+ fields: [
44
+ {
45
+ name: 'speed',
46
+ type: 'number',
47
+ label: 'Scroll Speed (seconds)',
48
+ defaultValue: 10,
49
+ required: true,
50
+ admin: { width: '50%' },
51
+ },
52
+ {
53
+ name: 'spacing',
54
+ type: 'number',
55
+ label: 'Spacing between images (px)',
56
+ defaultValue: 32,
57
+ required: true,
58
+ admin: { width: '50%' },
59
+ },
60
+ ],
61
+ },
62
+ ],
63
+ },
64
+ { name: 'priority', type: 'checkbox', label: 'High Priority Loading', defaultValue: false },
65
+ {
66
+ type: 'collapsible',
67
+ label: 'Dividers',
68
+ admin: { initCollapsed: true, className: 'custom-group-class' },
69
+ fields: [
70
+ { name: 'showTopDivider', type: 'checkbox', label: 'Show Top Divider' },
71
+ { name: 'showBottomDivider', type: 'checkbox', label: 'Show Bottom Divider' },
72
+ ],
73
+ },
74
+ ],
75
+ },
76
+ {
77
+ name: 'logoImages',
78
+ type: 'upload',
79
+ relationTo: 'media',
80
+ hasMany: true,
81
+ required: false,
82
+ filterOptions: { mimeType: { contains: 'image' } },
83
+ hooks: {
84
+ beforeChange: [
85
+ ({ value, siblingData }) => {
86
+ if (!Array.isArray(value) || value.length === 0) return value
87
+ const existingLogos = Array.isArray((siblingData as any)?.logos)
88
+ ? (siblingData as any).logos
89
+ : []
90
+ const normalizeImageId = (imageValue: unknown): number | string | undefined => {
91
+ if (typeof imageValue === 'number' || typeof imageValue === 'string')
92
+ return imageValue
93
+ if (imageValue && typeof imageValue === 'object' && 'id' in (imageValue as any)) {
94
+ const maybeId = (imageValue as any).id
95
+ if (typeof maybeId === 'number' || typeof maybeId === 'string') return maybeId
96
+ }
97
+ return undefined
98
+ }
99
+ const existingIds = new Set(
100
+ existingLogos
101
+ .map((row: any) => normalizeImageId(row?.image))
102
+ .filter((id: any) => id !== undefined),
103
+ )
104
+ const newRows = value
105
+ .map((id) => normalizeImageId(id))
106
+ .filter((id): id is number | string => id !== undefined)
107
+ .filter((id) => !existingIds.has(id))
108
+ .map((id) => ({ image: id, imageAltClass: 'hidden', imageClass: '' }))
109
+ ;(siblingData as any).logos = [...existingLogos, ...newRows]
110
+ return []
111
+ },
112
+ ],
113
+ },
114
+ },
115
+ {
116
+ name: 'logos',
117
+ type: 'array',
118
+ label: 'Images',
119
+ labels: { singular: 'Image', plural: 'Images' },
120
+ fields: [
121
+ {
122
+ name: 'image',
123
+ type: 'upload',
124
+ relationTo: 'media',
125
+ required: false,
126
+ filterOptions: { mimeType: { contains: 'image' } },
127
+ },
128
+ {
129
+ type: 'collapsible',
130
+ label: 'Alt Text Class',
131
+ admin: { initCollapsed: true, className: 'custom-css-class' },
132
+ fields: [
133
+ {
134
+ name: 'imageAltClass',
135
+ label: false,
136
+ type: 'text',
137
+ required: false,
138
+ defaultValue: 'hidden',
139
+ },
140
+ ],
141
+ },
142
+ {
143
+ type: 'collapsible',
144
+ label: 'Image Class',
145
+ admin: { initCollapsed: true, className: 'custom-css-class' },
146
+ fields: [{ name: 'imageClass', label: false, type: 'text', required: false }],
147
+ },
148
+ ],
149
+ },
150
+ // DDHG TODO: Re-enable custom CSS support after reviewing the CustomCssBlock bundle.
151
+ // { name: 'enableCustomCSS', type: 'checkbox', label: 'Inject Custom CSS', defaultValue: false },
152
+ // { name: 'customCSS', type: 'blocks', label: 'Custom CSS', blocks: [CustomCSSBlock], maxRows: 1, required: false, admin: { initCollapsed: true, className: 'for-devs-class custom-css-class', condition: (_, siblingData) => Boolean(siblingData.enableCustomCSS) } },
153
+ ],
154
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "type": "block",
3
+ "name": "DDHG-LogoMarquee",
4
+ "label": "Logo Marquee",
5
+ "sourceName": "LogoMarquee",
6
+ "portableName": "DDHG-LogoMarquee",
7
+ "slug": "DDHG-LogoMarquee",
8
+ "version": "0.0.1",
9
+ "source": { "repo": "Hadizainal/HeatherGrey2025", "originalPath": "src/blocks/LogoMarquee", "originalSlug": "logoMarquee", "originalConfigExport": "LogoMarquee", "originalComponentExport": "LogoMarquee", "originalInterfaceName": "LogoMarqueeBlock" },
10
+ "files": [
11
+ { "from": "Component.tsx", "to": "src/blocks/DDHG-LogoMarquee/Component.tsx" },
12
+ { "from": "config.ts", "to": "src/blocks/DDHG-LogoMarquee/config.ts" }
13
+ ],
14
+ "dependencies": [{ "name": "framer-motion" }],
15
+ "sharedFiles": [],
16
+ "requiredProjectFiles": [
17
+ { "path": "src/utilities/ui.ts", "reason": "Component uses the cn utility." }
18
+ ],
19
+ "optionalProjectFiles": [
20
+ { "path": "src/blocks/CustomCssBlock/config.ts", "reason": "Custom CSS block support is currently commented out pending deeper review." },
21
+ { "path": "src/components/ui/separator.tsx", "reason": "Optional divider rendering is currently commented out pending deeper review." },
22
+ { "path": "src/utilities/renderCustomCSS.ts", "reason": "Custom CSS extraction is currently commented out pending deeper review." }
23
+ ],
24
+ "collectionRegistration": { "enabled": true, "collections": ["Pages", "Posts"] },
25
+ "renderBlocksRegistration": { "enabled": true },
26
+ "renderBlocksBehavior": { "wrapperless": false },
27
+ "pageRouteIntegration": { "required": false, "manualSteps": [] },
28
+ "manualSteps": [
29
+ "Review CustomCssBlock, Separator and renderCustomCSS together before re-enabling those commented integrations.",
30
+ "Run payload generate:types after schema changes."
31
+ ],
32
+ "notes": [
33
+ "Converted from HeatherGrey2025 LogoMarquee.",
34
+ "Project-specific custom CSS and separator integrations are intentionally commented out pending review.",
35
+ "Installer must not overwrite existing target files."
36
+ ],
37
+ "exportName": "DDHGLogoMarquee",
38
+ "interfaceName": "DDHGLogoMarquee"
39
+ }
@@ -0,0 +1,227 @@
1
+ 'use client'
2
+
3
+ import Image from 'next/image'
4
+ import Link from 'next/link'
5
+ import * as LucideIcons from 'lucide-react'
6
+ import React from 'react'
7
+
8
+ import { getMediaUrl } from '@/utilities/getMediaUrl'
9
+ import { cn } from '@/utilities/ui'
10
+
11
+ type PortableDoc = {
12
+ slug?: string | null
13
+ breadcrumbs?: Array<{ url?: string | null }> | null
14
+ [key: string]: unknown
15
+ }
16
+
17
+ type Media = {
18
+ url?: string | null
19
+ alt?: string | null
20
+ [key: string]: unknown
21
+ }
22
+
23
+ type LinkReference =
24
+ | { relationTo: 'pages'; value: number | PortableDoc }
25
+ | { relationTo: 'posts'; value: number | PortableDoc }
26
+ | { relationTo: 'projects'; value: number | PortableDoc }
27
+ | { relationTo: 'thoughts'; value: number | PortableDoc }
28
+
29
+ type NavCodeGridLink = {
30
+ type?: 'reference' | 'custom' | null
31
+ reference?: LinkReference | null
32
+ url?: string | null
33
+ label?: string | null
34
+ newTab?: boolean | null
35
+ icon?: string | null
36
+ iconPosition?: 'before' | 'after' | null
37
+ customIcon?: number | Media | null
38
+ } | null
39
+
40
+ export type DDHGNavCodeGridItem = {
41
+ id?: string | null
42
+ code?: string | null
43
+ link?: NavCodeGridLink
44
+ }
45
+
46
+ export type DDHGNavCodeGridProps = {
47
+ items?: DDHGNavCodeGridItem[] | null
48
+ defaultHref?: string | null
49
+ containerClassName?: string | null
50
+ gridClassName?: string | null
51
+ cellClassName?: string | null
52
+ showIcons?: boolean | null
53
+ }
54
+
55
+ const getPageURLFromDoc = (doc: PortableDoc | number): string | null => {
56
+ if (typeof doc === 'number') return null
57
+ const crumbs = Array.isArray(doc?.breadcrumbs) ? doc.breadcrumbs : []
58
+ if (crumbs.length) {
59
+ const last = crumbs[crumbs.length - 1]
60
+ if (typeof last?.url === 'string' && last.url) return last.url
61
+ }
62
+ const slug = doc?.slug
63
+ if (!slug || slug === 'home') return '/'
64
+ return slug.startsWith('/') ? slug : `/${slug}`
65
+ }
66
+
67
+ const getDocumentSlug = (doc: PortableDoc | number): string | null => {
68
+ if (typeof doc === 'number') return null
69
+ return doc?.slug || null
70
+ }
71
+
72
+ const getCollectionPath = (relationTo: LinkReference['relationTo']): string => {
73
+ if (relationTo === 'posts') return 'internal-docs'
74
+ if (relationTo === 'thoughts') return 'thoughts'
75
+ if (relationTo === 'projects') return 'archives'
76
+ return ''
77
+ }
78
+
79
+ const isExternalUrl = (href: string): boolean =>
80
+ href.startsWith('http://') ||
81
+ href.startsWith('https://') ||
82
+ href.startsWith('mailto:') ||
83
+ href.startsWith('tel:')
84
+
85
+ const resolveHref = (link: NavCodeGridLink, defaultHref = '/archive'): string => {
86
+ if (!link) return defaultHref
87
+ if (link.type === 'custom' && link.url) return link.url
88
+ if (link.type === 'reference' && link.reference?.value) {
89
+ const { relationTo, value } = link.reference
90
+ if (relationTo === 'pages') return getPageURLFromDoc(value) || defaultHref
91
+ const slug = getDocumentSlug(value)
92
+ if (!slug) return defaultHref
93
+ const basePath = getCollectionPath(relationTo)
94
+ return basePath ? `/${basePath}/${slug}` : `/${slug}`
95
+ }
96
+ return defaultHref
97
+ }
98
+
99
+ const renderIcon = (link: NavCodeGridLink, showIcons = true) => {
100
+ if (!showIcons || !link) return null
101
+
102
+ if (link.customIcon && typeof link.customIcon === 'object') {
103
+ const iconUrl = getMediaUrl(link.customIcon.url)
104
+ if (iconUrl) {
105
+ return (
106
+ <span className="inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center overflow-hidden">
107
+ <Image
108
+ src={iconUrl}
109
+ alt={link.customIcon.alt || ''}
110
+ width={14}
111
+ height={14}
112
+ className="m-0 block h-full w-full object-contain"
113
+ />
114
+ </span>
115
+ )
116
+ }
117
+ }
118
+
119
+ if (link.icon) {
120
+ const LucideIcon = LucideIcons[link.icon as keyof typeof LucideIcons] as
121
+ React.ComponentType<{ className?: string }> | undefined
122
+ if (LucideIcon) {
123
+ return (
124
+ <span className="inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center">
125
+ <LucideIcon className="h-3.5 w-3.5" />
126
+ </span>
127
+ )
128
+ }
129
+ }
130
+
131
+ return null
132
+ }
133
+
134
+ const getDelayClass = (index: number) => {
135
+ const delay = Math.min(index * 40, 320)
136
+ return `[transition-delay:${delay}ms]`
137
+ }
138
+
139
+ export const DDHGNavCodeGrid: React.FC<DDHGNavCodeGridProps> = ({
140
+ items,
141
+ defaultHref = '/archive',
142
+ containerClassName,
143
+ gridClassName,
144
+ cellClassName,
145
+ showIcons = true,
146
+ }) => {
147
+ if (!Array.isArray(items) || items.length === 0) return null
148
+
149
+ return (
150
+ <div className={cn('w-full max-w-7xl mx-auto', containerClassName, 'pt-24')}>
151
+ <div
152
+ className={cn(
153
+ 'grid grid-cols-2 overflow-hidden bg-stone-100/50 dark:bg-stone-900/50 sm:grid-cols-4 !gap-0 shadow-lg',
154
+ gridClassName,
155
+ )}
156
+ >
157
+ {items.map((item, index) => {
158
+ const link = item.link || null
159
+ const href = resolveHref(link, defaultHref || '/archive')
160
+ const label = link?.label || item.code || 'Archive'
161
+ const icon = renderIcon(link, Boolean(showIcons))
162
+ const iconPosition = link?.iconPosition || 'before'
163
+ const target = link?.newTab ? '_blank' : undefined
164
+ const rel = link?.newTab ? 'noopener noreferrer' : undefined
165
+ const className = cn(
166
+ 'menu-cell-hover group relative flex items-center justify-center gap-2 bg-stone-200/50 py-2.5 text-xs font-normal uppercase tracking-[0.1em] text-sm [text-shadow:0px_2px_4px_#ffffff45] backdrop-blur-2xl transition-all duration-300 hover:-translate-y-0.5 hover:bg-stone-200/80 hover:text-stone-700 dark:bg-stone-900/50 dark:text-stone-200 dark:hover:bg-stone-800/70 sm:py-3 sm:text-xs md:py-4 hover:shadow-2xl',
167
+ 'border-r border-b border-border',
168
+ (index + 1) % 4 === 0 ? 'sm:border-r-0' : ' ',
169
+ index >= 4 ? 'sm:border-b-0' : '',
170
+ (index + 1) % 2 === 0 ? 'border-r-0' : 'border-r',
171
+ index >= 6 ? 'border-b-0' : 'border-b',
172
+ getDelayClass(index),
173
+ cellClassName,
174
+ )
175
+
176
+ const content = (
177
+ <>
178
+ {icon && iconPosition === 'before' && icon}
179
+ <span className="relative z-10">{label}</span>
180
+ {icon && iconPosition === 'after' && icon}
181
+ </>
182
+ )
183
+
184
+ if (isExternalUrl(href)) {
185
+ return (
186
+ <a
187
+ key={item.id || `${label}-${index}`}
188
+ href={href}
189
+ target={target}
190
+ rel={rel}
191
+ className={className}
192
+ style={{
193
+ fontFamily: "'Space Grotesk', sans-serif",
194
+ fontWeight: 400,
195
+ position: 'relative',
196
+ textDecoration: 'none',
197
+ }}
198
+ >
199
+ {content}
200
+ </a>
201
+ )
202
+ }
203
+
204
+ return (
205
+ <Link
206
+ key={item.id || `${label}-${index}`}
207
+ href={href}
208
+ target={target}
209
+ rel={rel}
210
+ className={className}
211
+ style={{
212
+ fontFamily: "'Space Grotesk', sans-serif",
213
+ fontWeight: 400,
214
+ position: 'relative',
215
+ textDecoration: 'none',
216
+ }}
217
+ >
218
+ {content}
219
+ </Link>
220
+ )
221
+ })}
222
+ </div>
223
+ </div>
224
+ )
225
+ }
226
+
227
+ export default DDHGNavCodeGrid
@@ -0,0 +1,64 @@
1
+ import type { Block } from 'payload'
2
+
3
+ import { link } from '@/fields/link'
4
+
5
+ export const DDHGNavCodeGrid: Block = {
6
+ slug: 'DDHG-NavCodeGrid',
7
+ interfaceName: 'DDHGNavCodeGrid',
8
+ labels: {
9
+ singular: 'Nav Code Grid',
10
+ plural: 'Nav Code Grids',
11
+ },
12
+ fields: [
13
+ {
14
+ name: 'items',
15
+ type: 'array',
16
+ label: 'Navigation Items',
17
+ minRows: 1,
18
+ fields: [
19
+ {
20
+ name: 'code',
21
+ type: 'text',
22
+ label: 'Fallback Code / Label',
23
+ },
24
+ link({
25
+ overrides: {
26
+ name: 'link',
27
+ label: 'Link',
28
+ },
29
+ disableLabel: false,
30
+ appearances: false,
31
+ }),
32
+ ],
33
+ },
34
+ {
35
+ type: 'row',
36
+ fields: [
37
+ {
38
+ name: 'defaultHref',
39
+ type: 'text',
40
+ label: 'Default href',
41
+ defaultValue: '/archive',
42
+ admin: { width: '50%' },
43
+ },
44
+ {
45
+ name: 'showIcons',
46
+ type: 'checkbox',
47
+ label: 'Show icons',
48
+ defaultValue: true,
49
+ admin: { width: '50%' },
50
+ },
51
+ ],
52
+ },
53
+ {
54
+ type: 'collapsible',
55
+ label: 'Classes',
56
+ admin: { initCollapsed: true },
57
+ fields: [
58
+ { name: 'containerClassName', type: 'text', label: 'Container class' },
59
+ { name: 'gridClassName', type: 'text', label: 'Grid class' },
60
+ { name: 'cellClassName', type: 'text', label: 'Cell class' },
61
+ ],
62
+ },
63
+ ],
64
+ }