@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.
Files changed (117) hide show
  1. package/app/admin/assets/page.tsx +6 -6
  2. package/app/admin/database/page.tsx +302 -302
  3. package/app/admin/error.tsx +53 -53
  4. package/app/admin/layout.tsx +320 -320
  5. package/app/admin/navigation/page.tsx +255 -255
  6. package/app/admin/pages/[slug]/page.tsx +6 -6
  7. package/app/admin/pages/page.tsx +11 -11
  8. package/app/admin/projects/page.tsx +14 -14
  9. package/app/admin/setup/page.tsx +1 -1
  10. package/app/admin/styles/page.tsx +1 -1
  11. package/components/admin/MetadataEditor.tsx +6 -6
  12. package/components/admin/nav-builder/NavBuilder.tsx +1 -1
  13. package/components/admin/nav-builder/NavBuilderGrid.tsx +3 -3
  14. package/components/admin/nav-builder/NavGridCell.tsx +48 -48
  15. package/components/admin/nav-builder/NavGridItem.tsx +4 -4
  16. package/components/admin/nav-builder/NavItemSettings.tsx +331 -331
  17. package/components/admin/nav-builder/NavItemTypePicker.tsx +102 -102
  18. package/components/admin/nav-builder/NavLivePreview.tsx +1 -1
  19. package/components/admin/nav-builder/NavMobileLivePreview.tsx +226 -226
  20. package/components/admin/nav-builder/NavMobileSettings.tsx +242 -242
  21. package/components/admin/nav-builder/NavSettingsFields.tsx +514 -514
  22. package/components/admin/setup-wizard/BrandingStep.tsx +3 -3
  23. package/components/admin/setup-wizard/DatabaseStep.tsx +2 -2
  24. package/components/admin/setup-wizard/DoneStep.tsx +1 -1
  25. package/components/admin/setup-wizard/SetupWizard.tsx +4 -4
  26. package/components/admin/setup-wizard/StorageStep.tsx +2 -2
  27. package/components/admin/setup-wizard/WelcomeStep.tsx +2 -2
  28. package/components/admin/styles/ColorsEditor.tsx +2 -2
  29. package/components/admin/styles/FontsEditor.tsx +6 -6
  30. package/components/admin/styles/GridLayoutEditor.tsx +9 -9
  31. package/components/admin/styles/LinksButtonsEditor.tsx +5 -5
  32. package/components/admin/styles/TypographyEditor.tsx +6 -6
  33. package/components/admin/styles/shared.tsx +68 -68
  34. package/components/blocks/AudioBlockRenderer.tsx +286 -286
  35. package/components/blocks/MarqueeBlockRenderer.tsx +316 -0
  36. package/components/blocks/ProjectCarouselBlockRenderer.tsx +1 -1
  37. package/components/builder/BlockCardIcons.tsx +316 -316
  38. package/components/builder/BlockTypePicker.tsx +1 -1
  39. package/components/builder/BubbleIcons.tsx +90 -0
  40. package/components/builder/BuilderCanvas.tsx +2 -0
  41. package/components/builder/CanvasMinimap.tsx +2 -2
  42. package/components/builder/CoverSectionCanvas.tsx +363 -363
  43. package/components/builder/DeviceFrame.tsx +1 -1
  44. package/components/builder/DndWrapper.tsx +3 -3
  45. package/components/builder/InsertionLines.tsx +1 -1
  46. package/components/builder/SectionCardIcons.tsx +421 -320
  47. package/components/builder/SectionEditorBar.tsx +1 -1
  48. package/components/builder/SectionTypePicker.tsx +4 -4
  49. package/components/builder/SectionV2Canvas.tsx +1 -1
  50. package/components/builder/SectionV2Column.tsx +69 -67
  51. package/components/builder/SortableBlock.tsx +93 -73
  52. package/components/builder/SortableRow.tsx +27 -26
  53. package/components/builder/VirtualAssetGrid.tsx +2 -2
  54. package/components/builder/asset-browser/R2BrowserContent.tsx +11 -11
  55. package/components/builder/blockStyles.tsx +192 -185
  56. package/components/builder/color-picker/AlphaSlider.tsx +141 -141
  57. package/components/builder/color-picker/ColorInputs.tsx +105 -105
  58. package/components/builder/color-picker/EyedropperButton.tsx +74 -74
  59. package/components/builder/color-picker/HueSlider.tsx +124 -124
  60. package/components/builder/color-picker/SaturationCanvas.tsx +142 -142
  61. package/components/builder/color-picker/SwatchBar.tsx +93 -93
  62. package/components/builder/editors/AudioBlockEditor.tsx +242 -242
  63. package/components/builder/editors/BeforeAfterBlockEditor.tsx +360 -360
  64. package/components/builder/editors/ButtonBlockEditor.tsx +4 -4
  65. package/components/builder/editors/EnterAnimationPicker.tsx +2 -2
  66. package/components/builder/editors/HoverEffectPicker.tsx +2 -2
  67. package/components/builder/editors/ImageBlockEditor.tsx +2 -2
  68. package/components/builder/editors/ImageGridBlockEditor.tsx +4 -4
  69. package/components/builder/editors/MarqueeBlockEditor.tsx +621 -0
  70. package/components/builder/editors/ProjectCarouselBlockEditor.tsx +443 -443
  71. package/components/builder/editors/ProjectGridEditor.tsx +9 -9
  72. package/components/builder/editors/SpacerBlockEditor.tsx +5 -5
  73. package/components/builder/editors/StaggerSettings.tsx +109 -109
  74. package/components/builder/editors/TextBlockEditor.tsx +3 -3
  75. package/components/builder/editors/TextStylePicker.tsx +1 -1
  76. package/components/builder/editors/VideoBlockEditor.tsx +2 -2
  77. package/components/builder/editors/index.ts +11 -10
  78. package/components/builder/editors/shared.tsx +6 -6
  79. package/components/builder/live-preview/LiveAudioPreview.tsx +120 -120
  80. package/components/builder/live-preview/LiveBeforeAfterPreview.tsx +1 -1
  81. package/components/builder/live-preview/LiveImageGridPreview.tsx +10 -2
  82. package/components/builder/live-preview/LiveImagePreview.tsx +1 -1
  83. package/components/builder/live-preview/LiveMarqueePreview.tsx +39 -0
  84. package/components/builder/live-preview/LiveProjectCarouselPreview.tsx +1 -1
  85. package/components/builder/live-preview/LiveVideoPreview.tsx +1 -1
  86. package/components/builder/live-preview/ProjectCardWrapper.tsx +291 -291
  87. package/components/builder/settings-panel/AnimationTab.tsx +138 -138
  88. package/components/builder/settings-panel/BlockLayoutTab.tsx +7 -7
  89. package/components/builder/settings-panel/CardEntranceSection.tsx +114 -114
  90. package/components/builder/settings-panel/ColumnV2Settings.tsx +5 -5
  91. package/components/builder/settings-panel/CoverSectionLayoutTab.tsx +71 -71
  92. package/components/builder/settings-panel/CoverSectionSettings.tsx +335 -335
  93. package/components/builder/settings-panel/PageSettings.tsx +3 -3
  94. package/components/builder/settings-panel/ParallaxSlideSettings.tsx +2 -2
  95. package/components/builder/settings-panel/SectionV2AnimationTab.tsx +4 -4
  96. package/components/builder/settings-panel/SectionV2LayoutTab.tsx +356 -356
  97. package/components/builder/settings-panel/SectionV2Settings.tsx +14 -14
  98. package/components/builder/settings-panel/TRBLInputs.tsx +1 -1
  99. package/lib/animation/enter-types.ts +1 -0
  100. package/lib/animation/hover-effect-presets.ts +210 -210
  101. package/lib/animation/hover-effect-types.ts +1 -0
  102. package/lib/builder/block-registrations.ts +468 -417
  103. package/lib/builder/constants.ts +111 -111
  104. package/lib/builder/store-sections.ts +2 -2
  105. package/lib/builder/types-slices.ts +414 -414
  106. package/lib/builder/types.ts +4 -1
  107. package/lib/config/index.ts +27 -27
  108. package/lib/sanity/types.ts +98 -1
  109. package/lib/version.ts +1 -1
  110. package/package.json +1 -1
  111. package/sanity/schemas/blocks/audioBlock.ts +69 -69
  112. package/sanity/schemas/blocks/index.ts +12 -11
  113. package/sanity/schemas/blocks/marqueeBlock.ts +292 -0
  114. package/sanity/schemas/index.ts +120 -117
  115. package/styles/admin.css +85 -85
  116. package/styles/animations.css +237 -237
  117. package/styles/base.css +114 -114
@@ -72,7 +72,7 @@ function SegmentedControl<T extends string>({
72
72
  onClick={() => onChange(opt.value)}
73
73
  className={`flex-1 px-2 py-1.5 text-xs rounded transition-colors ${
74
74
  active
75
- ? "bg-[#076bff] text-white"
75
+ ? "bg-[#3580f9] text-white"
76
76
  : "bg-neutral-100 text-neutral-600 hover:bg-neutral-200"
77
77
  }`}
78
78
  >
@@ -112,7 +112,7 @@ function RangeSlider({
112
112
  step={step}
113
113
  value={value}
114
114
  onChange={(e) => onChange(Number(e.target.value))}
115
- className="flex-1 h-1 accent-[#076bff] cursor-pointer"
115
+ className="flex-1 h-1 accent-[#3580f9] cursor-pointer"
116
116
  />
117
117
  <span className="text-[11px] text-neutral-500 w-8 text-right tabular-nums shrink-0">
118
118
  {value}{suffix}
@@ -154,7 +154,7 @@ function RatioChips({
154
154
  onClick={() => toggle(opt.value)}
155
155
  className={`flex-1 flex flex-col items-center gap-1 px-1.5 py-2 rounded-lg text-[10px] transition-colors ${
156
156
  active
157
- ? "bg-[#076bff] text-white"
157
+ ? "bg-[#3580f9] text-white"
158
158
  : "bg-neutral-100 text-neutral-500 hover:bg-neutral-200"
159
159
  }`}
160
160
  >
@@ -206,7 +206,7 @@ function CardRatioChips({
206
206
  onClick={() => onChange(opt.value as "16/9" | "1/1" | "9/16" | null)}
207
207
  className={`flex flex-col items-center gap-1 px-1.5 py-2 rounded-lg text-[10px] transition-colors ${
208
208
  active
209
- ? "bg-[#076bff] text-white"
209
+ ? "bg-[#3580f9] text-white"
210
210
  : "bg-neutral-100 text-neutral-500 hover:bg-neutral-200"
211
211
  }`}
212
212
  >
@@ -511,7 +511,7 @@ export default function ProjectGridEditor({ block }: ProjectGridEditorProps) {
511
511
  <React.Fragment key={item._key}>
512
512
  <div
513
513
  className={`flex items-center gap-2 px-2 py-1.5 group cursor-pointer transition-colors ${
514
- isCardSelected ? "bg-[#076bff]/10 ring-1 ring-[#076bff]/30 rounded-t-lg" : "bg-[#f5f5f5] hover:bg-[#efefef] rounded-lg"
514
+ isCardSelected ? "bg-[#3580f9]/10 ring-1 ring-[#3580f9]/30 rounded-t-lg" : "bg-[#f5f5f5] hover:bg-[#efefef] rounded-lg"
515
515
  }`}
516
516
  onClick={() => selectProjectCard(isCardSelected ? null : item._key)}
517
517
  >
@@ -576,10 +576,10 @@ export default function ProjectGridEditor({ block }: ProjectGridEditorProps) {
576
576
 
577
577
  {/* Per-card settings — expanded below this project row */}
578
578
  {isCardSelected && (
579
- <div className="px-2 pb-2 pt-1 -mt-1 rounded-b-lg bg-[#076bff]/5 border-x border-b border-[#076bff]/15">
579
+ <div className="px-2 pb-2 pt-1 -mt-1 rounded-b-lg bg-[#3580f9]/5 border-x border-b border-[#3580f9]/15">
580
580
  {isResponsive && (
581
- <div className="flex items-center gap-1.5 px-2 py-1 mb-1 rounded bg-[#076bff]/8">
582
- <span className="text-[10px] font-medium text-[#076bff]">
581
+ <div className="flex items-center gap-1.5 px-2 py-1 mb-1 rounded bg-[#3580f9]/8">
582
+ <span className="text-[10px] font-medium text-[#3580f9]">
583
583
  {activeViewport === "tablet" ? "Tablet" : "Phone"} override
584
584
  </span>
585
585
  </div>
@@ -614,7 +614,7 @@ export default function ProjectGridEditor({ block }: ProjectGridEditorProps) {
614
614
  placeholder="Search projects..."
615
615
  value={search}
616
616
  onChange={(e) => setSearch(e.target.value)}
617
- className="w-full rounded-md bg-[#f5f5f5] px-2.5 py-1.5 text-xs text-neutral-900 placeholder:text-neutral-400 outline-none focus:bg-white focus:ring-1 focus:ring-[#076bff]/20"
617
+ className="w-full rounded-md bg-[#f5f5f5] px-2.5 py-1.5 text-xs text-neutral-900 placeholder:text-neutral-400 outline-none focus:bg-white focus:ring-1 focus:ring-[#3580f9]/20"
618
618
  autoFocus
619
619
  />
620
620
  </div>
@@ -85,7 +85,7 @@ export default function SpacerBlockEditor({ block }: Props) {
85
85
  onClick={() => updateResponsive("height", preset.value)}
86
86
  className={`flex-1 rounded border py-1.5 text-xs transition-colors flex flex-col items-center gap-0.5 ${
87
87
  effectiveHeight === preset.value
88
- ? "border-[#076bff] bg-[#076bff]/20 text-neutral-900"
88
+ ? "border-[#3580f9] bg-[#3580f9]/20 text-neutral-900"
89
89
  : "border-neutral-200 bg-white text-neutral-500 hover:border-neutral-600"
90
90
  }`}
91
91
  title={
@@ -122,7 +122,7 @@ export default function SpacerBlockEditor({ block }: Props) {
122
122
  onChange={(e) =>
123
123
  updateResponsive("custom_height", parseInt(e.target.value))
124
124
  }
125
- className="flex-1 accent-[#076bff]"
125
+ className="flex-1 accent-[#3580f9]"
126
126
  />
127
127
  <input
128
128
  type="number"
@@ -146,9 +146,9 @@ export default function SpacerBlockEditor({ block }: Props) {
146
146
  style={{ height: `${Math.min(currentPx, 200)}px` }}
147
147
  >
148
148
  <div className="absolute left-0 right-0 top-1/2 border-t border-dashed border-neutral-200" />
149
- <div className="absolute left-2 top-0 w-px h-2 bg-[#076bff]" />
150
- <div className="absolute left-2 bottom-0 w-px h-2 bg-[#076bff]" />
151
- <div className="absolute left-2 top-0 bottom-0 w-px bg-[#076bff]/20" />
149
+ <div className="absolute left-2 top-0 w-px h-2 bg-[#3580f9]" />
150
+ <div className="absolute left-2 bottom-0 w-px h-2 bg-[#3580f9]" />
151
+ <div className="absolute left-2 top-0 bottom-0 w-px bg-[#3580f9]/20" />
152
152
  <div className="absolute inset-0 flex items-center justify-center">
153
153
  <span className="text-xs text-neutral-500 bg-white/80 px-1.5 py-0.5 rounded">
154
154
  {currentPx}px
@@ -1,109 +1,109 @@
1
- import { StaggerIcon } from "./section-icons";
2
- import { SettingsSection, SettingsField } from "./shared";
3
-
4
- // ============================================
5
- // Types
6
- // ============================================
7
-
8
- export interface StaggerConfig {
9
- enabled?: boolean;
10
- delayPerChild?: number;
11
- direction?: "left-to-right" | "right-to-left";
12
- }
13
-
14
- // ============================================
15
- // CSS constants
16
- // ============================================
17
-
18
- const SLIDER_CLASS =
19
- "w-full h-1.5 rounded-full bg-[#e5e5e5] appearance-none cursor-pointer accent-[#076bff] [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3.5 [&::-webkit-slider-thumb]:h-3.5 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-[#076bff] [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-white [&::-webkit-slider-thumb]:shadow-sm";
20
-
21
- const TOGGLE_CLASS_ON =
22
- "relative w-8 h-[18px] rounded-full bg-[#076bff] transition-colors cursor-pointer after:content-[''] after:absolute after:top-[2px] after:left-[15px] after:w-[14px] after:h-[14px] after:rounded-full after:bg-white after:shadow-sm after:transition-all";
23
-
24
- const TOGGLE_CLASS_OFF =
25
- "relative w-8 h-[18px] rounded-full bg-[#d4d4d4] transition-colors cursor-pointer after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:w-[14px] after:h-[14px] after:rounded-full after:bg-white after:shadow-sm after:transition-all";
26
-
27
- // ============================================
28
- // Stagger Section (row mode only)
29
- // ============================================
30
-
31
- export default function StaggerSettings({
32
- stagger,
33
- onChange,
34
- }: {
35
- stagger?: StaggerConfig;
36
- onChange: (s: StaggerConfig) => void;
37
- }) {
38
- const enabled = stagger?.enabled ?? false;
39
- const delay = stagger?.delayPerChild ?? 100;
40
- const direction = stagger?.direction ?? "left-to-right";
41
-
42
- return (
43
- <SettingsSection title="Stagger Children" icon={<StaggerIcon />}>
44
- <div className="space-y-3">
45
- {/* Enable toggle */}
46
- <div className="flex items-center justify-between">
47
- <span className="text-[11px] text-neutral-500">
48
- {enabled ? "Enabled" : "Disabled"}
49
- </span>
50
- <button
51
- type="button"
52
- onClick={() => onChange({ ...stagger, enabled: !enabled })}
53
- className={enabled ? TOGGLE_CLASS_ON : TOGGLE_CLASS_OFF}
54
- aria-label={enabled ? "Stagger enabled" : "Stagger disabled"}
55
- />
56
- </div>
57
-
58
- {enabled && (
59
- <>
60
- {/* Delay slider */}
61
- <SettingsField label={`Delay — ${delay}ms`}>
62
- <input
63
- type="range"
64
- min={50}
65
- max={5000}
66
- step={10}
67
- value={delay}
68
- onChange={(e) =>
69
- onChange({ ...stagger, enabled: true, delayPerChild: Number(e.target.value) })
70
- }
71
- className={SLIDER_CLASS}
72
- />
73
- <div className="flex justify-between mt-0.5">
74
- <span className="text-[10px] text-neutral-400">50ms</span>
75
- <span className="text-[10px] text-neutral-400">5000ms</span>
76
- </div>
77
- </SettingsField>
78
-
79
- {/* Direction */}
80
- <SettingsField label="Direction">
81
- <div className="flex gap-1">
82
- <button
83
- onClick={() => onChange({ ...stagger, enabled: true, direction: "left-to-right" })}
84
- className={`flex-1 py-1.5 rounded-md text-[10px] font-medium transition-all ${
85
- direction === "left-to-right"
86
- ? "bg-[#076bff] text-white"
87
- : "bg-[#f5f5f5] text-neutral-500 hover:bg-[#ebebeb]"
88
- }`}
89
- >
90
- L → R
91
- </button>
92
- <button
93
- onClick={() => onChange({ ...stagger, enabled: true, direction: "right-to-left" })}
94
- className={`flex-1 py-1.5 rounded-md text-[10px] font-medium transition-all ${
95
- direction === "right-to-left"
96
- ? "bg-[#076bff] text-white"
97
- : "bg-[#f5f5f5] text-neutral-500 hover:bg-[#ebebeb]"
98
- }`}
99
- >
100
- R → L
101
- </button>
102
- </div>
103
- </SettingsField>
104
- </>
105
- )}
106
- </div>
107
- </SettingsSection>
108
- );
109
- }
1
+ import { StaggerIcon } from "./section-icons";
2
+ import { SettingsSection, SettingsField } from "./shared";
3
+
4
+ // ============================================
5
+ // Types
6
+ // ============================================
7
+
8
+ export interface StaggerConfig {
9
+ enabled?: boolean;
10
+ delayPerChild?: number;
11
+ direction?: "left-to-right" | "right-to-left";
12
+ }
13
+
14
+ // ============================================
15
+ // CSS constants
16
+ // ============================================
17
+
18
+ const SLIDER_CLASS =
19
+ "w-full h-1.5 rounded-full bg-[#e5e5e5] appearance-none cursor-pointer accent-[#3580f9] [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3.5 [&::-webkit-slider-thumb]:h-3.5 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-[#3580f9] [&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-white [&::-webkit-slider-thumb]:shadow-sm";
20
+
21
+ const TOGGLE_CLASS_ON =
22
+ "relative w-8 h-[18px] rounded-full bg-[#3580f9] transition-colors cursor-pointer after:content-[''] after:absolute after:top-[2px] after:left-[15px] after:w-[14px] after:h-[14px] after:rounded-full after:bg-white after:shadow-sm after:transition-all";
23
+
24
+ const TOGGLE_CLASS_OFF =
25
+ "relative w-8 h-[18px] rounded-full bg-[#d4d4d4] transition-colors cursor-pointer after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:w-[14px] after:h-[14px] after:rounded-full after:bg-white after:shadow-sm after:transition-all";
26
+
27
+ // ============================================
28
+ // Stagger Section (row mode only)
29
+ // ============================================
30
+
31
+ export default function StaggerSettings({
32
+ stagger,
33
+ onChange,
34
+ }: {
35
+ stagger?: StaggerConfig;
36
+ onChange: (s: StaggerConfig) => void;
37
+ }) {
38
+ const enabled = stagger?.enabled ?? false;
39
+ const delay = stagger?.delayPerChild ?? 100;
40
+ const direction = stagger?.direction ?? "left-to-right";
41
+
42
+ return (
43
+ <SettingsSection title="Stagger Children" icon={<StaggerIcon />}>
44
+ <div className="space-y-3">
45
+ {/* Enable toggle */}
46
+ <div className="flex items-center justify-between">
47
+ <span className="text-[11px] text-neutral-500">
48
+ {enabled ? "Enabled" : "Disabled"}
49
+ </span>
50
+ <button
51
+ type="button"
52
+ onClick={() => onChange({ ...stagger, enabled: !enabled })}
53
+ className={enabled ? TOGGLE_CLASS_ON : TOGGLE_CLASS_OFF}
54
+ aria-label={enabled ? "Stagger enabled" : "Stagger disabled"}
55
+ />
56
+ </div>
57
+
58
+ {enabled && (
59
+ <>
60
+ {/* Delay slider */}
61
+ <SettingsField label={`Delay — ${delay}ms`}>
62
+ <input
63
+ type="range"
64
+ min={50}
65
+ max={5000}
66
+ step={10}
67
+ value={delay}
68
+ onChange={(e) =>
69
+ onChange({ ...stagger, enabled: true, delayPerChild: Number(e.target.value) })
70
+ }
71
+ className={SLIDER_CLASS}
72
+ />
73
+ <div className="flex justify-between mt-0.5">
74
+ <span className="text-[10px] text-neutral-400">50ms</span>
75
+ <span className="text-[10px] text-neutral-400">5000ms</span>
76
+ </div>
77
+ </SettingsField>
78
+
79
+ {/* Direction */}
80
+ <SettingsField label="Direction">
81
+ <div className="flex gap-1">
82
+ <button
83
+ onClick={() => onChange({ ...stagger, enabled: true, direction: "left-to-right" })}
84
+ className={`flex-1 py-1.5 rounded-md text-[10px] font-medium transition-all ${
85
+ direction === "left-to-right"
86
+ ? "bg-[#3580f9] text-white"
87
+ : "bg-[#f5f5f5] text-neutral-500 hover:bg-[#ebebeb]"
88
+ }`}
89
+ >
90
+ L → R
91
+ </button>
92
+ <button
93
+ onClick={() => onChange({ ...stagger, enabled: true, direction: "right-to-left" })}
94
+ className={`flex-1 py-1.5 rounded-md text-[10px] font-medium transition-all ${
95
+ direction === "right-to-left"
96
+ ? "bg-[#3580f9] text-white"
97
+ : "bg-[#f5f5f5] text-neutral-500 hover:bg-[#ebebeb]"
98
+ }`}
99
+ >
100
+ R → L
101
+ </button>
102
+ </div>
103
+ </SettingsField>
104
+ </>
105
+ )}
106
+ </div>
107
+ </SettingsSection>
108
+ );
109
+ }
@@ -62,7 +62,7 @@ function ResponsiveStyleField({
62
62
  <span className="block text-[9px] text-neutral-300 italic mt-0.5">inherited</span>
63
63
  )}
64
64
  {isOverridden && (
65
- <span className="block text-[9px] text-[#076bff] mt-0.5">overridden</span>
65
+ <span className="block text-[9px] text-[#3580f9] mt-0.5">overridden</span>
66
66
  )}
67
67
  </label>
68
68
  <div className="flex-1 min-w-0">
@@ -310,7 +310,7 @@ export default function TextBlockEditor({ block }: { block: TextBlock }) {
310
310
  </ResponsiveStyleField>
311
311
 
312
312
  <ResponsiveStyleField label="Size" subProp="fontSize" viewport={viewport} isOverridden={viewport !== "desktop" && hasStyleOverride("fontSize")} onReset={resetStyleOverride}>
313
- <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
+ <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-[#3580f9] focus-within:shadow-[0_0_0_3px_rgba(53, 128, 249,0.06)]">
314
314
  <input
315
315
  type="number"
316
316
  min={1}
@@ -450,7 +450,7 @@ export default function TextBlockEditor({ block }: { block: TextBlock }) {
450
450
  onChange={(e) =>
451
451
  updateStyleResponsive("opacity", parseInt(e.target.value) / 100)
452
452
  }
453
- className="flex-1 accent-[#076bff]"
453
+ className="flex-1 accent-[#3580f9]"
454
454
  />
455
455
  <span className="text-xs text-neutral-900 w-10 text-right tabular-nums">
456
456
  {Math.round((getEffectiveStyleValue<number>("opacity", style.opacity ?? 1)) * 100)}%
@@ -134,7 +134,7 @@ export default function TextStylePicker({
134
134
  onChange={(e) => setSearch(e.target.value)}
135
135
  placeholder="Search..."
136
136
  autoFocus
137
- className="w-full rounded-md bg-[#f5f5f5] px-2 py-1.5 text-xs text-neutral-900 border-none outline-none focus:bg-white focus:ring-1 focus:ring-[#076bff]/30"
137
+ className="w-full rounded-md bg-[#f5f5f5] px-2 py-1.5 text-xs text-neutral-900 border-none outline-none focus:bg-white focus:ring-1 focus:ring-[#3580f9]/30"
138
138
  />
139
139
  </div>
140
140
  <div className="max-h-[220px] overflow-y-auto py-1">
@@ -111,7 +111,7 @@ export default function VideoBlockEditor({ block }: Props) {
111
111
  onClick={() => update({ video_type: opt.value })}
112
112
  className={`flex-1 rounded border py-1 text-xs transition-colors ${
113
113
  (block.video_type || "vimeo") === opt.value
114
- ? "border-[#076bff] bg-[#076bff]/20 text-neutral-900"
114
+ ? "border-[#3580f9] bg-[#3580f9]/20 text-neutral-900"
115
115
  : "border-neutral-200 bg-white text-neutral-500 hover:border-neutral-600"
116
116
  }`}
117
117
  >
@@ -200,7 +200,7 @@ export default function VideoBlockEditor({ block }: Props) {
200
200
  onClick={() => updateResponsive("width", opt.value)}
201
201
  className={`flex-1 rounded border py-1 text-xs transition-colors ${
202
202
  effectiveWidth === opt.value
203
- ? "border-[#076bff] bg-[#076bff]/20 text-neutral-900"
203
+ ? "border-[#3580f9] bg-[#3580f9]/20 text-neutral-900"
204
204
  : "border-neutral-200 bg-white text-neutral-500 hover:border-neutral-600"
205
205
  }`}
206
206
  >
@@ -1,10 +1,11 @@
1
- export { default as TextBlockEditor } from "./TextBlockEditor";
2
- export { default as ImageBlockEditor } from "./ImageBlockEditor";
3
- export { default as ImageGridBlockEditor } from "./ImageGridBlockEditor";
4
- export { default as VideoBlockEditor } from "./VideoBlockEditor";
5
- export { default as SpacerBlockEditor } from "./SpacerBlockEditor";
6
- export { default as ButtonBlockEditor } from "./ButtonBlockEditor";
7
- export { default as ProjectGridEditor } from "./ProjectGridEditor";
8
- export { default as ProjectCarouselBlockEditor } from "./ProjectCarouselBlockEditor";
9
- export { SettingsField, SettingsSection, StyledSelect, StyledInput, StyledCheckbox } from "./shared";
10
- export { getSpacerPx } from "./SpacerBlockEditor";
1
+ export { default as TextBlockEditor } from "./TextBlockEditor";
2
+ export { default as ImageBlockEditor } from "./ImageBlockEditor";
3
+ export { default as ImageGridBlockEditor } from "./ImageGridBlockEditor";
4
+ export { default as VideoBlockEditor } from "./VideoBlockEditor";
5
+ export { default as SpacerBlockEditor } from "./SpacerBlockEditor";
6
+ export { default as ButtonBlockEditor } from "./ButtonBlockEditor";
7
+ export { default as ProjectGridEditor } from "./ProjectGridEditor";
8
+ export { default as ProjectCarouselBlockEditor } from "./ProjectCarouselBlockEditor";
9
+ export { default as MarqueeBlockEditor } from "./MarqueeBlockEditor";
10
+ export { SettingsField, SettingsSection, StyledSelect, StyledInput, StyledCheckbox } from "./shared";
11
+ export { getSpacerPx } from "./SpacerBlockEditor";
@@ -13,11 +13,11 @@ import AssetBrowser from "../AssetBrowser";
13
13
 
14
14
  /** Base input class: gray bg, no border, border on focus */
15
15
  const INPUT_CLASS =
16
- "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-[#076bff] focus:shadow-[0_0_0_3px_rgba(7,107,255,0.06)]";
16
+ "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)]";
17
17
 
18
18
  /** Select class — same as input */
19
19
  const SELECT_CLASS =
20
- "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-[#076bff] focus:shadow-[0_0_0_3px_rgba(7,107,255,0.06)]";
20
+ "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)]";
21
21
 
22
22
  // ============================================
23
23
  // Hooks
@@ -47,8 +47,8 @@ export function ViewportBadge() {
47
47
  };
48
48
 
49
49
  return (
50
- <div className="flex items-center gap-1.5 px-3 py-1.5 mb-2 rounded-lg bg-[#076bff]/8 border border-[#076bff]/15">
51
- <span className="text-[11px] font-medium text-[#076bff]">
50
+ <div className="flex items-center gap-1.5 px-3 py-1.5 mb-2 rounded-lg bg-[#3580f9]/8 border border-[#3580f9]/15">
51
+ <span className="text-[11px] font-medium text-[#3580f9]">
52
52
  Editing {labels[viewport]} overrides
53
53
  </span>
54
54
  </div>
@@ -88,7 +88,7 @@ export function ResponsiveField({
88
88
  <span className="block text-[9px] text-neutral-300 italic mt-0.5">inherited</span>
89
89
  )}
90
90
  {isOverridden && (
91
- <span className="block text-[9px] text-[#076bff] mt-0.5">overridden</span>
91
+ <span className="block text-[9px] text-[#3580f9] mt-0.5">overridden</span>
92
92
  )}
93
93
  </label>
94
94
  <div className="flex-1 min-w-0">
@@ -291,7 +291,7 @@ export function StyledCheckbox({
291
291
  type="button"
292
292
  onClick={() => onChange(!checked)}
293
293
  className={`relative w-8 h-[18px] rounded-full transition-colors ${
294
- checked ? "bg-[#076bff]" : "bg-neutral-200 group-hover:bg-neutral-300"
294
+ checked ? "bg-[#3580f9]" : "bg-neutral-200 group-hover:bg-neutral-300"
295
295
  }`}
296
296
  >
297
297
  <span