blocks-dusted 0.1.0

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 (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +68 -0
  3. package/bin/index.js +8 -0
  4. package/package.json +40 -0
  5. package/src/cli.js +79 -0
  6. package/src/commands/add.js +327 -0
  7. package/src/commands/doctor.js +21 -0
  8. package/src/commands/list.js +18 -0
  9. package/src/installers/checkRequirements.js +101 -0
  10. package/src/installers/copyTemplateFiles.js +79 -0
  11. package/src/installers/installDependencies.js +69 -0
  12. package/src/installers/patchPayloadBlocksArray.js +122 -0
  13. package/src/installers/patchRenderBlocks.js +110 -0
  14. package/src/installers/runGenerators.js +3 -0
  15. package/src/installers/writeInstalledBlockReadme.js +117 -0
  16. package/src/registry/listTemplates.js +17 -0
  17. package/src/registry/loadTemplateManifest.js +20 -0
  18. package/src/registry/validateTemplateManifest.js +69 -0
  19. package/src/utils/logger.js +8 -0
  20. package/src/utils/packageManager.js +42 -0
  21. package/src/utils/paths.js +7 -0
  22. package/src/utils/project.js +122 -0
  23. package/src/utils/strings.js +7 -0
  24. package/templates/blocks/DD-BookCall/Component.tsx +573 -0
  25. package/templates/blocks/DD-BookCall/config.ts +239 -0
  26. package/templates/blocks/DD-BookCall/manifest.json +112 -0
  27. package/templates/blocks/DD-CardTemplate01/Component.tsx +144 -0
  28. package/templates/blocks/DD-CardTemplate01/config.ts +106 -0
  29. package/templates/blocks/DD-CardTemplate01/manifest.json +84 -0
  30. package/templates/blocks/DD-Carousel-A/Component.tsx +266 -0
  31. package/templates/blocks/DD-Carousel-A/config.ts +163 -0
  32. package/templates/blocks/DD-Carousel-A/manifest.json +86 -0
  33. package/templates/blocks/DD-Carousel-B/Component.tsx +432 -0
  34. package/templates/blocks/DD-Carousel-B/config.ts +176 -0
  35. package/templates/blocks/DD-Carousel-B/manifest.json +86 -0
  36. package/templates/blocks/DD-ComparisonTable/Component.tsx +272 -0
  37. package/templates/blocks/DD-ComparisonTable/config.ts +105 -0
  38. package/templates/blocks/DD-ComparisonTable/manifest.json +78 -0
  39. package/templates/blocks/DD-Contact/Component.tsx +439 -0
  40. package/templates/blocks/DD-Contact/config.ts +217 -0
  41. package/templates/blocks/DD-Contact/manifest.json +107 -0
  42. package/templates/blocks/DD-FeatCat/Component.tsx +361 -0
  43. package/templates/blocks/DD-FeatCat/config.ts +204 -0
  44. package/templates/blocks/DD-FeatCat/manifest.json +87 -0
  45. package/templates/blocks/DD-FeatStrip/Component.tsx +615 -0
  46. package/templates/blocks/DD-FeatStrip/config.ts +134 -0
  47. package/templates/blocks/DD-FeatStrip/manifest.json +82 -0
  48. package/templates/blocks/DD-Hero/Component.tsx +317 -0
  49. package/templates/blocks/DD-Hero/config.ts +267 -0
  50. package/templates/blocks/DD-Hero/manifest.json +92 -0
  51. package/templates/blocks/DD-HorizontalScroll/Component.tsx +995 -0
  52. package/templates/blocks/DD-HorizontalScroll/config.ts +231 -0
  53. package/templates/blocks/DD-HorizontalScroll/manifest.json +85 -0
  54. package/templates/blocks/DD-MasonaryMedia/Component.tsx +571 -0
  55. package/templates/blocks/DD-MasonaryMedia/config.ts +390 -0
  56. package/templates/blocks/DD-MasonaryMedia/manifest.json +101 -0
  57. package/templates/blocks/DD-MasonaryMedia/vendor.d.ts +2 -0
  58. package/templates/blocks/DD-Pricing/Component.tsx +380 -0
  59. package/templates/blocks/DD-Pricing/config.ts +215 -0
  60. package/templates/blocks/DD-Pricing/manifest.json +78 -0
  61. package/templates/blocks/DD-Process/Component.tsx +155 -0
  62. package/templates/blocks/DD-Process/config.ts +150 -0
  63. package/templates/blocks/DD-Process/manifest.json +82 -0
  64. package/templates/blocks/DD-Section/Component.tsx +327 -0
  65. package/templates/blocks/DD-Section/config.ts +214 -0
  66. package/templates/blocks/DD-Section/manifest.json +85 -0
  67. package/templates/blocks/DD-Services/Component.tsx +188 -0
  68. package/templates/blocks/DD-Services/config.ts +149 -0
  69. package/templates/blocks/DD-Services/manifest.json +95 -0
  70. package/templates/blocks/DD-ShowcaseGrid/Component.tsx +317 -0
  71. package/templates/blocks/DD-ShowcaseGrid/config.ts +197 -0
  72. package/templates/blocks/DD-ShowcaseGrid/manifest.json +80 -0
  73. package/templates/blocks/DD-Slider-A/Component.tsx +252 -0
  74. package/templates/blocks/DD-Slider-A/config.ts +118 -0
  75. package/templates/blocks/DD-Slider-A/manifest.json +86 -0
  76. package/templates/blocks/DD-StackCards/Component.tsx +496 -0
  77. package/templates/blocks/DD-StackCards/config.ts +399 -0
  78. package/templates/blocks/DD-StackCards/manifest.json +87 -0
  79. package/templates/blocks/DD-Team/Component.tsx +265 -0
  80. package/templates/blocks/DD-Team/config.ts +173 -0
  81. package/templates/blocks/DD-Team/manifest.json +82 -0
  82. package/templates/blocks/DD-TechStack/Component.tsx +189 -0
  83. package/templates/blocks/DD-TechStack/config.ts +153 -0
  84. package/templates/blocks/DD-TechStack/manifest.json +118 -0
  85. package/templates/blocks/DD-Testimonials/Component.tsx +147 -0
  86. package/templates/blocks/DD-Testimonials/config.ts +120 -0
  87. package/templates/blocks/DD-Testimonials/manifest.json +87 -0
  88. package/templates/blocks/DD-Work/Component.tsx +328 -0
  89. package/templates/blocks/DD-Work/config.ts +165 -0
  90. package/templates/blocks/DD-Work/manifest.json +87 -0
  91. package/templates/blocks/DD-Work-B/Component.tsx +320 -0
  92. package/templates/blocks/DD-Work-B/config.ts +165 -0
  93. package/templates/blocks/DD-Work-B/manifest.json +75 -0
  94. package/templates/shared/components/ui/anims/fade.tsx +83 -0
  95. package/templates/shared/components/ui/button.tsx +233 -0
  96. package/templates/shared/components/ui/input.tsx +41 -0
  97. package/templates/shared/fields/lucide-icon-picker/Cell.tsx +24 -0
  98. package/templates/shared/fields/lucide-icon-picker/README.md +160 -0
  99. package/templates/shared/fields/lucide-icon-picker/field.ts +40 -0
  100. package/templates/shared/fields/lucide-icon-picker/index.tsx +203 -0
  101. package/templates/shared/utilities/canUseDOM.ts +1 -0
  102. package/templates/shared/utilities/getURL.ts +31 -0
@@ -0,0 +1,327 @@
1
+ "use client";
2
+ import React from "react";
3
+ import Link from "next/link";
4
+ import Image from "next/image";
5
+ import { ArrowUpRight, CheckCheck } from "lucide-react";
6
+ import { motion, type Variants } from "framer-motion";
7
+ import * as LucideIcons from "lucide-react";
8
+ export type DDSectionProps = Record<string, any>;
9
+ type ServiceItem = {
10
+ id?: string | null;
11
+ iconName?: string | null;
12
+ title?: string | null;
13
+ description?: string | null;
14
+ };
15
+ type ButtonItem = {
16
+ href?: string | null;
17
+ class?: string | null;
18
+ label?: string | null;
19
+ };
20
+
21
+ function isLocalImageSrc(src?: string | null): src is string {
22
+ return typeof src === "string" && src.startsWith("/api/media/file/");
23
+ }
24
+
25
+ function SectionImagePlaceholder() {
26
+ return (
27
+ <svg
28
+ aria-hidden="true"
29
+ className="h-full w-full"
30
+ viewBox="0 0 900 700"
31
+ preserveAspectRatio="none"
32
+ >
33
+ <defs>
34
+ <linearGradient id="dd-section-placeholder" x1="0" y1="0" x2="1" y2="1">
35
+ <stop offset="0%" stopColor="#111827" />
36
+ <stop offset="50%" stopColor="#251644" />
37
+ <stop offset="100%" stopColor="#09090b" />
38
+ </linearGradient>
39
+ <pattern
40
+ id="dd-section-grid"
41
+ width="72"
42
+ height="72"
43
+ patternUnits="userSpaceOnUse"
44
+ >
45
+ <path
46
+ d="M 72 0 L 0 0 0 72"
47
+ fill="none"
48
+ stroke="#ffffff"
49
+ strokeOpacity="0.07"
50
+ />
51
+ </pattern>
52
+ </defs>
53
+ <rect width="900" height="700" fill="url(#dd-section-placeholder)" />
54
+ <rect width="900" height="700" fill="url(#dd-section-grid)" />
55
+ <rect
56
+ x="155"
57
+ y="150"
58
+ width="590"
59
+ height="360"
60
+ rx="32"
61
+ fill="#ffffff"
62
+ fillOpacity="0.08"
63
+ />
64
+ <rect
65
+ x="210"
66
+ y="215"
67
+ width="270"
68
+ height="28"
69
+ rx="14"
70
+ fill="#ffffff"
71
+ fillOpacity="0.18"
72
+ />
73
+ <rect
74
+ x="210"
75
+ y="275"
76
+ width="430"
77
+ height="22"
78
+ rx="11"
79
+ fill="#ffffff"
80
+ fillOpacity="0.12"
81
+ />
82
+ <rect
83
+ x="210"
84
+ y="325"
85
+ width="360"
86
+ height="22"
87
+ rx="11"
88
+ fill="#ffffff"
89
+ fillOpacity="0.1"
90
+ />
91
+ <rect
92
+ x="210"
93
+ y="410"
94
+ width="150"
95
+ height="46"
96
+ rx="23"
97
+ fill="#a3e635"
98
+ fillOpacity="0.16"
99
+ />
100
+ </svg>
101
+ );
102
+ }
103
+
104
+ const containerVariants: Variants = {
105
+ hidden: {},
106
+ show: { transition: { staggerChildren: 0.1, delayChildren: 0.05 } },
107
+ };
108
+
109
+ const itemVariants: Variants = {
110
+ hidden: { opacity: 0, y: 20 },
111
+ show: { opacity: 1, y: 0, transition: { duration: 0.45, ease: "easeOut" } },
112
+ };
113
+
114
+ function DynamicIcon({
115
+ name,
116
+ ...props
117
+ }: { name?: string | null } & Omit<LucideIcons.LucideProps, "name">) {
118
+ if (!name) return null;
119
+ const Icon = (
120
+ LucideIcons as unknown as Record<string, React.FC<LucideIcons.LucideProps>>
121
+ )[name];
122
+ if (!Icon) return null;
123
+ return <Icon {...props} />;
124
+ }
125
+
126
+ export const DDSection: React.FC<DDSectionProps> = ({
127
+ eyebrow,
128
+ headlineMain,
129
+ headlineAccent,
130
+ description,
131
+ ctaLabel,
132
+ ctaHref,
133
+ services,
134
+ image,
135
+ imageFallbackUrl,
136
+ imageAlt,
137
+ badgeTitle,
138
+ badgeSubtitle,
139
+ showBadge,
140
+ sectionId,
141
+ customCSS,
142
+ showButtons = true,
143
+ buttons = [
144
+ { variant: "v1", icon: "Goal", label: "Choose Lane" },
145
+ { variant: "v1", icon: "Feather", label: "How it works" },
146
+ ],
147
+ }) => {
148
+ const serviceItems = (services ?? []) as ServiceItem[];
149
+ const buttonItems = buttons as ButtonItem[];
150
+ const imgSrc =
151
+ image && typeof image === "object" && "url" in image && image.url
152
+ ? image.url
153
+ : (imageFallbackUrl ?? "");
154
+ const safeImgSrc = isLocalImageSrc(imgSrc) ? imgSrc : null;
155
+
156
+ return (
157
+ <>
158
+ {customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
159
+
160
+ <div id={sectionId ?? "studio-section"} className="py-24 overflow-hidden">
161
+ <div className="max-w-6xl lg:max-w-7xl mx-auto px-4 md:px-6">
162
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-center">
163
+ {/* Left Content */}
164
+ <motion.div
165
+ variants={containerVariants}
166
+ initial="hidden"
167
+ whileInView="show"
168
+ viewport={{ once: false, amount: 0.15 }}
169
+ >
170
+ {eyebrow && (
171
+ <motion.p
172
+ variants={itemVariants}
173
+ className="text-[11.5px] font-semibold text-stone-400 tracking-widest uppercase mb-3 top-caption"
174
+ >
175
+ {eyebrow}
176
+ </motion.p>
177
+ )}
178
+
179
+ <motion.h2
180
+ variants={itemVariants}
181
+ className="text-3d text-4xl md:text-5xl font-bold text-stone-900 dark:text-stone-50 leading-tight mb-6"
182
+ >
183
+ {headlineMain}
184
+ <br />
185
+ <span className="text-stone-400">{headlineAccent}</span>
186
+ </motion.h2>
187
+
188
+ {description && (
189
+ <motion.p
190
+ variants={itemVariants}
191
+ className="text-stone-700 dark:text-stone-300 text-base leading-relaxed mb-10"
192
+ >
193
+ {description}
194
+ </motion.p>
195
+ )}
196
+
197
+ {serviceItems.length > 0 && (
198
+ <motion.div
199
+ variants={containerVariants}
200
+ className="grid grid-cols-1 sm:grid-cols-2 gap-5 mb-10"
201
+ >
202
+ {serviceItems.map((svc) => (
203
+ <motion.div
204
+ key={svc.id ?? svc.title}
205
+ variants={itemVariants}
206
+ className="flex gap-3"
207
+ >
208
+ <div className="w-8 h-8 flex items-center justify-center rounded-lg bg-stone-200/50 dark:bg-stone-800/50 text-stone-400 shrink-0 mt-0.5 border border-stone-200 dark:border-stone-600 hover:border-lime-500 duration-150">
209
+ <DynamicIcon
210
+ className="text-stone-400"
211
+ name={svc.iconName}
212
+ size={14}
213
+ />
214
+ </div>
215
+ <div>
216
+ <h3 className="text-sm font-semibold text-stone-800 dark:text-stone-50 mb-1">
217
+ {svc.title}
218
+ </h3>
219
+ <p className="text-sm text-stone-700 dark:text-stone-300 leading-relaxed">
220
+ {svc.description}
221
+ </p>
222
+ </div>
223
+ </motion.div>
224
+ ))}
225
+ </motion.div>
226
+ )}
227
+
228
+ {/* {ctaLabel && ctaHref && (
229
+ <motion.div variants={itemVariants}>
230
+ <Link
231
+ href={ctaHref}
232
+ className="inline-flex items-center gap-2 bg-stone-50 text-stone-900 px-6 py-3 rounded-lg text-sm font-semibold hover:bg-stone-100 transition-colors cursor-pointer whitespace-nowrap"
233
+ >
234
+ {ctaLabel}
235
+ <ArrowUpRight size={15} />
236
+ </Link>
237
+ </motion.div>
238
+ )} */}
239
+
240
+ {/* Dusted CTA Buttons */}
241
+ {showButtons && buttonItems.length > 0 && (
242
+ <motion.div
243
+ className="dusted-hero-cta-col flex col-start-2 col-span-2 gap-4"
244
+ variants={itemVariants}
245
+ >
246
+ {buttonItems.map((button, index) => (
247
+ <a
248
+ key={index}
249
+ href={(button as any).href ?? "#"}
250
+ className={
251
+ button.class ??
252
+ "inline-flex items-center gap-1.5 bg-indigo-700 text-stone-50 text-xs font-semibold px-3 py-1.5 rounded-lg hover:bg-indigo-600 group-hover:scale-[1.05] hover:shadow-xl transition-all duration-150 whitespace-nowrap"
253
+ }
254
+ style={{ cornerShape: "squircle" } as React.CSSProperties}
255
+ >
256
+ {/* TODO: Reconnect ButtonDustedFluid if this project provides it. */}
257
+ {button.label || "Button"}
258
+ </a>
259
+ ))}
260
+ </motion.div>
261
+ )}
262
+ </motion.div>
263
+
264
+ {/* Right Image */}
265
+ {(safeImgSrc || imgSrc) && (
266
+ <motion.div
267
+ className="relative"
268
+ initial={{ opacity: 0, x: 40 }}
269
+ whileInView={{ opacity: 1, x: 0 }}
270
+ viewport={{ once: false, amount: 0.15 }}
271
+ transition={{ duration: 0.6, ease: "easeOut" }}
272
+ >
273
+ <div
274
+ className="rounded-3xl overflow-hidden w-full h-125 relative shadow-xl"
275
+ style={{ cornerShape: "squircle" } as React.CSSProperties}
276
+ >
277
+ {safeImgSrc ? (
278
+ <Image
279
+ src={safeImgSrc}
280
+ alt={imageAlt ?? "DesignsDusted Studio"}
281
+ fill
282
+ sizes="(max-width: 768px) 100vw, 50vw"
283
+ className="object-cover object-top squircle"
284
+ style={{ cornerShape: "squircle" } as React.CSSProperties}
285
+ />
286
+ ) : (
287
+ <SectionImagePlaceholder />
288
+ )}
289
+ <div
290
+ className="absolute inset-0 bg-linear-to-t from-stone-950/70 via-transparent to-transparent rounded-2xl"
291
+ style={{ cornerShape: "squircle" } as React.CSSProperties}
292
+ />
293
+ </div>
294
+
295
+ {showBadge && (
296
+ <div
297
+ className="absolute bottom-6 left-6 right-6 bg-indigo-900/50 shadow-inner backdrop-blur-sm rounded-2xl p-4 border border-indigo-700"
298
+ style={{ cornerShape: "squircle" } as React.CSSProperties}
299
+ >
300
+ <div className="flex items-center gap-3">
301
+ <div className="w-10 h-10 flex items-center justify-center rounded-lg bg-stone-50 text-stone-900 shrink-0">
302
+ <CheckCheck size={16} />
303
+ </div>
304
+ <div>
305
+ {badgeTitle && (
306
+ <div className="text-sm font-semibold text-stone-50 dark:text-stone-50">
307
+ {badgeTitle}
308
+ </div>
309
+ )}
310
+ {badgeSubtitle && (
311
+ <div className="text-xs text-stone-300">
312
+ {badgeSubtitle}
313
+ </div>
314
+ )}
315
+ </div>
316
+ <div className="ml-auto w-2 h-2 rounded-full bg-lime-400 animate-pulse shrink-0" />
317
+ </div>
318
+ </div>
319
+ )}
320
+ </motion.div>
321
+ )}
322
+ </div>
323
+ </div>
324
+ </div>
325
+ </>
326
+ );
327
+ };
@@ -0,0 +1,214 @@
1
+ import type { Block } from 'payload'
2
+
3
+ export const DDSection: Block = {
4
+ slug: 'DD-Section',
5
+ interfaceName: 'DDSection',
6
+ labels: {
7
+ singular: 'Studio Section',
8
+ plural: 'Studio Sections'
9
+ },
10
+ fields: [
11
+ {
12
+ type: 'tabs',
13
+ tabs: [
14
+ {
15
+ label: 'Left Content',
16
+ fields: [
17
+ {
18
+ name: 'eyebrow',
19
+ type: 'text',
20
+ label: 'Eyebrow Label',
21
+ defaultValue: 'Studio Services'
22
+ },
23
+ {
24
+ name: 'headlineMain',
25
+ type: 'text',
26
+ label: 'Headline (Main)',
27
+ required: true,
28
+ defaultValue: 'We build what'
29
+ },
30
+ {
31
+ name: 'headlineAccent',
32
+ type: 'text',
33
+ label: 'Headline (Accent)',
34
+ required: true,
35
+ defaultValue: 'you imagine'
36
+ },
37
+ {
38
+ name: 'description',
39
+ type: 'textarea',
40
+ label: 'Description',
41
+ defaultValue:
42
+ 'DesignsDusted Studio is a small, focused team of designers and developers. We take on select projects where we can make a real impact — from product design to full-stack delivery.'
43
+ },
44
+ // Cta links
45
+ {
46
+ hidden: true,
47
+ name: 'ctaLabel',
48
+ type: 'text',
49
+ label: 'CTA Button Label',
50
+ defaultValue: 'Start a Project'
51
+ },
52
+ {
53
+ hidden: true,
54
+ name: 'ctaHref',
55
+ type: 'text',
56
+ label: 'CTA Button URL',
57
+ defaultValue: '/studio'
58
+ },
59
+ // DustedFluidButtons
60
+ {
61
+ hidden: true,
62
+ name: 'showButtons',
63
+ type: 'checkbox',
64
+ label: 'Show CTA Buttons',
65
+ defaultValue: true
66
+ },
67
+ {
68
+ name: 'buttons',
69
+ type: 'array',
70
+ label: 'CTA Buttons',
71
+ maxRows: 3,
72
+ // admin: {
73
+ // condition: (data) => data?.showButtons
74
+ // },
75
+ fields: [
76
+ {
77
+ name: 'variant',
78
+ type: 'select',
79
+ label: 'Button Variant',
80
+ options: [
81
+ { label: 'V1', value: 'v1' },
82
+ { label: 'V2', value: 'v2' },
83
+ { label: 'V3', value: 'v3' }
84
+ ],
85
+ defaultValue: 'v1'
86
+ },
87
+ {
88
+ name: 'icon',
89
+ type: 'text',
90
+ label: 'Icon Name (Lucide)',
91
+ defaultValue: 'Goal',
92
+ admin: {
93
+ description: 'Enter a Lucide icon name. (e.g., ArrowRight, ChevronRight)'
94
+ }
95
+ },
96
+ {
97
+ name: 'label',
98
+ type: 'text',
99
+ label: 'Button Label',
100
+ required: true
101
+ },
102
+ {
103
+ name: 'class',
104
+ type: 'text',
105
+ label: 'Extra CSS Class'
106
+ }
107
+ ],
108
+ defaultValue: [
109
+ { variant: 'v1', icon: 'Goal', label: 'Choose Lane' },
110
+ { variant: 'v1', icon: 'Feather', label: 'How it works' }
111
+ ]
112
+ }
113
+ ]
114
+ },
115
+ {
116
+ label: 'Services',
117
+ fields: [
118
+ {
119
+ name: 'services',
120
+ type: 'array',
121
+ label: 'Service Cards',
122
+ minRows: 1,
123
+ fields: [
124
+ {
125
+ name: 'iconName',
126
+ type: 'text',
127
+ label: 'Lucide Icon Name',
128
+ required: true,
129
+ defaultValue: 'Pen',
130
+ admin: {
131
+ description: 'Lucide icon name e.g. Pen, Code, Database, Lightbulb'
132
+ }
133
+ },
134
+ {
135
+ name: 'title',
136
+ type: 'text',
137
+ label: 'Service Title',
138
+ required: true
139
+ },
140
+ {
141
+ name: 'description',
142
+ type: 'textarea',
143
+ label: 'Service Description',
144
+ required: true
145
+ }
146
+ ]
147
+ }
148
+ ]
149
+ },
150
+ {
151
+ label: 'Image',
152
+ fields: [
153
+ {
154
+ name: 'image',
155
+ type: 'upload',
156
+ label: 'Studio Image',
157
+ relationTo: 'media'
158
+ },
159
+ {
160
+ name: 'imageFallbackUrl',
161
+ type: 'text',
162
+ label: 'Image Fallback URL',
163
+ admin: {
164
+ placeholder: '/assets/placeholder/01.png',
165
+ description: 'Used if no uploaded image is set'
166
+ }
167
+ },
168
+ {
169
+ name: 'imageAlt',
170
+ type: 'text',
171
+ label: 'Image Alt Text',
172
+ defaultValue: 'DesignsDusted Studio'
173
+ },
174
+ {
175
+ name: 'badgeTitle',
176
+ type: 'text',
177
+ label: 'Floating Badge Title',
178
+ defaultValue: 'Currently accepting projects'
179
+ },
180
+ {
181
+ name: 'badgeSubtitle',
182
+ type: 'text',
183
+ label: 'Floating Badge Subtitle',
184
+ defaultValue: 'Limited spots available for Q2 2026'
185
+ },
186
+ {
187
+ name: 'showBadge',
188
+ type: 'checkbox',
189
+ label: 'Show Floating Badge',
190
+ defaultValue: true
191
+ }
192
+ ]
193
+ },
194
+ {
195
+ label: 'Settings',
196
+ fields: [
197
+ {
198
+ name: 'sectionId',
199
+ type: 'text',
200
+ label: 'Section ID',
201
+ defaultValue: 'studio-section'
202
+ },
203
+ {
204
+ name: 'customCSS',
205
+ type: 'code',
206
+ label: 'Custom CSS',
207
+ admin: { language: 'css' }
208
+ }
209
+ ]
210
+ }
211
+ ]
212
+ }
213
+ ]
214
+ }
@@ -0,0 +1,85 @@
1
+ {
2
+ "type": "block",
3
+ "name": "DD-Section",
4
+ "label": "Studio Section Block",
5
+ "sourceName": "StudioSectionBlock",
6
+ "portableName": "DD-Section",
7
+ "slug": "DD-Section",
8
+ "version": "0.0.1",
9
+ "source": {
10
+ "repo": "Hadizainal/DesignsDustedv3",
11
+ "originalPath": "src/blocks/StudioSectionBlock",
12
+ "originalSlug": "studioSectionBlock",
13
+ "originalConfigExport": "StudioSectionBlock",
14
+ "originalComponentExport": "StudioSectionBlock",
15
+ "originalInterfaceName": "StudioSectionBlock"
16
+ },
17
+ "files": [
18
+ {
19
+ "from": "Component.tsx",
20
+ "to": "src/blocks/DD-Section/Component.tsx"
21
+ },
22
+ {
23
+ "from": "config.ts",
24
+ "to": "src/blocks/DD-Section/config.ts"
25
+ }
26
+ ],
27
+ "dependencies": [
28
+ {
29
+ "name": "framer-motion"
30
+ },
31
+ {
32
+ "name": "lucide-react"
33
+ }
34
+ ],
35
+ "sharedFiles": [],
36
+ "requiredProjectFiles": [],
37
+ "optionalProjectFiles": [],
38
+ "collectionRegistration": {
39
+ "enabled": true,
40
+ "collections": [
41
+ "Pages",
42
+ "Posts"
43
+ ]
44
+ },
45
+ "renderBlocksRegistration": {
46
+ "enabled": true
47
+ },
48
+ "renderBlocksBehavior": {
49
+ "wrapperless": false
50
+ },
51
+ "pageRouteIntegration": {
52
+ "required": false,
53
+ "manualSteps": []
54
+ },
55
+ "manual": [
56
+ "Replaced ButtonDustedFluid with portable fallback links; reconnect project ButtonDustedFluid manually if desired.",
57
+ "Register DDSection in Pages/Posts blocks arrays if automatic registration was skipped.",
58
+ "Register DD-Section in RenderBlocks if automatic registration was skipped.",
59
+ "Run payload generate:types after schema changes.",
60
+ "Run payload generate:importmap if admin/component imports changed."
61
+ ],
62
+ "manualSteps": [
63
+ "Replaced ButtonDustedFluid with portable fallback links; reconnect project ButtonDustedFluid manually if desired.",
64
+ "Register DDSection in Pages/Posts blocks arrays if automatic registration was skipped.",
65
+ "Register DD-Section in RenderBlocks if automatic registration was skipped.",
66
+ "Run payload generate:types after schema changes.",
67
+ "Run payload generate:importmap if admin/component imports changed."
68
+ ],
69
+ "patchTargets": {
70
+ "blockConfigRegistration": {
71
+ "description": "Installer can add import { DDSection } from '@/blocks/DD-Section/config' and add DDSection to clear Pages/Posts blocks arrays."
72
+ },
73
+ "renderBlocksRegistration": {
74
+ "description": "Installer can register DD-Section in src/blocks/**/RenderBlocks.tsx when the blockComponents map is clear."
75
+ }
76
+ },
77
+ "notes": [
78
+ "Converted from DesignsDustedv3 StudioSectionBlock.",
79
+ "Generated Payload type imports are replaced with portable fallback types when needed.",
80
+ "Installer must not overwrite existing target files.",
81
+ "Project-specific ButtonDustedFluid is intentionally not bundled."
82
+ ],
83
+ "exportName": "DDSection",
84
+ "interfaceName": "DDSection"
85
+ }