@morphika/andami 0.1.9 → 0.2.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/app/admin/pages/[slug]/page.tsx +3 -7
- package/app/api/admin/pages/[slug]/route.ts +2 -28
- package/app/api/admin/settings/route.ts +30 -0
- package/components/admin/nav-builder/NavBuilder.tsx +90 -14
- package/components/admin/nav-builder/NavGeneralSettings.tsx +521 -271
- package/components/admin/nav-builder/NavItemSettings.tsx +331 -312
- package/components/admin/nav-builder/NavMobileSettings.tsx +159 -140
- package/components/admin/nav-builder/NavSettingsFields.tsx +287 -21
- package/components/admin/nav-builder/NavSettingsPanel.tsx +137 -127
- package/components/blocks/EnterAnimationWrapper.tsx +19 -4
- package/components/blocks/PageRenderer.tsx +2 -15
- package/components/blocks/ProjectGridBlockRenderer.tsx +34 -36
- package/components/blocks/TextBlockRenderer.tsx +1 -1
- package/components/builder/DndWrapper.tsx +2 -24
- package/components/builder/InsertionLines.tsx +5 -5
- package/components/builder/ReadOnlyFrame.tsx +5 -49
- package/components/builder/SectionV2Canvas.tsx +2 -2
- package/components/builder/SectionV2Column.tsx +5 -5
- package/components/builder/SettingsPanel.tsx +0 -12
- package/components/builder/SortableBlock.tsx +3 -3
- package/components/builder/SortableRow.tsx +6 -27
- package/components/builder/editors/ButtonBlockEditor.tsx +8 -3
- package/components/builder/editors/CoverBlockEditor.tsx +14 -6
- package/components/builder/editors/ImageBlockEditor.tsx +8 -3
- package/components/builder/editors/ImageGridBlockEditor.tsx +8 -3
- package/components/builder/editors/ProjectGridEditor.tsx +7 -46
- package/components/builder/editors/SpacerBlockEditor.tsx +4 -1
- package/components/builder/editors/StaggerSettings.tsx +2 -1
- package/components/builder/editors/TextBlockEditor.tsx +8 -3
- package/components/builder/editors/VideoBlockEditor.tsx +10 -4
- package/components/builder/editors/section-icons.tsx +492 -0
- package/components/builder/editors/shared.tsx +23 -4
- package/components/builder/live-preview/LiveTextEditor.tsx +1 -1
- package/components/builder/live-preview/ProjectCardWrapper.tsx +3 -3
- package/components/builder/live-preview/drag-utils.tsx +2 -2
- package/components/builder/settings-panel/AnimationTab.tsx +2 -16
- package/components/builder/settings-panel/BlockLayoutTab.tsx +13 -58
- package/components/builder/settings-panel/ColumnV2Settings.tsx +4 -1
- package/components/builder/settings-panel/PageSettings.tsx +10 -4
- package/components/builder/settings-panel/ParallaxGroupSettings.tsx +6 -2
- package/components/builder/settings-panel/ParallaxSlideSettings.tsx +8 -3
- package/components/builder/settings-panel/SectionV2LayoutTab.tsx +11 -47
- package/components/builder/settings-panel/SectionV2Settings.tsx +6 -27
- package/components/builder/settings-panel/index.ts +0 -1
- package/components/builder/settings-panel/responsive-helpers.ts +2 -50
- package/components/builder/settings-panel/useSettingsPanelSelection.ts +1 -16
- package/components/ui/Navbar.tsx +151 -30
- package/lib/builder/constants.ts +5 -4
- package/lib/builder/serializer/normalizers.ts +2 -40
- package/lib/builder/serializer/serializers.ts +3 -74
- package/lib/builder/store-blocks.ts +3 -19
- package/lib/builder/store-helpers.ts +2 -2
- package/lib/builder/store-sections.ts +26 -64
- package/lib/builder/store.ts +3 -6
- package/lib/builder/templates.ts +9 -45
- package/lib/builder/types.ts +4 -11
- package/lib/sanity/queries.ts +6 -29
- package/lib/sanity/types.ts +24 -70
- package/package.json +4 -1
- package/sanity/schemas/index.ts +0 -5
- package/sanity/schemas/objects/parallaxGroup.ts +2 -2
- package/sanity/schemas/page.ts +1 -1
- package/sanity/schemas/pageSectionV2.ts +1 -0
- package/sanity/schemas/siteSettings.ts +42 -0
- package/styles/base.css +8 -2
- package/components/blocks/SectionRenderer.tsx +0 -171
- package/components/builder/settings-panel/LayoutTab.tsx +0 -382
- package/sanity/schemas/pageSection.ts +0 -157
|
@@ -145,59 +145,14 @@ function AlignmentButtons<T extends string>({
|
|
|
145
145
|
);
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
// ── Section title icons (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
</svg>
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function SpacingSectionIcon() {
|
|
161
|
-
return (
|
|
162
|
-
<svg width={14} height={14} viewBox="0 0 14 14" fill="none">
|
|
163
|
-
<rect x="4" y="4" width="6" height="6" rx="1" stroke="currentColor" strokeWidth="1" fill="none" opacity="0.5" />
|
|
164
|
-
<path d="M7 1 L7 3.5" stroke="currentColor" strokeWidth="0.8" opacity="0.7" />
|
|
165
|
-
<path d="M7 10.5 L7 13" stroke="currentColor" strokeWidth="0.8" opacity="0.7" />
|
|
166
|
-
<path d="M1 7 L3.5 7" stroke="currentColor" strokeWidth="0.8" opacity="0.7" />
|
|
167
|
-
<path d="M10.5 7 L13 7" stroke="currentColor" strokeWidth="0.8" opacity="0.7" />
|
|
168
|
-
</svg>
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function OffsetSectionIcon() {
|
|
173
|
-
return (
|
|
174
|
-
<svg width={14} height={14} viewBox="0 0 14 14" fill="none">
|
|
175
|
-
<rect x="3" y="3" width="8" height="8" rx="1" stroke="currentColor" strokeWidth="0.8" strokeDasharray="2 1" fill="none" opacity="0.35" />
|
|
176
|
-
<rect x="5" y="5" width="6" height="6" rx="1" stroke="currentColor" strokeWidth="1" fill="none" opacity="0.7" />
|
|
177
|
-
<path d="M4 4 L5 5" stroke="currentColor" strokeWidth="0.6" opacity="0.5" />
|
|
178
|
-
</svg>
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function BackgroundSectionIcon() {
|
|
183
|
-
return (
|
|
184
|
-
<svg width={14} height={14} viewBox="0 0 14 14" fill="none">
|
|
185
|
-
<rect x="1.5" y="1.5" width="11" height="11" rx="2" fill="currentColor" opacity="0.15" />
|
|
186
|
-
<rect x="1.5" y="1.5" width="11" height="11" rx="2" stroke="currentColor" strokeWidth="0.8" opacity="0.5" fill="none" />
|
|
187
|
-
<circle cx="5" cy="5" r="1.5" fill="currentColor" opacity="0.5" />
|
|
188
|
-
<path d="M1.5 10 L5 7 L8 9 L10.5 6.5 L12.5 8.5 L12.5 11 C12.5 11.8 11.8 12.5 11 12.5 L3 12.5 C2.2 12.5 1.5 11.8 1.5 11 Z" fill="currentColor" opacity="0.3" />
|
|
189
|
-
</svg>
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function BorderSectionIcon() {
|
|
194
|
-
return (
|
|
195
|
-
<svg width={14} height={14} viewBox="0 0 14 14" fill="none">
|
|
196
|
-
<rect x="2" y="2" width="10" height="10" rx="2" stroke="currentColor" strokeWidth="1.2" fill="none" opacity="0.6" />
|
|
197
|
-
<rect x="2" y="2" width="10" height="1.2" rx="0.5" fill="currentColor" opacity="0.7" />
|
|
198
|
-
</svg>
|
|
199
|
-
);
|
|
200
|
-
}
|
|
148
|
+
// ── Section title icons (centralized colored icons — Session 163) ──
|
|
149
|
+
import {
|
|
150
|
+
AlignmentIcon,
|
|
151
|
+
SpacingIcon,
|
|
152
|
+
OffsetIcon,
|
|
153
|
+
BackgroundIcon,
|
|
154
|
+
BorderIcon,
|
|
155
|
+
} from "../editors/section-icons";
|
|
201
156
|
|
|
202
157
|
// ── Override indicator badge ──
|
|
203
158
|
|
|
@@ -287,7 +242,7 @@ export function BlockLayoutTab({ block }: { block: ContentBlock }) {
|
|
|
287
242
|
)}
|
|
288
243
|
|
|
289
244
|
{/* Alignment */}
|
|
290
|
-
<SettingsSection title="Alignment" defaultOpen icon={<
|
|
245
|
+
<SettingsSection title="Alignment" defaultOpen icon={<AlignmentIcon />}>
|
|
291
246
|
<SettingsField label="Horizontal">
|
|
292
247
|
<AlignmentButtons<AlignH>
|
|
293
248
|
options={[
|
|
@@ -329,7 +284,7 @@ export function BlockLayoutTab({ block }: { block: ContentBlock }) {
|
|
|
329
284
|
</SettingsSection>
|
|
330
285
|
|
|
331
286
|
{/* Spacing (Padding) */}
|
|
332
|
-
<SettingsSection title="Spacing" defaultOpen icon={<
|
|
287
|
+
<SettingsSection title="Spacing" defaultOpen icon={<SpacingIcon />}>
|
|
333
288
|
<TRBLInputs
|
|
334
289
|
top={getBlockLayoutValue<string>(block, activeViewport, "spacing_top", "0")}
|
|
335
290
|
right={getBlockLayoutValue<string>(block, activeViewport, "spacing_right", "0")}
|
|
@@ -348,7 +303,7 @@ export function BlockLayoutTab({ block }: { block: ContentBlock }) {
|
|
|
348
303
|
</SettingsSection>
|
|
349
304
|
|
|
350
305
|
{/* Offset (Margin) */}
|
|
351
|
-
<SettingsSection title="Offset" icon={<
|
|
306
|
+
<SettingsSection title="Offset" icon={<OffsetIcon />}>
|
|
352
307
|
<TRBLInputs
|
|
353
308
|
top={getBlockLayoutValue<string>(block, activeViewport, "offset_top", "0")}
|
|
354
309
|
right={getBlockLayoutValue<string>(block, activeViewport, "offset_right", "0")}
|
|
@@ -367,7 +322,7 @@ export function BlockLayoutTab({ block }: { block: ContentBlock }) {
|
|
|
367
322
|
</SettingsSection>
|
|
368
323
|
|
|
369
324
|
{/* Background */}
|
|
370
|
-
<SettingsSection title="Background" defaultOpen icon={<
|
|
325
|
+
<SettingsSection title="Background" defaultOpen icon={<BackgroundIcon />}>
|
|
371
326
|
<SettingsField label="Color">
|
|
372
327
|
<ColorSwatchPicker
|
|
373
328
|
value={parseColorField(getBlockLayoutValue<string>(block, activeViewport, "background_color", ""))}
|
|
@@ -466,7 +421,7 @@ export function BlockLayoutTab({ block }: { block: ContentBlock }) {
|
|
|
466
421
|
</SettingsSection>
|
|
467
422
|
|
|
468
423
|
{/* Border */}
|
|
469
|
-
<SettingsSection title="Border" icon={<
|
|
424
|
+
<SettingsSection title="Border" icon={<BorderIcon />}>
|
|
470
425
|
<SettingsField label="Color">
|
|
471
426
|
<ColorSwatchPicker
|
|
472
427
|
value={parseColorField(getBlockLayoutValue<string>(block, activeViewport, "border_color", ""))}
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
|
|
17
17
|
import { useBuilderStore } from "../../../lib/builder/store";
|
|
18
18
|
import type { PageSectionV2, SectionColumn } from "../../../lib/sanity/types";
|
|
19
|
+
import {
|
|
20
|
+
ColumnSizeIcon,
|
|
21
|
+
} from "../editors/section-icons";
|
|
19
22
|
import {
|
|
20
23
|
SettingsField,
|
|
21
24
|
SettingsSection,
|
|
@@ -90,7 +93,7 @@ export default function ColumnV2Settings({
|
|
|
90
93
|
</div>
|
|
91
94
|
)}
|
|
92
95
|
|
|
93
|
-
<SettingsSection title="Column Size" defaultOpen>
|
|
96
|
+
<SettingsSection title="Column Size" defaultOpen icon={<ColumnSizeIcon />}>
|
|
94
97
|
<SettingsField label={
|
|
95
98
|
<span>
|
|
96
99
|
Span
|
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
|
|
12
12
|
import { useState } from "react";
|
|
13
13
|
import { useBuilderStore } from "../../../lib/builder/store";
|
|
14
|
+
import {
|
|
15
|
+
GeneralIcon,
|
|
16
|
+
AppearanceIcon,
|
|
17
|
+
NavigationIcon,
|
|
18
|
+
SEOIcon,
|
|
19
|
+
} from "../editors/section-icons";
|
|
14
20
|
import {
|
|
15
21
|
SettingsField,
|
|
16
22
|
SettingsSection,
|
|
@@ -39,7 +45,7 @@ export default function PageSettings() {
|
|
|
39
45
|
|
|
40
46
|
return (
|
|
41
47
|
<>
|
|
42
|
-
<SettingsSection title="General" defaultOpen>
|
|
48
|
+
<SettingsSection title="General" defaultOpen icon={<GeneralIcon />}>
|
|
43
49
|
<SettingsField label="Title">
|
|
44
50
|
<input
|
|
45
51
|
type="text"
|
|
@@ -73,7 +79,7 @@ export default function PageSettings() {
|
|
|
73
79
|
</SettingsField>
|
|
74
80
|
</SettingsSection>
|
|
75
81
|
|
|
76
|
-
<SettingsSection title="Appearance" defaultOpen>
|
|
82
|
+
<SettingsSection title="Appearance" defaultOpen icon={<AppearanceIcon />}>
|
|
77
83
|
<SettingsField label="Background">
|
|
78
84
|
<ColorSwatchPicker
|
|
79
85
|
value={parseColorField(store.pageSettings.background_color || "")}
|
|
@@ -91,7 +97,7 @@ export default function PageSettings() {
|
|
|
91
97
|
</SettingsField>
|
|
92
98
|
</SettingsSection>
|
|
93
99
|
|
|
94
|
-
<SettingsSection title="Navigation">
|
|
100
|
+
<SettingsSection title="Navigation" icon={<NavigationIcon />}>
|
|
95
101
|
<SettingsField label="Nav Color">
|
|
96
102
|
<ColorSwatchPicker
|
|
97
103
|
value={store.pageSettings.nav_color || ""}
|
|
@@ -164,7 +170,7 @@ export function PageSeoSettings() {
|
|
|
164
170
|
|
|
165
171
|
return (
|
|
166
172
|
<>
|
|
167
|
-
<SettingsSection title="SEO" defaultOpen>
|
|
173
|
+
<SettingsSection title="SEO" defaultOpen icon={<SEOIcon />}>
|
|
168
174
|
<SettingsField label="SEO Title">
|
|
169
175
|
<input
|
|
170
176
|
type="text"
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
|
|
15
15
|
import { useBuilderStore } from "../../../lib/builder/store";
|
|
16
16
|
import type { ParallaxGroup } from "../../../lib/sanity/types";
|
|
17
|
+
import {
|
|
18
|
+
TransitionIcon,
|
|
19
|
+
InfoIcon,
|
|
20
|
+
} from "../editors/section-icons";
|
|
17
21
|
import {
|
|
18
22
|
SettingsSection,
|
|
19
23
|
} from "../editors/shared";
|
|
@@ -56,7 +60,7 @@ export default function ParallaxGroupSettings({
|
|
|
56
60
|
|
|
57
61
|
return (
|
|
58
62
|
<>
|
|
59
|
-
<SettingsSection title="Transition Effect" defaultOpen>
|
|
63
|
+
<SettingsSection title="Transition Effect" defaultOpen icon={<TransitionIcon />}>
|
|
60
64
|
<div className="space-y-1.5">
|
|
61
65
|
{TRANSITION_EFFECTS.map((effect) => {
|
|
62
66
|
const isActive = activeEffect === effect.value;
|
|
@@ -103,7 +107,7 @@ export default function ParallaxGroupSettings({
|
|
|
103
107
|
</SettingsSection>
|
|
104
108
|
|
|
105
109
|
{/* Group info */}
|
|
106
|
-
<SettingsSection title="Info">
|
|
110
|
+
<SettingsSection title="Info" icon={<InfoIcon />}>
|
|
107
111
|
<div className="text-[11px] text-neutral-500 space-y-1">
|
|
108
112
|
<p>
|
|
109
113
|
{group.slides.length} slide{group.slides.length !== 1 ? "s" : ""}
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
|
|
20
20
|
import { useBuilderStore } from "../../../lib/builder/store";
|
|
21
21
|
import type { ParallaxSlideV2, ParallaxGroup, PageSectionV2 } from "../../../lib/sanity/types";
|
|
22
|
+
import {
|
|
23
|
+
BackgroundIcon,
|
|
24
|
+
NavbarColorIcon,
|
|
25
|
+
OverlayIcon,
|
|
26
|
+
} from "../editors/section-icons";
|
|
22
27
|
import {
|
|
23
28
|
SettingsField,
|
|
24
29
|
SettingsSection,
|
|
@@ -70,7 +75,7 @@ export default function ParallaxSlideSettings({
|
|
|
70
75
|
return (
|
|
71
76
|
<>
|
|
72
77
|
{/* Background Type */}
|
|
73
|
-
<SettingsSection title="Background" defaultOpen>
|
|
78
|
+
<SettingsSection title="Background" defaultOpen icon={<BackgroundIcon />}>
|
|
74
79
|
{/* Segmented control: Image / Video */}
|
|
75
80
|
<SettingsField label="Type">
|
|
76
81
|
<div className="flex rounded-lg bg-[#f0f0f0] p-[3px]">
|
|
@@ -123,7 +128,7 @@ export default function ParallaxSlideSettings({
|
|
|
123
128
|
</SettingsSection>
|
|
124
129
|
|
|
125
130
|
{/* Navbar Color Override */}
|
|
126
|
-
<SettingsSection title="Navbar Color" defaultOpen={false}>
|
|
131
|
+
<SettingsSection title="Navbar Color" defaultOpen={false} icon={<NavbarColorIcon />}>
|
|
127
132
|
<SettingsField label="Color">
|
|
128
133
|
<div className="flex items-center gap-2">
|
|
129
134
|
<ColorSwatchPicker
|
|
@@ -147,7 +152,7 @@ export default function ParallaxSlideSettings({
|
|
|
147
152
|
</SettingsSection>
|
|
148
153
|
|
|
149
154
|
{/* Overlay */}
|
|
150
|
-
<SettingsSection title="Overlay" defaultOpen>
|
|
155
|
+
<SettingsSection title="Overlay" defaultOpen icon={<OverlayIcon />}>
|
|
151
156
|
<SettingsField label="Color">
|
|
152
157
|
<ColorSwatchPicker
|
|
153
158
|
value={overlayColor}
|
|
@@ -25,49 +25,13 @@ import ColorSwatchPicker, { usePaletteSwatches } from "../ColorSwatchPicker";
|
|
|
25
25
|
import { serializeColorField, parseColorField, isGradient } from "../../../lib/color-utils";
|
|
26
26
|
import { TRBLInputs } from "./TRBLInputs";
|
|
27
27
|
|
|
28
|
-
// ── Section title icons (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<path d="M7 10.5 L7 13" stroke="currentColor" strokeWidth="0.8" opacity="0.7" />
|
|
36
|
-
<path d="M1 7 L3.5 7" stroke="currentColor" strokeWidth="0.8" opacity="0.7" />
|
|
37
|
-
<path d="M10.5 7 L13 7" stroke="currentColor" strokeWidth="0.8" opacity="0.7" />
|
|
38
|
-
</svg>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function BackgroundSectionIcon() {
|
|
43
|
-
return (
|
|
44
|
-
<svg width={14} height={14} viewBox="0 0 14 14" fill="none">
|
|
45
|
-
<rect x="1.5" y="1.5" width="11" height="11" rx="2" fill="currentColor" opacity="0.15" />
|
|
46
|
-
<rect x="1.5" y="1.5" width="11" height="11" rx="2" stroke="currentColor" strokeWidth="0.8" opacity="0.5" fill="none" />
|
|
47
|
-
<circle cx="5" cy="5" r="1.5" fill="currentColor" opacity="0.5" />
|
|
48
|
-
<path d="M1.5 10 L5 7 L8 9 L10.5 6.5 L12.5 8.5 L12.5 11 C12.5 11.8 11.8 12.5 11 12.5 L3 12.5 C2.2 12.5 1.5 11.8 1.5 11 Z" fill="currentColor" opacity="0.3" />
|
|
49
|
-
</svg>
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function OffsetSectionIcon() {
|
|
54
|
-
return (
|
|
55
|
-
<svg width={14} height={14} viewBox="0 0 14 14" fill="none">
|
|
56
|
-
<rect x="3" y="3" width="8" height="8" rx="1" stroke="currentColor" strokeWidth="0.8" strokeDasharray="2 1" fill="none" opacity="0.35" />
|
|
57
|
-
<rect x="5" y="5" width="6" height="6" rx="1" stroke="currentColor" strokeWidth="1" fill="none" opacity="0.7" />
|
|
58
|
-
<path d="M4 4 L5 5" stroke="currentColor" strokeWidth="0.6" opacity="0.5" />
|
|
59
|
-
</svg>
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function BorderSectionIcon() {
|
|
64
|
-
return (
|
|
65
|
-
<svg width={14} height={14} viewBox="0 0 14 14" fill="none">
|
|
66
|
-
<rect x="2" y="2" width="10" height="10" rx="2" stroke="currentColor" strokeWidth="1.2" fill="none" opacity="0.6" />
|
|
67
|
-
<rect x="2" y="2" width="10" height="1.2" rx="0.5" fill="currentColor" opacity="0.7" />
|
|
68
|
-
</svg>
|
|
69
|
-
);
|
|
70
|
-
}
|
|
28
|
+
// ── Section title icons (centralized colored icons — Session 163) ──
|
|
29
|
+
import {
|
|
30
|
+
SpacingIcon,
|
|
31
|
+
OffsetIcon,
|
|
32
|
+
BackgroundIcon,
|
|
33
|
+
BorderIcon,
|
|
34
|
+
} from "../editors/section-icons";
|
|
71
35
|
|
|
72
36
|
// ── Override indicator badge (matching BlockLayoutTab pattern) ──
|
|
73
37
|
|
|
@@ -179,7 +143,7 @@ export function SectionV2LayoutTab({ section }: { section: PageSectionV2 }) {
|
|
|
179
143
|
)}
|
|
180
144
|
|
|
181
145
|
{/* Spacing (Padding) */}
|
|
182
|
-
<SettingsSection title="Spacing" defaultOpen icon={<
|
|
146
|
+
<SettingsSection title="Spacing" defaultOpen icon={<SpacingIcon />}>
|
|
183
147
|
<TRBLInputs
|
|
184
148
|
top={getSettingValue<string>("spacing_top", "0")}
|
|
185
149
|
right={getSettingValue<string>("spacing_right", "0")}
|
|
@@ -197,7 +161,7 @@ export function SectionV2LayoutTab({ section }: { section: PageSectionV2 }) {
|
|
|
197
161
|
</SettingsSection>
|
|
198
162
|
|
|
199
163
|
{/* Offset (Margin) */}
|
|
200
|
-
<SettingsSection title="Offset" icon={<
|
|
164
|
+
<SettingsSection title="Offset" icon={<OffsetIcon />}>
|
|
201
165
|
<TRBLInputs
|
|
202
166
|
top={getSettingValue<string>("offset_top", "0")}
|
|
203
167
|
right={getSettingValue<string>("offset_right", "0")}
|
|
@@ -215,7 +179,7 @@ export function SectionV2LayoutTab({ section }: { section: PageSectionV2 }) {
|
|
|
215
179
|
</SettingsSection>
|
|
216
180
|
|
|
217
181
|
{/* Background */}
|
|
218
|
-
<SettingsSection title="Background" defaultOpen icon={<
|
|
182
|
+
<SettingsSection title="Background" defaultOpen icon={<BackgroundIcon />}>
|
|
219
183
|
<SettingsField label="Color">
|
|
220
184
|
<ColorSwatchPicker
|
|
221
185
|
value={parseColorField(getSettingValue<string>("background_color", ""))}
|
|
@@ -309,7 +273,7 @@ export function SectionV2LayoutTab({ section }: { section: PageSectionV2 }) {
|
|
|
309
273
|
</SettingsSection>
|
|
310
274
|
|
|
311
275
|
{/* Border */}
|
|
312
|
-
<SettingsSection title="Border" icon={<
|
|
276
|
+
<SettingsSection title="Border" icon={<BorderIcon />}>
|
|
313
277
|
<SettingsField label="Color">
|
|
314
278
|
<ColorSwatchPicker
|
|
315
279
|
value={parseColorField(getSettingValue<string>("border_color", ""))}
|
|
@@ -50,32 +50,11 @@ const PRESETS: PresetOption[] = [
|
|
|
50
50
|
|
|
51
51
|
const CUSTOM_PRESET: PresetOption = { id: "custom", label: "Custom", cols: [], readonly: true };
|
|
52
52
|
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return (
|
|
59
|
-
<svg width={14} height={14} viewBox="0 0 14 14" fill="none">
|
|
60
|
-
<rect x="1.5" y="1.5" width="11" height="11" rx="1.5" stroke="currentColor" strokeWidth="0.8" fill="none" opacity="0.4" />
|
|
61
|
-
<line x1="6" y1="1.5" x2="6" y2="12.5" stroke="currentColor" strokeWidth="0.8" opacity="0.6" />
|
|
62
|
-
<rect x="1.5" y="1.5" width="4.5" height="11" rx="0" fill="currentColor" opacity="0.12" />
|
|
63
|
-
</svg>
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function GridGapIcon() {
|
|
68
|
-
return (
|
|
69
|
-
<svg width={14} height={14} viewBox="0 0 14 14" fill="none">
|
|
70
|
-
<rect x="1" y="1" width="5" height="5" rx="1" fill="currentColor" opacity="0.25" />
|
|
71
|
-
<rect x="8" y="1" width="5" height="5" rx="1" fill="currentColor" opacity="0.25" />
|
|
72
|
-
<rect x="1" y="8" width="5" height="5" rx="1" fill="currentColor" opacity="0.25" />
|
|
73
|
-
<rect x="8" y="8" width="5" height="5" rx="1" fill="currentColor" opacity="0.25" />
|
|
74
|
-
<line x1="7" y1="1" x2="7" y2="13" stroke="currentColor" strokeWidth="0.8" strokeDasharray="1.5 1" opacity="0.5" />
|
|
75
|
-
<line x1="1" y1="7" x2="13" y2="7" stroke="currentColor" strokeWidth="0.8" strokeDasharray="1.5 1" opacity="0.5" />
|
|
76
|
-
</svg>
|
|
77
|
-
);
|
|
78
|
-
}
|
|
53
|
+
// ── Section title icons (centralized colored icons — Session 163) ──
|
|
54
|
+
import {
|
|
55
|
+
LayoutPresetIcon,
|
|
56
|
+
GridGapsIcon,
|
|
57
|
+
} from "../editors/section-icons";
|
|
79
58
|
|
|
80
59
|
// ============================================
|
|
81
60
|
// Preset Grid Component
|
|
@@ -278,7 +257,7 @@ export default function SectionV2Settings({ section }: { section: PageSectionV2
|
|
|
278
257
|
)}
|
|
279
258
|
|
|
280
259
|
{/* Gaps */}
|
|
281
|
-
<SettingsSection title="Grid Gaps" defaultOpen icon={<
|
|
260
|
+
<SettingsSection title="Grid Gaps" defaultOpen icon={<GridGapsIcon />}>
|
|
282
261
|
<SettingsField label={
|
|
283
262
|
<span>
|
|
284
263
|
Col Gap
|
|
@@ -1,60 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Responsive helpers for
|
|
2
|
+
* Responsive helpers for setting resolution.
|
|
3
3
|
*
|
|
4
4
|
* Session 64: Extracted from SettingsPanel.tsx.
|
|
5
|
-
* Session
|
|
6
|
-
* compatible with PageSection (settings + responsive shape).
|
|
5
|
+
* Session 166: Removed V1 PageSection helpers (getRowSettingValue, hasRowSettingOverride, setRowResponsiveOverride).
|
|
7
6
|
*/
|
|
8
7
|
|
|
9
|
-
import type { PageSection } from "../../../lib/sanity/types";
|
|
10
8
|
import type { DeviceViewport } from "../../../lib/builder/types";
|
|
11
9
|
|
|
12
|
-
/**
|
|
13
|
-
* Generic shape for items with settings + responsive overrides.
|
|
14
|
-
* Compatible with PageSection (and formerly Row).
|
|
15
|
-
* Uses `unknown` to accept any settings interface without index signature issues.
|
|
16
|
-
*/
|
|
17
|
-
type SettingsItem = {
|
|
18
|
-
settings?: unknown;
|
|
19
|
-
responsive?: Record<string, Record<string, unknown>>;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
/** Get effective value for a section setting, checking viewport overrides */
|
|
23
|
-
export function getRowSettingValue<T>(item: SettingsItem, viewport: DeviceViewport, property: string, fallback: T): T {
|
|
24
|
-
if (viewport === "desktop") {
|
|
25
|
-
const val = (item.settings as Record<string, unknown> || {})[property];
|
|
26
|
-
return (val !== undefined ? val : fallback) as T;
|
|
27
|
-
}
|
|
28
|
-
const override = item.responsive?.[viewport]?.[property];
|
|
29
|
-
if (override !== undefined) return override as T;
|
|
30
|
-
const base = (item.settings as Record<string, unknown> || {})[property];
|
|
31
|
-
return (base !== undefined ? base : fallback) as T;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Check if a section setting has a responsive override */
|
|
35
|
-
export function hasRowSettingOverride(item: SettingsItem, viewport: DeviceViewport, property: string): boolean {
|
|
36
|
-
if (viewport === "desktop") return false;
|
|
37
|
-
return item.responsive?.[viewport]?.[property] !== undefined;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Set a responsive override on a section setting, returning the updated fields */
|
|
41
|
-
export function setRowResponsiveOverride(item: SettingsItem, viewport: DeviceViewport, property: string, value: unknown): Partial<PageSection> {
|
|
42
|
-
if (viewport === "desktop") {
|
|
43
|
-
return { settings: { ...(item.settings as Record<string, unknown> || {}), [property]: value } } as Partial<PageSection>;
|
|
44
|
-
}
|
|
45
|
-
const existing = item.responsive || {};
|
|
46
|
-
const vp = viewport as "tablet" | "phone";
|
|
47
|
-
const vpOverrides = { ...(existing[vp] || {}), [property]: value };
|
|
48
|
-
if (value === undefined) {
|
|
49
|
-
delete (vpOverrides as Record<string, unknown>)[property];
|
|
50
|
-
}
|
|
51
|
-
const responsive = { ...existing, [vp]: vpOverrides };
|
|
52
|
-
if (Object.keys(vpOverrides).length === 0) {
|
|
53
|
-
delete responsive[vp];
|
|
54
|
-
}
|
|
55
|
-
return { responsive: Object.keys(responsive).length ? responsive : undefined } as Partial<PageSection>;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
10
|
// ============================================
|
|
59
11
|
// Block Layout responsive helpers
|
|
60
12
|
// ============================================
|
|
@@ -11,7 +11,6 @@ import { BLOCK_GRADIENTS, BLOCK_ICON_COMPONENTS } from "../blockStyles";
|
|
|
11
11
|
import type {
|
|
12
12
|
ContentBlock,
|
|
13
13
|
ContentItem,
|
|
14
|
-
PageSection,
|
|
15
14
|
PageSectionV2,
|
|
16
15
|
CustomSectionInstance,
|
|
17
16
|
ParallaxGroup,
|
|
@@ -19,7 +18,6 @@ import type {
|
|
|
19
18
|
SectionColumn,
|
|
20
19
|
} from "../../../lib/sanity/types";
|
|
21
20
|
import {
|
|
22
|
-
isPageSection,
|
|
23
21
|
isPageSectionV2,
|
|
24
22
|
isCustomSectionInstance,
|
|
25
23
|
isParallaxGroup,
|
|
@@ -43,7 +41,6 @@ export function useSettingsPanelSelection() {
|
|
|
43
41
|
|
|
44
42
|
// Find selected elements — handle page sections, V2 sections, and parallax groups/slides
|
|
45
43
|
const selectedItem: ContentItem | undefined = store.rows.find((r) => r._key === store.selectedRowKey);
|
|
46
|
-
const selectedSection: PageSection | null = selectedItem && isPageSection(selectedItem) ? selectedItem : null;
|
|
47
44
|
const selectedSectionV2: PageSectionV2 | null = selectedItem && isPageSectionV2(selectedItem) ? selectedItem : null;
|
|
48
45
|
const selectedCustomSectionInstance: CustomSectionInstance | null = selectedItem && isCustomSectionInstance(selectedItem) ? selectedItem as CustomSectionInstance : null;
|
|
49
46
|
|
|
@@ -76,15 +73,8 @@ export function useSettingsPanelSelection() {
|
|
|
76
73
|
? effectiveSectionV2.columns.find((c) => c._key === store.selectedColumnKey) || null
|
|
77
74
|
: null;
|
|
78
75
|
|
|
79
|
-
// For PageSections, the "block" is section.block[0] — selected automatically
|
|
80
76
|
const selectedBlock: SelectedBlockInfo | null = (() => {
|
|
81
|
-
//
|
|
82
|
-
if (selectedSection) {
|
|
83
|
-
const block = selectedSection.block[0];
|
|
84
|
-
if (block) return { block, rowKey: selectedSection._key, colKey: "", isSection: true };
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
// Regular block search inside rows, V2 sections, and parallax slides
|
|
77
|
+
// Block search inside V2 sections and parallax slides
|
|
88
78
|
if (!store.selectedBlockKey) return null;
|
|
89
79
|
for (const item of store.rows) {
|
|
90
80
|
// V2 sections: search inside columns
|
|
@@ -130,8 +120,6 @@ export function useSettingsPanelSelection() {
|
|
|
130
120
|
? (selectedCustomSectionInstance.custom_section_title || "Saved Section")
|
|
131
121
|
: selectedSectionV2
|
|
132
122
|
? "Section"
|
|
133
|
-
: selectedSection
|
|
134
|
-
? (selectedSection.section_type === "projectGrid" ? "Project Grid" : "Parallax Section")
|
|
135
123
|
: "Page";
|
|
136
124
|
|
|
137
125
|
// Resolve gradient + icon component for the header
|
|
@@ -145,8 +133,6 @@ export function useSettingsPanelSelection() {
|
|
|
145
133
|
? "customSectionInstance"
|
|
146
134
|
: selectedSectionV2
|
|
147
135
|
? "row"
|
|
148
|
-
: selectedSection
|
|
149
|
-
? (selectedSection.block[0]?._type || "row")
|
|
150
136
|
: "page";
|
|
151
137
|
const headerGradient = BLOCK_GRADIENTS[headerStyleKey] || BLOCK_GRADIENTS.page;
|
|
152
138
|
const HeaderIconComponent = BLOCK_ICON_COMPONENTS[headerStyleKey];
|
|
@@ -163,7 +149,6 @@ export function useSettingsPanelSelection() {
|
|
|
163
149
|
|
|
164
150
|
return {
|
|
165
151
|
selectedItem,
|
|
166
|
-
selectedSection,
|
|
167
152
|
selectedSectionV2,
|
|
168
153
|
selectedCustomSectionInstance,
|
|
169
154
|
selectedParallaxGroup,
|