@morphika/andami 0.5.0 → 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 (122) hide show
  1. package/README.md +151 -36
  2. package/app/admin/assets/page.tsx +6 -6
  3. package/app/admin/database/page.tsx +302 -302
  4. package/app/admin/error.tsx +53 -53
  5. package/app/admin/layout.tsx +320 -327
  6. package/app/admin/navigation/page.tsx +255 -255
  7. package/app/admin/pages/[slug]/page.tsx +6 -6
  8. package/app/admin/pages/page.tsx +11 -11
  9. package/app/admin/projects/page.tsx +14 -14
  10. package/app/admin/setup/page.tsx +1 -1
  11. package/app/admin/styles/page.tsx +1 -1
  12. package/components/admin/MetadataEditor.tsx +6 -6
  13. package/components/admin/nav-builder/NavBuilder.tsx +1 -1
  14. package/components/admin/nav-builder/NavBuilderGrid.tsx +3 -3
  15. package/components/admin/nav-builder/NavGridCell.tsx +48 -48
  16. package/components/admin/nav-builder/NavGridItem.tsx +4 -4
  17. package/components/admin/nav-builder/NavItemSettings.tsx +331 -331
  18. package/components/admin/nav-builder/NavItemTypePicker.tsx +102 -102
  19. package/components/admin/nav-builder/NavLivePreview.tsx +1 -1
  20. package/components/admin/nav-builder/NavMobileLivePreview.tsx +226 -226
  21. package/components/admin/nav-builder/NavMobileSettings.tsx +242 -242
  22. package/components/admin/nav-builder/NavSettingsFields.tsx +514 -514
  23. package/components/admin/setup-wizard/BrandingStep.tsx +3 -3
  24. package/components/admin/setup-wizard/DatabaseStep.tsx +2 -2
  25. package/components/admin/setup-wizard/DoneStep.tsx +1 -1
  26. package/components/admin/setup-wizard/SetupWizard.tsx +4 -4
  27. package/components/admin/setup-wizard/StorageStep.tsx +2 -2
  28. package/components/admin/setup-wizard/WelcomeStep.tsx +2 -2
  29. package/components/admin/styles/ColorsEditor.tsx +2 -2
  30. package/components/admin/styles/FontsEditor.tsx +6 -6
  31. package/components/admin/styles/GridLayoutEditor.tsx +9 -9
  32. package/components/admin/styles/LinksButtonsEditor.tsx +5 -5
  33. package/components/admin/styles/TypographyEditor.tsx +6 -6
  34. package/components/admin/styles/shared.tsx +68 -68
  35. package/components/blocks/AudioBlockRenderer.tsx +286 -0
  36. package/components/blocks/BeforeAfterBlockRenderer.tsx +274 -0
  37. package/components/blocks/MarqueeBlockRenderer.tsx +316 -0
  38. package/components/blocks/ProjectCarouselBlockRenderer.tsx +1 -1
  39. package/components/builder/BlockCardIcons.tsx +316 -227
  40. package/components/builder/BlockTypePicker.tsx +3 -1
  41. package/components/builder/BubbleIcons.tsx +90 -0
  42. package/components/builder/BuilderCanvas.tsx +2 -0
  43. package/components/builder/CanvasMinimap.tsx +2 -2
  44. package/components/builder/CoverSectionCanvas.tsx +363 -275
  45. package/components/builder/DeviceFrame.tsx +1 -1
  46. package/components/builder/DndWrapper.tsx +3 -3
  47. package/components/builder/InsertionLines.tsx +1 -1
  48. package/components/builder/SectionCardIcons.tsx +421 -320
  49. package/components/builder/SectionEditorBar.tsx +1 -1
  50. package/components/builder/SectionTypePicker.tsx +4 -4
  51. package/components/builder/SectionV2Canvas.tsx +20 -4
  52. package/components/builder/SectionV2Column.tsx +74 -68
  53. package/components/builder/SortableBlock.tsx +93 -73
  54. package/components/builder/SortableRow.tsx +27 -26
  55. package/components/builder/VirtualAssetGrid.tsx +2 -2
  56. package/components/builder/asset-browser/R2BrowserContent.tsx +34 -17
  57. package/components/builder/asset-browser/helpers.ts +4 -0
  58. package/components/builder/asset-browser/types.ts +2 -1
  59. package/components/builder/blockStyles.tsx +192 -173
  60. package/components/builder/color-picker/AlphaSlider.tsx +141 -141
  61. package/components/builder/color-picker/ColorInputs.tsx +105 -105
  62. package/components/builder/color-picker/EyedropperButton.tsx +74 -74
  63. package/components/builder/color-picker/HueSlider.tsx +124 -124
  64. package/components/builder/color-picker/SaturationCanvas.tsx +142 -142
  65. package/components/builder/color-picker/SwatchBar.tsx +93 -93
  66. package/components/builder/editors/AudioBlockEditor.tsx +242 -0
  67. package/components/builder/editors/BeforeAfterBlockEditor.tsx +360 -0
  68. package/components/builder/editors/ButtonBlockEditor.tsx +4 -4
  69. package/components/builder/editors/EnterAnimationPicker.tsx +2 -2
  70. package/components/builder/editors/HoverEffectPicker.tsx +2 -2
  71. package/components/builder/editors/ImageBlockEditor.tsx +2 -2
  72. package/components/builder/editors/ImageGridBlockEditor.tsx +4 -4
  73. package/components/builder/editors/MarqueeBlockEditor.tsx +621 -0
  74. package/components/builder/editors/ProjectCarouselBlockEditor.tsx +443 -443
  75. package/components/builder/editors/ProjectGridEditor.tsx +9 -9
  76. package/components/builder/editors/SpacerBlockEditor.tsx +5 -5
  77. package/components/builder/editors/StaggerSettings.tsx +109 -109
  78. package/components/builder/editors/TextBlockEditor.tsx +3 -3
  79. package/components/builder/editors/TextStylePicker.tsx +1 -1
  80. package/components/builder/editors/VideoBlockEditor.tsx +2 -2
  81. package/components/builder/editors/index.ts +11 -10
  82. package/components/builder/editors/shared.tsx +7 -7
  83. package/components/builder/live-preview/LiveAudioPreview.tsx +120 -0
  84. package/components/builder/live-preview/LiveBeforeAfterPreview.tsx +176 -0
  85. package/components/builder/live-preview/LiveImageGridPreview.tsx +10 -2
  86. package/components/builder/live-preview/LiveImagePreview.tsx +1 -1
  87. package/components/builder/live-preview/LiveMarqueePreview.tsx +39 -0
  88. package/components/builder/live-preview/LiveProjectCarouselPreview.tsx +1 -1
  89. package/components/builder/live-preview/LiveVideoPreview.tsx +1 -1
  90. package/components/builder/live-preview/ProjectCardWrapper.tsx +291 -291
  91. package/components/builder/settings-panel/AnimationTab.tsx +138 -138
  92. package/components/builder/settings-panel/BlockLayoutTab.tsx +7 -7
  93. package/components/builder/settings-panel/CardEntranceSection.tsx +114 -114
  94. package/components/builder/settings-panel/ColumnV2Settings.tsx +5 -5
  95. package/components/builder/settings-panel/CoverSectionLayoutTab.tsx +71 -71
  96. package/components/builder/settings-panel/CoverSectionSettings.tsx +335 -335
  97. package/components/builder/settings-panel/PageSettings.tsx +3 -3
  98. package/components/builder/settings-panel/ParallaxSlideSettings.tsx +2 -2
  99. package/components/builder/settings-panel/SectionV2AnimationTab.tsx +4 -4
  100. package/components/builder/settings-panel/SectionV2LayoutTab.tsx +356 -356
  101. package/components/builder/settings-panel/SectionV2Settings.tsx +14 -14
  102. package/components/builder/settings-panel/TRBLInputs.tsx +1 -1
  103. package/lib/animation/enter-types.ts +3 -0
  104. package/lib/animation/hover-effect-presets.ts +210 -210
  105. package/lib/animation/hover-effect-types.ts +3 -0
  106. package/lib/builder/block-registrations.ts +468 -335
  107. package/lib/builder/constants.ts +111 -111
  108. package/lib/builder/store-sections.ts +2 -2
  109. package/lib/builder/types-slices.ts +414 -414
  110. package/lib/builder/types.ts +6 -1
  111. package/lib/config/index.ts +27 -27
  112. package/lib/sanity/types.ts +156 -1
  113. package/lib/version.ts +1 -1
  114. package/package.json +1 -1
  115. package/sanity/schemas/blocks/audioBlock.ts +69 -0
  116. package/sanity/schemas/blocks/beforeAfterBlock.ts +121 -0
  117. package/sanity/schemas/blocks/index.ts +12 -9
  118. package/sanity/schemas/blocks/marqueeBlock.ts +292 -0
  119. package/sanity/schemas/index.ts +120 -111
  120. package/styles/admin.css +85 -85
  121. package/styles/animations.css +237 -237
  122. package/styles/base.css +114 -114
@@ -100,7 +100,7 @@ export function BrandingStep({ onNext, onBack }: WizardStepProps) {
100
100
  }, [siteTitle, onNext]);
101
101
 
102
102
  const inputClass =
103
- "w-full rounded-lg border border-black/[0.08] bg-white px-3 py-2.5 text-sm text-[#333] placeholder:text-[#bbb] focus:outline-none focus:ring-2 focus:ring-[#076bff]/20 focus:border-[#076bff]/40";
103
+ "w-full rounded-lg border border-black/[0.08] bg-white px-3 py-2.5 text-sm text-[#333] placeholder:text-[#bbb] focus:outline-none focus:ring-2 focus:ring-[#3580f9]/20 focus:border-[#3580f9]/40";
104
104
 
105
105
  if (loading) {
106
106
  return (
@@ -196,7 +196,7 @@ export function BrandingStep({ onNext, onBack }: WizardStepProps) {
196
196
  <button
197
197
  onClick={handleSave}
198
198
  disabled={saving || !siteTitle.trim()}
199
- className="px-5 py-2.5 bg-[#076bff] text-white text-sm font-medium rounded-lg hover:bg-[#0559d4] transition-colors disabled:opacity-50"
199
+ className="px-5 py-2.5 bg-[#3580f9] text-white text-sm font-medium rounded-lg hover:bg-[#2d6dd4] transition-colors disabled:opacity-50"
200
200
  >
201
201
  {saving ? "Saving..." : "Save & Continue"}
202
202
  </button>
@@ -206,7 +206,7 @@ export function BrandingStep({ onNext, onBack }: WizardStepProps) {
206
206
  {saved && (
207
207
  <button
208
208
  onClick={onNext}
209
- className="px-5 py-2.5 bg-[#076bff] text-white text-sm font-medium rounded-lg hover:bg-[#0559d4] transition-colors"
209
+ className="px-5 py-2.5 bg-[#3580f9] text-white text-sm font-medium rounded-lg hover:bg-[#2d6dd4] transition-colors"
210
210
  >
211
211
  Next
212
212
  </button>
@@ -309,7 +309,7 @@ export function DatabaseStep({ onNext, onBack }: WizardStepProps) {
309
309
  <button
310
310
  onClick={seedDocuments}
311
311
  disabled={seedState === "seeding"}
312
- className="px-4 py-2 text-sm bg-[#076bff] text-white rounded-lg hover:bg-[#0559d4] transition-colors disabled:opacity-50"
312
+ className="px-4 py-2 text-sm bg-[#3580f9] text-white rounded-lg hover:bg-[#2d6dd4] transition-colors disabled:opacity-50"
313
313
  >
314
314
  {seedState === "seeding" ? "Creating..." : "Create Initial Documents"}
315
315
  </button>
@@ -319,7 +319,7 @@ export function DatabaseStep({ onNext, onBack }: WizardStepProps) {
319
319
  {canAdvance && (
320
320
  <button
321
321
  onClick={onNext}
322
- className="px-5 py-2.5 bg-[#076bff] text-white text-sm font-medium rounded-lg hover:bg-[#0559d4] transition-colors"
322
+ className="px-5 py-2.5 bg-[#3580f9] text-white text-sm font-medium rounded-lg hover:bg-[#2d6dd4] transition-colors"
323
323
  >
324
324
  Next
325
325
  </button>
@@ -177,7 +177,7 @@ export function DoneStep({ onBack }: WizardStepProps) {
177
177
  <button
178
178
  onClick={handleComplete}
179
179
  disabled={completing}
180
- className="px-6 py-2.5 bg-[#076bff] text-white text-sm font-medium rounded-lg hover:bg-[#0559d4] transition-colors disabled:opacity-50"
180
+ className="px-6 py-2.5 bg-[#3580f9] text-white text-sm font-medium rounded-lg hover:bg-[#2d6dd4] transition-colors disabled:opacity-50"
181
181
  >
182
182
  {completing ? "Starting..." : "Start Building"}
183
183
  </button>
@@ -105,9 +105,9 @@ export function SetupWizard({ initialStatus }: SetupWizardProps) {
105
105
  <div
106
106
  className={`w-6 h-6 rounded-full flex items-center justify-center text-[10px] font-semibold transition-colors ${
107
107
  isActive
108
- ? "bg-[#076bff] text-white"
108
+ ? "bg-[#3580f9] text-white"
109
109
  : isDone
110
- ? "bg-[#076bff]/20 text-[#076bff]"
110
+ ? "bg-[#3580f9]/20 text-[#3580f9]"
111
111
  : "bg-black/[0.06] text-[#999]"
112
112
  }`}
113
113
  >
@@ -124,7 +124,7 @@ export function SetupWizard({ initialStatus }: SetupWizardProps) {
124
124
  isActive
125
125
  ? "text-[#333] font-medium"
126
126
  : isDone
127
- ? "text-[#076bff]"
127
+ ? "text-[#3580f9]"
128
128
  : "text-[#999]"
129
129
  }`}
130
130
  >
@@ -135,7 +135,7 @@ export function SetupWizard({ initialStatus }: SetupWizardProps) {
135
135
  {i < STEPS.length - 1 && (
136
136
  <div
137
137
  className={`w-8 h-px transition-colors ${
138
- i < currentStep ? "bg-[#076bff]/30" : "bg-black/[0.08]"
138
+ i < currentStep ? "bg-[#3580f9]/30" : "bg-black/[0.08]"
139
139
  }`}
140
140
  />
141
141
  )}
@@ -128,7 +128,7 @@ export function StorageStep({ onNext, onBack }: WizardStepProps) {
128
128
  );
129
129
 
130
130
  const inputClass =
131
- "w-full rounded-lg border border-black/[0.08] bg-white px-3 py-2 text-sm text-[#333] placeholder:text-[#bbb] focus:outline-none focus:ring-2 focus:ring-[#076bff]/20 focus:border-[#076bff]/40";
131
+ "w-full rounded-lg border border-black/[0.08] bg-white px-3 py-2 text-sm text-[#333] placeholder:text-[#bbb] focus:outline-none focus:ring-2 focus:ring-[#3580f9]/20 focus:border-[#3580f9]/40";
132
132
  const labelClass = "block text-xs font-medium text-[#666] mb-1";
133
133
 
134
134
  if (state === "loading") {
@@ -296,7 +296,7 @@ export function StorageStep({ onNext, onBack }: WizardStepProps) {
296
296
  {state === "connected" && (
297
297
  <button
298
298
  onClick={onNext}
299
- className="px-5 py-2.5 bg-[#076bff] text-white text-sm font-medium rounded-lg hover:bg-[#0559d4] transition-colors"
299
+ className="px-5 py-2.5 bg-[#3580f9] text-white text-sm font-medium rounded-lg hover:bg-[#2d6dd4] transition-colors"
300
300
  >
301
301
  Next
302
302
  </button>
@@ -75,7 +75,7 @@ export function WelcomeStep({ onNext }: WizardStepProps) {
75
75
  },
76
76
  ].map((item) => (
77
77
  <li key={item.label} className="flex items-start gap-3">
78
- <span className="text-[#076bff] mt-0.5 shrink-0">{item.icon}</span>
78
+ <span className="text-[#3580f9] mt-0.5 shrink-0">{item.icon}</span>
79
79
  <div>
80
80
  <span className="text-sm font-medium text-[#333]">{item.label}</span>
81
81
  <p className="text-xs text-[#999] mt-0.5">{item.desc}</p>
@@ -87,7 +87,7 @@ export function WelcomeStep({ onNext }: WizardStepProps) {
87
87
 
88
88
  <button
89
89
  onClick={onNext}
90
- className="px-6 py-2.5 bg-[#076bff] text-white text-sm font-medium rounded-lg hover:bg-[#0559d4] transition-colors"
90
+ className="px-6 py-2.5 bg-[#3580f9] text-white text-sm font-medium rounded-lg hover:bg-[#2d6dd4] transition-colors"
91
91
  >
92
92
  Get Started
93
93
  </button>
@@ -156,7 +156,7 @@ export function ColorsEditor({
156
156
  {!pickerOpen && (
157
157
  <button
158
158
  onClick={() => { setEditingIndex(null); setPickerOpen(true); }}
159
- className="rounded-xl border-2 border-dashed border-neutral-200 h-[100px] flex flex-col items-center justify-center gap-1 cursor-pointer hover:border-[#076bff] hover:text-[#076bff] text-neutral-400 transition-colors bg-transparent"
159
+ className="rounded-xl border-2 border-dashed border-neutral-200 h-[100px] flex flex-col items-center justify-center gap-1 cursor-pointer hover:border-[#3580f9] hover:text-[#3580f9] text-neutral-400 transition-colors bg-transparent"
160
160
  >
161
161
  <span className="text-xl leading-none">+</span>
162
162
  <span className="text-[10px] uppercase tracking-wider">Add</span>
@@ -190,7 +190,7 @@ export function ColorsEditor({
190
190
  {pickerOpen && (
191
191
  <div className="flex justify-center mb-4">
192
192
  <ColorPicker
193
- color={editingIndex !== null ? swatches[editingIndex].hex : "#076bff"}
193
+ color={editingIndex !== null ? swatches[editingIndex].hex : "#3580f9"}
194
194
  onChange={addSwatch}
195
195
  onClose={() => { setPickerOpen(false); setEditingIndex(null); }}
196
196
  confirmLabel={editingIndex !== null ? "Update color" : "Add to palette"}
@@ -115,7 +115,7 @@ export function FontsEditor({ fonts, onSave, saving }: { fonts: FontFamily[]; on
115
115
  key={font._key}
116
116
  className={`rounded-xl border overflow-hidden transition-all cursor-pointer ${
117
117
  isExpanded
118
- ? "border-[#076bff] shadow-sm ring-1 ring-[#076bff]/20"
118
+ ? "border-[#3580f9] shadow-sm ring-1 ring-[#3580f9]/20"
119
119
  : "border-neutral-200 hover:shadow-md hover:-translate-y-0.5"
120
120
  }`}
121
121
  onClick={() => setExpandedFont(isExpanded ? null : font._key)}
@@ -147,7 +147,7 @@ export function FontsEditor({ fonts, onSave, saving }: { fonts: FontFamily[]; on
147
147
  {/* Add font card */}
148
148
  <button
149
149
  onClick={addFont}
150
- className="rounded-xl border-2 border-dashed border-neutral-200 min-h-[120px] flex flex-col items-center justify-center gap-1.5 cursor-pointer hover:border-[#076bff] hover:text-[#076bff] text-neutral-400 transition-colors bg-transparent"
150
+ className="rounded-xl border-2 border-dashed border-neutral-200 min-h-[120px] flex flex-col items-center justify-center gap-1.5 cursor-pointer hover:border-[#3580f9] hover:text-[#3580f9] text-neutral-400 transition-colors bg-transparent"
151
151
  >
152
152
  <span className="text-xl leading-none">+</span>
153
153
  <span className="text-[10px] uppercase tracking-wider">Add Font Family</span>
@@ -166,7 +166,7 @@ export function FontsEditor({ fonts, onSave, saving }: { fonts: FontFamily[]; on
166
166
  value={font.family}
167
167
  onChange={(e) => updateFont(font._key, { family: e.target.value })}
168
168
  placeholder="Font Family Name (e.g. Inter)"
169
- className="flex-1 rounded-lg border border-neutral-200 bg-white px-3 py-1.5 text-sm text-neutral-900 focus:border-[#076bff] focus:outline-none"
169
+ className="flex-1 rounded-lg border border-neutral-200 bg-white px-3 py-1.5 text-sm text-neutral-900 focus:border-[#3580f9] focus:outline-none"
170
170
  disabled={font.is_builtin}
171
171
  onClick={(e) => e.stopPropagation()}
172
172
  />
@@ -190,7 +190,7 @@ export function FontsEditor({ fonts, onSave, saving }: { fonts: FontFamily[]; on
190
190
  <select
191
191
  value={v.weight}
192
192
  onChange={(e) => updateVariant(font._key, v._key, { weight: e.target.value })}
193
- className="rounded border border-neutral-200 bg-white px-2 py-1 text-xs focus:border-[#076bff] focus:outline-none"
193
+ className="rounded border border-neutral-200 bg-white px-2 py-1 text-xs focus:border-[#3580f9] focus:outline-none"
194
194
  >
195
195
  {["100", "300", "400", "500", "600", "700", "800", "900"].map((w) => (
196
196
  <option key={w} value={w}>{w}</option>
@@ -199,7 +199,7 @@ export function FontsEditor({ fonts, onSave, saving }: { fonts: FontFamily[]; on
199
199
  <select
200
200
  value={v.style}
201
201
  onChange={(e) => updateVariant(font._key, v._key, { style: e.target.value as "normal" | "italic" })}
202
- className="rounded border border-neutral-200 bg-white px-2 py-1 text-xs focus:border-[#076bff] focus:outline-none"
202
+ className="rounded border border-neutral-200 bg-white px-2 py-1 text-xs focus:border-[#3580f9] focus:outline-none"
203
203
  >
204
204
  <option value="normal">Normal</option>
205
205
  <option value="italic">Italic</option>
@@ -225,7 +225,7 @@ export function FontsEditor({ fonts, onSave, saving }: { fonts: FontFamily[]; on
225
225
  fileInputRef.current?.click();
226
226
  }}
227
227
  disabled={uploading}
228
- className="text-xs text-[#076bff] hover:text-[#0559d4] transition-colors mt-1"
228
+ className="text-xs text-[#3580f9] hover:text-[#2d6dd4] transition-colors mt-1"
229
229
  >
230
230
  {uploading && uploadTarget === font._key ? "Uploading..." : "+ Add variant file"}
231
231
  </button>
@@ -15,7 +15,7 @@ const DEFAULT_GRID = {
15
15
 
16
16
  /** SVG illustration for the Column Gutter card */
17
17
  function GutterIcon() {
18
- const ACCENT = "#4794E2";
18
+ const ACCENT = "#3580f9";
19
19
  return (
20
20
  <svg viewBox="0 0 120 72" fill="none" className="w-full h-full">
21
21
  {/* 5 columns (ghost blue) */}
@@ -44,7 +44,7 @@ function GutterIcon() {
44
44
  /** SVG illustration for the Max Page Width card */
45
45
  function MaxWidthIcon() {
46
46
  // Frame/dots/content stay neutral; arrows + dashed boundaries are the accent.
47
- const ACCENT = "#4794E2";
47
+ const ACCENT = "#3580f9";
48
48
  return (
49
49
  <svg viewBox="0 0 120 72" fill="none" className="w-full h-full">
50
50
  {/* Browser frame */}
@@ -73,7 +73,7 @@ function MaxWidthIcon() {
73
73
  /** SVG illustration for the Scroll Animations card */
74
74
  function ScrollAnimIcon() {
75
75
  // 3 blue layers with increasing opacity convey the fade-in effect; accent arrow below.
76
- const ACCENT = "#4794E2";
76
+ const ACCENT = "#3580f9";
77
77
  return (
78
78
  <svg viewBox="0 0 120 72" fill="none" className="w-full h-full">
79
79
  {/* 3 stacked layers (fade-in effect) */}
@@ -169,7 +169,7 @@ export function GridLayoutEditor({
169
169
  type="text"
170
170
  value={local.grid_gutter_desktop}
171
171
  onChange={(e) => setLocal({ ...local, grid_gutter_desktop: e.target.value })}
172
- className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-1.5 pr-8 text-sm text-neutral-900 focus:border-[#076bff] focus:outline-none"
172
+ className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-1.5 pr-8 text-sm text-neutral-900 focus:border-[#3580f9] focus:outline-none"
173
173
  placeholder="30"
174
174
  />
175
175
  <span className="absolute right-3 top-1/2 -translate-y-1/2 text-[11px] text-neutral-400 pointer-events-none">px</span>
@@ -187,7 +187,7 @@ export function GridLayoutEditor({
187
187
  type="text"
188
188
  value={local.grid_width}
189
189
  onChange={(e) => setLocal({ ...local, grid_width: e.target.value })}
190
- className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-1.5 pr-8 text-sm text-neutral-900 focus:border-[#076bff] focus:outline-none"
190
+ className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-1.5 pr-8 text-sm text-neutral-900 focus:border-[#3580f9] focus:outline-none"
191
191
  placeholder={DEFAULT_GRID_WIDTH}
192
192
  />
193
193
  <span className="absolute right-3 top-1/2 -translate-y-1/2 text-[11px] text-neutral-400 pointer-events-none">px</span>
@@ -206,7 +206,7 @@ export function GridLayoutEditor({
206
206
  type="button"
207
207
  onClick={() => setAnimLocal(!animLocal)}
208
208
  className={`relative w-9 h-5 rounded-full transition-colors shrink-0 ${
209
- animLocal ? "bg-[#076bff]" : "bg-neutral-300"
209
+ animLocal ? "bg-[#3580f9]" : "bg-neutral-300"
210
210
  }`}
211
211
  >
212
212
  <span
@@ -234,7 +234,7 @@ export function GridLayoutEditor({
234
234
  type="text"
235
235
  value={local.grid_gutter_desktop}
236
236
  onChange={(e) => setLocal({ ...local, grid_gutter_desktop: e.target.value })}
237
- className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-1.5 pr-8 text-sm text-neutral-900 focus:border-[#076bff] focus:outline-none"
237
+ className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-1.5 pr-8 text-sm text-neutral-900 focus:border-[#3580f9] focus:outline-none"
238
238
  placeholder="30"
239
239
  />
240
240
  <span className="absolute right-3 top-1/2 -translate-y-1/2 text-[11px] text-neutral-400 pointer-events-none">px</span>
@@ -253,7 +253,7 @@ export function GridLayoutEditor({
253
253
  type="text"
254
254
  value={local.grid_gutter_responsive}
255
255
  onChange={(e) => setLocal({ ...local, grid_gutter_responsive: e.target.value })}
256
- className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-1.5 pr-8 text-sm text-neutral-900 focus:border-[#076bff] focus:outline-none"
256
+ className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-1.5 pr-8 text-sm text-neutral-900 focus:border-[#3580f9] focus:outline-none"
257
257
  placeholder="30"
258
258
  />
259
259
  <span className="absolute right-3 top-1/2 -translate-y-1/2 text-[11px] text-neutral-400 pointer-events-none">px</span>
@@ -272,7 +272,7 @@ export function GridLayoutEditor({
272
272
  type="text"
273
273
  value={local.grid_gutter_phone || "16"}
274
274
  onChange={(e) => setLocal({ ...local, grid_gutter_phone: e.target.value })}
275
- className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-1.5 pr-8 text-sm text-neutral-900 focus:border-[#076bff] focus:outline-none"
275
+ className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-1.5 pr-8 text-sm text-neutral-900 focus:border-[#3580f9] focus:outline-none"
276
276
  placeholder="16"
277
277
  />
278
278
  <span className="absolute right-3 top-1/2 -translate-y-1/2 text-[11px] text-neutral-400 pointer-events-none">px</span>
@@ -16,8 +16,8 @@ export function LinksButtonsEditor({
16
16
  saving: boolean;
17
17
  }) {
18
18
  const [local, setLocal] = useState({
19
- link_color: linkStyle?.color || "#076bff",
20
- link_hover_color: linkStyle?.hover_color || "#0559d4",
19
+ link_color: linkStyle?.color || "#3580f9",
20
+ link_hover_color: linkStyle?.hover_color || "#2d6dd4",
21
21
  link_underline: linkStyle?.underline ?? true,
22
22
  button_primary_bg: buttonStyle?.primary_bg || "#ffffff",
23
23
  button_primary_text: buttonStyle?.primary_text || "#000000",
@@ -28,8 +28,8 @@ export function LinksButtonsEditor({
28
28
 
29
29
  useEffect(() => {
30
30
  setLocal({
31
- link_color: linkStyle?.color || "#076bff",
32
- link_hover_color: linkStyle?.hover_color || "#0559d4",
31
+ link_color: linkStyle?.color || "#3580f9",
32
+ link_hover_color: linkStyle?.hover_color || "#2d6dd4",
33
33
  link_underline: linkStyle?.underline ?? true,
34
34
  button_primary_bg: buttonStyle?.primary_bg || "#ffffff",
35
35
  button_primary_text: buttonStyle?.primary_text || "#000000",
@@ -51,7 +51,7 @@ export function LinksButtonsEditor({
51
51
  type="checkbox"
52
52
  checked={local.link_underline}
53
53
  onChange={(e) => setLocal({ ...local, link_underline: e.target.checked })}
54
- className="accent-[#076bff]"
54
+ className="accent-[#3580f9]"
55
55
  />
56
56
  <span className="text-xs text-neutral-700">Underline links</span>
57
57
  </label>
@@ -179,7 +179,7 @@ export function TypographyEditor({
179
179
  <select
180
180
  value={t.font_family || ""}
181
181
  onChange={(e) => updateLevel(level, { font_family: e.target.value })}
182
- className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1.5 text-[11px] text-neutral-700 focus:border-[#076bff] focus:outline-none"
182
+ className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1.5 text-[11px] text-neutral-700 focus:border-[#3580f9] focus:outline-none"
183
183
  >
184
184
  <option value="">Inherit</option>
185
185
  {fontFamilies.map((f) => (
@@ -193,7 +193,7 @@ export function TypographyEditor({
193
193
  type="text"
194
194
  value={t.font_size}
195
195
  onChange={(e) => updateLevel(level, { font_size: e.target.value })}
196
- className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1.5 text-[11px] text-neutral-700 focus:border-[#076bff] focus:outline-none"
196
+ className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1.5 text-[11px] text-neutral-700 focus:border-[#3580f9] focus:outline-none"
197
197
  placeholder="3rem"
198
198
  />
199
199
  </div>
@@ -202,7 +202,7 @@ export function TypographyEditor({
202
202
  <select
203
203
  value={t.font_weight}
204
204
  onChange={(e) => updateLevel(level, { font_weight: e.target.value })}
205
- className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1.5 text-[11px] text-neutral-700 focus:border-[#076bff] focus:outline-none"
205
+ className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1.5 text-[11px] text-neutral-700 focus:border-[#3580f9] focus:outline-none"
206
206
  >
207
207
  {["100", "300", "400", "500", "600", "700", "800", "900"].map((w) => (
208
208
  <option key={w} value={w}>{w}</option>
@@ -215,7 +215,7 @@ export function TypographyEditor({
215
215
  type="text"
216
216
  value={t.line_height}
217
217
  onChange={(e) => updateLevel(level, { line_height: e.target.value })}
218
- className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1.5 text-[11px] text-neutral-700 focus:border-[#076bff] focus:outline-none"
218
+ className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1.5 text-[11px] text-neutral-700 focus:border-[#3580f9] focus:outline-none"
219
219
  placeholder="1.1"
220
220
  />
221
221
  </div>
@@ -225,7 +225,7 @@ export function TypographyEditor({
225
225
  type="text"
226
226
  value={t.letter_spacing}
227
227
  onChange={(e) => updateLevel(level, { letter_spacing: e.target.value })}
228
- className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1.5 text-[11px] text-neutral-700 focus:border-[#076bff] focus:outline-none"
228
+ className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1.5 text-[11px] text-neutral-700 focus:border-[#3580f9] focus:outline-none"
229
229
  placeholder="-0.02em"
230
230
  />
231
231
  </div>
@@ -234,7 +234,7 @@ export function TypographyEditor({
234
234
  <select
235
235
  value={t.text_transform || "none"}
236
236
  onChange={(e) => updateLevel(level, { text_transform: e.target.value as TypographyLevel["text_transform"] })}
237
- className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1.5 text-[11px] text-neutral-700 focus:border-[#076bff] focus:outline-none"
237
+ className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1.5 text-[11px] text-neutral-700 focus:border-[#3580f9] focus:outline-none"
238
238
  >
239
239
  <option value="none">None</option>
240
240
  <option value="uppercase">UPPERCASE</option>
@@ -1,68 +1,68 @@
1
- "use client";
2
-
3
- export function Section({ title, description, children }: { title: string; description?: string; children: React.ReactNode }) {
4
- return (
5
- <section className="bg-white rounded-2xl border border-neutral-200 p-6">
6
- <h2 className="text-lg font-semibold text-neutral-900 mb-1">{title}</h2>
7
- {description && <p className="text-xs text-neutral-500 mb-5">{description}</p>}
8
- {!description && <div className="mb-5" />}
9
- {children}
10
- </section>
11
- );
12
- }
13
-
14
- export function ColorField({ label, value, onChange }: { label: string; value: string; onChange: (v: string) => void }) {
15
- return (
16
- <div className="flex items-center gap-3">
17
- <input
18
- type="color"
19
- value={value}
20
- onChange={(e) => onChange(e.target.value)}
21
- className="w-8 h-8 rounded-lg border border-neutral-200 cursor-pointer bg-transparent [&::-webkit-color-swatch-wrapper]:p-0 [&::-webkit-color-swatch]:rounded-md [&::-webkit-color-swatch]:border-none"
22
- />
23
- <div className="flex-1">
24
- <label className="text-xs text-neutral-500 block mb-0.5">{label}</label>
25
- <input
26
- type="text"
27
- value={value}
28
- onChange={(e) => onChange(e.target.value)}
29
- className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1 text-xs text-neutral-900 focus:border-[#076bff] focus:outline-none"
30
- />
31
- </div>
32
- </div>
33
- );
34
- }
35
-
36
- export function SaveButton({ onClick, saving, label = "Save" }: { onClick: () => void; saving: boolean; label?: string }) {
37
- return (
38
- <button
39
- onClick={onClick}
40
- disabled={saving}
41
- className="rounded-lg bg-[#076bff] px-5 py-1.5 text-sm font-medium text-white hover:bg-[#0559d4] transition-colors disabled:opacity-50"
42
- >
43
- {saving ? "Saving..." : label}
44
- </button>
45
- );
46
- }
47
-
48
- export function FieldInput({ label, value, onChange, placeholder, helpText }: {
49
- label: string;
50
- value: string;
51
- onChange: (v: string) => void;
52
- placeholder?: string;
53
- helpText?: string;
54
- }) {
55
- return (
56
- <div>
57
- <label className="text-[10px] text-neutral-400 uppercase tracking-wider block mb-1">{label}</label>
58
- <input
59
- type="text"
60
- value={value}
61
- onChange={(e) => onChange(e.target.value)}
62
- className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2 text-sm text-neutral-900 focus:border-[#076bff] focus:outline-none"
63
- placeholder={placeholder}
64
- />
65
- {helpText && <p className="text-[10px] text-neutral-400 mt-1">{helpText}</p>}
66
- </div>
67
- );
68
- }
1
+ "use client";
2
+
3
+ export function Section({ title, description, children }: { title: string; description?: string; children: React.ReactNode }) {
4
+ return (
5
+ <section className="bg-white rounded-2xl border border-neutral-200 p-6">
6
+ <h2 className="text-lg font-semibold text-neutral-900 mb-1">{title}</h2>
7
+ {description && <p className="text-xs text-neutral-500 mb-5">{description}</p>}
8
+ {!description && <div className="mb-5" />}
9
+ {children}
10
+ </section>
11
+ );
12
+ }
13
+
14
+ export function ColorField({ label, value, onChange }: { label: string; value: string; onChange: (v: string) => void }) {
15
+ return (
16
+ <div className="flex items-center gap-3">
17
+ <input
18
+ type="color"
19
+ value={value}
20
+ onChange={(e) => onChange(e.target.value)}
21
+ className="w-8 h-8 rounded-lg border border-neutral-200 cursor-pointer bg-transparent [&::-webkit-color-swatch-wrapper]:p-0 [&::-webkit-color-swatch]:rounded-md [&::-webkit-color-swatch]:border-none"
22
+ />
23
+ <div className="flex-1">
24
+ <label className="text-xs text-neutral-500 block mb-0.5">{label}</label>
25
+ <input
26
+ type="text"
27
+ value={value}
28
+ onChange={(e) => onChange(e.target.value)}
29
+ className="w-full rounded-lg border border-neutral-200 bg-white px-2 py-1 text-xs text-neutral-900 focus:border-[#3580f9] focus:outline-none"
30
+ />
31
+ </div>
32
+ </div>
33
+ );
34
+ }
35
+
36
+ export function SaveButton({ onClick, saving, label = "Save" }: { onClick: () => void; saving: boolean; label?: string }) {
37
+ return (
38
+ <button
39
+ onClick={onClick}
40
+ disabled={saving}
41
+ className="rounded-lg bg-[#3580f9] px-5 py-1.5 text-sm font-medium text-white hover:bg-[#2d6dd4] transition-colors disabled:opacity-50"
42
+ >
43
+ {saving ? "Saving..." : label}
44
+ </button>
45
+ );
46
+ }
47
+
48
+ export function FieldInput({ label, value, onChange, placeholder, helpText }: {
49
+ label: string;
50
+ value: string;
51
+ onChange: (v: string) => void;
52
+ placeholder?: string;
53
+ helpText?: string;
54
+ }) {
55
+ return (
56
+ <div>
57
+ <label className="text-[10px] text-neutral-400 uppercase tracking-wider block mb-1">{label}</label>
58
+ <input
59
+ type="text"
60
+ value={value}
61
+ onChange={(e) => onChange(e.target.value)}
62
+ className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2 text-sm text-neutral-900 focus:border-[#3580f9] focus:outline-none"
63
+ placeholder={placeholder}
64
+ />
65
+ {helpText && <p className="text-[10px] text-neutral-400 mt-1">{helpText}</p>}
66
+ </div>
67
+ );
68
+ }