@morphika/andami 0.1.8 → 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.
Files changed (49) hide show
  1. package/README.md +3 -0
  2. package/components/admin/nav-builder/NavBuilder.tsx +90 -14
  3. package/components/admin/nav-builder/NavGeneralSettings.tsx +521 -271
  4. package/components/admin/nav-builder/NavItemSettings.tsx +331 -312
  5. package/components/admin/nav-builder/NavMobileSettings.tsx +159 -140
  6. package/components/admin/nav-builder/NavSettingsFields.tsx +287 -21
  7. package/components/admin/nav-builder/NavSettingsPanel.tsx +137 -127
  8. package/components/blocks/TextBlockRenderer.tsx +1 -1
  9. package/components/builder/SettingsPanel.tsx +29 -543
  10. package/components/builder/editors/ButtonBlockEditor.tsx +8 -3
  11. package/components/builder/editors/CoverBlockEditor.tsx +14 -6
  12. package/components/builder/editors/ImageBlockEditor.tsx +8 -3
  13. package/components/builder/editors/ImageGridBlockEditor.tsx +8 -3
  14. package/components/builder/editors/ProjectGridEditor.tsx +7 -46
  15. package/components/builder/editors/SpacerBlockEditor.tsx +4 -1
  16. package/components/builder/editors/StaggerSettings.tsx +2 -1
  17. package/components/builder/editors/TextBlockEditor.tsx +8 -3
  18. package/components/builder/editors/VideoBlockEditor.tsx +10 -4
  19. package/components/builder/editors/section-icons.tsx +492 -0
  20. package/components/builder/editors/shared.tsx +23 -4
  21. package/components/builder/live-preview/GhostCard.tsx +84 -0
  22. package/components/builder/live-preview/LiveProjectGridPreview.tsx +294 -1010
  23. package/components/builder/live-preview/LiveTextEditor.tsx +1 -1
  24. package/components/builder/live-preview/ProjectCardWrapper.tsx +291 -0
  25. package/components/builder/live-preview/drag-utils.tsx +89 -0
  26. package/components/builder/live-preview/useDragReorder.ts +370 -0
  27. package/components/builder/settings-panel/AnimationTab.tsx +152 -0
  28. package/components/builder/settings-panel/BlockLayoutTab.tsx +13 -58
  29. package/components/builder/settings-panel/CardEntranceSection.tsx +114 -0
  30. package/components/builder/settings-panel/ColumnV2AnimationTab.tsx +32 -0
  31. package/components/builder/settings-panel/ColumnV2Settings.tsx +4 -1
  32. package/components/builder/settings-panel/CustomSectionSettings.tsx +150 -0
  33. package/components/builder/settings-panel/LayoutTab.tsx +11 -47
  34. package/components/builder/settings-panel/PageSettings.tsx +10 -4
  35. package/components/builder/settings-panel/ParallaxGroupSettings.tsx +6 -2
  36. package/components/builder/settings-panel/ParallaxSlideSettings.tsx +8 -3
  37. package/components/builder/settings-panel/SectionV2LayoutTab.tsx +11 -47
  38. package/components/builder/settings-panel/SectionV2Settings.tsx +6 -27
  39. package/components/builder/settings-panel/index.ts +6 -0
  40. package/components/builder/settings-panel/useSettingsPanelSelection.ts +184 -0
  41. package/components/ui/Navbar.tsx +151 -30
  42. package/lib/builder/serializer/migrations.ts +107 -0
  43. package/lib/builder/serializer/normalizers.ts +278 -0
  44. package/lib/builder/serializer/serializers.ts +393 -0
  45. package/lib/builder/serializer/shared.ts +102 -0
  46. package/lib/builder/serializer.ts +11 -846
  47. package/lib/sanity/types.ts +22 -0
  48. package/package.json +13 -10
  49. package/styles/base.css +7 -3
@@ -3,6 +3,14 @@
3
3
  import { useBuilderStore } from "../../../lib/builder/store";
4
4
  import { getEffectiveValue, setResponsiveOverride } from "../../../lib/builder/responsive";
5
5
  import type { CoverBlock, ContentBlock } from "../../../lib/sanity/types";
6
+ import {
7
+ ContentIcon,
8
+ CTAButtonIcon,
9
+ CoverBackgroundIcon,
10
+ CoverEffectsIcon,
11
+ LayoutIcon,
12
+ AppearanceIcon,
13
+ } from "./section-icons";
6
14
  import {
7
15
  SettingsField,
8
16
  SettingsSection,
@@ -190,7 +198,7 @@ export default function CoverBlockEditor({ block }: Props) {
190
198
  <ViewportBadge />
191
199
 
192
200
  {/* ========== CONTENT ========== */}
193
- <SettingsSection title="Content" defaultOpen>
201
+ <SettingsSection title="Content" defaultOpen icon={<ContentIcon />}>
194
202
  <SettingsField label="Headline">
195
203
  <StyledInput
196
204
  value={block.headline || ""}
@@ -211,7 +219,7 @@ export default function CoverBlockEditor({ block }: Props) {
211
219
  </SettingsSection>
212
220
 
213
221
  {/* ========== CTA BUTTON ========== */}
214
- <SettingsSection title="CTA Button">
222
+ <SettingsSection title="CTA Button" icon={<CTAButtonIcon />}>
215
223
  <SettingsField label="Button Text">
216
224
  <StyledInput
217
225
  value={cta.text || ""}
@@ -264,7 +272,7 @@ export default function CoverBlockEditor({ block }: Props) {
264
272
  </SettingsSection>
265
273
 
266
274
  {/* ========== MEDIA BACKGROUND ========== */}
267
- <SettingsSection title="Cover Background" defaultOpen>
275
+ <SettingsSection title="Cover Background" defaultOpen icon={<CoverBackgroundIcon />}>
268
276
  <SettingsField label="Media Type">
269
277
  <div className="flex gap-1">
270
278
  {(["image", "video"] as const).map((t) => (
@@ -355,7 +363,7 @@ export default function CoverBlockEditor({ block }: Props) {
355
363
  </SettingsSection>
356
364
 
357
365
  {/* ========== OVERLAY ========== */}
358
- <SettingsSection title="Cover Effects">
366
+ <SettingsSection title="Cover Effects" icon={<CoverEffectsIcon />}>
359
367
  {/* Toggle: Custom gradient vs Preset overlay */}
360
368
  <SettingsField label="Overlay Mode">
361
369
  <div className="flex gap-1">
@@ -448,7 +456,7 @@ export default function CoverBlockEditor({ block }: Props) {
448
456
  </SettingsSection>
449
457
 
450
458
  {/* ========== LAYOUT ========== */}
451
- <SettingsSection title="Layout">
459
+ <SettingsSection title="Layout" icon={<LayoutIcon />}>
452
460
  <ResponsiveField
453
461
  label="Content Pos"
454
462
  block={block as ContentBlock}
@@ -522,7 +530,7 @@ export default function CoverBlockEditor({ block }: Props) {
522
530
  </SettingsSection>
523
531
 
524
532
  {/* ========== APPEARANCE ========== */}
525
- <SettingsSection title="Appearance">
533
+ <SettingsSection title="Appearance" icon={<AppearanceIcon />}>
526
534
  <SettingsField label="Text Color">
527
535
  <ColorSwatchPicker
528
536
  value={block.text_color || ""}
@@ -3,6 +3,11 @@
3
3
  import { useBuilderStore } from "../../../lib/builder/store";
4
4
  import { getEffectiveValue, setResponsiveOverride } from "../../../lib/builder/responsive";
5
5
  import type { ImageBlock, ContentBlock } from "../../../lib/sanity/types";
6
+ import {
7
+ SourceIcon,
8
+ LayoutIcon,
9
+ AppearanceIcon,
10
+ } from "./section-icons";
6
11
  import {
7
12
  SettingsField,
8
13
  SettingsSection,
@@ -61,7 +66,7 @@ export default function ImageBlockEditor({ block }: Props) {
61
66
  <>
62
67
  <ViewportBadge />
63
68
 
64
- <SettingsSection title="Source" defaultOpen>
69
+ <SettingsSection title="Source" defaultOpen icon={<SourceIcon />}>
65
70
  <SettingsField label="Asset Path" hint="Relative path from seed URL">
66
71
  <AssetPathInput
67
72
  value={block.asset_path || ""}
@@ -95,7 +100,7 @@ export default function ImageBlockEditor({ block }: Props) {
95
100
  </SettingsField>
96
101
  </SettingsSection>
97
102
 
98
- <SettingsSection title="Layout">
103
+ <SettingsSection title="Layout" icon={<LayoutIcon />}>
99
104
  <ResponsiveField
100
105
  label="Width"
101
106
  block={block}
@@ -147,7 +152,7 @@ export default function ImageBlockEditor({ block }: Props) {
147
152
  </ResponsiveField>
148
153
  </SettingsSection>
149
154
 
150
- <SettingsSection title="Appearance">
155
+ <SettingsSection title="Appearance" icon={<AppearanceIcon />}>
151
156
  <ResponsiveField
152
157
  label="Border Radius"
153
158
  block={block}
@@ -5,6 +5,11 @@ import { useBuilderStore } from "../../../lib/builder/store";
5
5
  import { getEffectiveValue, setResponsiveOverride } from "../../../lib/builder/responsive";
6
6
  import type { ImageGridBlock, ContentBlock } from "../../../lib/sanity/types";
7
7
  import AssetBrowser from "../AssetBrowser";
8
+ import {
9
+ ImagesIcon,
10
+ SettingsIcon,
11
+ AppearanceIcon,
12
+ } from "./section-icons";
8
13
  import {
9
14
  SettingsField,
10
15
  SettingsSection,
@@ -158,7 +163,7 @@ export default function ImageGridBlockEditor({ block }: Props) {
158
163
  <ViewportBadge />
159
164
 
160
165
  {/* ====== Images Section ====== */}
161
- <SettingsSection title="Images" defaultOpen>
166
+ <SettingsSection title="Images" defaultOpen icon={<ImagesIcon />}>
162
167
  {/* Thumbnail grid preview */}
163
168
  {images.length > 0 && (
164
169
  <div className="grid grid-cols-4 gap-1.5 mb-3">
@@ -209,7 +214,7 @@ export default function ImageGridBlockEditor({ block }: Props) {
209
214
  </SettingsSection>
210
215
 
211
216
  {/* ====== Settings Section ====== */}
212
- <SettingsSection title="Settings" defaultOpen>
217
+ <SettingsSection title="Settings" defaultOpen icon={<SettingsIcon />}>
213
218
  {/* H-Gutter & V-Gutter side by side */}
214
219
  <div className="flex gap-3">
215
220
  <ResponsiveField
@@ -336,7 +341,7 @@ export default function ImageGridBlockEditor({ block }: Props) {
336
341
  </SettingsSection>
337
342
 
338
343
  {/* ====== Appearance Section ====== */}
339
- <SettingsSection title="Appearance">
344
+ <SettingsSection title="Appearance" icon={<AppearanceIcon />}>
340
345
  <ResponsiveField
341
346
  label="Object Fit"
342
347
  block={block}
@@ -232,52 +232,13 @@ function CardRatioChips({
232
232
  );
233
233
  }
234
234
 
235
- // ============================================
236
- // Section title icons (small, inline — matching BlockLayoutTab)
237
- // ============================================
238
-
239
- function GridSectionIcon() {
240
- return (
241
- <svg width={14} height={14} viewBox="0 0 14 14" fill="none">
242
- <rect x="1.5" y="1.5" width="4.5" height="4.5" rx="1" stroke="currentColor" strokeWidth="0.8" fill="none" opacity="0.6" />
243
- <rect x="8" y="1.5" width="4.5" height="4.5" rx="1" stroke="currentColor" strokeWidth="0.8" fill="none" opacity="0.6" />
244
- <rect x="1.5" y="8" width="4.5" height="4.5" rx="1" stroke="currentColor" strokeWidth="0.8" fill="none" opacity="0.6" />
245
- <rect x="8" y="8" width="4.5" height="4.5" rx="1" stroke="currentColor" strokeWidth="0.8" fill="none" opacity="0.6" />
246
- </svg>
247
- );
248
- }
249
-
250
- function AppearanceSectionIcon() {
251
- return (
252
- <svg width={14} height={14} viewBox="0 0 14 14" fill="none">
253
- <circle cx="7" cy="7" r="5" stroke="currentColor" strokeWidth="0.8" fill="none" opacity="0.5" />
254
- <path d="M7 2 A5 5 0 0 1 7 12 Z" fill="currentColor" opacity="0.3" />
255
- <circle cx="7" cy="7" r="1.5" fill="currentColor" opacity="0.6" />
256
- </svg>
257
- );
258
- }
259
-
260
- function VideoSectionIcon() {
261
- return (
262
- <svg width={14} height={14} viewBox="0 0 14 14" fill="none">
263
- <rect x="1.5" y="3" width="8" height="8" rx="1.5" stroke="currentColor" strokeWidth="0.8" fill="none" opacity="0.5" />
264
- <path d="M10 6 L12.5 4.5 L12.5 9.5 L10 8 Z" fill="currentColor" opacity="0.5" />
265
- </svg>
266
- );
267
- }
268
-
269
- function ProjectsSectionIcon() {
270
- return (
271
- <svg width={14} height={14} viewBox="0 0 14 14" fill="none">
272
- <rect x="1.5" y="2" width="11" height="3" rx="1" stroke="currentColor" strokeWidth="0.8" fill="none" opacity="0.5" />
273
- <rect x="1.5" y="7" width="11" height="3" rx="1" stroke="currentColor" strokeWidth="0.8" fill="none" opacity="0.5" />
274
- <circle cx="4" cy="3.5" r="0.8" fill="currentColor" opacity="0.6" />
275
- <circle cx="4" cy="8.5" r="0.8" fill="currentColor" opacity="0.6" />
276
- <rect x="6" y="3" width="4" height="1" rx="0.5" fill="currentColor" opacity="0.4" />
277
- <rect x="6" y="8" width="4" height="1" rx="0.5" fill="currentColor" opacity="0.4" />
278
- </svg>
279
- );
280
- }
235
+ // ── Section title icons (centralized colored icons — Session 163) ──
236
+ import {
237
+ GridIcon as GridSectionIcon,
238
+ AppearanceIcon as AppearanceSectionIcon,
239
+ VideoIcon as VideoSectionIcon,
240
+ ProjectsIcon as ProjectsSectionIcon,
241
+ } from "./section-icons";
281
242
 
282
243
  // ============================================
283
244
  // Main Editor
@@ -3,6 +3,9 @@
3
3
  import { useBuilderStore } from "../../../lib/builder/store";
4
4
  import { getEffectiveValue, setResponsiveOverride } from "../../../lib/builder/responsive";
5
5
  import type { SpacerBlock, ContentBlock } from "../../../lib/sanity/types";
6
+ import {
7
+ HeightIcon,
8
+ } from "./section-icons";
6
9
  import {
7
10
  SettingsField,
8
11
  SettingsSection,
@@ -68,7 +71,7 @@ export default function SpacerBlockEditor({ block }: Props) {
68
71
  <>
69
72
  <ViewportBadge />
70
73
 
71
- <SettingsSection title="Height" defaultOpen>
74
+ <SettingsSection title="Height" defaultOpen icon={<HeightIcon />}>
72
75
  <ResponsiveField
73
76
  label="Preset"
74
77
  block={block}
@@ -1,3 +1,4 @@
1
+ import { StaggerIcon } from "./section-icons";
1
2
  import { SettingsSection, SettingsField } from "./shared";
2
3
 
3
4
  // ============================================
@@ -39,7 +40,7 @@ export default function StaggerSettings({
39
40
  const direction = stagger?.direction ?? "left-to-right";
40
41
 
41
42
  return (
42
- <SettingsSection title="Stagger Children">
43
+ <SettingsSection title="Stagger Children" icon={<StaggerIcon />}>
43
44
  <div className="space-y-3">
44
45
  {/* Enable toggle */}
45
46
  <div className="flex items-center justify-between">
@@ -5,6 +5,11 @@ import { useBuilderStore } from "../../../lib/builder/store";
5
5
  import { getEffectiveValue, setResponsiveOverride } from "../../../lib/builder/responsive";
6
6
  import type { TextBlock, ContentBlock } from "../../../lib/sanity/types";
7
7
  import type { DeviceViewport } from "../../../lib/builder/types";
8
+ import {
9
+ TextIcon,
10
+ TypographyIcon,
11
+ ColumnsIcon,
12
+ } from "./section-icons";
8
13
  import {
9
14
  SettingsSection,
10
15
  SettingsField,
@@ -267,7 +272,7 @@ export default function TextBlockEditor({ block }: { block: TextBlock }) {
267
272
  <ViewportBadge />
268
273
 
269
274
  {/* Text section: Style, Color, Align */}
270
- <SettingsSection title="Text" defaultOpen>
275
+ <SettingsSection title="Text" defaultOpen icon={<TextIcon />}>
271
276
  <SettingsField label="Style">
272
277
  <TextStylePicker
273
278
  presets={presets}
@@ -307,7 +312,7 @@ export default function TextBlockEditor({ block }: { block: TextBlock }) {
307
312
  </SettingsSection>
308
313
 
309
314
  {/* Typography section: Size, Weight, Line height, Letter spacing */}
310
- <SettingsSection title="Typography" defaultOpen>
315
+ <SettingsSection title="Typography" defaultOpen icon={<TypographyIcon />}>
311
316
  <ResponsiveStyleField label="Size" subProp="fontSize" viewport={viewport} isOverridden={viewport !== "desktop" && hasStyleOverride("fontSize")} onReset={resetStyleOverride}>
312
317
  <div className="flex items-center gap-0 bg-[#f5f5f5] rounded-lg overflow-hidden transition-all border border-transparent focus-within:bg-white focus-within:border-[#076bff] focus-within:shadow-[0_0_0_3px_rgba(7,107,255,0.06)]">
313
318
  <input
@@ -401,7 +406,7 @@ export default function TextBlockEditor({ block }: { block: TextBlock }) {
401
406
  </SettingsSection>
402
407
 
403
408
  {/* Columns section */}
404
- <SettingsSection title="Columns">
409
+ <SettingsSection title="Columns" icon={<ColumnsIcon />}>
405
410
  <ResponsiveField
406
411
  label="Columns"
407
412
  block={block as ContentBlock}
@@ -3,6 +3,12 @@
3
3
  import { useBuilderStore } from "../../../lib/builder/store";
4
4
  import { getEffectiveValue, setResponsiveOverride } from "../../../lib/builder/responsive";
5
5
  import type { VideoBlock, ContentBlock } from "../../../lib/sanity/types";
6
+ import {
7
+ SourceIcon,
8
+ LayoutIcon,
9
+ AppearanceIcon,
10
+ PlaybackIcon,
11
+ } from "./section-icons";
6
12
  import {
7
13
  SettingsField,
8
14
  SettingsSection,
@@ -89,7 +95,7 @@ export default function VideoBlockEditor({ block }: Props) {
89
95
  <>
90
96
  <ViewportBadge />
91
97
 
92
- <SettingsSection title="Source" defaultOpen>
98
+ <SettingsSection title="Source" defaultOpen icon={<SourceIcon />}>
93
99
  <SettingsField label="Video Type">
94
100
  <div className="flex gap-1">
95
101
  {(
@@ -174,7 +180,7 @@ export default function VideoBlockEditor({ block }: Props) {
174
180
  </SettingsField>
175
181
  </SettingsSection>
176
182
 
177
- <SettingsSection title="Layout">
183
+ <SettingsSection title="Layout" icon={<LayoutIcon />}>
178
184
  <ResponsiveField
179
185
  label="Width"
180
186
  block={block as ContentBlock}
@@ -224,7 +230,7 @@ export default function VideoBlockEditor({ block }: Props) {
224
230
  </ResponsiveField>
225
231
  </SettingsSection>
226
232
 
227
- <SettingsSection title="Appearance">
233
+ <SettingsSection title="Appearance" icon={<AppearanceIcon />}>
228
234
  <ResponsiveField
229
235
  label="Border Radius"
230
236
  block={block as ContentBlock}
@@ -249,7 +255,7 @@ export default function VideoBlockEditor({ block }: Props) {
249
255
  </ResponsiveField>
250
256
  </SettingsSection>
251
257
 
252
- <SettingsSection title="Playback">
258
+ <SettingsSection title="Playback" icon={<PlaybackIcon />}>
253
259
  <div className="space-y-1.5">
254
260
  <StyledCheckbox
255
261
  label="Autoplay"