blocks-dusted 0.1.1 → 0.1.2
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/README.md +967 -3
- package/package.json +2 -2
- package/src/commands/add.js +143 -45
- package/src/commands/list.js +2 -2
- package/src/installers/checkRequirements.js +1 -0
- package/src/installers/copyTemplateFiles.js +23 -2
- package/src/installers/patchPayloadConfigCollections.js +92 -0
- package/src/installers/writeInstalledBlockReadme.js +17 -4
- package/src/registry/listTemplates.js +16 -7
- package/src/registry/loadTemplateManifest.js +20 -11
- package/src/registry/validateTemplateManifest.js +6 -5
- package/src/utils/paths.js +7 -0
- package/templates/blocks/DD-BookCall/Component.tsx +535 -573
- package/templates/blocks/DD-CardTemplate01/Component.tsx +45 -49
- package/templates/blocks/DD-Carousel-A/Component.tsx +249 -266
- package/templates/blocks/DD-Carousel-B/Component.tsx +403 -432
- package/templates/blocks/DD-ComparisonTable/Component.tsx +256 -272
- package/templates/blocks/DD-Contact/Component.tsx +434 -439
- package/templates/blocks/DD-Contact/config.ts +8 -3
- package/templates/blocks/DD-FeatCat/Component.tsx +302 -361
- package/templates/blocks/DD-FeatCat/config.ts +201 -204
- package/templates/blocks/DD-FeatStrip/Component.tsx +171 -201
- package/templates/blocks/DD-Hero/Component.tsx +297 -317
- package/templates/blocks/DD-HorizontalScroll/Component.tsx +244 -303
- package/templates/blocks/DD-MasonaryMedia/Component.tsx +202 -228
- package/templates/blocks/DD-MasonaryMedia/config.ts +13 -14
- package/templates/blocks/DD-Pricing/Component.tsx +372 -380
- package/templates/blocks/DD-Process/Component.tsx +149 -155
- package/templates/blocks/DD-Section/Component.tsx +266 -327
- package/templates/blocks/DD-Services/Component.tsx +176 -188
- package/templates/blocks/DD-ShowcaseGrid/Component.tsx +307 -317
- package/templates/blocks/DD-Slider-A/Component.tsx +237 -252
- package/templates/blocks/DD-StackCards/Component.tsx +137 -160
- package/templates/blocks/DD-Team/Component.tsx +247 -265
- package/templates/blocks/DD-TechStack/Component.tsx +57 -72
- package/templates/blocks/DD-Testimonials/Component.tsx +147 -147
- package/templates/blocks/DD-Testimonials/config.ts +66 -66
- package/templates/blocks/DD-Work/Component.tsx +315 -328
- package/templates/blocks/DD-Work-B/Component.tsx +294 -320
- package/templates/collections/Testimonials/README.md +11 -0
- package/templates/collections/Testimonials/Testimonials.ts +161 -0
- package/templates/collections/Testimonials/manifest.json +55 -0
- package/templates/components/RichText/README.md +13 -0
- package/templates/components/RichText/converter/componentConverter/blocks.tsx +43 -0
- package/templates/components/RichText/converter/componentConverter/types.ts +11 -0
- package/templates/components/RichText/converter/index.tsx +18 -0
- package/templates/components/RichText/converter/internalLinks.tsx +45 -0
- package/templates/components/RichText/converter/textConverter.tsx +27 -0
- package/templates/components/RichText/index.tsx +35 -0
- package/templates/components/RichText/manifest.json +80 -0
|
@@ -1,63 +1,60 @@
|
|
|
1
1
|
/* eslint-disable react-hooks/rules-of-hooks */
|
|
2
|
-
|
|
2
|
+
'use client'
|
|
3
3
|
|
|
4
|
-
import { useState, useEffect } from
|
|
5
|
-
import Link from
|
|
6
|
-
import Image from
|
|
7
|
-
import dynamic from
|
|
8
|
-
import { ArrowRight } from
|
|
4
|
+
import { useState, useEffect } from 'react'
|
|
5
|
+
import Link from 'next/link'
|
|
6
|
+
import Image from 'next/image'
|
|
7
|
+
import dynamic from 'next/dynamic'
|
|
8
|
+
import { ArrowRight } from 'lucide-react'
|
|
9
9
|
|
|
10
10
|
const DotLottieReact = dynamic(
|
|
11
|
-
() => import(
|
|
11
|
+
() => import('@lottiefiles/dotlottie-react').then((m) => m.DotLottieReact),
|
|
12
12
|
{ ssr: false },
|
|
13
|
-
)
|
|
13
|
+
)
|
|
14
14
|
|
|
15
15
|
/* ── Label color maps ─────────────────────────────────────────── */
|
|
16
16
|
|
|
17
17
|
const labelColorMap: Record<string, string> = {
|
|
18
|
-
indigo:
|
|
19
|
-
emerald:
|
|
20
|
-
amber:
|
|
21
|
-
rose:
|
|
22
|
-
violet:
|
|
23
|
-
sky:
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const exploreColorMap: Record<
|
|
27
|
-
string,
|
|
28
|
-
{ base: string; hover: string; glow: string }
|
|
29
|
-
> = {
|
|
18
|
+
indigo: 'text-indigo-400',
|
|
19
|
+
emerald: 'text-emerald-400',
|
|
20
|
+
amber: 'text-amber-400',
|
|
21
|
+
rose: 'text-rose-400',
|
|
22
|
+
violet: 'text-violet-400',
|
|
23
|
+
sky: 'text-sky-400',
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const exploreColorMap: Record<string, { base: string; hover: string; glow: string }> = {
|
|
30
27
|
indigo: {
|
|
31
|
-
base:
|
|
32
|
-
hover:
|
|
33
|
-
glow:
|
|
28
|
+
base: 'text-indigo-300',
|
|
29
|
+
hover: 'group-hover:text-indigo-400',
|
|
30
|
+
glow: 'rgba(99,102,241,0.08)',
|
|
34
31
|
},
|
|
35
32
|
emerald: {
|
|
36
|
-
base:
|
|
37
|
-
hover:
|
|
38
|
-
glow:
|
|
33
|
+
base: 'text-emerald-300',
|
|
34
|
+
hover: 'group-hover:text-emerald-400',
|
|
35
|
+
glow: 'rgba(16,185,129,0.08)',
|
|
39
36
|
},
|
|
40
37
|
amber: {
|
|
41
|
-
base:
|
|
42
|
-
hover:
|
|
43
|
-
glow:
|
|
38
|
+
base: 'text-amber-300',
|
|
39
|
+
hover: 'group-hover:text-amber-400',
|
|
40
|
+
glow: 'rgba(245,158,11,0.08)',
|
|
44
41
|
},
|
|
45
42
|
rose: {
|
|
46
|
-
base:
|
|
47
|
-
hover:
|
|
48
|
-
glow:
|
|
43
|
+
base: 'text-rose-300',
|
|
44
|
+
hover: 'group-hover:text-rose-400',
|
|
45
|
+
glow: 'rgba(244,63,94,0.08)',
|
|
49
46
|
},
|
|
50
47
|
violet: {
|
|
51
|
-
base:
|
|
52
|
-
hover:
|
|
53
|
-
glow:
|
|
48
|
+
base: 'text-violet-300',
|
|
49
|
+
hover: 'group-hover:text-violet-400',
|
|
50
|
+
glow: 'rgba(167,139,250,0.08)',
|
|
54
51
|
},
|
|
55
52
|
sky: {
|
|
56
|
-
base:
|
|
57
|
-
hover:
|
|
58
|
-
glow:
|
|
53
|
+
base: 'text-sky-300',
|
|
54
|
+
hover: 'group-hover:text-sky-400',
|
|
55
|
+
glow: 'rgba(56,189,248,0.08)',
|
|
59
56
|
},
|
|
60
|
-
}
|
|
57
|
+
}
|
|
61
58
|
|
|
62
59
|
/* ── Isometric SVG Icons ─────────────────────────────────────── */
|
|
63
60
|
|
|
@@ -69,32 +66,32 @@ function UIBlocksIcon({ hovered }: { hovered: boolean }) {
|
|
|
69
66
|
xmlns="http://www.w3.org/2000/svg"
|
|
70
67
|
className="w-full h-full"
|
|
71
68
|
style={{
|
|
72
|
-
transition:
|
|
73
|
-
filter: hovered ?
|
|
69
|
+
transition: 'filter 0.4s ease',
|
|
70
|
+
filter: hovered ? 'drop-shadow(0 0 12px rgba(99,102,241,0.7))' : 'none',
|
|
74
71
|
}}
|
|
75
72
|
>
|
|
76
73
|
<g
|
|
77
74
|
style={{
|
|
78
|
-
transform: hovered ?
|
|
79
|
-
transition:
|
|
75
|
+
transform: hovered ? 'translateY(-4px)' : 'translateY(0)',
|
|
76
|
+
transition: 'transform 0.4s cubic-bezier(0.34,1.56,0.64,1)',
|
|
80
77
|
}}
|
|
81
78
|
>
|
|
82
79
|
<polygon
|
|
83
80
|
points="60,4 108,28 60,52 12,28"
|
|
84
|
-
fill={hovered ?
|
|
85
|
-
stroke={hovered ?
|
|
81
|
+
fill={hovered ? '#312e81' : '#1e1b4b'}
|
|
82
|
+
stroke={hovered ? '#818cf8' : '#4f46e5'}
|
|
86
83
|
strokeWidth="1.2"
|
|
87
84
|
/>
|
|
88
85
|
<polygon
|
|
89
86
|
points="12,28 12,58 60,82 60,52"
|
|
90
|
-
fill={hovered ?
|
|
91
|
-
stroke={hovered ?
|
|
87
|
+
fill={hovered ? '#1e1b4b' : '#161430'}
|
|
88
|
+
stroke={hovered ? '#6366f1' : '#3730a3'}
|
|
92
89
|
strokeWidth="1.2"
|
|
93
90
|
/>
|
|
94
91
|
<polygon
|
|
95
92
|
points="108,28 108,58 60,82 60,52"
|
|
96
|
-
fill={hovered ?
|
|
97
|
-
stroke={hovered ?
|
|
93
|
+
fill={hovered ? '#2e2a6e' : '#1a1740'}
|
|
94
|
+
stroke={hovered ? '#818cf8' : '#4338ca'}
|
|
98
95
|
strokeWidth="1.2"
|
|
99
96
|
/>
|
|
100
97
|
<line
|
|
@@ -102,7 +99,7 @@ function UIBlocksIcon({ hovered }: { hovered: boolean }) {
|
|
|
102
99
|
y1="4"
|
|
103
100
|
x2="60"
|
|
104
101
|
y2="52"
|
|
105
|
-
stroke={hovered ?
|
|
102
|
+
stroke={hovered ? '#818cf8' : '#4f46e5'}
|
|
106
103
|
strokeWidth="0.6"
|
|
107
104
|
strokeDasharray="3 3"
|
|
108
105
|
/>
|
|
@@ -111,7 +108,7 @@ function UIBlocksIcon({ hovered }: { hovered: boolean }) {
|
|
|
111
108
|
y1="16"
|
|
112
109
|
x2="84"
|
|
113
110
|
y2="40"
|
|
114
|
-
stroke={hovered ?
|
|
111
|
+
stroke={hovered ? '#818cf8' : '#4f46e5'}
|
|
115
112
|
strokeWidth="0.6"
|
|
116
113
|
strokeDasharray="3 3"
|
|
117
114
|
/>
|
|
@@ -120,31 +117,31 @@ function UIBlocksIcon({ hovered }: { hovered: boolean }) {
|
|
|
120
117
|
y1="16"
|
|
121
118
|
x2="36"
|
|
122
119
|
y2="40"
|
|
123
|
-
stroke={hovered ?
|
|
120
|
+
stroke={hovered ? '#818cf8' : '#4f46e5'}
|
|
124
121
|
strokeWidth="0.6"
|
|
125
122
|
strokeDasharray="3 3"
|
|
126
123
|
/>
|
|
127
124
|
<polygon
|
|
128
125
|
points="60,14 78,23 60,32 42,23"
|
|
129
|
-
fill={hovered ?
|
|
130
|
-
stroke={hovered ?
|
|
126
|
+
fill={hovered ? '#4f46e5' : '#312e81'}
|
|
127
|
+
stroke={hovered ? '#a5b4fc' : '#6366f1'}
|
|
131
128
|
strokeWidth="1"
|
|
132
129
|
/>
|
|
133
130
|
<polygon
|
|
134
131
|
points="42,23 42,33 60,42 60,32"
|
|
135
|
-
fill={hovered ?
|
|
136
|
-
stroke={hovered ?
|
|
132
|
+
fill={hovered ? '#3730a3' : '#1e1b4b'}
|
|
133
|
+
stroke={hovered ? '#818cf8' : '#4338ca'}
|
|
137
134
|
strokeWidth="1"
|
|
138
135
|
/>
|
|
139
136
|
<polygon
|
|
140
137
|
points="78,23 78,33 60,42 60,32"
|
|
141
|
-
fill={hovered ?
|
|
142
|
-
stroke={hovered ?
|
|
138
|
+
fill={hovered ? '#4338ca' : '#272466'}
|
|
139
|
+
stroke={hovered ? '#a5b4fc' : '#6366f1'}
|
|
143
140
|
strokeWidth="1"
|
|
144
141
|
/>
|
|
145
142
|
</g>
|
|
146
143
|
</svg>
|
|
147
|
-
)
|
|
144
|
+
)
|
|
148
145
|
}
|
|
149
146
|
|
|
150
147
|
function TemplatesIcon({ hovered }: { hovered: boolean }) {
|
|
@@ -155,32 +152,32 @@ function TemplatesIcon({ hovered }: { hovered: boolean }) {
|
|
|
155
152
|
xmlns="http://www.w3.org/2000/svg"
|
|
156
153
|
className="w-full h-full"
|
|
157
154
|
style={{
|
|
158
|
-
transition:
|
|
159
|
-
filter: hovered ?
|
|
155
|
+
transition: 'filter 0.4s ease',
|
|
156
|
+
filter: hovered ? 'drop-shadow(0 0 12px rgba(16,185,129,0.6))' : 'none',
|
|
160
157
|
}}
|
|
161
158
|
>
|
|
162
159
|
<g
|
|
163
160
|
style={{
|
|
164
|
-
transform: hovered ?
|
|
165
|
-
transition:
|
|
161
|
+
transform: hovered ? 'translateY(-4px)' : 'translateY(0)',
|
|
162
|
+
transition: 'transform 0.4s cubic-bezier(0.34,1.56,0.64,1)',
|
|
166
163
|
}}
|
|
167
164
|
>
|
|
168
165
|
<polygon
|
|
169
166
|
points="60,6 104,30 60,54 16,30"
|
|
170
|
-
fill={hovered ?
|
|
171
|
-
stroke={hovered ?
|
|
167
|
+
fill={hovered ? '#064e3b' : '#022c22'}
|
|
168
|
+
stroke={hovered ? '#34d399' : '#059669'}
|
|
172
169
|
strokeWidth="1.2"
|
|
173
170
|
/>
|
|
174
171
|
<polygon
|
|
175
172
|
points="16,30 16,60 60,84 60,54"
|
|
176
|
-
fill={hovered ?
|
|
177
|
-
stroke={hovered ?
|
|
173
|
+
fill={hovered ? '#022c22' : '#011a15'}
|
|
174
|
+
stroke={hovered ? '#10b981' : '#047857'}
|
|
178
175
|
strokeWidth="1.2"
|
|
179
176
|
/>
|
|
180
177
|
<polygon
|
|
181
178
|
points="104,30 104,60 60,84 60,54"
|
|
182
|
-
fill={hovered ?
|
|
183
|
-
stroke={hovered ?
|
|
179
|
+
fill={hovered ? '#043927' : '#011a15'}
|
|
180
|
+
stroke={hovered ? '#34d399' : '#059669'}
|
|
184
181
|
strokeWidth="1.2"
|
|
185
182
|
/>
|
|
186
183
|
<line
|
|
@@ -188,7 +185,7 @@ function TemplatesIcon({ hovered }: { hovered: boolean }) {
|
|
|
188
185
|
y1="30"
|
|
189
186
|
x2="60"
|
|
190
187
|
y2="16"
|
|
191
|
-
stroke={hovered ?
|
|
188
|
+
stroke={hovered ? '#6ee7b7' : '#34d399'}
|
|
192
189
|
strokeWidth="1"
|
|
193
190
|
opacity="0.7"
|
|
194
191
|
/>
|
|
@@ -197,7 +194,7 @@ function TemplatesIcon({ hovered }: { hovered: boolean }) {
|
|
|
197
194
|
y1="36"
|
|
198
195
|
x2="60"
|
|
199
196
|
y2="22"
|
|
200
|
-
stroke={hovered ?
|
|
197
|
+
stroke={hovered ? '#6ee7b7' : '#34d399'}
|
|
201
198
|
strokeWidth="0.8"
|
|
202
199
|
opacity="0.5"
|
|
203
200
|
/>
|
|
@@ -206,7 +203,7 @@ function TemplatesIcon({ hovered }: { hovered: boolean }) {
|
|
|
206
203
|
y1="42"
|
|
207
204
|
x2="52"
|
|
208
205
|
y2="30"
|
|
209
|
-
stroke={hovered ?
|
|
206
|
+
stroke={hovered ? '#6ee7b7' : '#34d399'}
|
|
210
207
|
strokeWidth="0.8"
|
|
211
208
|
opacity="0.4"
|
|
212
209
|
/>
|
|
@@ -215,7 +212,7 @@ function TemplatesIcon({ hovered }: { hovered: boolean }) {
|
|
|
215
212
|
y1="22"
|
|
216
213
|
x2="96"
|
|
217
214
|
y2="34"
|
|
218
|
-
stroke={hovered ?
|
|
215
|
+
stroke={hovered ? '#6ee7b7' : '#34d399'}
|
|
219
216
|
strokeWidth="1"
|
|
220
217
|
opacity="0.7"
|
|
221
218
|
/>
|
|
@@ -224,7 +221,7 @@ function TemplatesIcon({ hovered }: { hovered: boolean }) {
|
|
|
224
221
|
y1="28"
|
|
225
222
|
x2="90"
|
|
226
223
|
y2="37"
|
|
227
|
-
stroke={hovered ?
|
|
224
|
+
stroke={hovered ? '#6ee7b7' : '#34d399'}
|
|
228
225
|
strokeWidth="0.8"
|
|
229
226
|
opacity="0.5"
|
|
230
227
|
/>
|
|
@@ -233,7 +230,7 @@ function TemplatesIcon({ hovered }: { hovered: boolean }) {
|
|
|
233
230
|
y1="34"
|
|
234
231
|
x2="84"
|
|
235
232
|
y2="40"
|
|
236
|
-
stroke={hovered ?
|
|
233
|
+
stroke={hovered ? '#6ee7b7' : '#34d399'}
|
|
237
234
|
strokeWidth="0.8"
|
|
238
235
|
opacity="0.4"
|
|
239
236
|
/>
|
|
@@ -242,13 +239,13 @@ function TemplatesIcon({ hovered }: { hovered: boolean }) {
|
|
|
242
239
|
y1="12"
|
|
243
240
|
x2="66"
|
|
244
241
|
y2="50"
|
|
245
|
-
stroke={hovered ?
|
|
242
|
+
stroke={hovered ? '#34d399' : '#059669'}
|
|
246
243
|
strokeWidth="0.8"
|
|
247
244
|
strokeDasharray="2 2"
|
|
248
245
|
/>
|
|
249
246
|
</g>
|
|
250
247
|
</svg>
|
|
251
|
-
)
|
|
248
|
+
)
|
|
252
249
|
}
|
|
253
250
|
|
|
254
251
|
function UIKitIcon({ hovered }: { hovered: boolean }) {
|
|
@@ -259,133 +256,109 @@ function UIKitIcon({ hovered }: { hovered: boolean }) {
|
|
|
259
256
|
xmlns="http://www.w3.org/2000/svg"
|
|
260
257
|
className="w-full h-full"
|
|
261
258
|
style={{
|
|
262
|
-
transition:
|
|
263
|
-
filter: hovered ?
|
|
259
|
+
transition: 'filter 0.4s ease',
|
|
260
|
+
filter: hovered ? 'drop-shadow(0 0 12px rgba(245,158,11,0.6))' : 'none',
|
|
264
261
|
}}
|
|
265
262
|
>
|
|
266
263
|
<g
|
|
267
264
|
style={{
|
|
268
|
-
transform: hovered ?
|
|
269
|
-
transition:
|
|
265
|
+
transform: hovered ? 'translateY(-4px)' : 'translateY(0)',
|
|
266
|
+
transition: 'transform 0.4s cubic-bezier(0.34,1.56,0.64,1)',
|
|
270
267
|
}}
|
|
271
268
|
>
|
|
272
269
|
<polygon
|
|
273
270
|
points="60,42 100,62 60,82 20,62"
|
|
274
|
-
fill={hovered ?
|
|
275
|
-
stroke={hovered ?
|
|
271
|
+
fill={hovered ? '#451a03' : '#27100a'}
|
|
272
|
+
stroke={hovered ? '#f59e0b' : '#b45309'}
|
|
276
273
|
strokeWidth="1.2"
|
|
277
274
|
/>
|
|
278
275
|
<polygon
|
|
279
276
|
points="20,52 20,62 60,82 60,72"
|
|
280
|
-
fill={hovered ?
|
|
281
|
-
stroke={hovered ?
|
|
277
|
+
fill={hovered ? '#27100a' : '#1a0a05'}
|
|
278
|
+
stroke={hovered ? '#d97706' : '#92400e'}
|
|
282
279
|
strokeWidth="1"
|
|
283
280
|
/>
|
|
284
281
|
<polygon
|
|
285
282
|
points="100,52 100,62 60,82 60,72"
|
|
286
|
-
fill={hovered ?
|
|
287
|
-
stroke={hovered ?
|
|
283
|
+
fill={hovered ? '#3b1a06' : '#1a0a05'}
|
|
284
|
+
stroke={hovered ? '#f59e0b' : '#b45309'}
|
|
288
285
|
strokeWidth="1"
|
|
289
286
|
/>
|
|
290
287
|
<polygon
|
|
291
288
|
points="60,26 100,46 60,66 20,46"
|
|
292
|
-
fill={hovered ?
|
|
293
|
-
stroke={hovered ?
|
|
289
|
+
fill={hovered ? '#78350f' : '#451a03'}
|
|
290
|
+
stroke={hovered ? '#fbbf24' : '#d97706'}
|
|
294
291
|
strokeWidth="1.2"
|
|
295
292
|
/>
|
|
296
293
|
<polygon
|
|
297
294
|
points="20,36 20,46 60,66 60,56"
|
|
298
|
-
fill={hovered ?
|
|
299
|
-
stroke={hovered ?
|
|
295
|
+
fill={hovered ? '#451a03' : '#27100a'}
|
|
296
|
+
stroke={hovered ? '#f59e0b' : '#b45309'}
|
|
300
297
|
strokeWidth="1"
|
|
301
298
|
/>
|
|
302
299
|
<polygon
|
|
303
300
|
points="100,36 100,46 60,66 60,56"
|
|
304
|
-
fill={hovered ?
|
|
305
|
-
stroke={hovered ?
|
|
301
|
+
fill={hovered ? '#5c2a07' : '#2d1108'}
|
|
302
|
+
stroke={hovered ? '#fbbf24' : '#d97706'}
|
|
306
303
|
strokeWidth="1"
|
|
307
304
|
/>
|
|
308
305
|
<polygon
|
|
309
306
|
points="60,10 100,30 60,50 20,30"
|
|
310
|
-
fill={hovered ?
|
|
311
|
-
stroke={hovered ?
|
|
307
|
+
fill={hovered ? '#92400e' : '#78350f'}
|
|
308
|
+
stroke={hovered ? '#fcd34d' : '#fbbf24'}
|
|
312
309
|
strokeWidth="1.2"
|
|
313
310
|
/>
|
|
314
311
|
<polygon
|
|
315
312
|
points="20,20 20,30 60,50 60,40"
|
|
316
|
-
fill={hovered ?
|
|
317
|
-
stroke={hovered ?
|
|
313
|
+
fill={hovered ? '#78350f' : '#451a03'}
|
|
314
|
+
stroke={hovered ? '#fbbf24' : '#d97706'}
|
|
318
315
|
strokeWidth="1"
|
|
319
316
|
/>
|
|
320
317
|
<polygon
|
|
321
318
|
points="100,20 100,30 60,50 60,40"
|
|
322
|
-
fill={hovered ?
|
|
323
|
-
stroke={hovered ?
|
|
319
|
+
fill={hovered ? '#7c3a0e' : '#4a2008'}
|
|
320
|
+
stroke={hovered ? '#fcd34d' : '#fbbf24'}
|
|
324
321
|
strokeWidth="1"
|
|
325
322
|
/>
|
|
326
|
-
<circle
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
r="2.5"
|
|
330
|
-
fill={hovered ? "#fcd34d" : "#fbbf24"}
|
|
331
|
-
opacity="0.9"
|
|
332
|
-
/>
|
|
333
|
-
<circle
|
|
334
|
-
cx="60"
|
|
335
|
-
cy="20"
|
|
336
|
-
r="2.5"
|
|
337
|
-
fill={hovered ? "#fcd34d" : "#fbbf24"}
|
|
338
|
-
opacity="0.9"
|
|
339
|
-
/>
|
|
340
|
-
<circle
|
|
341
|
-
cx="76"
|
|
342
|
-
cy="28"
|
|
343
|
-
r="2.5"
|
|
344
|
-
fill={hovered ? "#fcd34d" : "#fbbf24"}
|
|
345
|
-
opacity="0.9"
|
|
346
|
-
/>
|
|
323
|
+
<circle cx="44" cy="28" r="2.5" fill={hovered ? '#fcd34d' : '#fbbf24'} opacity="0.9" />
|
|
324
|
+
<circle cx="60" cy="20" r="2.5" fill={hovered ? '#fcd34d' : '#fbbf24'} opacity="0.9" />
|
|
325
|
+
<circle cx="76" cy="28" r="2.5" fill={hovered ? '#fcd34d' : '#fbbf24'} opacity="0.9" />
|
|
347
326
|
</g>
|
|
348
327
|
</svg>
|
|
349
|
-
)
|
|
328
|
+
)
|
|
350
329
|
}
|
|
351
330
|
|
|
352
331
|
const iconMap: Record<string, React.FC<{ hovered: boolean }>> = {
|
|
353
332
|
uiBlocks: UIBlocksIcon,
|
|
354
333
|
templates: TemplatesIcon,
|
|
355
334
|
uiKit: UIKitIcon,
|
|
356
|
-
}
|
|
335
|
+
}
|
|
357
336
|
|
|
358
337
|
/* ── Icon renderer ───────────────────────────────────────────── */
|
|
359
338
|
|
|
360
339
|
type MediaLike = {
|
|
361
|
-
url?: string | null
|
|
362
|
-
mimeType?: string | null
|
|
363
|
-
filename?: string | null
|
|
364
|
-
}
|
|
340
|
+
url?: string | null
|
|
341
|
+
mimeType?: string | null
|
|
342
|
+
filename?: string | null
|
|
343
|
+
}
|
|
365
344
|
|
|
366
345
|
function isLocalMediaSrc(src?: string | null): src is string {
|
|
367
|
-
return typeof src ===
|
|
346
|
+
return typeof src === 'string' && src.startsWith('/api/media/file/')
|
|
368
347
|
}
|
|
369
348
|
|
|
370
|
-
function CardIconMedia({
|
|
371
|
-
media
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
media
|
|
375
|
-
hovered: boolean;
|
|
376
|
-
}) {
|
|
377
|
-
const url = media.url ?? "";
|
|
378
|
-
const safeUrl = isLocalMediaSrc(url) ? url : "";
|
|
379
|
-
const mime = media.mimeType ?? "";
|
|
380
|
-
const filename = media.filename ?? "";
|
|
349
|
+
function CardIconMedia({ media, hovered }: { media: MediaLike; hovered: boolean }) {
|
|
350
|
+
const url = media.url ?? ''
|
|
351
|
+
const safeUrl = isLocalMediaSrc(url) ? url : ''
|
|
352
|
+
const mime = media.mimeType ?? ''
|
|
353
|
+
const filename = media.filename ?? ''
|
|
381
354
|
const isLottie =
|
|
382
|
-
mime ===
|
|
383
|
-
filename.endsWith(
|
|
384
|
-
(mime ===
|
|
385
|
-
const isDotLottie = filename.endsWith(
|
|
386
|
-
const isJson = mime ===
|
|
355
|
+
mime === 'application/json' ||
|
|
356
|
+
filename.endsWith('.lottie') ||
|
|
357
|
+
(mime === 'application/octet-stream' && filename.endsWith('.lottie'))
|
|
358
|
+
const isDotLottie = filename.endsWith('.lottie')
|
|
359
|
+
const isJson = mime === 'application/json' || filename.endsWith('.json')
|
|
387
360
|
|
|
388
|
-
if (!safeUrl) return null
|
|
361
|
+
if (!safeUrl) return null
|
|
389
362
|
|
|
390
363
|
if (isDotLottie || isJson) {
|
|
391
364
|
return (
|
|
@@ -394,13 +367,13 @@ function CardIconMedia({
|
|
|
394
367
|
loop
|
|
395
368
|
autoplay
|
|
396
369
|
style={{
|
|
397
|
-
width:
|
|
398
|
-
height:
|
|
399
|
-
transform: hovered ?
|
|
400
|
-
transition:
|
|
370
|
+
width: '100%',
|
|
371
|
+
height: '100%',
|
|
372
|
+
transform: hovered ? 'scale(1.08)' : 'scale(1)',
|
|
373
|
+
transition: 'transform 0.4s cubic-bezier(0.34,1.56,0.64,1)',
|
|
401
374
|
}}
|
|
402
375
|
/>
|
|
403
|
-
)
|
|
376
|
+
)
|
|
404
377
|
}
|
|
405
378
|
|
|
406
379
|
// SVG or raster image
|
|
@@ -411,16 +384,16 @@ function CardIconMedia({
|
|
|
411
384
|
fill
|
|
412
385
|
className="object-contain"
|
|
413
386
|
style={{
|
|
414
|
-
transform: hovered ?
|
|
415
|
-
transition:
|
|
387
|
+
transform: hovered ? 'scale(1.08)' : 'scale(1)',
|
|
388
|
+
transition: 'transform 0.4s cubic-bezier(0.34,1.56,0.64,1)',
|
|
416
389
|
}}
|
|
417
390
|
/>
|
|
418
|
-
)
|
|
391
|
+
)
|
|
419
392
|
}
|
|
420
393
|
|
|
421
394
|
/* ── Card ────────────────────────────────────────────────────── */
|
|
422
395
|
|
|
423
|
-
type CardData = { [key: string]: any }
|
|
396
|
+
type CardData = { [key: string]: any }
|
|
424
397
|
|
|
425
398
|
function FeatureCard({
|
|
426
399
|
card,
|
|
@@ -429,47 +402,43 @@ function FeatureCard({
|
|
|
429
402
|
totalCards,
|
|
430
403
|
isMobile,
|
|
431
404
|
}: {
|
|
432
|
-
card: CardData
|
|
433
|
-
index: number
|
|
434
|
-
isLast: boolean
|
|
435
|
-
totalCards: number
|
|
436
|
-
isMobile: boolean
|
|
405
|
+
card: CardData
|
|
406
|
+
index: number
|
|
407
|
+
isLast: boolean
|
|
408
|
+
totalCards: number
|
|
409
|
+
isMobile: boolean
|
|
437
410
|
}) {
|
|
438
|
-
const [hovered, setHovered] = useState(false)
|
|
439
|
-
const colorKey = card.labelColor ||
|
|
440
|
-
const colors = exploreColorMap[colorKey] || exploreColorMap.indigo
|
|
441
|
-
const labelClass = labelColorMap[colorKey] || labelColorMap.indigo
|
|
442
|
-
const FallbackIcon = iconMap[card.iconType ||
|
|
411
|
+
const [hovered, setHovered] = useState(false)
|
|
412
|
+
const colorKey = card.labelColor || 'indigo'
|
|
413
|
+
const colors = exploreColorMap[colorKey] || exploreColorMap.indigo
|
|
414
|
+
const labelClass = labelColorMap[colorKey] || labelColorMap.indigo
|
|
415
|
+
const FallbackIcon = iconMap[card.iconType || 'uiBlocks'] || UIBlocksIcon
|
|
443
416
|
const iconMedia =
|
|
444
|
-
card.iconMedia &&
|
|
445
|
-
typeof card.iconMedia === "object" &&
|
|
446
|
-
(card.iconMedia as MediaLike).url
|
|
417
|
+
card.iconMedia && typeof card.iconMedia === 'object' && (card.iconMedia as MediaLike).url
|
|
447
418
|
? (card.iconMedia as MediaLike)
|
|
448
|
-
: null
|
|
419
|
+
: null
|
|
449
420
|
|
|
450
421
|
// On mobile, last card is full-width if total is odd
|
|
451
|
-
const isFullWidthOnMobile = isMobile && totalCards % 2 !== 0 && isLast
|
|
422
|
+
const isFullWidthOnMobile = isMobile && totalCards % 2 !== 0 && isLast
|
|
452
423
|
|
|
453
|
-
let borderStyle: React.CSSProperties = {}
|
|
424
|
+
let borderStyle: React.CSSProperties = {}
|
|
454
425
|
if (isMobile) {
|
|
455
|
-
const isEvenPosition = index % 2 === 0
|
|
456
|
-
const isSecondRowOrLater = index >= 2
|
|
426
|
+
const isEvenPosition = index % 2 === 0
|
|
427
|
+
const isSecondRowOrLater = index >= 2
|
|
457
428
|
borderStyle = {
|
|
458
429
|
borderRight:
|
|
459
430
|
isEvenPosition && index + 1 < totalCards && !isFullWidthOnMobile
|
|
460
|
-
?
|
|
461
|
-
:
|
|
462
|
-
borderTop: isSecondRowOrLater
|
|
463
|
-
|
|
464
|
-
: "none",
|
|
465
|
-
};
|
|
431
|
+
? '1px solid rgba(255,255,255,0.07)'
|
|
432
|
+
: 'none',
|
|
433
|
+
borderTop: isSecondRowOrLater ? '1px solid rgba(255,255,255,0.07)' : 'none',
|
|
434
|
+
}
|
|
466
435
|
} else {
|
|
467
436
|
borderStyle = {
|
|
468
|
-
borderRight: !isLast ?
|
|
469
|
-
}
|
|
437
|
+
borderRight: !isLast ? '1px solid rgba(255,255,255,0.07)' : 'none',
|
|
438
|
+
}
|
|
470
439
|
}
|
|
471
440
|
|
|
472
|
-
const cardClass = `group relative flex flex-col sm:flex-row items-start gap-4 sm:gap-6 px-5 py-7 sm:px-8 sm:py-10${card.href ?
|
|
441
|
+
const cardClass = `group relative flex flex-col sm:flex-row items-start gap-4 sm:gap-6 px-5 py-7 sm:px-8 sm:py-10${card.href ? ' cursor-pointer' : ''}${isFullWidthOnMobile ? 'col-span-1' : ''}`
|
|
473
442
|
|
|
474
443
|
const innerContent = (
|
|
475
444
|
<>
|
|
@@ -487,8 +456,8 @@ function FeatureCard({
|
|
|
487
456
|
style={
|
|
488
457
|
!iconMedia
|
|
489
458
|
? {
|
|
490
|
-
transform: hovered ?
|
|
491
|
-
transition:
|
|
459
|
+
transform: hovered ? 'scale(1.08)' : 'scale(1)',
|
|
460
|
+
transition: 'transform 0.4s cubic-bezier(0.34,1.56,0.64,1)',
|
|
492
461
|
}
|
|
493
462
|
: undefined
|
|
494
463
|
}
|
|
@@ -504,7 +473,7 @@ function FeatureCard({
|
|
|
504
473
|
<div className="relative flex flex-col gap-2 pt-1">
|
|
505
474
|
<span
|
|
506
475
|
className={`text-sm font-bold tracking-[0.15em] uppercase ${labelClass} transition-all duration-300`}
|
|
507
|
-
style={{ letterSpacing: hovered ?
|
|
476
|
+
style={{ letterSpacing: hovered ? '0.2em' : '0.15em' }}
|
|
508
477
|
>
|
|
509
478
|
{card.label}
|
|
510
479
|
</span>
|
|
@@ -519,15 +488,15 @@ function FeatureCard({
|
|
|
519
488
|
<ArrowRight
|
|
520
489
|
size={14}
|
|
521
490
|
style={{
|
|
522
|
-
transform: hovered ?
|
|
523
|
-
transition:
|
|
491
|
+
transform: hovered ? 'translateX(4px)' : 'translateX(0)',
|
|
492
|
+
transition: 'transform 0.3s ease',
|
|
524
493
|
}}
|
|
525
494
|
/>
|
|
526
495
|
</span>
|
|
527
496
|
)}
|
|
528
497
|
</div>
|
|
529
498
|
</>
|
|
530
|
-
)
|
|
499
|
+
)
|
|
531
500
|
|
|
532
501
|
if (card.href) {
|
|
533
502
|
return (
|
|
@@ -540,7 +509,7 @@ function FeatureCard({
|
|
|
540
509
|
>
|
|
541
510
|
{innerContent}
|
|
542
511
|
</Link>
|
|
543
|
-
)
|
|
512
|
+
)
|
|
544
513
|
}
|
|
545
514
|
|
|
546
515
|
return (
|
|
@@ -552,12 +521,12 @@ function FeatureCard({
|
|
|
552
521
|
>
|
|
553
522
|
{innerContent}
|
|
554
523
|
</div>
|
|
555
|
-
)
|
|
524
|
+
)
|
|
556
525
|
}
|
|
557
526
|
|
|
558
527
|
/* ── Block ───────────────────────────────────────────────────── */
|
|
559
528
|
|
|
560
|
-
export type DDFeatStripProps = Record<string, any
|
|
529
|
+
export type DDFeatStripProps = Record<string, any>
|
|
561
530
|
|
|
562
531
|
export const DDFeatStrip: React.FC<DDFeatStripProps> = ({
|
|
563
532
|
cards,
|
|
@@ -565,27 +534,28 @@ export const DDFeatStrip: React.FC<DDFeatStripProps> = ({
|
|
|
565
534
|
sectionId,
|
|
566
535
|
customCSS,
|
|
567
536
|
}) => {
|
|
568
|
-
if (!cards || cards.length === 0) return null
|
|
537
|
+
if (!cards || cards.length === 0) return null
|
|
569
538
|
|
|
570
|
-
const cardItems = cards as CardData[]
|
|
571
|
-
const [isMobile, setIsMobile] = useState(false)
|
|
539
|
+
const cardItems = cards as CardData[]
|
|
540
|
+
const [isMobile, setIsMobile] = useState(false)
|
|
572
541
|
|
|
573
542
|
useEffect(() => {
|
|
574
|
-
const check = () => setIsMobile(window.innerWidth < 768)
|
|
575
|
-
check()
|
|
576
|
-
window.addEventListener(
|
|
577
|
-
return () => window.removeEventListener(
|
|
578
|
-
}, [])
|
|
543
|
+
const check = () => setIsMobile(window.innerWidth < 768)
|
|
544
|
+
check()
|
|
545
|
+
window.addEventListener('resize', check)
|
|
546
|
+
return () => window.removeEventListener('resize', check)
|
|
547
|
+
}, [])
|
|
579
548
|
|
|
580
|
-
const totalCards = cardItems.length
|
|
549
|
+
const totalCards = cardItems.length
|
|
581
550
|
|
|
582
551
|
return (
|
|
583
552
|
<>
|
|
584
553
|
{customCSS && <style dangerouslySetInnerHTML={{ __html: customCSS }} />}
|
|
585
554
|
|
|
586
555
|
<div id={sectionId ?? undefined} className="py-24">
|
|
556
|
+
#BlockName-DDFeatStrip
|
|
587
557
|
<div
|
|
588
|
-
className={`w-full bg-stone-100 dark:bg-stone-950 border-t border-b border-white/6 ${containerClass ||
|
|
558
|
+
className={`w-full bg-stone-100 dark:bg-stone-950 border-t border-b border-white/6 ${containerClass || ''}`}
|
|
589
559
|
>
|
|
590
560
|
<div
|
|
591
561
|
className="grid grid-cols-1"
|
|
@@ -611,5 +581,5 @@ export const DDFeatStrip: React.FC<DDFeatStripProps> = ({
|
|
|
611
581
|
</div>
|
|
612
582
|
</div>
|
|
613
583
|
</>
|
|
614
|
-
)
|
|
615
|
-
}
|
|
584
|
+
)
|
|
585
|
+
}
|