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.
- package/LICENSE +21 -0
- package/README.md +68 -0
- package/bin/index.js +8 -0
- package/package.json +40 -0
- package/src/cli.js +79 -0
- package/src/commands/add.js +327 -0
- package/src/commands/doctor.js +21 -0
- package/src/commands/list.js +18 -0
- package/src/installers/checkRequirements.js +101 -0
- package/src/installers/copyTemplateFiles.js +79 -0
- package/src/installers/installDependencies.js +69 -0
- package/src/installers/patchPayloadBlocksArray.js +122 -0
- package/src/installers/patchRenderBlocks.js +110 -0
- package/src/installers/runGenerators.js +3 -0
- package/src/installers/writeInstalledBlockReadme.js +117 -0
- package/src/registry/listTemplates.js +17 -0
- package/src/registry/loadTemplateManifest.js +20 -0
- package/src/registry/validateTemplateManifest.js +69 -0
- package/src/utils/logger.js +8 -0
- package/src/utils/packageManager.js +42 -0
- package/src/utils/paths.js +7 -0
- package/src/utils/project.js +122 -0
- package/src/utils/strings.js +7 -0
- package/templates/blocks/DD-BookCall/Component.tsx +573 -0
- package/templates/blocks/DD-BookCall/config.ts +239 -0
- package/templates/blocks/DD-BookCall/manifest.json +112 -0
- package/templates/blocks/DD-CardTemplate01/Component.tsx +144 -0
- package/templates/blocks/DD-CardTemplate01/config.ts +106 -0
- package/templates/blocks/DD-CardTemplate01/manifest.json +84 -0
- package/templates/blocks/DD-Carousel-A/Component.tsx +266 -0
- package/templates/blocks/DD-Carousel-A/config.ts +163 -0
- package/templates/blocks/DD-Carousel-A/manifest.json +86 -0
- package/templates/blocks/DD-Carousel-B/Component.tsx +432 -0
- package/templates/blocks/DD-Carousel-B/config.ts +176 -0
- package/templates/blocks/DD-Carousel-B/manifest.json +86 -0
- package/templates/blocks/DD-ComparisonTable/Component.tsx +272 -0
- package/templates/blocks/DD-ComparisonTable/config.ts +105 -0
- package/templates/blocks/DD-ComparisonTable/manifest.json +78 -0
- package/templates/blocks/DD-Contact/Component.tsx +439 -0
- package/templates/blocks/DD-Contact/config.ts +217 -0
- package/templates/blocks/DD-Contact/manifest.json +107 -0
- package/templates/blocks/DD-FeatCat/Component.tsx +361 -0
- package/templates/blocks/DD-FeatCat/config.ts +204 -0
- package/templates/blocks/DD-FeatCat/manifest.json +87 -0
- package/templates/blocks/DD-FeatStrip/Component.tsx +615 -0
- package/templates/blocks/DD-FeatStrip/config.ts +134 -0
- package/templates/blocks/DD-FeatStrip/manifest.json +82 -0
- package/templates/blocks/DD-Hero/Component.tsx +317 -0
- package/templates/blocks/DD-Hero/config.ts +267 -0
- package/templates/blocks/DD-Hero/manifest.json +92 -0
- package/templates/blocks/DD-HorizontalScroll/Component.tsx +995 -0
- package/templates/blocks/DD-HorizontalScroll/config.ts +231 -0
- package/templates/blocks/DD-HorizontalScroll/manifest.json +85 -0
- package/templates/blocks/DD-MasonaryMedia/Component.tsx +571 -0
- package/templates/blocks/DD-MasonaryMedia/config.ts +390 -0
- package/templates/blocks/DD-MasonaryMedia/manifest.json +101 -0
- package/templates/blocks/DD-MasonaryMedia/vendor.d.ts +2 -0
- package/templates/blocks/DD-Pricing/Component.tsx +380 -0
- package/templates/blocks/DD-Pricing/config.ts +215 -0
- package/templates/blocks/DD-Pricing/manifest.json +78 -0
- package/templates/blocks/DD-Process/Component.tsx +155 -0
- package/templates/blocks/DD-Process/config.ts +150 -0
- package/templates/blocks/DD-Process/manifest.json +82 -0
- package/templates/blocks/DD-Section/Component.tsx +327 -0
- package/templates/blocks/DD-Section/config.ts +214 -0
- package/templates/blocks/DD-Section/manifest.json +85 -0
- package/templates/blocks/DD-Services/Component.tsx +188 -0
- package/templates/blocks/DD-Services/config.ts +149 -0
- package/templates/blocks/DD-Services/manifest.json +95 -0
- package/templates/blocks/DD-ShowcaseGrid/Component.tsx +317 -0
- package/templates/blocks/DD-ShowcaseGrid/config.ts +197 -0
- package/templates/blocks/DD-ShowcaseGrid/manifest.json +80 -0
- package/templates/blocks/DD-Slider-A/Component.tsx +252 -0
- package/templates/blocks/DD-Slider-A/config.ts +118 -0
- package/templates/blocks/DD-Slider-A/manifest.json +86 -0
- package/templates/blocks/DD-StackCards/Component.tsx +496 -0
- package/templates/blocks/DD-StackCards/config.ts +399 -0
- package/templates/blocks/DD-StackCards/manifest.json +87 -0
- package/templates/blocks/DD-Team/Component.tsx +265 -0
- package/templates/blocks/DD-Team/config.ts +173 -0
- package/templates/blocks/DD-Team/manifest.json +82 -0
- package/templates/blocks/DD-TechStack/Component.tsx +189 -0
- package/templates/blocks/DD-TechStack/config.ts +153 -0
- package/templates/blocks/DD-TechStack/manifest.json +118 -0
- package/templates/blocks/DD-Testimonials/Component.tsx +147 -0
- package/templates/blocks/DD-Testimonials/config.ts +120 -0
- package/templates/blocks/DD-Testimonials/manifest.json +87 -0
- package/templates/blocks/DD-Work/Component.tsx +328 -0
- package/templates/blocks/DD-Work/config.ts +165 -0
- package/templates/blocks/DD-Work/manifest.json +87 -0
- package/templates/blocks/DD-Work-B/Component.tsx +320 -0
- package/templates/blocks/DD-Work-B/config.ts +165 -0
- package/templates/blocks/DD-Work-B/manifest.json +75 -0
- package/templates/shared/components/ui/anims/fade.tsx +83 -0
- package/templates/shared/components/ui/button.tsx +233 -0
- package/templates/shared/components/ui/input.tsx +41 -0
- package/templates/shared/fields/lucide-icon-picker/Cell.tsx +24 -0
- package/templates/shared/fields/lucide-icon-picker/README.md +160 -0
- package/templates/shared/fields/lucide-icon-picker/field.ts +40 -0
- package/templates/shared/fields/lucide-icon-picker/index.tsx +203 -0
- package/templates/shared/utilities/canUseDOM.ts +1 -0
- 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
|
+
}
|