@morphika/andami 0.5.1 → 0.5.3
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 +27 -2
- 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 +332 -320
- package/app/admin/navigation/page.tsx +255 -255
- package/app/admin/pages/[slug]/page.tsx +44 -27
- package/app/admin/pages/page.tsx +24 -19
- package/app/admin/projects/page.tsx +30 -21
- package/app/admin/setup/page.tsx +1 -1
- package/app/admin/styles/page.tsx +1 -1
- package/app/api/admin/assets/register/route.ts +51 -14
- package/app/api/admin/assets/registry/route.ts +4 -1
- package/app/api/admin/assets/relink/confirm/route.ts +4 -1
- package/app/api/admin/assets/relink/route.ts +4 -1
- package/app/api/admin/assets/scan/route.ts +4 -1
- package/app/api/admin/backups/restore-data/route.ts +4 -1
- package/app/api/admin/r2/connect/route.ts +4 -1
- package/app/api/admin/r2/delete/route.ts +4 -1
- package/app/api/admin/r2/rename/route.ts +4 -1
- package/app/api/admin/r2/upload-url/route.ts +4 -1
- package/app/api/admin/revalidate/route.ts +4 -1
- package/app/api/admin/storage/switch/route.ts +4 -1
- package/app/api/custom-sections/[id]/route.ts +5 -6
- package/components/admin/MetadataEditor.tsx +6 -6
- package/components/admin/PublishToggle.tsx +2 -2
- 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 +8 -6
- 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 +518 -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 +9 -8
- package/components/admin/styles/FontsEditor.tsx +9 -7
- 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/CoverSectionRenderer.tsx +7 -1
- package/components/blocks/MarqueeBlockRenderer.tsx +316 -0
- package/components/blocks/ProjectCarouselBlockRenderer.tsx +1 -1
- package/components/blocks/SectionV2Renderer.tsx +8 -1
- package/components/builder/BlockCardIcons.tsx +316 -316
- package/components/builder/BlockTypePicker.tsx +1 -1
- package/components/builder/BubbleIcons.tsx +104 -0
- package/components/builder/BuilderCanvas.tsx +2 -0
- package/components/builder/CanvasMinimap.tsx +66 -49
- package/components/builder/CanvasToolbar.tsx +31 -41
- 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 +5 -3
- package/components/builder/SectionTypePicker.tsx +7 -5
- package/components/builder/SectionV2Canvas.tsx +1 -1
- package/components/builder/SectionV2Column.tsx +82 -68
- package/components/builder/SettingsPanel.tsx +21 -17
- package/components/builder/SortableBlock.tsx +93 -73
- package/components/builder/SortableRow.tsx +33 -35
- package/components/builder/VirtualAssetGrid.tsx +10 -4
- package/components/builder/asset-browser/R2BrowserContent.tsx +18 -14
- 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 +75 -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 +98 -93
- package/components/builder/color-picker/UnifiedColorPicker.tsx +11 -6
- 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 +8 -6
- package/components/builder/editors/MarqueeBlockEditor.tsx +622 -0
- package/components/builder/editors/ProjectCarouselBlockEditor.tsx +443 -443
- package/components/builder/editors/ProjectGridEditor.tsx +21 -16
- package/components/builder/editors/SpacerBlockEditor.tsx +29 -27
- package/components/builder/editors/StaggerSettings.tsx +109 -109
- package/components/builder/editors/TextBlockEditor.tsx +22 -17
- 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 +10 -8
- 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 +4 -2
- 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 +293 -291
- package/components/builder/live-preview/RichTextBubbleMenu.tsx +10 -6
- package/components/builder/live-preview/shared.tsx +5 -2
- package/components/builder/settings-panel/AnimationTab.tsx +138 -138
- package/components/builder/settings-panel/BlockLayoutTab.tsx +11 -9
- package/components/builder/settings-panel/CardEntranceSection.tsx +114 -114
- package/components/builder/settings-panel/ColumnV2LayoutTab.tsx +242 -0
- 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 +337 -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 +25 -20
- package/components/builder/settings-panel/TRBLInputs.tsx +1 -1
- package/components/builder/settings-panel/index.ts +1 -0
- 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/serializer/normalizers.ts +14 -0
- package/lib/builder/serializer/serializers.ts +27 -0
- package/lib/builder/store-sections.ts +23 -2
- package/lib/builder/types-slices.ts +428 -414
- package/lib/builder/types.ts +4 -1
- package/lib/config/index.ts +27 -27
- package/lib/sanity/queries.ts +48 -0
- package/lib/sanity/types.ts +112 -1
- package/lib/version.ts +1 -1
- package/package.json +7 -5
- 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/sanity/schemas/objects/coverSection.ts +32 -0
- package/sanity/schemas/objects/parallaxSlide.ts +32 -0
- package/sanity/schemas/pageSectionV2.ts +32 -0
- package/styles/admin.css +85 -85
- package/styles/animations.css +237 -237
- package/styles/base.css +114 -114
|
@@ -1,335 +1,337 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* CoverSectionSettings — Settings panel for a Cover Section.
|
|
5
|
-
*
|
|
6
|
-
* Displays:
|
|
7
|
-
* - Background type segmented control (Image / Video)
|
|
8
|
-
* - AssetBrowser picker for image or video
|
|
9
|
-
* - Background position / size dropdowns
|
|
10
|
-
* - Overlay color + overlay opacity slider
|
|
11
|
-
* - Section height selector (100vh / 80vh / 50vh)
|
|
12
|
-
* - Row list with percentages and vertical align
|
|
13
|
-
* - Add/Remove row controls
|
|
14
|
-
*
|
|
15
|
-
* Layout and Animation tabs are delegated to SectionV2LayoutTab / SectionV2AnimationTab
|
|
16
|
-
* via a virtual PageSectionV2 (same pattern as parallax slides).
|
|
17
|
-
*
|
|
18
|
-
* Session 176: Cover Sections — Phase 6 (Settings Panel).
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { useBuilderStore } from "../../../lib/builder/store";
|
|
22
|
-
import type { CoverSection } from "../../../lib/sanity/types";
|
|
23
|
-
import {
|
|
24
|
-
BackgroundIcon,
|
|
25
|
-
NavbarColorIcon,
|
|
26
|
-
OverlayIcon,
|
|
27
|
-
SpacingIcon,
|
|
28
|
-
GridGapsIcon,
|
|
29
|
-
} from "../editors/section-icons";
|
|
30
|
-
import {
|
|
31
|
-
SettingsField,
|
|
32
|
-
SettingsSection,
|
|
33
|
-
} from "../editors/shared";
|
|
34
|
-
import { AssetPathInput } from "../editors/shared";
|
|
35
|
-
import ColorSwatchPicker, { usePaletteSwatches } from "../ColorSwatchPicker";
|
|
36
|
-
import StaggerSettings from "../editors/StaggerSettings";
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
{ value: "
|
|
41
|
-
{ value: "
|
|
42
|
-
{ value: "center
|
|
43
|
-
{ value: "center
|
|
44
|
-
{ value: "
|
|
45
|
-
{ value: "top
|
|
46
|
-
{ value: "
|
|
47
|
-
{ value: "bottom
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
{ value: "
|
|
53
|
-
{ value: "
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
{ value: "
|
|
59
|
-
{ value: "
|
|
60
|
-
{ value: "
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
{ value: "
|
|
66
|
-
{ value: "
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CoverSectionSettings — Settings panel for a Cover Section.
|
|
5
|
+
*
|
|
6
|
+
* Displays:
|
|
7
|
+
* - Background type segmented control (Image / Video)
|
|
8
|
+
* - AssetBrowser picker for image or video
|
|
9
|
+
* - Background position / size dropdowns
|
|
10
|
+
* - Overlay color + overlay opacity slider
|
|
11
|
+
* - Section height selector (100vh / 80vh / 50vh)
|
|
12
|
+
* - Row list with percentages and vertical align
|
|
13
|
+
* - Add/Remove row controls
|
|
14
|
+
*
|
|
15
|
+
* Layout and Animation tabs are delegated to SectionV2LayoutTab / SectionV2AnimationTab
|
|
16
|
+
* via a virtual PageSectionV2 (same pattern as parallax slides).
|
|
17
|
+
*
|
|
18
|
+
* Session 176: Cover Sections — Phase 6 (Settings Panel).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { useBuilderStore } from "../../../lib/builder/store";
|
|
22
|
+
import type { CoverSection } from "../../../lib/sanity/types";
|
|
23
|
+
import {
|
|
24
|
+
BackgroundIcon,
|
|
25
|
+
NavbarColorIcon,
|
|
26
|
+
OverlayIcon,
|
|
27
|
+
SpacingIcon,
|
|
28
|
+
GridGapsIcon,
|
|
29
|
+
} from "../editors/section-icons";
|
|
30
|
+
import {
|
|
31
|
+
SettingsField,
|
|
32
|
+
SettingsSection,
|
|
33
|
+
} from "../editors/shared";
|
|
34
|
+
import { AssetPathInput } from "../editors/shared";
|
|
35
|
+
import ColorSwatchPicker, { usePaletteSwatches } from "../ColorSwatchPicker";
|
|
36
|
+
import StaggerSettings from "../editors/StaggerSettings";
|
|
37
|
+
import { BubbleTooltip } from "../BubbleIcons";
|
|
38
|
+
|
|
39
|
+
const BG_POSITION_OPTIONS = [
|
|
40
|
+
{ value: "center center", label: "Center" },
|
|
41
|
+
{ value: "top center", label: "Top" },
|
|
42
|
+
{ value: "bottom center", label: "Bottom" },
|
|
43
|
+
{ value: "center left", label: "Left" },
|
|
44
|
+
{ value: "center right", label: "Right" },
|
|
45
|
+
{ value: "top left", label: "Top Left" },
|
|
46
|
+
{ value: "top right", label: "Top Right" },
|
|
47
|
+
{ value: "bottom left", label: "Bottom Left" },
|
|
48
|
+
{ value: "bottom right", label: "Bottom Right" },
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
const BG_SIZE_OPTIONS = [
|
|
52
|
+
{ value: "cover", label: "Cover" },
|
|
53
|
+
{ value: "contain", label: "Contain" },
|
|
54
|
+
{ value: "auto", label: "Auto" },
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const HEIGHT_OPTIONS = [
|
|
58
|
+
{ value: "100vh", label: "Full Viewport (100vh)" },
|
|
59
|
+
{ value: "80vh", label: "80% Viewport (80vh)" },
|
|
60
|
+
{ value: "50vh", label: "50% Viewport (50vh)" },
|
|
61
|
+
{ value: "20vh", label: "20% Viewport (20vh)" },
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
const ALIGN_OPTIONS = [
|
|
65
|
+
{ value: "start", label: "Top" },
|
|
66
|
+
{ value: "center", label: "Center" },
|
|
67
|
+
{ value: "end", label: "Bottom" },
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
const SELECT_CLASS = "w-full rounded-lg border border-transparent bg-[#f5f5f5] px-2.5 py-[7px] text-xs text-neutral-900 font-normal outline-none transition-all hover:bg-[#efefef] focus:bg-white focus:border-[#3580f9] focus:shadow-[0_0_0_3px_rgba(53, 128, 249,0.06)]";
|
|
71
|
+
|
|
72
|
+
interface CoverSectionSettingsProps {
|
|
73
|
+
section: CoverSection;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default function CoverSectionSettings({ section }: CoverSectionSettingsProps) {
|
|
77
|
+
const store = useBuilderStore();
|
|
78
|
+
const paletteSwatches = usePaletteSwatches();
|
|
79
|
+
|
|
80
|
+
const bgType = section.background_type || "image";
|
|
81
|
+
const bgPosition = section.background_position || "center center";
|
|
82
|
+
const bgSize = section.background_size || "cover";
|
|
83
|
+
const overlayColor = section.background_overlay_color || "#000000";
|
|
84
|
+
const overlayOpacity = section.background_overlay_opacity ?? 0;
|
|
85
|
+
|
|
86
|
+
const updateBg = (fields: Partial<Pick<CoverSection,
|
|
87
|
+
"background_type" | "background_color" | "background_image" | "background_video" |
|
|
88
|
+
"background_position" | "background_size" |
|
|
89
|
+
"background_overlay_color" | "background_overlay_opacity" |
|
|
90
|
+
"nav_color"
|
|
91
|
+
>>) => {
|
|
92
|
+
store.updateCoverBackground(section._key, fields);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<>
|
|
97
|
+
{/* Background */}
|
|
98
|
+
<SettingsSection title="Background" defaultOpen icon={<BackgroundIcon />}>
|
|
99
|
+
<SettingsField label="Type">
|
|
100
|
+
<div className="flex rounded-lg bg-[#f0f0f0] p-[3px]">
|
|
101
|
+
{(["image", "video", "color"] as const).map((type) => (
|
|
102
|
+
<button
|
|
103
|
+
key={type}
|
|
104
|
+
onClick={() => updateBg({ background_type: type })}
|
|
105
|
+
className={`flex-1 py-1.5 rounded-md text-[11px] font-medium transition-all ${
|
|
106
|
+
bgType === type
|
|
107
|
+
? "bg-white text-neutral-900 shadow-sm border border-[#e5e5e5]"
|
|
108
|
+
: "text-neutral-400 hover:text-neutral-500"
|
|
109
|
+
}`}
|
|
110
|
+
>
|
|
111
|
+
{type === "image" ? "Image" : type === "video" ? "Video" : "Color"}
|
|
112
|
+
</button>
|
|
113
|
+
))}
|
|
114
|
+
</div>
|
|
115
|
+
</SettingsField>
|
|
116
|
+
|
|
117
|
+
{bgType === "color" ? (
|
|
118
|
+
<SettingsField label="Color">
|
|
119
|
+
<ColorSwatchPicker
|
|
120
|
+
value={section.background_color || "#000000"}
|
|
121
|
+
onChange={(val) => updateBg({ background_color: typeof val === "string" ? val : "" })}
|
|
122
|
+
swatches={paletteSwatches}
|
|
123
|
+
/>
|
|
124
|
+
</SettingsField>
|
|
125
|
+
) : (
|
|
126
|
+
<>
|
|
127
|
+
<SettingsField label={bgType === "image" ? "Image" : "Video"}>
|
|
128
|
+
<AssetPathInput
|
|
129
|
+
value={bgType === "image" ? (section.background_image || "") : (section.background_video || "")}
|
|
130
|
+
onChange={(path) => {
|
|
131
|
+
if (bgType === "image") {
|
|
132
|
+
updateBg({ background_image: path });
|
|
133
|
+
} else {
|
|
134
|
+
updateBg({ background_video: path });
|
|
135
|
+
}
|
|
136
|
+
}}
|
|
137
|
+
filterType={bgType === "image" ? "image" : "video"}
|
|
138
|
+
placeholder={bgType === "image" ? "path/to/image.jpg" : "path/to/video.mp4"}
|
|
139
|
+
/>
|
|
140
|
+
</SettingsField>
|
|
141
|
+
|
|
142
|
+
<SettingsField label="Position">
|
|
143
|
+
<select
|
|
144
|
+
value={bgPosition}
|
|
145
|
+
onChange={(e) => updateBg({ background_position: e.target.value })}
|
|
146
|
+
className={SELECT_CLASS}
|
|
147
|
+
>
|
|
148
|
+
{BG_POSITION_OPTIONS.map((opt) => (
|
|
149
|
+
<option key={opt.value} value={opt.value}>{opt.label}</option>
|
|
150
|
+
))}
|
|
151
|
+
</select>
|
|
152
|
+
</SettingsField>
|
|
153
|
+
|
|
154
|
+
<SettingsField label="Size">
|
|
155
|
+
<select
|
|
156
|
+
value={bgSize}
|
|
157
|
+
onChange={(e) => updateBg({ background_size: e.target.value as CoverSection["background_size"] })}
|
|
158
|
+
className={SELECT_CLASS}
|
|
159
|
+
>
|
|
160
|
+
{BG_SIZE_OPTIONS.map((opt) => (
|
|
161
|
+
<option key={opt.value} value={opt.value}>{opt.label}</option>
|
|
162
|
+
))}
|
|
163
|
+
</select>
|
|
164
|
+
</SettingsField>
|
|
165
|
+
</>
|
|
166
|
+
)}
|
|
167
|
+
</SettingsSection>
|
|
168
|
+
|
|
169
|
+
{/* Navbar Color Override */}
|
|
170
|
+
<SettingsSection title="Navbar Color" defaultOpen={false} icon={<NavbarColorIcon />}>
|
|
171
|
+
<SettingsField label="Color">
|
|
172
|
+
<div className="flex items-center gap-2">
|
|
173
|
+
<ColorSwatchPicker
|
|
174
|
+
value={section.nav_color || ""}
|
|
175
|
+
onChange={(val) => updateBg({ nav_color: typeof val === "string" ? val : undefined })}
|
|
176
|
+
swatches={paletteSwatches}
|
|
177
|
+
/>
|
|
178
|
+
{section.nav_color && (
|
|
179
|
+
<button
|
|
180
|
+
onClick={() => updateBg({ nav_color: undefined })}
|
|
181
|
+
className="text-[10px] text-neutral-400 hover:text-neutral-600 transition-colors shrink-0"
|
|
182
|
+
>
|
|
183
|
+
Clear
|
|
184
|
+
</button>
|
|
185
|
+
)}
|
|
186
|
+
</div>
|
|
187
|
+
</SettingsField>
|
|
188
|
+
<p className="text-[10px] text-neutral-400 leading-snug px-0.5">
|
|
189
|
+
Override the navbar text color while this cover section is on screen. Clears when the next section takes over.
|
|
190
|
+
</p>
|
|
191
|
+
</SettingsSection>
|
|
192
|
+
|
|
193
|
+
{/* Overlay */}
|
|
194
|
+
<SettingsSection title="Overlay" defaultOpen icon={<OverlayIcon />}>
|
|
195
|
+
<SettingsField label="Color">
|
|
196
|
+
<ColorSwatchPicker
|
|
197
|
+
value={overlayColor}
|
|
198
|
+
onChange={(val) => updateBg({ background_overlay_color: typeof val === "string" ? val : "" })}
|
|
199
|
+
swatches={paletteSwatches}
|
|
200
|
+
/>
|
|
201
|
+
</SettingsField>
|
|
202
|
+
|
|
203
|
+
<SettingsField label="Opacity">
|
|
204
|
+
<div className="flex items-center gap-2">
|
|
205
|
+
<input
|
|
206
|
+
type="range"
|
|
207
|
+
min={0}
|
|
208
|
+
max={100}
|
|
209
|
+
step={5}
|
|
210
|
+
value={overlayOpacity}
|
|
211
|
+
onChange={(e) => updateBg({ background_overlay_opacity: parseInt(e.target.value) })}
|
|
212
|
+
className="flex-1 accent-[#3580f9]"
|
|
213
|
+
/>
|
|
214
|
+
<span className="text-xs text-neutral-900 w-10 text-right tabular-nums">
|
|
215
|
+
{overlayOpacity}%
|
|
216
|
+
</span>
|
|
217
|
+
</div>
|
|
218
|
+
</SettingsField>
|
|
219
|
+
</SettingsSection>
|
|
220
|
+
|
|
221
|
+
{/* Section Height */}
|
|
222
|
+
<SettingsSection title="Height" defaultOpen icon={<SpacingIcon />}>
|
|
223
|
+
<SettingsField label="Height">
|
|
224
|
+
<select
|
|
225
|
+
value={section.height}
|
|
226
|
+
onChange={(e) => store.updateCoverHeight(section._key, e.target.value as CoverSection["height"])}
|
|
227
|
+
className={SELECT_CLASS}
|
|
228
|
+
>
|
|
229
|
+
{HEIGHT_OPTIONS.map((opt) => (
|
|
230
|
+
<option key={opt.value} value={opt.value}>{opt.label}</option>
|
|
231
|
+
))}
|
|
232
|
+
</select>
|
|
233
|
+
</SettingsField>
|
|
234
|
+
</SettingsSection>
|
|
235
|
+
|
|
236
|
+
{/* Rows */}
|
|
237
|
+
<SettingsSection title="Rows" defaultOpen icon={<GridGapsIcon />}>
|
|
238
|
+
<div className="space-y-2">
|
|
239
|
+
{section.cover_rows.map((row, i) => (
|
|
240
|
+
<div
|
|
241
|
+
key={row._key}
|
|
242
|
+
className="flex items-center gap-2 rounded-lg bg-[#f5f5f5] px-2.5 py-2"
|
|
243
|
+
>
|
|
244
|
+
<span className="text-[10px] font-semibold text-neutral-400 w-6 shrink-0">
|
|
245
|
+
R{i + 1}
|
|
246
|
+
</span>
|
|
247
|
+
<span className="text-xs text-neutral-700 font-medium tabular-nums w-10">
|
|
248
|
+
{row.height_percent}%
|
|
249
|
+
</span>
|
|
250
|
+
<select
|
|
251
|
+
value={row.vertical_align}
|
|
252
|
+
onChange={(e) =>
|
|
253
|
+
store.updateCoverRowAlign(
|
|
254
|
+
section._key,
|
|
255
|
+
row._key,
|
|
256
|
+
e.target.value as "start" | "center" | "end"
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
className="flex-1 rounded-md border border-transparent bg-white px-2 py-1 text-[11px] text-neutral-700 outline-none hover:border-[#e5e5e5] focus:border-[#3580f9]"
|
|
260
|
+
>
|
|
261
|
+
{ALIGN_OPTIONS.map((opt) => (
|
|
262
|
+
<option key={opt.value} value={opt.value}>{opt.label}</option>
|
|
263
|
+
))}
|
|
264
|
+
</select>
|
|
265
|
+
{section.cover_rows.length > 1 && (
|
|
266
|
+
<button
|
|
267
|
+
onClick={() => store.removeCoverRow(section._key, row._key)}
|
|
268
|
+
className="group/bb relative text-neutral-300 hover:text-red-500 transition-colors text-xs shrink-0"
|
|
269
|
+
aria-label="Remove row"
|
|
270
|
+
>
|
|
271
|
+
✕
|
|
272
|
+
<BubbleTooltip>Remove row</BubbleTooltip>
|
|
273
|
+
</button>
|
|
274
|
+
)}
|
|
275
|
+
</div>
|
|
276
|
+
))}
|
|
277
|
+
</div>
|
|
278
|
+
|
|
279
|
+
{section.cover_rows.length < 5 && (
|
|
280
|
+
<button
|
|
281
|
+
onClick={() => store.addCoverRow(section._key)}
|
|
282
|
+
className="w-full mt-2 rounded-lg border border-dashed border-neutral-300 py-2 text-[11px] font-medium text-neutral-400 hover:text-neutral-600 hover:border-neutral-400 transition-colors"
|
|
283
|
+
>
|
|
284
|
+
+ Add Row
|
|
285
|
+
</button>
|
|
286
|
+
)}
|
|
287
|
+
|
|
288
|
+
<p className="text-[10px] text-neutral-400 leading-snug px-0.5 mt-2">
|
|
289
|
+
Drag the handles between rows in the canvas to resize. Heights always sum to 100%.
|
|
290
|
+
</p>
|
|
291
|
+
</SettingsSection>
|
|
292
|
+
|
|
293
|
+
{/* Grid Gaps */}
|
|
294
|
+
<SettingsSection title="Grid" defaultOpen={false} icon={<GridGapsIcon />}>
|
|
295
|
+
<SettingsField label="Col Gap">
|
|
296
|
+
<div className="flex items-center gap-2">
|
|
297
|
+
<input
|
|
298
|
+
type="range"
|
|
299
|
+
min={0}
|
|
300
|
+
max={60}
|
|
301
|
+
step={2}
|
|
302
|
+
value={section.settings.col_gap ?? 20}
|
|
303
|
+
onChange={(e) => store.updateCoverSettings(section._key, { col_gap: parseInt(e.target.value) })}
|
|
304
|
+
className="flex-1 accent-[#3580f9]"
|
|
305
|
+
/>
|
|
306
|
+
<span className="text-xs text-neutral-900 w-10 text-right tabular-nums">
|
|
307
|
+
{section.settings.col_gap ?? 20}px
|
|
308
|
+
</span>
|
|
309
|
+
</div>
|
|
310
|
+
</SettingsField>
|
|
311
|
+
|
|
312
|
+
<SettingsField label="Row Gap">
|
|
313
|
+
<div className="flex items-center gap-2">
|
|
314
|
+
<input
|
|
315
|
+
type="range"
|
|
316
|
+
min={0}
|
|
317
|
+
max={60}
|
|
318
|
+
step={2}
|
|
319
|
+
value={section.settings.row_gap ?? 20}
|
|
320
|
+
onChange={(e) => store.updateCoverSettings(section._key, { row_gap: parseInt(e.target.value) })}
|
|
321
|
+
className="flex-1 accent-[#3580f9]"
|
|
322
|
+
/>
|
|
323
|
+
<span className="text-xs text-neutral-900 w-10 text-right tabular-nums">
|
|
324
|
+
{section.settings.row_gap ?? 20}px
|
|
325
|
+
</span>
|
|
326
|
+
</div>
|
|
327
|
+
</SettingsField>
|
|
328
|
+
</SettingsSection>
|
|
329
|
+
|
|
330
|
+
{/* Stagger */}
|
|
331
|
+
<StaggerSettings
|
|
332
|
+
stagger={section.settings.stagger}
|
|
333
|
+
onChange={(s) => store.updateCoverSettings(section._key, { stagger: s })}
|
|
334
|
+
/>
|
|
335
|
+
</>
|
|
336
|
+
);
|
|
337
|
+
}
|