@morphika/andami 0.5.1 → 0.5.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/app/admin/assets/page.tsx +6 -6
- package/app/admin/database/page.tsx +302 -302
- package/app/admin/error.tsx +53 -53
- package/app/admin/layout.tsx +320 -320
- package/app/admin/navigation/page.tsx +255 -255
- package/app/admin/pages/[slug]/page.tsx +6 -6
- package/app/admin/pages/page.tsx +11 -11
- package/app/admin/projects/page.tsx +14 -14
- package/app/admin/setup/page.tsx +1 -1
- package/app/admin/styles/page.tsx +1 -1
- package/components/admin/MetadataEditor.tsx +6 -6
- package/components/admin/nav-builder/NavBuilder.tsx +1 -1
- package/components/admin/nav-builder/NavBuilderGrid.tsx +3 -3
- package/components/admin/nav-builder/NavGridCell.tsx +48 -48
- package/components/admin/nav-builder/NavGridItem.tsx +4 -4
- package/components/admin/nav-builder/NavItemSettings.tsx +331 -331
- package/components/admin/nav-builder/NavItemTypePicker.tsx +102 -102
- package/components/admin/nav-builder/NavLivePreview.tsx +1 -1
- package/components/admin/nav-builder/NavMobileLivePreview.tsx +226 -226
- package/components/admin/nav-builder/NavMobileSettings.tsx +242 -242
- package/components/admin/nav-builder/NavSettingsFields.tsx +514 -514
- package/components/admin/setup-wizard/BrandingStep.tsx +3 -3
- package/components/admin/setup-wizard/DatabaseStep.tsx +2 -2
- package/components/admin/setup-wizard/DoneStep.tsx +1 -1
- package/components/admin/setup-wizard/SetupWizard.tsx +4 -4
- package/components/admin/setup-wizard/StorageStep.tsx +2 -2
- package/components/admin/setup-wizard/WelcomeStep.tsx +2 -2
- package/components/admin/styles/ColorsEditor.tsx +2 -2
- package/components/admin/styles/FontsEditor.tsx +6 -6
- package/components/admin/styles/GridLayoutEditor.tsx +9 -9
- package/components/admin/styles/LinksButtonsEditor.tsx +5 -5
- package/components/admin/styles/TypographyEditor.tsx +6 -6
- package/components/admin/styles/shared.tsx +68 -68
- package/components/blocks/AudioBlockRenderer.tsx +286 -286
- package/components/blocks/MarqueeBlockRenderer.tsx +316 -0
- package/components/blocks/ProjectCarouselBlockRenderer.tsx +1 -1
- package/components/builder/BlockCardIcons.tsx +316 -316
- package/components/builder/BlockTypePicker.tsx +1 -1
- package/components/builder/BubbleIcons.tsx +90 -0
- package/components/builder/BuilderCanvas.tsx +2 -0
- package/components/builder/CanvasMinimap.tsx +2 -2
- package/components/builder/CoverSectionCanvas.tsx +363 -363
- package/components/builder/DeviceFrame.tsx +1 -1
- package/components/builder/DndWrapper.tsx +3 -3
- package/components/builder/InsertionLines.tsx +1 -1
- package/components/builder/SectionCardIcons.tsx +421 -320
- package/components/builder/SectionEditorBar.tsx +1 -1
- package/components/builder/SectionTypePicker.tsx +4 -4
- package/components/builder/SectionV2Canvas.tsx +1 -1
- package/components/builder/SectionV2Column.tsx +69 -67
- package/components/builder/SortableBlock.tsx +93 -73
- package/components/builder/SortableRow.tsx +27 -26
- package/components/builder/VirtualAssetGrid.tsx +2 -2
- package/components/builder/asset-browser/R2BrowserContent.tsx +11 -11
- package/components/builder/blockStyles.tsx +192 -185
- package/components/builder/color-picker/AlphaSlider.tsx +141 -141
- package/components/builder/color-picker/ColorInputs.tsx +105 -105
- package/components/builder/color-picker/EyedropperButton.tsx +74 -74
- package/components/builder/color-picker/HueSlider.tsx +124 -124
- package/components/builder/color-picker/SaturationCanvas.tsx +142 -142
- package/components/builder/color-picker/SwatchBar.tsx +93 -93
- package/components/builder/editors/AudioBlockEditor.tsx +242 -242
- package/components/builder/editors/BeforeAfterBlockEditor.tsx +360 -360
- package/components/builder/editors/ButtonBlockEditor.tsx +4 -4
- package/components/builder/editors/EnterAnimationPicker.tsx +2 -2
- package/components/builder/editors/HoverEffectPicker.tsx +2 -2
- package/components/builder/editors/ImageBlockEditor.tsx +2 -2
- package/components/builder/editors/ImageGridBlockEditor.tsx +4 -4
- package/components/builder/editors/MarqueeBlockEditor.tsx +621 -0
- package/components/builder/editors/ProjectCarouselBlockEditor.tsx +443 -443
- package/components/builder/editors/ProjectGridEditor.tsx +9 -9
- package/components/builder/editors/SpacerBlockEditor.tsx +5 -5
- package/components/builder/editors/StaggerSettings.tsx +109 -109
- package/components/builder/editors/TextBlockEditor.tsx +3 -3
- package/components/builder/editors/TextStylePicker.tsx +1 -1
- package/components/builder/editors/VideoBlockEditor.tsx +2 -2
- package/components/builder/editors/index.ts +11 -10
- package/components/builder/editors/shared.tsx +6 -6
- package/components/builder/live-preview/LiveAudioPreview.tsx +120 -120
- package/components/builder/live-preview/LiveBeforeAfterPreview.tsx +1 -1
- package/components/builder/live-preview/LiveImageGridPreview.tsx +10 -2
- package/components/builder/live-preview/LiveImagePreview.tsx +1 -1
- package/components/builder/live-preview/LiveMarqueePreview.tsx +39 -0
- package/components/builder/live-preview/LiveProjectCarouselPreview.tsx +1 -1
- package/components/builder/live-preview/LiveVideoPreview.tsx +1 -1
- package/components/builder/live-preview/ProjectCardWrapper.tsx +291 -291
- package/components/builder/settings-panel/AnimationTab.tsx +138 -138
- package/components/builder/settings-panel/BlockLayoutTab.tsx +7 -7
- package/components/builder/settings-panel/CardEntranceSection.tsx +114 -114
- package/components/builder/settings-panel/ColumnV2Settings.tsx +5 -5
- package/components/builder/settings-panel/CoverSectionLayoutTab.tsx +71 -71
- package/components/builder/settings-panel/CoverSectionSettings.tsx +335 -335
- package/components/builder/settings-panel/PageSettings.tsx +3 -3
- package/components/builder/settings-panel/ParallaxSlideSettings.tsx +2 -2
- package/components/builder/settings-panel/SectionV2AnimationTab.tsx +4 -4
- package/components/builder/settings-panel/SectionV2LayoutTab.tsx +356 -356
- package/components/builder/settings-panel/SectionV2Settings.tsx +14 -14
- package/components/builder/settings-panel/TRBLInputs.tsx +1 -1
- package/lib/animation/enter-types.ts +1 -0
- package/lib/animation/hover-effect-presets.ts +210 -210
- package/lib/animation/hover-effect-types.ts +1 -0
- package/lib/builder/block-registrations.ts +468 -417
- package/lib/builder/constants.ts +111 -111
- package/lib/builder/store-sections.ts +2 -2
- package/lib/builder/types-slices.ts +414 -414
- package/lib/builder/types.ts +4 -1
- package/lib/config/index.ts +27 -27
- package/lib/sanity/types.ts +98 -1
- package/lib/version.ts +1 -1
- package/package.json +1 -1
- package/sanity/schemas/blocks/audioBlock.ts +69 -69
- package/sanity/schemas/blocks/index.ts +12 -11
- package/sanity/schemas/blocks/marqueeBlock.ts +292 -0
- package/sanity/schemas/index.ts +120 -117
- package/styles/admin.css +85 -85
- package/styles/animations.css +237 -237
- package/styles/base.css +114 -114
|
@@ -315,7 +315,7 @@ function AssetGridItem({
|
|
|
315
315
|
onContextMenu={onContextMenu ? (e) => onContextMenu(e, asset) : undefined}
|
|
316
316
|
className={`relative flex flex-col rounded-lg overflow-hidden transition-all ${
|
|
317
317
|
isSelected
|
|
318
|
-
? "ring-2 ring-[#
|
|
318
|
+
? "ring-2 ring-[#3580f9] ring-offset-2 shadow-lg"
|
|
319
319
|
: "hover:shadow-md"
|
|
320
320
|
}`}
|
|
321
321
|
>
|
|
@@ -323,7 +323,7 @@ function AssetGridItem({
|
|
|
323
323
|
{multiSelect && (
|
|
324
324
|
<div
|
|
325
325
|
className={`absolute top-1.5 left-1.5 z-10 w-5 h-5 rounded flex items-center justify-center text-white text-[10px] font-bold transition-colors ${
|
|
326
|
-
isSelected ? "bg-[#
|
|
326
|
+
isSelected ? "bg-[#3580f9]" : "bg-black/30 border border-white/50"
|
|
327
327
|
}`}
|
|
328
328
|
>
|
|
329
329
|
{isSelected && (
|
|
@@ -232,16 +232,16 @@ export function R2BrowserContent({
|
|
|
232
232
|
|
|
233
233
|
{/* Drag & drop overlay */}
|
|
234
234
|
{dnd.dragOver && (
|
|
235
|
-
<div className="absolute inset-0 z-50 flex items-center justify-center bg-[#
|
|
235
|
+
<div className="absolute inset-0 z-50 flex items-center justify-center bg-[#3580f9]/10 border-2 border-dashed border-[#3580f9] rounded-lg backdrop-blur-[2px]">
|
|
236
236
|
<div className="flex flex-col items-center gap-3">
|
|
237
|
-
<div className="w-16 h-16 rounded-full bg-[#
|
|
237
|
+
<div className="w-16 h-16 rounded-full bg-[#3580f9]/10 flex items-center justify-center">
|
|
238
238
|
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke={ADMIN_ACCENT} strokeWidth="1.5">
|
|
239
239
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
|
|
240
240
|
<polyline points="17 8 12 3 7 8" />
|
|
241
241
|
<line x1="12" y1="3" x2="12" y2="15" />
|
|
242
242
|
</svg>
|
|
243
243
|
</div>
|
|
244
|
-
<p className="text-sm font-medium text-[#
|
|
244
|
+
<p className="text-sm font-medium text-[#3580f9]">
|
|
245
245
|
Drop files or folders here{currentFolder ? ` to ${currentFolder}` : ""}
|
|
246
246
|
</p>
|
|
247
247
|
<p className="text-xs text-neutral-500">Supported formats: JPG, PNG, WebP, GIF, SVG, MP4, WebM, MOV, MP3, WAV, OGG, M4A, AAC, FLAC</p>
|
|
@@ -301,7 +301,7 @@ export function R2BrowserContent({
|
|
|
301
301
|
<button
|
|
302
302
|
onClick={() => ops.fileInputRef.current?.click()}
|
|
303
303
|
disabled={uploading.some((u) => u.status === "uploading" || u.status === "registering")}
|
|
304
|
-
className="inline-flex items-center gap-1.5 rounded-lg bg-[#
|
|
304
|
+
className="inline-flex items-center gap-1.5 rounded-lg bg-[#3580f9] px-3 py-1.5 text-[11px] text-white font-medium uppercase tracking-wider hover:bg-[#3580f9]/90 transition-colors disabled:opacity-50"
|
|
305
305
|
title={`Upload files${currentFolder ? ` to ${currentFolder}` : ""}`}
|
|
306
306
|
type="button"
|
|
307
307
|
>
|
|
@@ -327,7 +327,7 @@ export function R2BrowserContent({
|
|
|
327
327
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#ef4444" strokeWidth="2"><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></svg>
|
|
328
328
|
</button>
|
|
329
329
|
) : (
|
|
330
|
-
<div className="w-3.5 h-3.5 border-2 border-[#
|
|
330
|
+
<div className="w-3.5 h-3.5 border-2 border-[#3580f9] border-t-transparent rounded-full animate-spin" />
|
|
331
331
|
)}
|
|
332
332
|
<span className="text-[11px] text-neutral-600 truncate flex-1 min-w-0">
|
|
333
333
|
{u.file.name}
|
|
@@ -336,7 +336,7 @@ export function R2BrowserContent({
|
|
|
336
336
|
</span>
|
|
337
337
|
{(u.status === "uploading" || u.status === "registering") && (
|
|
338
338
|
<div className="w-24 h-1.5 bg-neutral-200 rounded-full overflow-hidden">
|
|
339
|
-
<div className="h-full bg-[#
|
|
339
|
+
<div className="h-full bg-[#3580f9] rounded-full transition-all duration-300" style={{ width: `${u.progress}%` }} />
|
|
340
340
|
</div>
|
|
341
341
|
)}
|
|
342
342
|
<span className="text-[10px] text-neutral-400 tabular-nums">{formatFileSize(u.file.size)}</span>
|
|
@@ -356,7 +356,7 @@ export function R2BrowserContent({
|
|
|
356
356
|
{error && (
|
|
357
357
|
<div className="flex flex-col items-center justify-center h-40 gap-3 px-8">
|
|
358
358
|
<span className="text-xs text-red-500 text-center max-w-md leading-relaxed">{error}</span>
|
|
359
|
-
<button onClick={onRetry} className="text-xs text-[#
|
|
359
|
+
<button onClick={onRetry} className="text-xs text-[#3580f9] hover:underline">Retry</button>
|
|
360
360
|
</div>
|
|
361
361
|
)}
|
|
362
362
|
|
|
@@ -372,9 +372,9 @@ export function R2BrowserContent({
|
|
|
372
372
|
ref={newFolderInputRef}
|
|
373
373
|
type="text" value={ops.newFolderName} onChange={(e) => ops.setNewFolderName(e.target.value)}
|
|
374
374
|
onKeyDown={(e) => { e.stopPropagation(); if (e.key === "Enter") ops.handleCreateFolder(); if (e.key === "Escape") ops.cancelNewFolderInput(); }}
|
|
375
|
-
placeholder="Folder name..." className="flex-1 text-sm text-neutral-900 bg-white border border-neutral-300 rounded px-2 py-1 focus:outline-none focus:border-[#
|
|
375
|
+
placeholder="Folder name..." className="flex-1 text-sm text-neutral-900 bg-white border border-neutral-300 rounded px-2 py-1 focus:outline-none focus:border-[#3580f9]"
|
|
376
376
|
/>
|
|
377
|
-
<button onClick={ops.handleCreateFolder} disabled={!ops.newFolderName.trim() || ops.actionLoading} className="text-xs px-3 py-1 rounded bg-[#
|
|
377
|
+
<button onClick={ops.handleCreateFolder} disabled={!ops.newFolderName.trim() || ops.actionLoading} className="text-xs px-3 py-1 rounded bg-[#3580f9] text-white disabled:opacity-50" type="button">Create</button>
|
|
378
378
|
<button onClick={ops.cancelNewFolderInput} className="text-xs px-2 py-1 text-neutral-500 hover:text-neutral-800" type="button">Cancel</button>
|
|
379
379
|
</div>
|
|
380
380
|
)}
|
|
@@ -387,9 +387,9 @@ export function R2BrowserContent({
|
|
|
387
387
|
ref={renameInputRef}
|
|
388
388
|
type="text" value={ops.renameValue} onChange={(e) => ops.setRenameValue(e.target.value)}
|
|
389
389
|
onKeyDown={(e) => { e.stopPropagation(); if (e.key === "Enter") ops.handleRename(); if (e.key === "Escape") ops.cancelRename(); }}
|
|
390
|
-
className="flex-1 text-sm text-neutral-900 bg-white border border-neutral-300 rounded px-2 py-1 focus:outline-none focus:border-[#
|
|
390
|
+
className="flex-1 text-sm text-neutral-900 bg-white border border-neutral-300 rounded px-2 py-1 focus:outline-none focus:border-[#3580f9]"
|
|
391
391
|
/>
|
|
392
|
-
<button onClick={ops.handleRename} disabled={!ops.renameValue.trim() || ops.actionLoading} className="text-xs px-3 py-1 rounded bg-[#
|
|
392
|
+
<button onClick={ops.handleRename} disabled={!ops.renameValue.trim() || ops.actionLoading} className="text-xs px-3 py-1 rounded bg-[#3580f9] text-white disabled:opacity-50" type="button">Rename</button>
|
|
393
393
|
<button onClick={ops.cancelRename} className="text-xs px-2 py-1 text-neutral-500 hover:text-neutral-800" type="button">Cancel</button>
|
|
394
394
|
</div>
|
|
395
395
|
)}
|
|
@@ -1,185 +1,192 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Shared block visual styles — gradients and SVG icon components.
|
|
5
|
-
* Used by BlockTypePicker (add block cards) and SettingsPanel (header).
|
|
6
|
-
*
|
|
7
|
-
* The compact block/section icons exported here are thin wrappers that render
|
|
8
|
-
* the full card icons (`BlockCardIcons.tsx` / `SectionCardIcons.tsx`) at a
|
|
9
|
-
* smaller size. This keeps iconography 100% consistent between the modal
|
|
10
|
-
* cards and the settings panel header — same visual, just scaled.
|
|
11
|
-
*
|
|
12
|
-
* `size` represents the HEIGHT in pixels. Width is derived from the
|
|
13
|
-
* card icon's 220×120 aspect ratio (≈ height × 1.833).
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import {
|
|
17
|
-
TextBlockCardIcon,
|
|
18
|
-
ImageBlockCardIcon,
|
|
19
|
-
ImageGridBlockCardIcon,
|
|
20
|
-
VideoBlockCardIcon,
|
|
21
|
-
SpacerBlockCardIcon,
|
|
22
|
-
ButtonBlockCardIcon,
|
|
23
|
-
BeforeAfterBlockCardIcon,
|
|
24
|
-
AudioBlockCardIcon,
|
|
25
|
-
} from "./BlockCardIcons";
|
|
26
|
-
import {
|
|
27
|
-
CoverSectionCardIcon,
|
|
28
|
-
EmptySectionV2CardIcon,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
<rect x="
|
|
124
|
-
<rect x="
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
<rect x="
|
|
144
|
-
<rect x="
|
|
145
|
-
<rect x="12" y="
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Shared block visual styles — gradients and SVG icon components.
|
|
5
|
+
* Used by BlockTypePicker (add block cards) and SettingsPanel (header).
|
|
6
|
+
*
|
|
7
|
+
* The compact block/section icons exported here are thin wrappers that render
|
|
8
|
+
* the full card icons (`BlockCardIcons.tsx` / `SectionCardIcons.tsx`) at a
|
|
9
|
+
* smaller size. This keeps iconography 100% consistent between the modal
|
|
10
|
+
* cards and the settings panel header — same visual, just scaled.
|
|
11
|
+
*
|
|
12
|
+
* `size` represents the HEIGHT in pixels. Width is derived from the
|
|
13
|
+
* card icon's 220×120 aspect ratio (≈ height × 1.833).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
TextBlockCardIcon,
|
|
18
|
+
ImageBlockCardIcon,
|
|
19
|
+
ImageGridBlockCardIcon,
|
|
20
|
+
VideoBlockCardIcon,
|
|
21
|
+
SpacerBlockCardIcon,
|
|
22
|
+
ButtonBlockCardIcon,
|
|
23
|
+
BeforeAfterBlockCardIcon,
|
|
24
|
+
AudioBlockCardIcon,
|
|
25
|
+
} from "./BlockCardIcons";
|
|
26
|
+
import {
|
|
27
|
+
CoverSectionCardIcon,
|
|
28
|
+
EmptySectionV2CardIcon,
|
|
29
|
+
MarqueeCardIcon,
|
|
30
|
+
ParallaxGroupCardIcon,
|
|
31
|
+
ProjectCarouselCardIcon,
|
|
32
|
+
ProjectGridCardIcon,
|
|
33
|
+
SavedSectionCardIcon,
|
|
34
|
+
} from "./SectionCardIcons";
|
|
35
|
+
|
|
36
|
+
// ── Gradient backgrounds per block type ──
|
|
37
|
+
|
|
38
|
+
export const BLOCK_GRADIENTS: Record<string, string> = {
|
|
39
|
+
textBlock: "linear-gradient(135deg, #c9b8ff 0%, #8eb5ff 50%, #b8d4ff 100%)",
|
|
40
|
+
imageBlock: "linear-gradient(135deg, #b8ffb8 0%, #d4ffa8 50%, #f0ffc0 100%)",
|
|
41
|
+
imageGridBlock: "linear-gradient(135deg, #a8c8ff 0%, #c0d8ff 50%, #d8e8ff 100%)",
|
|
42
|
+
videoBlock: "linear-gradient(135deg, #ffb8d4 0%, #ffc8a8 50%, #ffe0b8 100%)",
|
|
43
|
+
spacerBlock: "linear-gradient(135deg, #d8d8e8 0%, #e8e8f0 50%, #f0f0f8 100%)",
|
|
44
|
+
buttonBlock: "linear-gradient(135deg, #ffb8e0 0%, #b8ffe8 50%, #a8ffd8 100%)",
|
|
45
|
+
beforeAfterBlock: "linear-gradient(135deg, #d8d8e8 0%, #a8c8ff 50%, #b8ffe0 100%)",
|
|
46
|
+
audioBlock: "linear-gradient(135deg, #a8c8ff 0%, #d8c0ff 50%, #e0b8ff 100%)",
|
|
47
|
+
projectGridBlock: "linear-gradient(135deg, #ffd4a8 0%, #ffe8b8 50%, #fff0c8 100%)",
|
|
48
|
+
marqueeBlock: "linear-gradient(135deg, #e0c8ff 0%, #c8b0ff 50%, #b8a0ff 100%)",
|
|
49
|
+
coverSection: "linear-gradient(135deg, #b2f5ea 0%, #81e6d9 50%, #5eead4 100%)",
|
|
50
|
+
parallaxGroup: "linear-gradient(135deg, #c8a8ff 0%, #d8b8ff 50%, #e8d0ff 100%)",
|
|
51
|
+
customSectionInstance: "linear-gradient(135deg, #d0b8ff 0%, #b8a8f8 50%, #c8b8ff 100%)",
|
|
52
|
+
// Non-block contexts
|
|
53
|
+
row: "linear-gradient(135deg, #e0e0f0 0%, #d0d8e8 50%, #c8d0e0 100%)",
|
|
54
|
+
column: "linear-gradient(135deg, #d8e8f8 0%, #c8ddf0 50%, #b8d0e8 100%)",
|
|
55
|
+
page: "linear-gradient(135deg, #f0e8d8 0%, #e8dcc8 50%, #e0d0b8 100%)",
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// ── Compact wrappers that render the full card icon at a smaller size ──
|
|
59
|
+
//
|
|
60
|
+
// Card icons are 220×120 (landscape ≈11:6). `size` here is the HEIGHT in px;
|
|
61
|
+
// width is derived automatically to preserve aspect.
|
|
62
|
+
|
|
63
|
+
const ASPECT = 220 / 120;
|
|
64
|
+
|
|
65
|
+
function scaleToHeight(size: number): React.CSSProperties {
|
|
66
|
+
return {
|
|
67
|
+
width: Math.round(size * ASPECT),
|
|
68
|
+
height: size,
|
|
69
|
+
display: "inline-block",
|
|
70
|
+
flexShrink: 0,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function TextBlockIcon({ size = 28 }: { size?: number }) {
|
|
75
|
+
return <span style={scaleToHeight(size)}><TextBlockCardIcon /></span>;
|
|
76
|
+
}
|
|
77
|
+
export function ImageBlockIcon({ size = 28 }: { size?: number }) {
|
|
78
|
+
return <span style={scaleToHeight(size)}><ImageBlockCardIcon /></span>;
|
|
79
|
+
}
|
|
80
|
+
export function ImageGridBlockIcon({ size = 28 }: { size?: number }) {
|
|
81
|
+
return <span style={scaleToHeight(size)}><ImageGridBlockCardIcon /></span>;
|
|
82
|
+
}
|
|
83
|
+
export function VideoBlockIcon({ size = 28 }: { size?: number }) {
|
|
84
|
+
return <span style={scaleToHeight(size)}><VideoBlockCardIcon /></span>;
|
|
85
|
+
}
|
|
86
|
+
export function SpacerBlockIcon({ size = 28 }: { size?: number }) {
|
|
87
|
+
return <span style={scaleToHeight(size)}><SpacerBlockCardIcon /></span>;
|
|
88
|
+
}
|
|
89
|
+
export function ButtonBlockIcon({ size = 28 }: { size?: number }) {
|
|
90
|
+
return <span style={scaleToHeight(size)}><ButtonBlockCardIcon /></span>;
|
|
91
|
+
}
|
|
92
|
+
export function BeforeAfterBlockIcon({ size = 28 }: { size?: number }) {
|
|
93
|
+
return <span style={scaleToHeight(size)}><BeforeAfterBlockCardIcon /></span>;
|
|
94
|
+
}
|
|
95
|
+
export function AudioBlockIcon({ size = 28 }: { size?: number }) {
|
|
96
|
+
return <span style={scaleToHeight(size)}><AudioBlockCardIcon /></span>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ── Non-block context icons (compact wrappers of the section card icons) ──
|
|
100
|
+
|
|
101
|
+
export function CoverSectionSettingsIcon({ size = 28 }: { size?: number }) {
|
|
102
|
+
return <span style={scaleToHeight(size)}><CoverSectionCardIcon /></span>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Plain V2 section (row-level) — uses the Empty Section card icon so the
|
|
106
|
+
* settings panel matches the Add Section modal iconography. */
|
|
107
|
+
export function RowIcon({ size = 28 }: { size?: number }) {
|
|
108
|
+
return <span style={scaleToHeight(size)}><EmptySectionV2CardIcon /></span>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function ColumnIcon({ size = 28 }: { size?: number }) {
|
|
112
|
+
return (
|
|
113
|
+
<svg width={size} height={size} viewBox="0 0 40 40" fill="none">
|
|
114
|
+
<defs>
|
|
115
|
+
<linearGradient id="colGrad" x1="4" y1="4" x2="36" y2="36">
|
|
116
|
+
<stop offset="0%" stopColor="#6090c8" />
|
|
117
|
+
<stop offset="100%" stopColor="#4878b8" />
|
|
118
|
+
</linearGradient>
|
|
119
|
+
<filter id="colDrop">
|
|
120
|
+
<feDropShadow dx="0" dy="1" stdDeviation="1" floodColor="rgba(0,0,0,0.12)" />
|
|
121
|
+
</filter>
|
|
122
|
+
</defs>
|
|
123
|
+
<rect x="6" y="4" width="10" height="32" rx="3" fill="url(#colGrad)" opacity="0.9" filter="url(#colDrop)" />
|
|
124
|
+
<rect x="6" y="4" width="10" height="10" rx="3" fill="white" opacity="0.18" />
|
|
125
|
+
<rect x="20" y="4" width="14" height="32" rx="3" fill="url(#colGrad)" opacity="0.55" filter="url(#colDrop)" />
|
|
126
|
+
<rect x="20" y="4" width="14" height="10" rx="3" fill="white" opacity="0.12" />
|
|
127
|
+
</svg>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function PageIcon({ size = 28 }: { size?: number }) {
|
|
132
|
+
return (
|
|
133
|
+
<svg width={size} height={size} viewBox="0 0 40 40" fill="none">
|
|
134
|
+
<defs>
|
|
135
|
+
<linearGradient id="pageGrad" x1="8" y1="2" x2="32" y2="38">
|
|
136
|
+
<stop offset="0%" stopColor="#c8a870" />
|
|
137
|
+
<stop offset="100%" stopColor="#a88850" />
|
|
138
|
+
</linearGradient>
|
|
139
|
+
<filter id="pageDrop">
|
|
140
|
+
<feDropShadow dx="0" dy="1.5" stdDeviation="1.5" floodColor="rgba(0,0,0,0.15)" />
|
|
141
|
+
</filter>
|
|
142
|
+
</defs>
|
|
143
|
+
<rect x="8" y="3" width="24" height="34" rx="3" fill="url(#pageGrad)" filter="url(#pageDrop)" />
|
|
144
|
+
<rect x="8" y="3" width="24" height="10" rx="3" fill="white" opacity="0.2" />
|
|
145
|
+
<rect x="12" y="17" width="16" height="2" rx="1" fill="white" opacity="0.35" />
|
|
146
|
+
<rect x="12" y="22" width="12" height="2" rx="1" fill="white" opacity="0.25" />
|
|
147
|
+
<rect x="12" y="27" width="14" height="2" rx="1" fill="white" opacity="0.2" />
|
|
148
|
+
</svg>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ── Lookup maps ──
|
|
153
|
+
|
|
154
|
+
export function ProjectGridBlockIcon({ size = 28 }: { size?: number }) {
|
|
155
|
+
return <span style={scaleToHeight(size)}><ProjectGridCardIcon /></span>;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function ProjectCarouselBlockIcon({ size = 28 }: { size?: number }) {
|
|
159
|
+
return <span style={scaleToHeight(size)}><ProjectCarouselCardIcon /></span>;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function MarqueeBlockIcon({ size = 28 }: { size?: number }) {
|
|
163
|
+
return <span style={scaleToHeight(size)}><MarqueeCardIcon /></span>;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function ParallaxGroupIcon({ size = 28 }: { size?: number }) {
|
|
167
|
+
return <span style={scaleToHeight(size)}><ParallaxGroupCardIcon /></span>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function CustomSectionInstanceIcon({ size = 28 }: { size?: number }) {
|
|
171
|
+
return <span style={scaleToHeight(size)}><SavedSectionCardIcon /></span>;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export const BLOCK_ICON_COMPONENTS: Record<string, React.FC<{ size?: number }>> = {
|
|
175
|
+
textBlock: TextBlockIcon,
|
|
176
|
+
imageBlock: ImageBlockIcon,
|
|
177
|
+
imageGridBlock: ImageGridBlockIcon,
|
|
178
|
+
videoBlock: VideoBlockIcon,
|
|
179
|
+
spacerBlock: SpacerBlockIcon,
|
|
180
|
+
buttonBlock: ButtonBlockIcon,
|
|
181
|
+
beforeAfterBlock: BeforeAfterBlockIcon,
|
|
182
|
+
audioBlock: AudioBlockIcon,
|
|
183
|
+
projectGridBlock: ProjectGridBlockIcon,
|
|
184
|
+
projectCarouselBlock: ProjectCarouselBlockIcon,
|
|
185
|
+
marqueeBlock: MarqueeBlockIcon,
|
|
186
|
+
parallaxGroup: ParallaxGroupIcon,
|
|
187
|
+
coverSection: CoverSectionSettingsIcon,
|
|
188
|
+
customSectionInstance: CustomSectionInstanceIcon,
|
|
189
|
+
row: RowIcon,
|
|
190
|
+
column: ColumnIcon,
|
|
191
|
+
page: PageIcon,
|
|
192
|
+
};
|