blocks-dusted 0.1.10 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/README.md +35 -0
  2. package/package.json +5 -2
  3. package/src/cli.js +39 -3
  4. package/src/commands/shop.js +59 -0
  5. package/src/commands/warehouse.js +73 -0
  6. package/src/utils/paths.js +13 -13
  7. package/templates/blocks/DD-Accordion/Component.tsx +229 -0
  8. package/templates/blocks/DD-Accordion/README.md +3 -0
  9. package/templates/blocks/DD-Accordion/config.ts +73 -0
  10. package/templates/blocks/DD-Accordion/manifest.json +75 -0
  11. package/templates/blocks/DD-AnimText/Component.tsx +788 -0
  12. package/templates/blocks/DD-AnimText/README.md +3 -0
  13. package/templates/blocks/DD-AnimText/config.ts +295 -0
  14. package/templates/blocks/DD-AnimText/manifest.json +85 -0
  15. package/templates/blocks/DD-AsideNav/Component.tsx +321 -0
  16. package/templates/blocks/DD-AsideNav/config.ts +204 -0
  17. package/templates/blocks/DD-AsideNav/manifest.json +80 -0
  18. package/templates/blocks/DD-Banner/Component.tsx +51 -0
  19. package/templates/blocks/DD-Banner/config.ts +57 -0
  20. package/templates/blocks/DD-Banner/manifest.json +72 -0
  21. package/templates/blocks/DD-BgLightning/Component.tsx +44 -0
  22. package/templates/blocks/DD-BgLightning/README.md +3 -0
  23. package/templates/blocks/DD-BgLightning/config.ts +97 -0
  24. package/templates/blocks/DD-BgLightning/manifest.json +79 -0
  25. package/templates/blocks/DD-BookCall/Component.tsx +535 -535
  26. package/templates/blocks/DD-BookCall/config.ts +238 -238
  27. package/templates/blocks/DD-ButtonPop/Component.tsx +117 -0
  28. package/templates/blocks/DD-ButtonPop/config.ts +105 -0
  29. package/templates/blocks/DD-ButtonPop/manifest.json +88 -0
  30. package/templates/blocks/DD-ButtonPop/svg-icons/Dust2.tsx +167 -0
  31. package/templates/blocks/DD-Card/Component.tsx +251 -0
  32. package/templates/blocks/DD-Card/README.md +4 -0
  33. package/templates/blocks/DD-Card/config.ts +154 -0
  34. package/templates/blocks/DD-Card/manifest.json +82 -0
  35. package/templates/blocks/DD-CardTemplate01/Component.tsx +140 -140
  36. package/templates/blocks/DD-CardTemplate01/config.ts +106 -106
  37. package/templates/blocks/DD-Carousel-A/Component.tsx +249 -249
  38. package/templates/blocks/DD-Carousel-B/Component.tsx +403 -403
  39. package/templates/blocks/DD-Chip/Component.tsx +250 -0
  40. package/templates/blocks/DD-Chip/EXAMPLES.md +313 -0
  41. package/templates/blocks/DD-Chip/README.md +202 -0
  42. package/templates/blocks/DD-Chip/config.ts +369 -0
  43. package/templates/blocks/DD-Chip/manifest.json +74 -0
  44. package/templates/blocks/DD-ComparisonTable/Component.tsx +256 -256
  45. package/templates/blocks/DD-Contact/Component.tsx +435 -434
  46. package/templates/blocks/DD-Contact/config.ts +22 -22
  47. package/templates/blocks/DD-Counter/Component.tsx +190 -0
  48. package/templates/blocks/DD-Counter/README.md +4 -0
  49. package/templates/blocks/DD-Counter/config.ts +291 -0
  50. package/templates/blocks/DD-Counter/manifest.json +74 -0
  51. package/templates/blocks/DD-CustomCSS/Component.tsx +8 -0
  52. package/templates/blocks/DD-CustomCSS/README.md +4 -0
  53. package/templates/blocks/DD-CustomCSS/addToLayout.md +5 -0
  54. package/templates/blocks/DD-CustomCSS/config.ts +22 -0
  55. package/templates/blocks/DD-CustomCSS/manifest.json +72 -0
  56. package/templates/blocks/DD-CustomCSS/renderCustomCSS.md +7 -0
  57. package/templates/blocks/DD-FeatCat/Component.tsx +302 -302
  58. package/templates/blocks/DD-FeatCat/config.ts +201 -201
  59. package/templates/blocks/DD-FeatStrip/Component.tsx +585 -585
  60. package/templates/blocks/DD-FeatStrip/config.ts +134 -134
  61. package/templates/blocks/DD-FluidBtn/ButtonsEyeCatching.tsx +628 -0
  62. package/templates/blocks/DD-FluidBtn/Component.tsx +43 -0
  63. package/templates/blocks/DD-FluidBtn/README.md +6 -0
  64. package/templates/blocks/DD-FluidBtn/config.ts +102 -0
  65. package/templates/blocks/DD-FluidBtn/manifest.json +86 -0
  66. package/templates/blocks/DD-GooeyInfo/Component.tsx +149 -0
  67. package/templates/blocks/DD-GooeyInfo/config.ts +135 -0
  68. package/templates/blocks/DD-GooeyInfo/manifest.json +72 -0
  69. package/templates/blocks/DD-Hero/Component.tsx +297 -297
  70. package/templates/blocks/DD-Hero/config.ts +267 -267
  71. package/templates/blocks/DD-HorizontalScroll/Component.tsx +936 -936
  72. package/templates/blocks/DD-HorizontalScroll/config.ts +231 -231
  73. package/templates/blocks/DD-Icon/Component.tsx +287 -0
  74. package/templates/blocks/DD-Icon/README.md +4 -0
  75. package/templates/blocks/DD-Icon/config.ts +258 -0
  76. package/templates/blocks/DD-Icon/hooks/revalidateBlockIds.ts +66 -0
  77. package/templates/blocks/DD-Icon/manifest.json +82 -0
  78. package/templates/blocks/DD-IconButton/Component.tsx +455 -0
  79. package/templates/blocks/DD-IconButton/README.md +326 -0
  80. package/templates/blocks/DD-IconButton/config.ts +239 -0
  81. package/templates/blocks/DD-IconButton/manifest.json +85 -0
  82. package/templates/blocks/DD-IdTag/Component.tsx +21 -0
  83. package/templates/blocks/DD-IdTag/README.md +4 -0
  84. package/templates/blocks/DD-IdTag/config.ts +41 -0
  85. package/templates/blocks/DD-IdTag/manifest.json +72 -0
  86. package/templates/blocks/DD-Iframe/Component.tsx +45 -0
  87. package/templates/blocks/DD-Iframe/README.md +4 -0
  88. package/templates/blocks/DD-Iframe/config.ts +47 -0
  89. package/templates/blocks/DD-Iframe/manifest.json +72 -0
  90. package/templates/blocks/DD-IframeMedia/Component.tsx +133 -0
  91. package/templates/blocks/DD-IframeMedia/README.md +4 -0
  92. package/templates/blocks/DD-IframeMedia/config.ts +79 -0
  93. package/templates/blocks/DD-IframeMedia/manifest.json +72 -0
  94. package/templates/blocks/DD-LineAnim/Component.tsx +36 -0
  95. package/templates/blocks/DD-LineAnim/README.md +4 -0
  96. package/templates/blocks/DD-LineAnim/config.ts +90 -0
  97. package/templates/blocks/DD-LineAnim/manifest.json +80 -0
  98. package/templates/blocks/DD-LinkGrid/Component.tsx +119 -0
  99. package/templates/blocks/DD-LinkGrid/README.md +4 -0
  100. package/templates/blocks/DD-LinkGrid/config.ts +51 -0
  101. package/templates/blocks/DD-LinkGrid/manifest.json +74 -0
  102. package/templates/blocks/DD-LogoMarq/Component.tsx +132 -0
  103. package/templates/blocks/DD-LogoMarq/README.md +4 -0
  104. package/templates/blocks/DD-LogoMarq/config.ts +264 -0
  105. package/templates/blocks/DD-LogoMarq/manifest.json +82 -0
  106. package/templates/blocks/DD-Lottie/Component.tsx +459 -0
  107. package/templates/blocks/DD-Lottie/README.md +4 -0
  108. package/templates/blocks/DD-Lottie/config.ts +379 -0
  109. package/templates/blocks/DD-Lottie/index.tsx +28 -0
  110. package/templates/blocks/DD-Lottie/manifest.json +83 -0
  111. package/templates/blocks/DD-MagicBento/Component.tsx +777 -0
  112. package/templates/blocks/DD-MagicBento/README.md +4 -0
  113. package/templates/blocks/DD-MagicBento/config.ts +264 -0
  114. package/templates/blocks/DD-MagicBento/manifest.json +74 -0
  115. package/templates/blocks/DD-MasonaryMedia/Component.tsx +545 -545
  116. package/templates/blocks/DD-MasonaryMedia/config.ts +2 -2
  117. package/templates/blocks/DD-MasonaryMedia/vendor.d.ts +2 -2
  118. package/templates/blocks/DD-Masonry/Component.tsx +645 -0
  119. package/templates/blocks/DD-Masonry/README.md +4 -0
  120. package/templates/blocks/DD-Masonry/config.ts +475 -0
  121. package/templates/blocks/DD-Masonry/manifest.json +82 -0
  122. package/templates/blocks/DD-Pricing/Component.tsx +2 -5
  123. package/templates/blocks/DD-Process/Component.tsx +2 -4
  124. package/templates/blocks/DD-Process/config.ts +150 -150
  125. package/templates/blocks/DD-Progress/Component.tsx +156 -0
  126. package/templates/blocks/DD-Progress/README.md +4 -0
  127. package/templates/blocks/DD-Progress/config.ts +175 -0
  128. package/templates/blocks/DD-Progress/manifest.json +74 -0
  129. package/templates/blocks/DD-ProjHeader/Component.tsx +91 -0
  130. package/templates/blocks/DD-ProjHeader/README.md +4 -0
  131. package/templates/blocks/DD-ProjHeader/config.ts +96 -0
  132. package/templates/blocks/DD-ProjHeader/manifest.json +72 -0
  133. package/templates/blocks/DD-ProjSlider/Component.tsx +123 -0
  134. package/templates/blocks/DD-ProjSlider/README.md +4 -0
  135. package/templates/blocks/DD-ProjSlider/config.ts +64 -0
  136. package/templates/blocks/DD-ProjSlider/manifest.json +72 -0
  137. package/templates/blocks/DD-ScrollText/Component.tsx +114 -0
  138. package/templates/blocks/DD-ScrollText/README.md +4 -0
  139. package/templates/blocks/DD-ScrollText/config.ts +58 -0
  140. package/templates/blocks/DD-ScrollText/manifest.json +72 -0
  141. package/templates/blocks/DD-Section/Component.tsx +266 -266
  142. package/templates/blocks/DD-Separator/Component.tsx +66 -0
  143. package/templates/blocks/DD-Separator/README.md +4 -0
  144. package/templates/blocks/DD-Separator/config.ts +58 -0
  145. package/templates/blocks/DD-Separator/manifest.json +72 -0
  146. package/templates/blocks/DD-Services/Component.tsx +176 -176
  147. package/templates/blocks/DD-Services/config.ts +149 -149
  148. package/templates/blocks/DD-ShowcaseGrid/Component.tsx +307 -307
  149. package/templates/blocks/DD-Slider-A/Component.tsx +1 -1
  150. package/templates/blocks/DD-StackCards/Component.tsx +1 -1
  151. package/templates/blocks/DD-StackCards/config.ts +399 -399
  152. package/templates/blocks/DD-Team/Component.tsx +247 -247
  153. package/templates/blocks/DD-Team/config.ts +173 -173
  154. package/templates/blocks/DD-TeamCards/Component.tsx +251 -0
  155. package/templates/blocks/DD-TeamCards/README.md +4 -0
  156. package/templates/blocks/DD-TeamCards/config.ts +302 -0
  157. package/templates/blocks/DD-TeamCards/manifest.json +74 -0
  158. package/templates/blocks/DD-TechStack/Component.tsx +174 -174
  159. package/templates/blocks/DD-TechStack/config.ts +153 -153
  160. package/templates/blocks/DD-TestMarq/Component.tsx +132 -0
  161. package/templates/blocks/DD-TestMarq/README.md +4 -0
  162. package/templates/blocks/DD-TestMarq/RowLabel.tsx +9 -0
  163. package/templates/blocks/DD-TestMarq/config.ts +88 -0
  164. package/templates/blocks/DD-TestMarq/manifest.json +72 -0
  165. package/templates/blocks/DD-Testim/Component.tsx +247 -0
  166. package/templates/blocks/DD-Testim/README.md +4 -0
  167. package/templates/blocks/DD-Testim/config.ts +101 -0
  168. package/templates/blocks/DD-Testim/manifest.json +75 -0
  169. package/templates/blocks/DD-Testim2/Component.tsx +256 -0
  170. package/templates/blocks/DD-Testim2/README.md +4 -0
  171. package/templates/blocks/DD-Testim2/config.ts +100 -0
  172. package/templates/blocks/DD-Testim2/manifest.json +74 -0
  173. package/templates/blocks/DD-Testimonials/Component.tsx +139 -147
  174. package/templates/blocks/DD-Testimonials/config.ts +120 -120
  175. package/templates/blocks/DD-TextMarq/Component.tsx +157 -0
  176. package/templates/blocks/DD-TextMarq/README.md +4 -0
  177. package/templates/blocks/DD-TextMarq/config.ts +237 -0
  178. package/templates/blocks/DD-TextMarq/manifest.json +82 -0
  179. package/templates/blocks/DD-Thanks/Component.tsx +501 -0
  180. package/templates/blocks/DD-Thanks/README.md +4 -0
  181. package/templates/blocks/DD-Thanks/config.ts +224 -0
  182. package/templates/blocks/DD-Thanks/manifest.json +72 -0
  183. package/templates/blocks/DD-VertMarq/Component.tsx +154 -0
  184. package/templates/blocks/DD-VertMarq/README.md +4 -0
  185. package/templates/blocks/DD-VertMarq/config.ts +236 -0
  186. package/templates/blocks/DD-VertMarq/dist/index.css +6 -0
  187. package/templates/blocks/DD-VertMarq/dist/index.min.css +1 -0
  188. package/templates/blocks/DD-VertMarq/manifest.json +74 -0
  189. package/templates/blocks/DD-Work/Component.tsx +318 -315
  190. package/templates/blocks/DD-Work/config.ts +165 -165
  191. package/templates/blocks/DD-Work-B/Component.tsx +294 -294
  192. package/templates/blocks/DDHG-CTASection2/Component.tsx +185 -0
  193. package/templates/blocks/DDHG-CTASection2/config.ts +140 -0
  194. package/templates/blocks/DDHG-CTASection2/manifest.json +45 -0
  195. package/templates/blocks/DDHG-HighlightArc/Component.tsx +243 -0
  196. package/templates/blocks/DDHG-HighlightArc/config.ts +85 -0
  197. package/templates/blocks/DDHG-HighlightArc/manifest.json +46 -0
  198. package/templates/blocks/DDHG-LogoMarquee/Component.tsx +143 -0
  199. package/templates/blocks/DDHG-LogoMarquee/config.ts +154 -0
  200. package/templates/blocks/DDHG-LogoMarquee/manifest.json +39 -0
  201. package/templates/blocks/DDHG-NavCodeGrid/Component.tsx +227 -0
  202. package/templates/blocks/DDHG-NavCodeGrid/config.ts +64 -0
  203. package/templates/blocks/DDHG-NavCodeGrid/manifest.json +45 -0
  204. package/templates/blocks/DDHG-ProcessSec/Component.tsx +574 -0
  205. package/templates/blocks/DDHG-ProcessSec/config.ts +170 -0
  206. package/templates/blocks/DDHG-ProcessSec/manifest.json +56 -0
  207. package/templates/blocks/DDHG-ServiceDetails/Component.tsx +164 -0
  208. package/templates/blocks/DDHG-ServiceDetails/ServiceDetailCard.tsx +390 -0
  209. package/templates/blocks/DDHG-ServiceDetails/config.ts +77 -0
  210. package/templates/blocks/DDHG-ServiceDetails/manifest.json +50 -0
  211. package/templates/blocks/DDHG-ServiceHero/Component.tsx +234 -0
  212. package/templates/blocks/DDHG-ServiceHero/config.ts +49 -0
  213. package/templates/blocks/DDHG-ServiceHero/manifest.json +26 -0
  214. package/templates/blocks/DDHG-ServiceOverview/Component.tsx +277 -0
  215. package/templates/blocks/DDHG-ServiceOverview/config.ts +64 -0
  216. package/templates/blocks/DDHG-ServiceOverview/manifest.json +44 -0
  217. package/templates/blocks/DDHG-StatsFAQ/Component.tsx +389 -0
  218. package/templates/blocks/DDHG-StatsFAQ/config.ts +204 -0
  219. package/templates/blocks/DDHG-StatsFAQ/manifest.json +45 -0
  220. package/templates/blocks/DDHG-TeamCards/Component.tsx +169 -0
  221. package/templates/blocks/DDHG-TeamCards/config.ts +48 -0
  222. package/templates/blocks/DDHG-TeamCards/manifest.json +29 -0
  223. package/templates/shared/src/components/BgLightning/index.tsx +242 -0
  224. package/templates/shared/src/components/ui/ShareButton/index.tsx +80 -0
  225. package/templates/shared/src/components/ui/anims/FadeOnScroll.tsx +48 -0
  226. package/templates/shared/src/components/ui/anims/FadeUpOnInView.tsx +63 -0
  227. package/templates/shared/src/components/ui/anims/GlareHover.tsx +111 -0
  228. package/templates/shared/src/components/ui/anims/LineAnims.tsx +81 -0
  229. package/templates/shared/src/components/ui/anims/TitleAnims01.tsx +54 -0
  230. package/templates/shared/src/components/ui/anims/animation-container.tsx +29 -0
  231. package/templates/shared/src/components/ui/anims/blur-in.tsx +26 -0
  232. package/templates/shared/src/components/ui/anims/counter.tsx +53 -0
  233. package/templates/shared/src/components/ui/anims/fade.tsx +83 -0
  234. package/templates/shared/src/components/ui/anims/gradual-spacing.tsx +39 -0
  235. package/templates/shared/src/components/ui/anims/pull-up.tsx +93 -0
  236. package/templates/shared/src/components/ui/anims/reveal-text.tsx +76 -0
  237. package/templates/shared/src/components/ui/anims/rotate-words.tsx +43 -0
  238. package/templates/shared/src/components/ui/anims/shiny-text.tsx +58 -0
  239. package/templates/shared/src/components/ui/anims/shuffle-text.tsx +85 -0
  240. package/templates/shared/src/components/ui/anims/split-text.tsx +211 -0
  241. package/templates/shared/src/components/ui/anims/staggered-fade.tsx +133 -0
  242. package/templates/shared/src/components/ui/anims/text-scroll.tsx +111 -0
  243. package/templates/shared/src/components/ui/anims/typing-effect.tsx +112 -0
  244. package/templates/shared/src/components/ui/button-dusted-fluid/index.tsx +1521 -0
  245. package/templates/shared/src/components/ui/separator.tsx +85 -0
  246. package/templates/shared/src/hooks/useBodyScrollLock.ts +97 -0
  247. package/templates/shared/src/hooks/useClickOutside.ts +28 -0
  248. package/templates/shared/src/utilities/renderCustomCSS.ts +5 -0
  249. package/templates/shared/src/utilities/smoothScroll.ts +65 -0
@@ -1,147 +1,139 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import Image from "next/image";
5
- import { Star } from "lucide-react";
6
- import { motion, type Variants } from "framer-motion";
7
- export type DDTestimonialsProps = Record<string, any>;
8
- type Media = { url?: string | null };
9
- type Testimonial = {
10
- id?: string | null;
11
- title?: string | null;
12
- content?: unknown;
13
- designation?: unknown;
14
- companyLogo?: Media | string | null;
15
- fallbackAvatarUrl?: string | null;
16
- rating?: number | null;
17
- };
18
-
19
- function isLocalImageSrc(src?: string | null): src is string {
20
- return typeof src === "string" && src.startsWith("/api/media/file/");
21
- }
22
-
23
- const containerVariants: Variants = {
24
- hidden: {},
25
- show: { transition: { staggerChildren: 0.12, delayChildren: 0.05 } },
26
- };
27
-
28
- const cardVariants: Variants = {
29
- hidden: { opacity: 0, y: 24 },
30
- show: { opacity: 1, y: 0, transition: { duration: 0.5, ease: "easeOut" } },
31
- };
32
-
33
- export const DDTestimonials: React.FC<DDTestimonialsProps> = ({
34
- eyebrow,
35
- headline,
36
- testimonials,
37
- sectionId,
38
- customCSS,
39
- }) => {
40
- const populated = ((testimonials ?? []) as unknown[]).filter(
41
- (t): t is Testimonial => typeof t === "object" && t !== null,
42
- );
43
-
44
- return (
45
- <>
46
- {customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
47
-
48
- <div id={sectionId ?? "testimonials"} className="py-24">
49
- <div className="max-w-6xl lg:max-w-7xl mx-auto px-4 md:px-6">
50
- {/* Header */}#BlockName-DDTestimonials
51
- <div className="text-center max-w-xl mx-auto mb-14">
52
- {eyebrow && (
53
- <p className="text-[11.5px] font-semibold text-stone-400 tracking-widest uppercase mb-3 top-caption">
54
- {eyebrow}
55
- </p>
56
- )}
57
- <h2 className="text-3xl font-semibold text-stone-900 dark:text-stone-50 leading-tight">
58
- {headline}
59
- </h2>
60
- </div>
61
- {/* Testimonials */}
62
- {populated.length > 0 && (
63
- <motion.div
64
- className="grid grid-cols-1 md:grid-cols-3 gap-6"
65
- variants={containerVariants}
66
- initial="hidden"
67
- whileInView="show"
68
- viewport={{ once: false, amount: 0.15 }}
69
- >
70
- {populated.map((t, i) => {
71
- const avatarUrl =
72
- typeof t.companyLogo === "object" &&
73
- t.companyLogo !== null &&
74
- "url" in t.companyLogo
75
- ? t.companyLogo.url
76
- : (t.fallbackAvatarUrl ?? null);
77
- const safeAvatarUrl = isLocalImageSrc(avatarUrl)
78
- ? avatarUrl
79
- : null;
80
-
81
- const stars = Math.min(5, Math.max(1, t.rating ?? 5));
82
-
83
- return (
84
- <motion.div
85
- key={t.id ?? i}
86
- className="rounded-2xl bg-stone-100 dark:bg-stone-900 border border-stone-100 dark:border-stone-800 p-8 flex flex-col"
87
- variants={cardVariants}
88
- style={{ cornerShape: "squircle" } as React.CSSProperties}
89
- >
90
- {/* Stars */}
91
- <div className="flex items-center gap-1 mb-5">
92
- {Array.from({ length: stars }).map((_, si) => (
93
- <Star
94
- key={si}
95
- size={14}
96
- className="text-amber-400"
97
- fill="currentColor"
98
- />
99
- ))}
100
- </div>
101
-
102
- {/* Quote */}
103
- {t.content ? (
104
- <div className="text-sm text-stone-400 leading-relaxed flex-1 mb-6">
105
- {/* TODO: Reconnect this project's RichText renderer for testimonial content. */}
106
- <span>
107
- Reconnect this project's RichText renderer for
108
- testimonial content.
109
- </span>
110
- </div>
111
- ) : null}
112
-
113
- {/* Author / Company */}
114
- <div className="flex items-center gap-3 pt-5 border-t border-stone-800">
115
- {safeAvatarUrl && (
116
- <div className="w-10 h-10 rounded-full overflow-hidden shrink-0 relative">
117
- <Image
118
- src={safeAvatarUrl}
119
- alt={t.title ?? ""}
120
- fill
121
- sizes="40px"
122
- className="object-cover object-top"
123
- />
124
- </div>
125
- )}
126
- <div>
127
- <div className="text-sm font-semibold text-stone-800 dark:text-stone-50">
128
- {t.title}
129
- </div>
130
- {t.designation ? (
131
- <div className="text-xs text-stone-300">
132
- {/* TODO: Reconnect RichText for designation if needed. */}
133
- <span>Reconnect RichText for designation</span>
134
- </div>
135
- ) : null}
136
- </div>
137
- </div>
138
- </motion.div>
139
- );
140
- })}
141
- </motion.div>
142
- )}
143
- </div>
144
- </div>
145
- </>
146
- );
147
- };
1
+ 'use client'
2
+
3
+ import React from 'react'
4
+ import Image from 'next/image'
5
+ import { Star } from 'lucide-react'
6
+ import { motion, type Variants } from 'framer-motion'
7
+ export type DDTestimonialsProps = Record<string, any>
8
+ type Media = { url?: string | null }
9
+ type Testimonial = {
10
+ id?: string | null
11
+ title?: string | null
12
+ content?: unknown
13
+ designation?: unknown
14
+ companyLogo?: Media | string | null
15
+ fallbackAvatarUrl?: string | null
16
+ rating?: number | null
17
+ }
18
+
19
+ function isLocalImageSrc(src?: string | null): src is string {
20
+ return typeof src === 'string' && src.startsWith('/api/media/file/')
21
+ }
22
+
23
+ const containerVariants: Variants = {
24
+ hidden: {},
25
+ show: { transition: { staggerChildren: 0.12, delayChildren: 0.05 } },
26
+ }
27
+
28
+ const cardVariants: Variants = {
29
+ hidden: { opacity: 0, y: 24 },
30
+ show: { opacity: 1, y: 0, transition: { duration: 0.5, ease: 'easeOut' } },
31
+ }
32
+
33
+ export const DDTestimonials: React.FC<DDTestimonialsProps> = ({
34
+ eyebrow,
35
+ headline,
36
+ testimonials,
37
+ sectionId,
38
+ customCSS,
39
+ }) => {
40
+ const populated = ((testimonials ?? []) as unknown[]).filter(
41
+ (t): t is Testimonial => typeof t === 'object' && t !== null,
42
+ )
43
+
44
+ return (
45
+ <>
46
+ {customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
47
+
48
+ <div id={sectionId ?? 'testimonials'} className="py-24">
49
+ <div className="max-w-6xl lg:max-w-7xl mx-auto px-4 md:px-6">
50
+ {/* Header */}#BlockName-DDTestimonials
51
+ <div className="text-center max-w-xl mx-auto mb-14">
52
+ {eyebrow && (
53
+ <p className="text-[11.5px] font-semibold text-stone-400 tracking-widest uppercase mb-3 top-caption">
54
+ {eyebrow}
55
+ </p>
56
+ )}
57
+ <h2 className="text-3xl font-semibold text-stone-900 dark:text-stone-50 leading-tight">
58
+ {headline}
59
+ </h2>
60
+ </div>
61
+ {/* Testimonials */}
62
+ {populated.length > 0 && (
63
+ <motion.div
64
+ className="grid grid-cols-1 md:grid-cols-3 gap-6"
65
+ variants={containerVariants}
66
+ initial="hidden"
67
+ whileInView="show"
68
+ viewport={{ once: false, amount: 0.15 }}
69
+ >
70
+ {populated.map((t, i) => {
71
+ const avatarUrl =
72
+ typeof t.companyLogo === 'object' &&
73
+ t.companyLogo !== null &&
74
+ 'url' in t.companyLogo
75
+ ? t.companyLogo.url
76
+ : (t.fallbackAvatarUrl ?? null)
77
+ const safeAvatarUrl = isLocalImageSrc(avatarUrl) ? avatarUrl : null
78
+
79
+ const stars = Math.min(5, Math.max(1, t.rating ?? 5))
80
+
81
+ return (
82
+ <motion.div
83
+ key={t.id ?? i}
84
+ className="rounded-2xl bg-stone-100 dark:bg-stone-900 border border-stone-100 dark:border-stone-800 p-8 flex flex-col"
85
+ variants={cardVariants}
86
+ style={{ cornerShape: 'squircle' } as React.CSSProperties}
87
+ >
88
+ {/* Stars */}
89
+ <div className="flex items-center gap-1 mb-5">
90
+ {Array.from({ length: stars }).map((_, si) => (
91
+ <Star key={si} size={14} className="text-amber-400" fill="currentColor" />
92
+ ))}
93
+ </div>
94
+
95
+ {/* Quote */}
96
+ {t.content ? (
97
+ <div className="text-sm text-stone-400 leading-relaxed flex-1 mb-6">
98
+ {/* TODO: Reconnect this project's RichText renderer for testimonial content. */}
99
+ <span>
100
+ Reconnect this project's RichText renderer for testimonial content.
101
+ </span>
102
+ </div>
103
+ ) : null}
104
+
105
+ {/* Author / Company */}
106
+ <div className="flex items-center gap-3 pt-5 border-t border-stone-800">
107
+ {safeAvatarUrl && (
108
+ <div className="w-10 h-10 rounded-full overflow-hidden shrink-0 relative">
109
+ <Image
110
+ src={safeAvatarUrl}
111
+ alt={t.title ?? ''}
112
+ fill
113
+ sizes="40px"
114
+ className="object-cover object-top"
115
+ />
116
+ </div>
117
+ )}
118
+ <div>
119
+ <div className="text-sm font-semibold text-stone-800 dark:text-stone-50">
120
+ {t.title}
121
+ </div>
122
+ {t.designation ? (
123
+ <div className="text-xs text-stone-300">
124
+ {/* TODO: Reconnect RichText for designation if needed. */}
125
+ <span>Reconnect RichText for designation</span>
126
+ </div>
127
+ ) : null}
128
+ </div>
129
+ </div>
130
+ </motion.div>
131
+ )
132
+ })}
133
+ </motion.div>
134
+ )}
135
+ </div>
136
+ </div>
137
+ </>
138
+ )
139
+ }
@@ -1,120 +1,120 @@
1
- import type { Block } from 'payload'
2
-
3
- export const DDTestimonials: Block = {
4
- slug: 'DD-Testimonials',
5
- interfaceName: 'DDTestimonials',
6
- labels: {
7
- singular: 'Studio Testimonials',
8
- plural: 'Studio Testimonials Sections'
9
- },
10
- fields: [
11
- {
12
- type: 'tabs',
13
- tabs: [
14
- {
15
- label: 'Header',
16
- fields: [
17
- {
18
- name: 'eyebrow',
19
- type: 'text',
20
- label: 'Eyebrow Label',
21
- defaultValue: 'Client Stories'
22
- },
23
- {
24
- name: 'headline',
25
- type: 'text',
26
- label: 'Headline',
27
- required: true,
28
- defaultValue: "Don't take our word for it"
29
- }
30
- ]
31
- },
32
- {
33
- label: 'Testimonials',
34
- fields: [
35
- // Reconnect option:
36
- // If the target project has a Testimonials collection, replace the standalone
37
- // array below with this relationship field.
38
- // {
39
- // name: 'testimonials',
40
- // type: 'relationship',
41
- // relationTo: 'testimonials',
42
- // hasMany: true,
43
- // label: 'Select Testimonials',
44
- // admin: {
45
- // description:
46
- // 'Pick from the Testimonials collection. Fields used: quote, author, role, avatar, fallbackAvatarUrl, rating.'
47
- // }
48
- // },
49
- {
50
- name: 'testimonials',
51
- type: 'array',
52
- label: 'Testimonials',
53
- fields: [
54
- {
55
- name: 'title',
56
- type: 'text',
57
- label: 'Author',
58
- required: true
59
- },
60
- {
61
- name: 'content',
62
- type: 'richText',
63
- label: 'Quote'
64
- },
65
- {
66
- name: 'designation',
67
- type: 'richText',
68
- label: 'Designation'
69
- },
70
- {
71
- name: 'companyLogo',
72
- type: 'upload',
73
- relationTo: 'media',
74
- label: 'Avatar / Logo'
75
- },
76
- {
77
- name: 'fallbackAvatarUrl',
78
- type: 'text',
79
- label: 'Fallback Avatar URL'
80
- },
81
- {
82
- name: 'rating',
83
- type: 'number',
84
- label: 'Rating',
85
- defaultValue: 5,
86
- min: 1,
87
- max: 5
88
- }
89
- ],
90
- defaultValue: [
91
- {
92
- title: 'DesignsDusted Client',
93
- fallbackAvatarUrl: '',
94
- rating: 5
95
- }
96
- ]
97
- }
98
- ]
99
- },
100
- {
101
- label: 'Settings',
102
- fields: [
103
- {
104
- name: 'sectionId',
105
- type: 'text',
106
- label: 'Section ID',
107
- defaultValue: 'testimonials'
108
- },
109
- {
110
- name: 'customCSS',
111
- type: 'code',
112
- label: 'Custom CSS',
113
- admin: { language: 'css' }
114
- }
115
- ]
116
- }
117
- ]
118
- }
119
- ]
120
- }
1
+ import type { Block } from 'payload'
2
+
3
+ export const DDTestimonials: Block = {
4
+ slug: 'DD-Testimonials',
5
+ interfaceName: 'DDTestimonials',
6
+ labels: {
7
+ singular: 'Studio Testimonials',
8
+ plural: 'Studio Testimonials Sections'
9
+ },
10
+ fields: [
11
+ {
12
+ type: 'tabs',
13
+ tabs: [
14
+ {
15
+ label: 'Header',
16
+ fields: [
17
+ {
18
+ name: 'eyebrow',
19
+ type: 'text',
20
+ label: 'Eyebrow Label',
21
+ defaultValue: 'Client Stories'
22
+ },
23
+ {
24
+ name: 'headline',
25
+ type: 'text',
26
+ label: 'Headline',
27
+ required: true,
28
+ defaultValue: "Don't take our word for it"
29
+ }
30
+ ]
31
+ },
32
+ {
33
+ label: 'Testimonials',
34
+ fields: [
35
+ // Reconnect option:
36
+ // If the target project has a Testimonials collection, replace the standalone
37
+ // array below with this relationship field.
38
+ // {
39
+ // name: 'testimonials',
40
+ // type: 'relationship',
41
+ // relationTo: 'testimonials',
42
+ // hasMany: true,
43
+ // label: 'Select Testimonials',
44
+ // admin: {
45
+ // description:
46
+ // 'Pick from the Testimonials collection. Fields used: quote, author, role, avatar, fallbackAvatarUrl, rating.'
47
+ // }
48
+ // },
49
+ {
50
+ name: 'testimonials',
51
+ type: 'array',
52
+ label: 'Testimonials',
53
+ fields: [
54
+ {
55
+ name: 'title',
56
+ type: 'text',
57
+ label: 'Author',
58
+ required: true
59
+ },
60
+ {
61
+ name: 'content',
62
+ type: 'richText',
63
+ label: 'Quote'
64
+ },
65
+ {
66
+ name: 'designation',
67
+ type: 'richText',
68
+ label: 'Designation'
69
+ },
70
+ {
71
+ name: 'companyLogo',
72
+ type: 'upload',
73
+ relationTo: 'media',
74
+ label: 'Avatar / Logo'
75
+ },
76
+ {
77
+ name: 'fallbackAvatarUrl',
78
+ type: 'text',
79
+ label: 'Fallback Avatar URL'
80
+ },
81
+ {
82
+ name: 'rating',
83
+ type: 'number',
84
+ label: 'Rating',
85
+ defaultValue: 5,
86
+ min: 1,
87
+ max: 5
88
+ }
89
+ ],
90
+ defaultValue: [
91
+ {
92
+ title: 'DesignsDusted Client',
93
+ fallbackAvatarUrl: '',
94
+ rating: 5
95
+ }
96
+ ]
97
+ }
98
+ ]
99
+ },
100
+ {
101
+ label: 'Settings',
102
+ fields: [
103
+ {
104
+ name: 'sectionId',
105
+ type: 'text',
106
+ label: 'Section ID',
107
+ defaultValue: 'testimonials'
108
+ },
109
+ {
110
+ name: 'customCSS',
111
+ type: 'code',
112
+ label: 'Custom CSS',
113
+ admin: { language: 'css' }
114
+ }
115
+ ]
116
+ }
117
+ ]
118
+ }
119
+ ]
120
+ }