@morphika/andami 0.1.9 → 0.1.10
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/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/TextBlockRenderer.tsx +1 -1
- 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/settings-panel/BlockLayoutTab.tsx +13 -58
- package/components/builder/settings-panel/ColumnV2Settings.tsx +4 -1
- package/components/builder/settings-panel/LayoutTab.tsx +11 -47
- 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/ui/Navbar.tsx +151 -30
- package/lib/sanity/types.ts +22 -0
- package/package.json +5 -2
- package/styles/base.css +7 -3
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
SelectInput,
|
|
11
11
|
SegmentedControl,
|
|
12
12
|
RangeSlider,
|
|
13
|
-
|
|
13
|
+
CardSection,
|
|
14
|
+
Divider,
|
|
14
15
|
} from "./NavSettingsFields";
|
|
15
16
|
|
|
16
17
|
// ============================================
|
|
@@ -46,31 +47,47 @@ export default function NavMobileSettings({
|
|
|
46
47
|
[design, onChange]
|
|
47
48
|
);
|
|
48
49
|
|
|
50
|
+
// ── Icon components for card sections ──
|
|
51
|
+
const OverlayIcon = (
|
|
52
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#7c3aed" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
53
|
+
<rect x="2" y="3" width="20" height="14" rx="2" /><line x1="8" y1="21" x2="16" y2="21" /><line x1="12" y1="17" x2="12" y2="21" />
|
|
54
|
+
</svg>
|
|
55
|
+
);
|
|
56
|
+
const NavbarBarIcon = (
|
|
57
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#2563eb" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
58
|
+
<rect x="3" y="3" width="18" height="18" rx="2" /><line x1="3" y1="9" x2="21" y2="9" />
|
|
59
|
+
</svg>
|
|
60
|
+
);
|
|
61
|
+
|
|
49
62
|
return (
|
|
50
|
-
<div className="bg-white rounded-2xl overflow-hidden border border-neutral-200">
|
|
51
|
-
{/*
|
|
52
|
-
<div className="px-
|
|
53
|
-
<div
|
|
54
|
-
|
|
63
|
+
<div className="bg-white rounded-2xl overflow-hidden border border-neutral-200 flex flex-col" style={{ minHeight: "calc(100vh - 180px)" }}>
|
|
64
|
+
{/* ── Gradient header (matching Desktop panel) ── */}
|
|
65
|
+
<div className="relative flex items-center px-4 py-3.5 overflow-hidden" style={{ background: "linear-gradient(135deg, #f3e8ff 0%, #e9d5ff 40%, #ddd6fe 100%)" }}>
|
|
66
|
+
<div className="absolute inset-0 pointer-events-none" style={{ background: "linear-gradient(135deg, rgba(255,255,255,0.25) 0%, rgba(255,255,255,0.05) 100%)" }} />
|
|
67
|
+
<div className="relative shrink-0 flex items-center justify-center" style={{ width: 34, height: 34, borderRadius: 10, background: "rgba(255,255,255,0.4)", backdropFilter: "blur(8px)", boxShadow: "0 2px 8px rgba(0,0,0,0.06), inset 0 1px 0 rgba(255,255,255,0.5)" }}>
|
|
68
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="rgba(0,0,0,0.55)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
69
|
+
<rect x="5" y="2" width="14" height="20" rx="2" /><line x1="12" y1="18" x2="12.01" y2="18" />
|
|
70
|
+
</svg>
|
|
71
|
+
</div>
|
|
72
|
+
<div className="relative z-10 ml-2.5 min-w-0 flex-1">
|
|
73
|
+
<h3 className="text-[13px] font-semibold truncate" style={{ color: "rgba(0,0,0,0.72)", textShadow: "0 1px 0 rgba(255,255,255,0.3)" }}>
|
|
55
74
|
Mobile Menu
|
|
56
|
-
</
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
</
|
|
75
|
+
</h3>
|
|
76
|
+
<p className="text-[10px] mt-0.5" style={{ color: "rgba(0,0,0,0.38)" }}>
|
|
77
|
+
Independent from the desktop navbar
|
|
78
|
+
</p>
|
|
60
79
|
</div>
|
|
61
|
-
<div className="flex items-center gap-3">
|
|
80
|
+
<div className="relative z-10 flex items-center gap-3">
|
|
62
81
|
{hasChanges && (
|
|
63
|
-
<span className="text-[11px] text-amber-
|
|
64
|
-
Unsaved changes
|
|
65
|
-
</span>
|
|
82
|
+
<span className="text-[11px] text-amber-600 font-medium">Unsaved</span>
|
|
66
83
|
)}
|
|
67
84
|
<button
|
|
68
85
|
onClick={onSave}
|
|
69
86
|
disabled={saving || !hasChanges}
|
|
70
|
-
className={`px-
|
|
87
|
+
className={`px-4 py-1.5 text-[11px] font-medium rounded-lg transition-all ${
|
|
71
88
|
saving || !hasChanges
|
|
72
|
-
? "bg-
|
|
73
|
-
: "bg-[#076bff]
|
|
89
|
+
? "bg-white/40 text-neutral-400 cursor-not-allowed"
|
|
90
|
+
: "bg-white text-[#076bff] shadow-sm hover:shadow-md"
|
|
74
91
|
}`}
|
|
75
92
|
>
|
|
76
93
|
{saving ? "Saving..." : "Save"}
|
|
@@ -78,139 +95,141 @@ export default function NavMobileSettings({
|
|
|
78
95
|
</div>
|
|
79
96
|
</div>
|
|
80
97
|
|
|
81
|
-
{/* Side-by-side: settings left, preview right */}
|
|
82
|
-
<div className="flex">
|
|
98
|
+
{/* Side-by-side: settings left, preview right — flex-1 fills remaining height */}
|
|
99
|
+
<div className="flex flex-1 min-h-0">
|
|
83
100
|
{/* Settings content */}
|
|
84
|
-
<div className="flex-1 min-w-0
|
|
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
|
-
</
|
|
101
|
+
<div className="flex-1 min-w-0 py-2 border-r border-neutral-200 overflow-y-auto">
|
|
102
|
+
{/* ── Menu Overlay card ── */}
|
|
103
|
+
<CardSection title="Overlay" icon={OverlayIcon} iconBg="#ede9fe">
|
|
104
|
+
<Field label="BG">
|
|
105
|
+
<ColorSwatchPicker
|
|
106
|
+
value={design.overlay_bg || ""}
|
|
107
|
+
onChange={(v) => update({ overlay_bg: typeof v === "string" ? v : "" })}
|
|
108
|
+
swatches={swatches}
|
|
109
|
+
/>
|
|
110
|
+
</Field>
|
|
111
|
+
<Field label="Text">
|
|
112
|
+
<ColorSwatchPicker
|
|
113
|
+
value={design.text_color || ""}
|
|
114
|
+
onChange={(v) => update({ text_color: typeof v === "string" ? v : "" })}
|
|
115
|
+
swatches={swatches}
|
|
116
|
+
/>
|
|
117
|
+
</Field>
|
|
118
|
+
<Divider />
|
|
119
|
+
<Field label="Size">
|
|
120
|
+
<TextInput
|
|
121
|
+
value={design.font_size ?? 24}
|
|
122
|
+
onChange={(v) =>
|
|
123
|
+
update({
|
|
124
|
+
font_size: Math.max(12, Math.min(72, parseInt(v) || 24)),
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
type="number"
|
|
128
|
+
/>
|
|
129
|
+
</Field>
|
|
130
|
+
<Field label="Case">
|
|
131
|
+
<SelectInput
|
|
132
|
+
value={design.text_transform || "uppercase"}
|
|
133
|
+
onChange={(v) =>
|
|
134
|
+
update({
|
|
135
|
+
text_transform: v as MobileNavDesign["text_transform"],
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
options={[
|
|
139
|
+
{ value: "uppercase", label: "AA" },
|
|
140
|
+
{ value: "capitalize", label: "Aa" },
|
|
141
|
+
{ value: "lowercase", label: "aa" },
|
|
142
|
+
{ value: "none", label: "—" },
|
|
143
|
+
]}
|
|
144
|
+
/>
|
|
145
|
+
</Field>
|
|
146
|
+
<Field label="Align">
|
|
147
|
+
<SegmentedControl
|
|
148
|
+
value={design.items_align || "center"}
|
|
149
|
+
onChange={(v) =>
|
|
150
|
+
update({ items_align: v as MobileNavDesign["items_align"] })
|
|
151
|
+
}
|
|
152
|
+
options={[
|
|
153
|
+
{ value: "left", label: "Left" },
|
|
154
|
+
{ value: "center", label: "Center" },
|
|
155
|
+
{ value: "right", label: "Right" },
|
|
156
|
+
]}
|
|
157
|
+
/>
|
|
158
|
+
</Field>
|
|
159
|
+
<Divider />
|
|
160
|
+
<Field label="Gap">
|
|
161
|
+
<RangeSlider
|
|
162
|
+
value={design.items_gap ?? 32}
|
|
163
|
+
onChange={(v) => update({ items_gap: v })}
|
|
164
|
+
min={8}
|
|
165
|
+
max={80}
|
|
166
|
+
suffix="px"
|
|
167
|
+
/>
|
|
168
|
+
</Field>
|
|
169
|
+
</CardSection>
|
|
152
170
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
<RangeSlider
|
|
165
|
-
value={design.navbar_bg_opacity ?? 100}
|
|
166
|
-
onChange={(v) => update({ navbar_bg_opacity: v })}
|
|
167
|
-
min={0}
|
|
168
|
-
max={100}
|
|
169
|
-
suffix="%"
|
|
170
|
-
/>
|
|
171
|
-
</Field>
|
|
172
|
-
)}
|
|
173
|
-
<Field label="Icon color">
|
|
174
|
-
<ColorSwatchPicker
|
|
175
|
-
value={design.hamburger_color || ""}
|
|
176
|
-
onChange={(v) => update({ hamburger_color: typeof v === "string" ? v : "" })}
|
|
177
|
-
swatches={swatches}
|
|
178
|
-
/>
|
|
179
|
-
</Field>
|
|
180
|
-
<Field label="Pad H">
|
|
171
|
+
{/* ── Navbar Bar card ── */}
|
|
172
|
+
<CardSection title="Top Bar" icon={NavbarBarIcon} iconBg="#dbeafe">
|
|
173
|
+
<Field label="BG">
|
|
174
|
+
<ColorSwatchPicker
|
|
175
|
+
value={design.navbar_bg || ""}
|
|
176
|
+
onChange={(v) => update({ navbar_bg: typeof v === "string" ? v : "" })}
|
|
177
|
+
swatches={swatches}
|
|
178
|
+
/>
|
|
179
|
+
</Field>
|
|
180
|
+
{design.navbar_bg && (
|
|
181
|
+
<Field label="Opacity">
|
|
181
182
|
<RangeSlider
|
|
182
|
-
value={design.
|
|
183
|
-
onChange={(v) => update({
|
|
183
|
+
value={design.navbar_bg_opacity ?? 100}
|
|
184
|
+
onChange={(v) => update({ navbar_bg_opacity: v })}
|
|
184
185
|
min={0}
|
|
185
|
-
max={
|
|
186
|
-
suffix="
|
|
186
|
+
max={100}
|
|
187
|
+
suffix="%"
|
|
187
188
|
/>
|
|
188
189
|
</Field>
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
190
|
+
)}
|
|
191
|
+
<Field label="Icon">
|
|
192
|
+
<ColorSwatchPicker
|
|
193
|
+
value={design.hamburger_color || ""}
|
|
194
|
+
onChange={(v) => update({ hamburger_color: typeof v === "string" ? v : "" })}
|
|
195
|
+
swatches={swatches}
|
|
196
|
+
/>
|
|
197
|
+
</Field>
|
|
198
|
+
<Divider />
|
|
199
|
+
<Field label="Pad H">
|
|
200
|
+
<RangeSlider
|
|
201
|
+
value={design.padding_h ?? 24}
|
|
202
|
+
onChange={(v) => update({ padding_h: v })}
|
|
203
|
+
min={0}
|
|
204
|
+
max={60}
|
|
205
|
+
suffix="px"
|
|
206
|
+
/>
|
|
207
|
+
</Field>
|
|
208
|
+
<Field label="Pad V">
|
|
209
|
+
<RangeSlider
|
|
210
|
+
value={design.padding_v ?? 27}
|
|
211
|
+
onChange={(v) => update({ padding_v: v })}
|
|
212
|
+
min={0}
|
|
213
|
+
max={60}
|
|
214
|
+
suffix="px"
|
|
215
|
+
/>
|
|
216
|
+
</Field>
|
|
217
|
+
</CardSection>
|
|
199
218
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
</p>
|
|
208
|
-
</div>
|
|
219
|
+
{/* Info notice — card style */}
|
|
220
|
+
<div className="mx-2.5 my-1 px-3 py-2.5 bg-blue-50/60 rounded-[10px] border border-blue-100">
|
|
221
|
+
<p className="text-[10px] text-blue-500 leading-relaxed">
|
|
222
|
+
<strong>Independent from page overrides.</strong> Page-level{" "}
|
|
223
|
+
<code className="bg-blue-100 px-1 rounded text-[9px]">nav_color</code>{" "}
|
|
224
|
+
and parallax color changes only affect the desktop navbar.
|
|
225
|
+
</p>
|
|
209
226
|
</div>
|
|
227
|
+
|
|
228
|
+
<div className="h-2" />
|
|
210
229
|
</div>
|
|
211
230
|
|
|
212
|
-
{/* Live preview —
|
|
213
|
-
<div className="w-[340px] shrink-0
|
|
231
|
+
{/* Live preview — stretches full height */}
|
|
232
|
+
<div className="w-[340px] shrink-0 sticky top-0 self-stretch">
|
|
214
233
|
<NavMobileLivePreview
|
|
215
234
|
items={items}
|
|
216
235
|
design={desktopDesign}
|