blocks-dusted 0.1.12 → 0.1.13

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 (148) hide show
  1. package/package.json +1 -1
  2. package/src/installers/patchRenderBlocks.js +1 -1
  3. package/src/registry/validateTemplateManifest.js +2 -1
  4. package/templates/blocks/BannerDD790432/Component.tsx +63 -0
  5. package/templates/blocks/BannerDD790432/config.ts +54 -0
  6. package/templates/blocks/BannerDD790432/manifest.json +80 -0
  7. package/templates/blocks/Button47/Component.tsx +124 -0
  8. package/templates/blocks/Button47/config.ts +75 -0
  9. package/templates/blocks/Button47/link.ts +22 -0
  10. package/templates/blocks/Button47/manifest.json +105 -0
  11. package/templates/blocks/Button47/styles.module.scss +75 -0
  12. package/templates/blocks/DD-Accordion/Component.tsx +55 -36
  13. package/templates/blocks/DD-Accordion/config.ts +71 -59
  14. package/templates/blocks/DD-AnimText/Component.tsx +50 -32
  15. package/templates/blocks/DD-AnimText/config.ts +296 -295
  16. package/templates/blocks/DD-AsideNav/Component.tsx +323 -319
  17. package/templates/blocks/DD-Banner/Component.tsx +54 -51
  18. package/templates/blocks/DD-BookCall/Component.tsx +535 -535
  19. package/templates/blocks/DD-ButtonPop/Component.tsx +118 -117
  20. package/templates/blocks/DD-Card/Component.tsx +4 -4
  21. package/templates/blocks/DD-CardTemplate01/Component.tsx +139 -140
  22. package/templates/blocks/DD-CardsWithVariantV3/Component.tsx +472 -0
  23. package/templates/blocks/DD-CardsWithVariantV3/ElectricBorder/index.tsx +203 -0
  24. package/templates/blocks/DD-CardsWithVariantV3/ElectricBorder/styles.ts +87 -0
  25. package/templates/blocks/DD-CardsWithVariantV3/ElectricBorder/useInjectStyle.ts +39 -0
  26. package/templates/blocks/DD-CardsWithVariantV3/config.ts +326 -0
  27. package/templates/blocks/DD-CardsWithVariantV3/manifest.json +110 -0
  28. package/templates/blocks/DD-Carousel-A/Component.tsx +251 -249
  29. package/templates/blocks/DD-Carousel-B/Component.tsx +405 -403
  30. package/templates/blocks/DD-ComparisonTable/Component.tsx +255 -256
  31. package/templates/blocks/DD-Contact/Component.tsx +433 -435
  32. package/templates/blocks/DD-Counter/Component.tsx +11 -6
  33. package/templates/blocks/DD-DeliCard/Component.tsx +303 -0
  34. package/templates/blocks/DD-DeliCard/config.ts +186 -0
  35. package/templates/blocks/DD-DeliCard/manifest.json +94 -0
  36. package/templates/blocks/DD-FeatCat/Component.tsx +302 -302
  37. package/templates/blocks/DD-FeatProd/CircularGallery.tsx +1179 -0
  38. package/templates/blocks/DD-FeatProd/Component.tsx +484 -0
  39. package/templates/blocks/DD-FeatProd/config.ts +173 -0
  40. package/templates/blocks/DD-FeatProd/manifest.json +93 -0
  41. package/templates/blocks/DD-FeatServ/Component.tsx +607 -0
  42. package/templates/blocks/DD-FeatServ/config.ts +213 -0
  43. package/templates/blocks/DD-FeatServ/manifest.json +113 -0
  44. package/templates/blocks/DD-FeatStrip/Component.tsx +584 -585
  45. package/templates/blocks/DD-FluidBtn/ButtonsEyeCatching.tsx +627 -628
  46. package/templates/blocks/DD-FluidBtn/Component.tsx +46 -43
  47. package/templates/blocks/DD-GooeyInfo/Component.tsx +150 -149
  48. package/templates/blocks/DD-GooeyInfo/config.ts +136 -135
  49. package/templates/blocks/DD-Hero/Component.tsx +296 -297
  50. package/templates/blocks/DD-HeroPlas/Component.tsx +50 -0
  51. package/templates/blocks/DD-HeroPlas/ThreeScene.tsx +109 -0
  52. package/templates/blocks/DD-HeroPlas/config.ts +33 -0
  53. package/templates/blocks/DD-HeroPlas/manifest.json +88 -0
  54. package/templates/blocks/DD-HorizontalScroll/Component.tsx +937 -936
  55. package/templates/blocks/DD-Icon/Component.tsx +46 -81
  56. package/templates/blocks/DD-IconButton/Component.tsx +13 -20
  57. package/templates/blocks/DD-IdTag/Component.tsx +22 -21
  58. package/templates/blocks/DD-LineAnim/Component.tsx +42 -36
  59. package/templates/blocks/DD-LogoMarq/Component.tsx +38 -48
  60. package/templates/blocks/DD-Lottie/Component.tsx +11 -3
  61. package/templates/blocks/DD-MasonaryMedia/Component.tsx +544 -545
  62. package/templates/blocks/DD-MasonaryMedia/config.ts +389 -389
  63. package/templates/blocks/DD-Masonry/Component.tsx +654 -644
  64. package/templates/blocks/DD-Masonry/config.ts +475 -475
  65. package/templates/blocks/DD-MaterialSwatches/Component.tsx +85 -0
  66. package/templates/blocks/DD-MaterialSwatches/config.ts +232 -0
  67. package/templates/blocks/DD-MaterialSwatches/manifest.json +84 -0
  68. package/templates/blocks/DD-MaterialSwatches/material.ts +107 -0
  69. package/templates/blocks/DD-NineCanvas/Component.tsx +129 -0
  70. package/templates/blocks/DD-NineCanvas/RenderBlocks.tsx +244 -0
  71. package/templates/blocks/DD-NineCanvas/allowedCanvasBlocks.ts +6 -0
  72. package/templates/blocks/DD-NineCanvas/blockComponents.tsx +8 -0
  73. package/templates/blocks/DD-NineCanvas/canvas/CanvasGrid.tsx +316 -0
  74. package/templates/blocks/DD-NineCanvas/canvas/RadialNav.tsx +432 -0
  75. package/templates/blocks/DD-NineCanvas/canvas/canvas-panels.css +889 -0
  76. package/templates/blocks/DD-NineCanvas/canvas/icons/custom-icons.tsx +364 -0
  77. package/templates/blocks/DD-NineCanvas/config.ts +61 -0
  78. package/templates/blocks/DD-NineCanvas/manifest.json +165 -0
  79. package/templates/blocks/DD-NineCanvas/styles.scss +152 -0
  80. package/templates/blocks/DD-NineCanvas/tooltip/get-strict-context.tsx +26 -0
  81. package/templates/blocks/DD-NineCanvas/tooltip/primitives.tsx +178 -0
  82. package/templates/blocks/DD-NineCanvas/tooltip/tooltip.tsx +71 -0
  83. package/templates/blocks/DD-NineCanvas/tooltip/use-controlled-state.tsx +33 -0
  84. package/templates/blocks/DD-NineCanvas/utilities/FadeOnScroll.tsx +68 -0
  85. package/templates/blocks/DD-NineCanvas/utilities/ParallaxWrapper.tsx +157 -0
  86. package/templates/blocks/DD-NineCanvas/utilities/renderCustomCSS.ts +5 -0
  87. package/templates/blocks/DD-NineCanvas/utilities/webglCleanup.ts +27 -0
  88. package/templates/blocks/DD-PayloadAIAssistant/Component.tsx +78 -0
  89. package/templates/blocks/DD-PayloadAIAssistant/DustedBot.tsx +590 -0
  90. package/templates/blocks/DD-PayloadAIAssistant/config.ts +37 -0
  91. package/templates/blocks/DD-PayloadAIAssistant/demo.css +125 -0
  92. package/templates/blocks/DD-PayloadAIAssistant/manifest.json +93 -0
  93. package/templates/blocks/DD-PayloadAIAssistant/source-defaults.ts +17 -0
  94. package/templates/blocks/DD-PayloadAIAssistant/styles.ts +306 -0
  95. package/templates/blocks/DD-Pricing/Component.tsx +2 -3
  96. package/templates/blocks/DD-Pricing/config.ts +215 -215
  97. package/templates/blocks/DD-Process/Component.tsx +2 -2
  98. package/templates/blocks/DD-ProjHeader/Component.tsx +93 -91
  99. package/templates/blocks/DD-ProjSlider/Component.tsx +1 -1
  100. package/templates/blocks/DD-Section/Component.tsx +265 -266
  101. package/templates/blocks/DD-Separator/Component.tsx +66 -66
  102. package/templates/blocks/DD-Services/Component.tsx +176 -176
  103. package/templates/blocks/DD-ShowcaseGrid/Component.tsx +306 -307
  104. package/templates/blocks/DD-Slider-A/Component.tsx +2 -2
  105. package/templates/blocks/DD-StackCards/Component.tsx +172 -171
  106. package/templates/blocks/DD-Team/Component.tsx +247 -247
  107. package/templates/blocks/DD-TeamCards/Component.tsx +251 -251
  108. package/templates/blocks/DD-TechStack/Component.tsx +173 -174
  109. package/templates/blocks/DD-TestMarq/Component.tsx +158 -132
  110. package/templates/blocks/DD-Testim/Component.tsx +247 -247
  111. package/templates/blocks/DD-Testim2/Component.tsx +265 -256
  112. package/templates/blocks/DD-Testimonials/Component.tsx +139 -139
  113. package/templates/blocks/DD-Thanks/Component.tsx +1 -1
  114. package/templates/blocks/DD-Work/Component.tsx +318 -318
  115. package/templates/blocks/DD-Work-B/Component.tsx +294 -294
  116. package/templates/blocks/DDHG-CTASection2/Component.tsx +183 -184
  117. package/templates/blocks/DDHG-HighlightArc/Component.tsx +6 -3
  118. package/templates/blocks/DDHG-LogoMarquee/Component.tsx +45 -8
  119. package/templates/blocks/DDHG-NavCodeGrid/Component.tsx +1 -3
  120. package/templates/blocks/DDHG-ServiceDetails/ServiceDetailCard.tsx +9 -22
  121. package/templates/blocks/DDHG-ServiceHero/Component.tsx +10 -10
  122. package/templates/blocks/DDHG-TeamCards/Component.tsx +6 -35
  123. package/templates/blocks/Form/Checkbox/index.tsx +45 -0
  124. package/templates/blocks/Form/Component.tsx +163 -0
  125. package/templates/blocks/Form/Country/index.tsx +65 -0
  126. package/templates/blocks/Form/Country/options.ts +982 -0
  127. package/templates/blocks/Form/Email/index.tsx +38 -0
  128. package/templates/blocks/Form/Error/index.tsx +15 -0
  129. package/templates/blocks/Form/Message/index.tsx +13 -0
  130. package/templates/blocks/Form/Number/index.tsx +36 -0
  131. package/templates/blocks/Form/Select/index.tsx +63 -0
  132. package/templates/blocks/Form/State/index.tsx +64 -0
  133. package/templates/blocks/Form/State/options.ts +52 -0
  134. package/templates/blocks/Form/Text/index.tsx +32 -0
  135. package/templates/blocks/Form/Textarea/index.tsx +40 -0
  136. package/templates/blocks/Form/Width/index.tsx +13 -0
  137. package/templates/blocks/Form/config.ts +51 -0
  138. package/templates/blocks/Form/fields.tsx +21 -0
  139. package/templates/blocks/Form/manifest.json +168 -0
  140. package/templates/blocks/MediaBlock/Component.tsx +67 -0
  141. package/templates/blocks/MediaBlock/config.ts +14 -0
  142. package/templates/blocks/MediaBlock/manifest.json +92 -0
  143. package/templates/blocks/TransitionsDustedShowcase/Component.tsx +9 -0
  144. package/templates/blocks/TransitionsDustedShowcase/config.ts +13 -0
  145. package/templates/blocks/TransitionsDustedShowcase/manifest.json +80 -0
  146. package/templates/blocks/rawHtml/Component.tsx +25 -0
  147. package/templates/blocks/rawHtml/config.ts +56 -0
  148. package/templates/blocks/rawHtml/manifest.json +80 -0
@@ -75,13 +75,13 @@ export const Counter: React.FC<CounterItem> = ({
75
75
  }, [ref, inView, from, to, duration])
76
76
 
77
77
  return (
78
- <div className="counter-wrapper flex items-center justify-center">
78
+ <div className="counter-wrapper flex min-h-12 items-baseline justify-center gap-1 tabular-nums">
79
79
  {prefix && (
80
80
  <span className={prefixClass || 'text-xl font-bold sm:text-2xl md:text-4xl'}>{prefix}</span>
81
81
  )}
82
82
  <span ref={ref} className={className || 'text-xl font-bold sm:text-2xl md:text-4xl'} />
83
83
  {suffix && (
84
- <span className={suffixClass || 'text-md font-base sm:text-lg md:text-xl ml-2'}>
84
+ <span className={suffixClass || 'text-base font-medium sm:text-lg md:text-xl'}>
85
85
  {suffix}
86
86
  </span>
87
87
  )}
@@ -166,13 +166,18 @@ export const DDCounter: React.FC<CounterBlockProps> = ({
166
166
  }
167
167
 
168
168
  return (
169
- <div className={getLayoutClasses()} id={counterContId}>
169
+ <div className={`w-full ${getLayoutClasses()}`} id={counterContId}>
170
170
  {counters.map((counter) => (
171
- <div key={counter.id} className="counter-item" id={counterId}>
171
+ <div
172
+ key={counter.id}
173
+ className="counter-item flex min-h-40 w-full flex-col items-center justify-center gap-3 rounded-2xl border border-border bg-card p-6 text-center shadow-sm"
174
+ id={counterId}
175
+ >
172
176
  <RichText
173
177
  data={counter.beforeCounter}
174
178
  enableGutter={false}
175
- className="counter_label-before"
179
+ enableProse={false}
180
+ className="counter_label-before text-sm font-medium text-muted-foreground [&_*]:m-0 [&_*]:text-current"
176
181
  />
177
182
 
178
183
  <Counter {...counter} />
@@ -181,7 +186,7 @@ export const DDCounter: React.FC<CounterBlockProps> = ({
181
186
  data={counter.label}
182
187
  enableProse={false}
183
188
  enableGutter={false}
184
- className="counter_label-after scale-80 origin-top"
189
+ className="counter_label-after text-sm font-medium text-foreground [&_*]:m-0 [&_*]:text-current"
185
190
  />
186
191
  </div>
187
192
  ))}
@@ -0,0 +1,303 @@
1
+ 'use client'
2
+
3
+ import React, { useMemo, useState } from 'react'
4
+ import Image from 'next/image'
5
+ import * as LucideIcons from 'lucide-react'
6
+ import { Truck } from 'lucide-react'
7
+
8
+ import { cn } from '@/utilities/ui'
9
+ import RichText from '@/components/RichText'
10
+
11
+ type MediaObj = {
12
+ url?: string | null
13
+ alt?: string | null
14
+ }
15
+
16
+ type IconMedia = MediaObj | string | number | null | undefined
17
+
18
+ type Badge = {
19
+ icon?: string | null
20
+ customIcon?: IconMedia
21
+ title?: string | null
22
+ description?: string | null
23
+ }
24
+
25
+ type Feature = {
26
+ id?: string | null
27
+ icon?: string | null
28
+ customIcon?: IconMedia
29
+ title?: string | null
30
+ description?: string | null
31
+ }
32
+
33
+ type PricingItem = {
34
+ id?: string | null
35
+ price?: string | null
36
+ label?: string | null
37
+ }
38
+
39
+ export type DDDeliCardProps = {
40
+ blockType?: 'DD-DeliCard'
41
+ blockName?: string | null
42
+ sectionId?: string | null
43
+ customCSS?: string | null
44
+ image?: MediaObj | string | null
45
+ imageAlt?: string | null
46
+ badge?: Badge | null
47
+ heading?: string | null
48
+ description?: any | null
49
+ features?: Feature[] | null
50
+ pricingItems?: PricingItem[] | null
51
+ }
52
+
53
+ function getMediaUrl(media?: IconMedia): string | undefined {
54
+ if (!media) return undefined
55
+ if (typeof media === 'string') return media
56
+ if (typeof media === 'object' && 'url' in media && typeof media.url === 'string') return media.url
57
+ return undefined
58
+ }
59
+
60
+ function getMediaAlt(media?: MediaObj | string | null, fallback = ''): string {
61
+ if (!media || typeof media === 'string') return fallback
62
+ return media.alt ?? fallback
63
+ }
64
+
65
+ function IconRenderer({
66
+ icon,
67
+ customIcon,
68
+ className,
69
+ size = 22,
70
+ }: {
71
+ icon?: string | null
72
+ customIcon?: IconMedia
73
+ className?: string
74
+ size?: number
75
+ }) {
76
+ const customIconUrl = getMediaUrl(customIcon)
77
+
78
+ if (customIconUrl) {
79
+ return (
80
+ <Image
81
+ src={customIconUrl}
82
+ alt=""
83
+ width={size}
84
+ height={size}
85
+ className={cn('h-auto w-auto object-contain', className)}
86
+ />
87
+ )
88
+ }
89
+
90
+ const Icon = icon
91
+ ? ((LucideIcons as Record<string, any>)[icon] as
92
+ | React.ComponentType<{ size?: number; strokeWidth?: number; className?: string }>
93
+ | undefined)
94
+ : undefined
95
+
96
+ if (Icon) return <Icon size={size} strokeWidth={2.2} className={className} />
97
+
98
+ return <Truck size={size} strokeWidth={2.2} className={className} />
99
+ }
100
+
101
+ export const DDDeliCard: React.FC<DDDeliCardProps> = ({
102
+ sectionId,
103
+ customCSS,
104
+ image,
105
+ imageAlt,
106
+ badge,
107
+ heading = 'Reliable Delivery, Every Time',
108
+ description,
109
+ features = [],
110
+ pricingItems = [],
111
+ }) => {
112
+ const safeFeatures = useMemo(() => {
113
+ return features?.filter((feature) => feature?.title) ?? []
114
+ }, [features])
115
+
116
+ const safePricingItems = useMemo(() => {
117
+ return pricingItems?.filter((item) => item?.price || item?.label) ?? []
118
+ }, [pricingItems])
119
+
120
+ const [activeTab, setActiveTab] = useState(0)
121
+
122
+ const activeFeature = safeFeatures[activeTab] ?? safeFeatures[0]
123
+ const imageUrl = getMediaUrl(image)
124
+
125
+ return (
126
+ <div
127
+ id={sectionId || undefined}
128
+ data-block-type="DD-DeliCard"
129
+ className="delivery-card-block mx-auto w-full max-w-7xl bg-stone-50/50 text-stone-900 dark:bg-stone-950 dark:text-stone-100 rounded-3xl squircle"
130
+ >
131
+ {customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
132
+
133
+ <div
134
+ data-container-type={`${sectionId}-container`}
135
+ className="overflow-hidden rounded-3xl border border-stone-200 dark:border-stone-800 squircle"
136
+ >
137
+ <div data-col-type={`${sectionId}-col`} className="grid grid-cols-1 lg:grid-cols-2">
138
+ <div className="relative min-h-[400px] overflow-hidden">
139
+ {imageUrl ? (
140
+ <>
141
+ <Image
142
+ data-image-type={`${sectionId}-img`}
143
+ src={imageUrl}
144
+ alt={imageAlt || getMediaAlt(image, 'BFS Plastics delivery truck')}
145
+ width={900}
146
+ height={600}
147
+ className="h-full min-h-[400px] w-full object-cover"
148
+ />
149
+ <img
150
+ data-image-type={`${sectionId}-bgimg`}
151
+ src="/assets/svg/lines.svg"
152
+ alt=""
153
+ aria-hidden="true"
154
+ className="pointer-events-none absolute inset-0 h-full min-h-[400px] w-full object-cover"
155
+ />
156
+ </>
157
+ ) : (
158
+ <div className="flex h-full min-h-[400px] w-full items-center justify-center border border-dashed border-stone-300 dark:border-stone-700 text-sm text-stone-600 dark:text-stone-300">
159
+ Upload a delivery image
160
+ </div>
161
+ )}
162
+
163
+ <div className="absolute inset-0 bg-gradient-to-r from-transparent to-stone-950/60 lg:bg-gradient-to-l lg:from-stone-950/60 lg:to-transparent" />
164
+
165
+ {(badge?.title || badge?.description) && (
166
+ <div
167
+ data-content-type={`${sectionId}-description`}
168
+ className="absolute bottom-6 left-6 rounded-xl bg-stone-50/95 dark:bg-stone-900/95 px-4 py-3 shadow-lg backdrop-blur-sm"
169
+ >
170
+ <div
171
+ data-container-type={`${sectionId}-container`}
172
+ className="flex items-center gap-2"
173
+ >
174
+ <span className="flex h-8 w-8 items-center justify-center rounded-full bg-indigo-100 dark:bg-indigo-950/70">
175
+ <IconRenderer
176
+ icon={badge?.icon || 'Truck'}
177
+ customIcon={badge?.customIcon}
178
+ size={18}
179
+ className="text-indigo-700 dark:text-indigo-300"
180
+ />
181
+ </span>
182
+
183
+ <div data-container-type={`${sectionId}-badge-desc`}>
184
+ {badge?.title && (
185
+ <div className="text-sm font-bold text-stone-900 dark:text-stone-100">
186
+ {badge.title}
187
+ </div>
188
+ )}
189
+ {badge?.description && (
190
+ <div className="text-xs text-stone-600 dark:text-stone-300">
191
+ {badge.description}
192
+ </div>
193
+ )}
194
+ </div>
195
+ </div>
196
+ </div>
197
+ )}
198
+ </div>
199
+
200
+ <div
201
+ data-container-type={`${sectionId}-heading`}
202
+ className="flex flex-col justify-center p-6 md:p-10 lg:p-12"
203
+ >
204
+ {heading && (
205
+ <h3 className="mb-0 text-2xl font-bold text-stone-900 dark:text-stone-100 md:text-3xl">
206
+ {heading}
207
+ </h3>
208
+ )}
209
+
210
+ {description && (
211
+ <RichText
212
+ data-content-type={`${sectionId}-richtext`}
213
+ data={description}
214
+ className="mb-8 max-w-none text-base leading-relaxed text-stone-600 dark:text-stone-300"
215
+ enableGutter={false}
216
+ enableProse={false}
217
+ />
218
+ )}
219
+
220
+ {safeFeatures.length > 0 && (
221
+ <>
222
+ <div
223
+ data-container-type="delivery-location-tags"
224
+ className="mb-6 mt-6 flex flex-wrap gap-2"
225
+ >
226
+ {safeFeatures.map((feature, index) => (
227
+ <button
228
+ key={feature.id || feature.title || index}
229
+ type="button"
230
+ onClick={() => setActiveTab(index)}
231
+ className={cn(
232
+ 'cursor-pointer whitespace-nowrap rounded-full px-4 py-2 text-sm font-medium transition-all duration-300 hover:duration-300',
233
+ activeTab === index
234
+ ? 'border border-solid border-indigo-600 bg-indigo-600 text-white dark:border-indigo-400 dark:bg-indigo-500 dark:text-stone-950'
235
+ : 'border border-stone-200 bg-stone-100 text-stone-700 hover:bg-stone-200 hover:text-stone-950 dark:border-stone-700 dark:bg-stone-900 dark:text-stone-300 dark:hover:bg-stone-800 dark:hover:text-stone-100',
236
+ )}
237
+ >
238
+ {feature.title}
239
+ </button>
240
+ ))}
241
+ </div>
242
+
243
+ {activeFeature && (
244
+ <div className="rounded-xl border border-stone-200 bg-stone-50 dark:border-stone-800 dark:bg-stone-900/80 p-5 md:p-6">
245
+ <div className="flex items-start gap-4">
246
+ <span className="flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-xl bg-indigo-100 dark:bg-indigo-950/70">
247
+ <IconRenderer
248
+ icon={activeFeature.icon || 'MapPin'}
249
+ customIcon={activeFeature.customIcon}
250
+ size={20}
251
+ className="text-indigo-700 dark:text-indigo-300"
252
+ />
253
+ </span>
254
+
255
+ <div>
256
+ {activeFeature.title && (
257
+ <h4 className="mb-1 text-lg font-bold text-foreground">
258
+ {activeFeature.title}
259
+ </h4>
260
+ )}
261
+
262
+ {activeFeature.description && (
263
+ <p className="text-sm leading-relaxed text-stone-600 dark:text-stone-300">
264
+ {activeFeature.description}
265
+ </p>
266
+ )}
267
+ </div>
268
+ </div>
269
+ </div>
270
+ )}
271
+ </>
272
+ )}
273
+
274
+ {safePricingItems.length > 0 && (
275
+ <div className="mt-6 grid grid-cols-1 gap-3 sm:grid-cols-3">
276
+ {safePricingItems.map((item, index) => (
277
+ <div
278
+ key={item.id || item.price || index}
279
+ className="rounded-xl border border-stone-200 bg-stone-50 dark:border-stone-800 dark:bg-stone-900/80 p-3 text-center"
280
+ >
281
+ {item.price && (
282
+ <div className="text-lg font-bold text-indigo-700 dark:text-indigo-300">
283
+ {item.price}
284
+ </div>
285
+ )}
286
+
287
+ {item.label && (
288
+ <div className="mt-0.5 text-xs text-stone-600 dark:text-stone-300">
289
+ {item.label}
290
+ </div>
291
+ )}
292
+ </div>
293
+ ))}
294
+ </div>
295
+ )}
296
+ </div>
297
+ </div>
298
+ </div>
299
+ </div>
300
+ )
301
+ }
302
+
303
+ export default DDDeliCard
@@ -0,0 +1,186 @@
1
+ import type { Block } from 'payload'
2
+
3
+ /**
4
+ * Author: Hadi Zainal | Designs Dusted
5
+ * Delivery Card Block - version 1.0 BFS variant
6
+ * Main delivery/freight card with editable image, badge, tabbed features,
7
+ * pricing summary, lucide icon picker defaults, and uploaded custom icon overrides.
8
+ */
9
+
10
+ import { iconPicker } from '@/fields/lucide-icon-picker/field'
11
+ import { defaultLexical } from '@/fields/defaultLexical'
12
+
13
+ const iconFields = [
14
+ iconPicker({
15
+ name: 'icon',
16
+ description: 'Choose a Lucide icon. Overridden by custom icon upload if provided.',
17
+ }),
18
+ {
19
+ name: 'customIcon',
20
+ type: 'upload' as const,
21
+ relationTo: 'media' as const,
22
+ required: false,
23
+ label: 'Custom Icon (overrides Lucide)',
24
+ admin: {
25
+ description: 'Upload a custom icon image. If set, this takes priority over the Lucide icon.',
26
+ },
27
+ },
28
+ ]
29
+
30
+ export const DDDeliCard: Block = {
31
+ slug: 'DD-DeliCard',
32
+ dbName: 'dd_deli_card',
33
+ interfaceName: 'DDDeliCard',
34
+ labels: {
35
+ singular: 'DD Deli Card',
36
+ plural: 'DD Deli Cards',
37
+ },
38
+ fields: [
39
+ {
40
+ type: 'tabs',
41
+ tabs: [
42
+ {
43
+ label: 'Content',
44
+ fields: [
45
+ {
46
+ name: 'image',
47
+ type: 'upload',
48
+ relationTo: 'media',
49
+ required: false,
50
+ label: 'Delivery Image',
51
+ },
52
+ {
53
+ name: 'imageAlt',
54
+ type: 'text',
55
+ label: 'Image Alt Text',
56
+ defaultValue: 'BFS Plastics delivery truck',
57
+ },
58
+ {
59
+ name: 'badge',
60
+ type: 'group',
61
+ label: 'Floating Badge',
62
+ fields: [
63
+ ...iconFields,
64
+ {
65
+ name: 'title',
66
+ type: 'text',
67
+ defaultValue: 'Australia-wide',
68
+ },
69
+ {
70
+ name: 'description',
71
+ type: 'text',
72
+ defaultValue: 'Delivery coverage',
73
+ },
74
+ ],
75
+ },
76
+ {
77
+ name: 'heading',
78
+ type: 'text',
79
+ defaultValue: 'Reliable Delivery, Every Time',
80
+ },
81
+ {
82
+ name: 'description',
83
+ type: 'richText',
84
+ label: 'Description',
85
+ editor: defaultLexical,
86
+ required: false,
87
+ },
88
+ {
89
+ name: 'features',
90
+ type: 'array',
91
+ label: 'Delivery Features',
92
+ minRows: 1,
93
+ defaultValue: [
94
+ {
95
+ icon: 'MapPin',
96
+ title: 'Brisbane Metro',
97
+ description:
98
+ 'From $35 + GST across all Brisbane metro areas. Fast, reliable local delivery.',
99
+ },
100
+ {
101
+ icon: 'Sun',
102
+ title: 'Gold & Sunshine Coast',
103
+ description:
104
+ 'From $40 + GST covering Sunshine Coast and Gold Coast regional areas.',
105
+ },
106
+ {
107
+ icon: 'Map',
108
+ title: 'Interstate Freight',
109
+ description:
110
+ 'Interstate charges quoted as per request. We ship Australia-wide with trusted freight partners.',
111
+ },
112
+ ],
113
+ fields: [
114
+ ...iconFields,
115
+ {
116
+ name: 'title',
117
+ type: 'text',
118
+ required: true,
119
+ },
120
+ {
121
+ name: 'description',
122
+ type: 'textarea',
123
+ },
124
+ ],
125
+ },
126
+ {
127
+ name: 'pricingItems',
128
+ type: 'array',
129
+ label: 'Pricing Summary',
130
+ minRows: 1,
131
+ defaultValue: [
132
+ {
133
+ price: '$35',
134
+ label: 'Brisbane Metro',
135
+ },
136
+ {
137
+ price: '$40',
138
+ label: 'Coast Regions',
139
+ },
140
+ {
141
+ price: 'Quote',
142
+ label: 'Interstate',
143
+ },
144
+ ],
145
+ fields: [
146
+ {
147
+ name: 'price',
148
+ type: 'text',
149
+ required: true,
150
+ },
151
+ {
152
+ name: 'label',
153
+ type: 'text',
154
+ required: true,
155
+ },
156
+ ],
157
+ },
158
+ ],
159
+ },
160
+ {
161
+ label: 'Settings',
162
+ fields: [
163
+ {
164
+ name: 'sectionId',
165
+ type: 'text',
166
+ label: 'Section ID',
167
+ admin: {
168
+ description: 'Optional ID for anchor linking',
169
+ },
170
+ },
171
+ {
172
+ name: 'customCSS',
173
+ type: 'code',
174
+ label: 'Custom CSS',
175
+ admin: {
176
+ language: 'css',
177
+ },
178
+ },
179
+ ],
180
+ },
181
+ ],
182
+ },
183
+ ],
184
+ }
185
+
186
+ export default DDDeliCard
@@ -0,0 +1,94 @@
1
+ {
2
+ "type": "block",
3
+ "name": "DD-DeliCard",
4
+ "label": "Delivery Card",
5
+ "sourceName": "DD-DeliCard",
6
+ "portableName": "DD-DeliCard",
7
+ "slug": "DD-DeliCard",
8
+ "version": "0.0.1",
9
+ "source": {
10
+ "repo": "Hadizainal/Dusted-Payload-Blocks",
11
+ "originalPath": "CLI-TestGround/dusted-blocks-demo/src/blocks/DD-DeliCard",
12
+ "originalSlug": "DD-DeliCard",
13
+ "originalConfigExport": "DDDeliCard",
14
+ "originalComponentExport": "DDDeliCard",
15
+ "originalInterfaceName": "DDDeliCard"
16
+ },
17
+ "files": [
18
+ {
19
+ "from": "Component.tsx",
20
+ "to": "src/blocks/DD-DeliCard/Component.tsx"
21
+ },
22
+ {
23
+ "from": "config.ts",
24
+ "to": "src/blocks/DD-DeliCard/config.ts"
25
+ }
26
+ ],
27
+ "dependencies": [
28
+ "lucide-react"
29
+ ],
30
+ "sharedFiles": [],
31
+ "requiredProjectFiles": [
32
+ {
33
+ "path": "src/fields/defaultLexical.ts",
34
+ "reason": "Payload config uses the project Lexical editor configuration."
35
+ },
36
+ {
37
+ "path": "src/fields/lucide-icon-picker/field.ts",
38
+ "reason": "Payload config uses the Lucide icon picker field."
39
+ },
40
+ {
41
+ "path": "src/components/RichText/index.tsx",
42
+ "reason": "Component renders Payload rich text."
43
+ },
44
+ {
45
+ "path": "src/utilities/ui.ts",
46
+ "reason": "Component imports cn from @/utilities/ui."
47
+ }
48
+ ],
49
+ "optionalProjectFiles": [],
50
+ "collectionRegistration": {
51
+ "enabled": true,
52
+ "collections": [
53
+ "Pages",
54
+ "Posts"
55
+ ]
56
+ },
57
+ "renderBlocksRegistration": {
58
+ "enabled": true
59
+ },
60
+ "renderBlocksBehavior": {
61
+ "wrapperless": false
62
+ },
63
+ "pageRouteIntegration": {
64
+ "required": false,
65
+ "manualSteps": []
66
+ },
67
+ "manual": [
68
+ "Register DDDeliCard in Pages/Posts block arrays if automatic registration was skipped.",
69
+ "Register DD-DeliCard in RenderBlocks if automatic registration was skipped.",
70
+ "Run payload generate:types after schema changes.",
71
+ "Run payload generate:importmap if admin/component imports changed."
72
+ ],
73
+ "manualSteps": [
74
+ "Register DDDeliCard in Pages/Posts block arrays if automatic registration was skipped.",
75
+ "Register DD-DeliCard in RenderBlocks if automatic registration was skipped.",
76
+ "Run payload generate:types after schema changes.",
77
+ "Run payload generate:importmap if admin/component imports changed."
78
+ ],
79
+ "patchTargets": {
80
+ "blockConfigRegistration": {
81
+ "description": "Installer can register DDDeliCard from @/blocks/DD-DeliCard/config."
82
+ },
83
+ "renderBlocksRegistration": {
84
+ "description": "Installer can register DD-DeliCard with component export DDDeliCard."
85
+ }
86
+ },
87
+ "notes": [
88
+ "Promoted from the verified Dusted Blocks demo implementation.",
89
+ "Installer preserves existing destination files and reports project requirements before writing."
90
+ ],
91
+ "exportName": "DDDeliCard",
92
+ "componentExportName": "DDDeliCard",
93
+ "interfaceName": "DDDeliCard"
94
+ }