blocks-dusted 0.1.9 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/README.md +35 -0
  2. package/package.json +1 -1
  3. package/src/utils/paths.js +13 -13
  4. package/templates/blocks/DD-Accordion/Component.tsx +229 -0
  5. package/templates/blocks/DD-Accordion/README.md +3 -0
  6. package/templates/blocks/DD-Accordion/config.ts +73 -0
  7. package/templates/blocks/DD-Accordion/manifest.json +75 -0
  8. package/templates/blocks/DD-AnimText/Component.tsx +788 -0
  9. package/templates/blocks/DD-AnimText/README.md +3 -0
  10. package/templates/blocks/DD-AnimText/config.ts +295 -0
  11. package/templates/blocks/DD-AnimText/manifest.json +85 -0
  12. package/templates/blocks/DD-AsideNav/Component.tsx +321 -0
  13. package/templates/blocks/DD-AsideNav/config.ts +204 -0
  14. package/templates/blocks/DD-AsideNav/manifest.json +80 -0
  15. package/templates/blocks/DD-Banner/Component.tsx +51 -0
  16. package/templates/blocks/DD-Banner/config.ts +57 -0
  17. package/templates/blocks/DD-Banner/manifest.json +72 -0
  18. package/templates/blocks/DD-BgLightning/Component.tsx +44 -0
  19. package/templates/blocks/DD-BgLightning/README.md +3 -0
  20. package/templates/blocks/DD-BgLightning/config.ts +97 -0
  21. package/templates/blocks/DD-BgLightning/manifest.json +79 -0
  22. package/templates/blocks/DD-BookCall/Component.tsx +10 -11
  23. package/templates/blocks/DD-BookCall/config.ts +238 -238
  24. package/templates/blocks/DD-ButtonPop/Component.tsx +117 -0
  25. package/templates/blocks/DD-ButtonPop/config.ts +105 -0
  26. package/templates/blocks/DD-ButtonPop/manifest.json +88 -0
  27. package/templates/blocks/DD-ButtonPop/svg-icons/Dust2.tsx +167 -0
  28. package/templates/blocks/DD-Card/Component.tsx +251 -0
  29. package/templates/blocks/DD-Card/README.md +4 -0
  30. package/templates/blocks/DD-Card/config.ts +154 -0
  31. package/templates/blocks/DD-Card/manifest.json +82 -0
  32. package/templates/blocks/DD-CardTemplate01/Component.tsx +5 -6
  33. package/templates/blocks/DD-CardTemplate01/config.ts +106 -106
  34. package/templates/blocks/DD-Carousel-A/Component.tsx +249 -249
  35. package/templates/blocks/DD-Carousel-B/Component.tsx +403 -403
  36. package/templates/blocks/DD-Chip/Component.tsx +250 -0
  37. package/templates/blocks/DD-Chip/EXAMPLES.md +313 -0
  38. package/templates/blocks/DD-Chip/README.md +202 -0
  39. package/templates/blocks/DD-Chip/config.ts +369 -0
  40. package/templates/blocks/DD-Chip/manifest.json +74 -0
  41. package/templates/blocks/DD-ComparisonTable/Component.tsx +256 -256
  42. package/templates/blocks/DD-Contact/Component.tsx +434 -434
  43. package/templates/blocks/DD-Contact/config.ts +22 -22
  44. package/templates/blocks/DD-Counter/Component.tsx +190 -0
  45. package/templates/blocks/DD-Counter/README.md +4 -0
  46. package/templates/blocks/DD-Counter/config.ts +291 -0
  47. package/templates/blocks/DD-Counter/manifest.json +74 -0
  48. package/templates/blocks/DD-CustomCSS/Component.tsx +8 -0
  49. package/templates/blocks/DD-CustomCSS/README.md +4 -0
  50. package/templates/blocks/DD-CustomCSS/addToLayout.md +5 -0
  51. package/templates/blocks/DD-CustomCSS/config.ts +22 -0
  52. package/templates/blocks/DD-CustomCSS/manifest.json +72 -0
  53. package/templates/blocks/DD-CustomCSS/renderCustomCSS.md +7 -0
  54. package/templates/blocks/DD-FeatCat/Component.tsx +302 -302
  55. package/templates/blocks/DD-FeatCat/config.ts +201 -201
  56. package/templates/blocks/DD-FeatStrip/Component.tsx +585 -585
  57. package/templates/blocks/DD-FeatStrip/config.ts +134 -134
  58. package/templates/blocks/DD-FluidBtn/ButtonsEyeCatching.tsx +628 -0
  59. package/templates/blocks/DD-FluidBtn/Component.tsx +43 -0
  60. package/templates/blocks/DD-FluidBtn/README.md +6 -0
  61. package/templates/blocks/DD-FluidBtn/config.ts +102 -0
  62. package/templates/blocks/DD-FluidBtn/manifest.json +86 -0
  63. package/templates/blocks/DD-GooeyInfo/Component.tsx +149 -0
  64. package/templates/blocks/DD-GooeyInfo/config.ts +135 -0
  65. package/templates/blocks/DD-GooeyInfo/manifest.json +72 -0
  66. package/templates/blocks/DD-Hero/Component.tsx +40 -17
  67. package/templates/blocks/DD-Hero/config.ts +267 -267
  68. package/templates/blocks/DD-HorizontalScroll/Component.tsx +4 -2
  69. package/templates/blocks/DD-HorizontalScroll/config.ts +231 -231
  70. package/templates/blocks/DD-Icon/Component.tsx +287 -0
  71. package/templates/blocks/DD-Icon/README.md +4 -0
  72. package/templates/blocks/DD-Icon/config.ts +258 -0
  73. package/templates/blocks/DD-Icon/hooks/revalidateBlockIds.ts +66 -0
  74. package/templates/blocks/DD-Icon/manifest.json +82 -0
  75. package/templates/blocks/DD-IconButton/Component.tsx +455 -0
  76. package/templates/blocks/DD-IconButton/README.md +326 -0
  77. package/templates/blocks/DD-IconButton/config.ts +239 -0
  78. package/templates/blocks/DD-IconButton/manifest.json +85 -0
  79. package/templates/blocks/DD-IdTag/Component.tsx +21 -0
  80. package/templates/blocks/DD-IdTag/README.md +4 -0
  81. package/templates/blocks/DD-IdTag/config.ts +41 -0
  82. package/templates/blocks/DD-IdTag/manifest.json +72 -0
  83. package/templates/blocks/DD-Iframe/Component.tsx +45 -0
  84. package/templates/blocks/DD-Iframe/README.md +4 -0
  85. package/templates/blocks/DD-Iframe/config.ts +47 -0
  86. package/templates/blocks/DD-Iframe/manifest.json +72 -0
  87. package/templates/blocks/DD-IframeMedia/Component.tsx +129 -0
  88. package/templates/blocks/DD-IframeMedia/README.md +4 -0
  89. package/templates/blocks/DD-IframeMedia/config.ts +79 -0
  90. package/templates/blocks/DD-IframeMedia/manifest.json +72 -0
  91. package/templates/blocks/DD-LineAnim/Component.tsx +36 -0
  92. package/templates/blocks/DD-LineAnim/README.md +4 -0
  93. package/templates/blocks/DD-LineAnim/config.ts +90 -0
  94. package/templates/blocks/DD-LineAnim/manifest.json +80 -0
  95. package/templates/blocks/DD-LinkGrid/Component.tsx +119 -0
  96. package/templates/blocks/DD-LinkGrid/README.md +4 -0
  97. package/templates/blocks/DD-LinkGrid/config.ts +51 -0
  98. package/templates/blocks/DD-LinkGrid/manifest.json +74 -0
  99. package/templates/blocks/DD-LogoMarq/Component.tsx +132 -0
  100. package/templates/blocks/DD-LogoMarq/README.md +4 -0
  101. package/templates/blocks/DD-LogoMarq/config.ts +264 -0
  102. package/templates/blocks/DD-LogoMarq/manifest.json +82 -0
  103. package/templates/blocks/DD-Lottie/Component.tsx +459 -0
  104. package/templates/blocks/DD-Lottie/README.md +4 -0
  105. package/templates/blocks/DD-Lottie/config.ts +379 -0
  106. package/templates/blocks/DD-Lottie/index.tsx +28 -0
  107. package/templates/blocks/DD-Lottie/manifest.json +83 -0
  108. package/templates/blocks/DD-MagicBento/Component.tsx +777 -0
  109. package/templates/blocks/DD-MagicBento/README.md +4 -0
  110. package/templates/blocks/DD-MagicBento/config.ts +264 -0
  111. package/templates/blocks/DD-MagicBento/manifest.json +74 -0
  112. package/templates/blocks/DD-MasonaryMedia/Component.tsx +547 -545
  113. package/templates/blocks/DD-MasonaryMedia/config.ts +2 -2
  114. package/templates/blocks/DD-MasonaryMedia/vendor.d.ts +2 -2
  115. package/templates/blocks/DD-Masonry/Component.tsx +645 -0
  116. package/templates/blocks/DD-Masonry/README.md +4 -0
  117. package/templates/blocks/DD-Masonry/config.ts +475 -0
  118. package/templates/blocks/DD-Masonry/manifest.json +82 -0
  119. package/templates/blocks/DD-Pricing/Component.tsx +372 -372
  120. package/templates/blocks/DD-Process/Component.tsx +149 -149
  121. package/templates/blocks/DD-Process/config.ts +150 -150
  122. package/templates/blocks/DD-Progress/Component.tsx +141 -0
  123. package/templates/blocks/DD-Progress/README.md +4 -0
  124. package/templates/blocks/DD-Progress/config.ts +175 -0
  125. package/templates/blocks/DD-Progress/manifest.json +74 -0
  126. package/templates/blocks/DD-ProjHeader/Component.tsx +91 -0
  127. package/templates/blocks/DD-ProjHeader/README.md +4 -0
  128. package/templates/blocks/DD-ProjHeader/config.ts +96 -0
  129. package/templates/blocks/DD-ProjHeader/manifest.json +72 -0
  130. package/templates/blocks/DD-ProjSlider/Component.tsx +123 -0
  131. package/templates/blocks/DD-ProjSlider/README.md +4 -0
  132. package/templates/blocks/DD-ProjSlider/config.ts +64 -0
  133. package/templates/blocks/DD-ProjSlider/manifest.json +72 -0
  134. package/templates/blocks/DD-ScrollText/Component.tsx +114 -0
  135. package/templates/blocks/DD-ScrollText/README.md +4 -0
  136. package/templates/blocks/DD-ScrollText/config.ts +58 -0
  137. package/templates/blocks/DD-ScrollText/manifest.json +72 -0
  138. package/templates/blocks/DD-Section/Component.tsx +266 -266
  139. package/templates/blocks/DD-Separator/Component.tsx +66 -0
  140. package/templates/blocks/DD-Separator/README.md +4 -0
  141. package/templates/blocks/DD-Separator/config.ts +58 -0
  142. package/templates/blocks/DD-Separator/manifest.json +72 -0
  143. package/templates/blocks/DD-Services/Component.tsx +176 -176
  144. package/templates/blocks/DD-Services/config.ts +149 -149
  145. package/templates/blocks/DD-ShowcaseGrid/Component.tsx +307 -307
  146. package/templates/blocks/DD-Slider-A/Component.tsx +237 -237
  147. package/templates/blocks/DD-StackCards/Component.tsx +473 -473
  148. package/templates/blocks/DD-StackCards/config.ts +399 -399
  149. package/templates/blocks/DD-Team/Component.tsx +247 -247
  150. package/templates/blocks/DD-Team/config.ts +173 -173
  151. package/templates/blocks/DD-TeamCards/Component.tsx +251 -0
  152. package/templates/blocks/DD-TeamCards/README.md +4 -0
  153. package/templates/blocks/DD-TeamCards/config.ts +302 -0
  154. package/templates/blocks/DD-TeamCards/manifest.json +74 -0
  155. package/templates/blocks/DD-TechStack/Component.tsx +168 -162
  156. package/templates/blocks/DD-TechStack/config.ts +153 -153
  157. package/templates/blocks/DD-TestMarq/Component.tsx +132 -0
  158. package/templates/blocks/DD-TestMarq/README.md +4 -0
  159. package/templates/blocks/DD-TestMarq/RowLabel.tsx +9 -0
  160. package/templates/blocks/DD-TestMarq/config.ts +88 -0
  161. package/templates/blocks/DD-TestMarq/manifest.json +72 -0
  162. package/templates/blocks/DD-Testim/Component.tsx +247 -0
  163. package/templates/blocks/DD-Testim/README.md +4 -0
  164. package/templates/blocks/DD-Testim/config.ts +101 -0
  165. package/templates/blocks/DD-Testim/manifest.json +75 -0
  166. package/templates/blocks/DD-Testim2/Component.tsx +256 -0
  167. package/templates/blocks/DD-Testim2/README.md +4 -0
  168. package/templates/blocks/DD-Testim2/config.ts +100 -0
  169. package/templates/blocks/DD-Testim2/manifest.json +74 -0
  170. package/templates/blocks/DD-Testimonials/Component.tsx +147 -147
  171. package/templates/blocks/DD-Testimonials/config.ts +120 -120
  172. package/templates/blocks/DD-TextMarq/Component.tsx +157 -0
  173. package/templates/blocks/DD-TextMarq/README.md +4 -0
  174. package/templates/blocks/DD-TextMarq/config.ts +237 -0
  175. package/templates/blocks/DD-TextMarq/manifest.json +82 -0
  176. package/templates/blocks/DD-Thanks/Component.tsx +500 -0
  177. package/templates/blocks/DD-Thanks/README.md +4 -0
  178. package/templates/blocks/DD-Thanks/config.ts +224 -0
  179. package/templates/blocks/DD-Thanks/manifest.json +72 -0
  180. package/templates/blocks/DD-VertMarq/Component.tsx +154 -0
  181. package/templates/blocks/DD-VertMarq/README.md +4 -0
  182. package/templates/blocks/DD-VertMarq/config.ts +236 -0
  183. package/templates/blocks/DD-VertMarq/dist/index.css +6 -0
  184. package/templates/blocks/DD-VertMarq/dist/index.min.css +1 -0
  185. package/templates/blocks/DD-VertMarq/manifest.json +74 -0
  186. package/templates/blocks/DD-Work/Component.tsx +318 -315
  187. package/templates/blocks/DD-Work/config.ts +165 -165
  188. package/templates/blocks/DD-Work-B/Component.tsx +294 -294
  189. package/templates/blocks/DDHG-CTASection2/Component.tsx +185 -0
  190. package/templates/blocks/DDHG-CTASection2/config.ts +140 -0
  191. package/templates/blocks/DDHG-CTASection2/manifest.json +45 -0
  192. package/templates/blocks/DDHG-HighlightArc/Component.tsx +243 -0
  193. package/templates/blocks/DDHG-HighlightArc/config.ts +85 -0
  194. package/templates/blocks/DDHG-HighlightArc/manifest.json +46 -0
  195. package/templates/blocks/DDHG-LogoMarquee/Component.tsx +93 -0
  196. package/templates/blocks/DDHG-LogoMarquee/config.ts +66 -0
  197. package/templates/blocks/DDHG-LogoMarquee/manifest.json +39 -0
  198. package/templates/blocks/DDHG-NavCodeGrid/Component.tsx +213 -0
  199. package/templates/blocks/DDHG-NavCodeGrid/config.ts +64 -0
  200. package/templates/blocks/DDHG-NavCodeGrid/manifest.json +45 -0
  201. package/templates/blocks/DDHG-ProcessSec/Component.tsx +575 -0
  202. package/templates/blocks/DDHG-ProcessSec/config.ts +170 -0
  203. package/templates/blocks/DDHG-ProcessSec/manifest.json +56 -0
  204. package/templates/blocks/DDHG-ServiceDetails/Component.tsx +164 -0
  205. package/templates/blocks/DDHG-ServiceDetails/ServiceDetailCard.tsx +394 -0
  206. package/templates/blocks/DDHG-ServiceDetails/config.ts +77 -0
  207. package/templates/blocks/DDHG-ServiceDetails/manifest.json +50 -0
  208. package/templates/blocks/DDHG-ServiceHero/Component.tsx +234 -0
  209. package/templates/blocks/DDHG-ServiceHero/config.ts +49 -0
  210. package/templates/blocks/DDHG-ServiceHero/manifest.json +26 -0
  211. package/templates/blocks/DDHG-ServiceOverview/Component.tsx +277 -0
  212. package/templates/blocks/DDHG-ServiceOverview/config.ts +64 -0
  213. package/templates/blocks/DDHG-ServiceOverview/manifest.json +44 -0
  214. package/templates/blocks/DDHG-StatsFAQ/Component.tsx +389 -0
  215. package/templates/blocks/DDHG-StatsFAQ/config.ts +204 -0
  216. package/templates/blocks/DDHG-StatsFAQ/manifest.json +45 -0
  217. package/templates/blocks/DDHG-TeamCards/Component.tsx +131 -0
  218. package/templates/blocks/DDHG-TeamCards/config.ts +48 -0
  219. package/templates/blocks/DDHG-TeamCards/manifest.json +29 -0
  220. package/templates/components/HeaderDD02/MobileBottomNav/index.tsx +352 -257
  221. package/templates/components/HeaderDD02/index.tsx +313 -229
  222. package/templates/shared/src/components/BgLightning/index.tsx +242 -0
  223. package/templates/shared/src/components/ui/ShareButton/index.tsx +80 -0
  224. package/templates/shared/src/components/ui/anims/FadeOnScroll.tsx +48 -0
  225. package/templates/shared/src/components/ui/anims/FadeUpOnInView.tsx +63 -0
  226. package/templates/shared/src/components/ui/anims/GlareHover.tsx +111 -0
  227. package/templates/shared/src/components/ui/anims/LineAnims.tsx +81 -0
  228. package/templates/shared/src/components/ui/anims/TitleAnims01.tsx +54 -0
  229. package/templates/shared/src/components/ui/anims/animation-container.tsx +29 -0
  230. package/templates/shared/src/components/ui/anims/blur-in.tsx +26 -0
  231. package/templates/shared/src/components/ui/anims/counter.tsx +53 -0
  232. package/templates/shared/src/components/ui/anims/fade.tsx +83 -0
  233. package/templates/shared/src/components/ui/anims/gradual-spacing.tsx +39 -0
  234. package/templates/shared/src/components/ui/anims/pull-up.tsx +93 -0
  235. package/templates/shared/src/components/ui/anims/reveal-text.tsx +76 -0
  236. package/templates/shared/src/components/ui/anims/rotate-words.tsx +43 -0
  237. package/templates/shared/src/components/ui/anims/shiny-text.tsx +58 -0
  238. package/templates/shared/src/components/ui/anims/shuffle-text.tsx +85 -0
  239. package/templates/shared/src/components/ui/anims/split-text.tsx +211 -0
  240. package/templates/shared/src/components/ui/anims/staggered-fade.tsx +133 -0
  241. package/templates/shared/src/components/ui/anims/text-scroll.tsx +111 -0
  242. package/templates/shared/src/components/ui/anims/typing-effect.tsx +112 -0
  243. package/templates/shared/src/components/ui/button-dusted-fluid/index.tsx +1521 -0
  244. package/templates/shared/src/components/ui/separator.tsx +85 -0
  245. package/templates/shared/src/hooks/useBodyScrollLock.ts +97 -0
  246. package/templates/shared/src/hooks/useClickOutside.ts +28 -0
  247. package/templates/shared/src/utilities/renderCustomCSS.ts +5 -0
  248. package/templates/shared/src/utilities/smoothScroll.ts +65 -0
@@ -1,147 +1,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)
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 */}
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,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
+ }