@morphika/andami 0.5.1 → 0.5.3
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/README.md +27 -2
- package/app/admin/assets/page.tsx +6 -6
- package/app/admin/database/page.tsx +302 -302
- package/app/admin/error.tsx +53 -53
- package/app/admin/layout.tsx +332 -320
- package/app/admin/navigation/page.tsx +255 -255
- package/app/admin/pages/[slug]/page.tsx +44 -27
- package/app/admin/pages/page.tsx +24 -19
- package/app/admin/projects/page.tsx +30 -21
- package/app/admin/setup/page.tsx +1 -1
- package/app/admin/styles/page.tsx +1 -1
- package/app/api/admin/assets/register/route.ts +51 -14
- package/app/api/admin/assets/registry/route.ts +4 -1
- package/app/api/admin/assets/relink/confirm/route.ts +4 -1
- package/app/api/admin/assets/relink/route.ts +4 -1
- package/app/api/admin/assets/scan/route.ts +4 -1
- package/app/api/admin/backups/restore-data/route.ts +4 -1
- package/app/api/admin/r2/connect/route.ts +4 -1
- package/app/api/admin/r2/delete/route.ts +4 -1
- package/app/api/admin/r2/rename/route.ts +4 -1
- package/app/api/admin/r2/upload-url/route.ts +4 -1
- package/app/api/admin/revalidate/route.ts +4 -1
- package/app/api/admin/storage/switch/route.ts +4 -1
- package/app/api/custom-sections/[id]/route.ts +5 -6
- package/components/admin/MetadataEditor.tsx +6 -6
- package/components/admin/PublishToggle.tsx +2 -2
- package/components/admin/nav-builder/NavBuilder.tsx +1 -1
- package/components/admin/nav-builder/NavBuilderGrid.tsx +3 -3
- package/components/admin/nav-builder/NavGridCell.tsx +48 -48
- package/components/admin/nav-builder/NavGridItem.tsx +8 -6
- package/components/admin/nav-builder/NavItemSettings.tsx +331 -331
- package/components/admin/nav-builder/NavItemTypePicker.tsx +102 -102
- package/components/admin/nav-builder/NavLivePreview.tsx +1 -1
- package/components/admin/nav-builder/NavMobileLivePreview.tsx +226 -226
- package/components/admin/nav-builder/NavMobileSettings.tsx +242 -242
- package/components/admin/nav-builder/NavSettingsFields.tsx +518 -514
- package/components/admin/setup-wizard/BrandingStep.tsx +3 -3
- package/components/admin/setup-wizard/DatabaseStep.tsx +2 -2
- package/components/admin/setup-wizard/DoneStep.tsx +1 -1
- package/components/admin/setup-wizard/SetupWizard.tsx +4 -4
- package/components/admin/setup-wizard/StorageStep.tsx +2 -2
- package/components/admin/setup-wizard/WelcomeStep.tsx +2 -2
- package/components/admin/styles/ColorsEditor.tsx +9 -8
- package/components/admin/styles/FontsEditor.tsx +9 -7
- package/components/admin/styles/GridLayoutEditor.tsx +9 -9
- package/components/admin/styles/LinksButtonsEditor.tsx +5 -5
- package/components/admin/styles/TypographyEditor.tsx +6 -6
- package/components/admin/styles/shared.tsx +68 -68
- package/components/blocks/AudioBlockRenderer.tsx +286 -286
- package/components/blocks/CoverSectionRenderer.tsx +7 -1
- package/components/blocks/MarqueeBlockRenderer.tsx +316 -0
- package/components/blocks/ProjectCarouselBlockRenderer.tsx +1 -1
- package/components/blocks/SectionV2Renderer.tsx +8 -1
- package/components/builder/BlockCardIcons.tsx +316 -316
- package/components/builder/BlockTypePicker.tsx +1 -1
- package/components/builder/BubbleIcons.tsx +104 -0
- package/components/builder/BuilderCanvas.tsx +2 -0
- package/components/builder/CanvasMinimap.tsx +66 -49
- package/components/builder/CanvasToolbar.tsx +31 -41
- package/components/builder/CoverSectionCanvas.tsx +363 -363
- package/components/builder/DeviceFrame.tsx +1 -1
- package/components/builder/DndWrapper.tsx +3 -3
- package/components/builder/InsertionLines.tsx +1 -1
- package/components/builder/SectionCardIcons.tsx +421 -320
- package/components/builder/SectionEditorBar.tsx +5 -3
- package/components/builder/SectionTypePicker.tsx +7 -5
- package/components/builder/SectionV2Canvas.tsx +1 -1
- package/components/builder/SectionV2Column.tsx +82 -68
- package/components/builder/SettingsPanel.tsx +21 -17
- package/components/builder/SortableBlock.tsx +93 -73
- package/components/builder/SortableRow.tsx +33 -35
- package/components/builder/VirtualAssetGrid.tsx +10 -4
- package/components/builder/asset-browser/R2BrowserContent.tsx +18 -14
- package/components/builder/blockStyles.tsx +192 -185
- package/components/builder/color-picker/AlphaSlider.tsx +141 -141
- package/components/builder/color-picker/ColorInputs.tsx +105 -105
- package/components/builder/color-picker/EyedropperButton.tsx +75 -74
- package/components/builder/color-picker/HueSlider.tsx +124 -124
- package/components/builder/color-picker/SaturationCanvas.tsx +142 -142
- package/components/builder/color-picker/SwatchBar.tsx +98 -93
- package/components/builder/color-picker/UnifiedColorPicker.tsx +11 -6
- package/components/builder/editors/AudioBlockEditor.tsx +242 -242
- package/components/builder/editors/BeforeAfterBlockEditor.tsx +360 -360
- package/components/builder/editors/ButtonBlockEditor.tsx +4 -4
- package/components/builder/editors/EnterAnimationPicker.tsx +2 -2
- package/components/builder/editors/HoverEffectPicker.tsx +2 -2
- package/components/builder/editors/ImageBlockEditor.tsx +2 -2
- package/components/builder/editors/ImageGridBlockEditor.tsx +8 -6
- package/components/builder/editors/MarqueeBlockEditor.tsx +622 -0
- package/components/builder/editors/ProjectCarouselBlockEditor.tsx +443 -443
- package/components/builder/editors/ProjectGridEditor.tsx +21 -16
- package/components/builder/editors/SpacerBlockEditor.tsx +29 -27
- package/components/builder/editors/StaggerSettings.tsx +109 -109
- package/components/builder/editors/TextBlockEditor.tsx +22 -17
- package/components/builder/editors/TextStylePicker.tsx +1 -1
- package/components/builder/editors/VideoBlockEditor.tsx +2 -2
- package/components/builder/editors/index.ts +11 -10
- package/components/builder/editors/shared.tsx +10 -8
- package/components/builder/live-preview/LiveAudioPreview.tsx +120 -120
- package/components/builder/live-preview/LiveBeforeAfterPreview.tsx +1 -1
- package/components/builder/live-preview/LiveImageGridPreview.tsx +10 -2
- package/components/builder/live-preview/LiveImagePreview.tsx +4 -2
- package/components/builder/live-preview/LiveMarqueePreview.tsx +39 -0
- package/components/builder/live-preview/LiveProjectCarouselPreview.tsx +1 -1
- package/components/builder/live-preview/LiveVideoPreview.tsx +1 -1
- package/components/builder/live-preview/ProjectCardWrapper.tsx +293 -291
- package/components/builder/live-preview/RichTextBubbleMenu.tsx +10 -6
- package/components/builder/live-preview/shared.tsx +5 -2
- package/components/builder/settings-panel/AnimationTab.tsx +138 -138
- package/components/builder/settings-panel/BlockLayoutTab.tsx +11 -9
- package/components/builder/settings-panel/CardEntranceSection.tsx +114 -114
- package/components/builder/settings-panel/ColumnV2LayoutTab.tsx +242 -0
- package/components/builder/settings-panel/ColumnV2Settings.tsx +5 -5
- package/components/builder/settings-panel/CoverSectionLayoutTab.tsx +71 -71
- package/components/builder/settings-panel/CoverSectionSettings.tsx +337 -335
- package/components/builder/settings-panel/PageSettings.tsx +3 -3
- package/components/builder/settings-panel/ParallaxSlideSettings.tsx +2 -2
- package/components/builder/settings-panel/SectionV2AnimationTab.tsx +4 -4
- package/components/builder/settings-panel/SectionV2LayoutTab.tsx +356 -356
- package/components/builder/settings-panel/SectionV2Settings.tsx +25 -20
- package/components/builder/settings-panel/TRBLInputs.tsx +1 -1
- package/components/builder/settings-panel/index.ts +1 -0
- package/lib/animation/enter-types.ts +1 -0
- package/lib/animation/hover-effect-presets.ts +210 -210
- package/lib/animation/hover-effect-types.ts +1 -0
- package/lib/builder/block-registrations.ts +468 -417
- package/lib/builder/constants.ts +111 -111
- package/lib/builder/serializer/normalizers.ts +14 -0
- package/lib/builder/serializer/serializers.ts +27 -0
- package/lib/builder/store-sections.ts +23 -2
- package/lib/builder/types-slices.ts +428 -414
- package/lib/builder/types.ts +4 -1
- package/lib/config/index.ts +27 -27
- package/lib/sanity/queries.ts +48 -0
- package/lib/sanity/types.ts +112 -1
- package/lib/version.ts +1 -1
- package/package.json +7 -5
- package/sanity/schemas/blocks/audioBlock.ts +69 -69
- package/sanity/schemas/blocks/index.ts +12 -11
- package/sanity/schemas/blocks/marqueeBlock.ts +292 -0
- package/sanity/schemas/index.ts +120 -117
- package/sanity/schemas/objects/coverSection.ts +32 -0
- package/sanity/schemas/objects/parallaxSlide.ts +32 -0
- package/sanity/schemas/pageSectionV2.ts +32 -0
- package/styles/admin.css +85 -85
- package/styles/animations.css +237 -237
- package/styles/base.css +114 -114
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ColumnV2LayoutTab — Layout tab for a selected V2/cover/parallax-slide column.
|
|
5
|
+
*
|
|
6
|
+
* Desktop-only for now. Viewport-aware column layout would require extending
|
|
7
|
+
* ColumnOverride (currently position-only) — not yet implemented.
|
|
8
|
+
*
|
|
9
|
+
* Sections: Background (color/opacity/image), Border (color/width/style/sides/radius).
|
|
10
|
+
* Columns intentionally have no Spacing or Offset — use the parent section's
|
|
11
|
+
* row_gap/col_gap, or block-level padding.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { useBuilderStore } from "../../../lib/builder/store";
|
|
15
|
+
import type { PageSectionV2, SectionColumn } from "../../../lib/sanity/types";
|
|
16
|
+
import {
|
|
17
|
+
SettingsField,
|
|
18
|
+
SettingsSection,
|
|
19
|
+
SELECT_CLASS,
|
|
20
|
+
AssetPathInput,
|
|
21
|
+
} from "../editors/shared";
|
|
22
|
+
import ColorSwatchPicker, { usePaletteSwatches } from "../ColorSwatchPicker";
|
|
23
|
+
import { serializeColorField, parseColorField, isGradient } from "../../../lib/color-utils";
|
|
24
|
+
import { BackgroundIcon, BorderIcon } from "../editors/section-icons";
|
|
25
|
+
|
|
26
|
+
type LayoutField =
|
|
27
|
+
| "background_color" | "background_opacity" | "background_image"
|
|
28
|
+
| "background_size" | "background_position" | "background_repeat"
|
|
29
|
+
| "border_color" | "border_width" | "border_style" | "border_sides" | "border_radius";
|
|
30
|
+
|
|
31
|
+
export function ColumnV2LayoutTab({
|
|
32
|
+
section,
|
|
33
|
+
column,
|
|
34
|
+
}: {
|
|
35
|
+
section: PageSectionV2;
|
|
36
|
+
column: SectionColumn;
|
|
37
|
+
}) {
|
|
38
|
+
const store = useBuilderStore();
|
|
39
|
+
const paletteSwatches = usePaletteSwatches();
|
|
40
|
+
const activeViewport = store.activeViewport;
|
|
41
|
+
|
|
42
|
+
const isResponsive = activeViewport !== "desktop";
|
|
43
|
+
|
|
44
|
+
const update = (field: LayoutField, value: unknown) => {
|
|
45
|
+
store._pushSnapshot();
|
|
46
|
+
store.updateColumnV2Layout(section._key, column._key, {
|
|
47
|
+
[field]: value,
|
|
48
|
+
} as Partial<SectionColumn>);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const getValue = <T,>(field: LayoutField, fallback: T): T => {
|
|
52
|
+
const val = (column as unknown as Record<string, unknown>)[field];
|
|
53
|
+
return (val !== undefined && val !== null ? val : fallback) as T;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const handleBgPreview = (val: import("../../../lib/sanity/types").ColorField) => {
|
|
57
|
+
store.setColorPickerPreview({ sectionKey: section._key, field: "column_background_color", value: val });
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const bgIsGradient = isGradient(parseColorField(getValue<string>("background_color", "")));
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<>
|
|
64
|
+
{isResponsive && (
|
|
65
|
+
<div className="px-4 pt-3">
|
|
66
|
+
<div className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-neutral-100 border border-neutral-200">
|
|
67
|
+
<span className="text-[11px] font-medium text-neutral-500">
|
|
68
|
+
Column layout is desktop-only for now
|
|
69
|
+
</span>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
)}
|
|
73
|
+
|
|
74
|
+
{/* Background */}
|
|
75
|
+
<SettingsSection title="Background" defaultOpen icon={<BackgroundIcon />}>
|
|
76
|
+
<SettingsField label="Color">
|
|
77
|
+
<ColorSwatchPicker
|
|
78
|
+
value={parseColorField(getValue<string>("background_color", ""))}
|
|
79
|
+
onChange={(val) => {
|
|
80
|
+
store.clearColorPickerPreview();
|
|
81
|
+
update("background_color", serializeColorField(val));
|
|
82
|
+
}}
|
|
83
|
+
swatches={paletteSwatches}
|
|
84
|
+
allowGradients
|
|
85
|
+
onPreview={handleBgPreview}
|
|
86
|
+
/>
|
|
87
|
+
</SettingsField>
|
|
88
|
+
|
|
89
|
+
<SettingsField label="Opacity">
|
|
90
|
+
<div className="flex items-center gap-2">
|
|
91
|
+
<input
|
|
92
|
+
type="range"
|
|
93
|
+
min={0}
|
|
94
|
+
max={100}
|
|
95
|
+
value={getValue<number>("background_opacity", 100)}
|
|
96
|
+
onChange={(e) => update("background_opacity", parseInt(e.target.value))}
|
|
97
|
+
className={`flex-1 accent-[#3580f9] ${bgIsGradient ? "opacity-40 pointer-events-none" : ""}`}
|
|
98
|
+
disabled={bgIsGradient}
|
|
99
|
+
/>
|
|
100
|
+
<span className="text-xs text-neutral-900 w-10 text-right">
|
|
101
|
+
{getValue<number>("background_opacity", 100)}%
|
|
102
|
+
</span>
|
|
103
|
+
</div>
|
|
104
|
+
{bgIsGradient && (
|
|
105
|
+
<p className="text-[9px] text-neutral-400 italic mt-1">
|
|
106
|
+
Opacity is controlled per stop in gradient mode
|
|
107
|
+
</p>
|
|
108
|
+
)}
|
|
109
|
+
</SettingsField>
|
|
110
|
+
|
|
111
|
+
<SettingsField label="Image">
|
|
112
|
+
<AssetPathInput
|
|
113
|
+
value={getValue<string>("background_image", "")}
|
|
114
|
+
onFocus={() => store._pushSnapshot()}
|
|
115
|
+
onChange={(v) => update("background_image", v)}
|
|
116
|
+
placeholder="path/to/image.jpg"
|
|
117
|
+
filterType="image"
|
|
118
|
+
/>
|
|
119
|
+
</SettingsField>
|
|
120
|
+
|
|
121
|
+
{getValue<string>("background_image", "") && (
|
|
122
|
+
<>
|
|
123
|
+
<SettingsField label="Size">
|
|
124
|
+
<select
|
|
125
|
+
value={getValue<string>("background_size", "cover")}
|
|
126
|
+
onChange={(e) => update("background_size", e.target.value)}
|
|
127
|
+
className={SELECT_CLASS}
|
|
128
|
+
>
|
|
129
|
+
<option value="cover">Cover</option>
|
|
130
|
+
<option value="contain">Contain</option>
|
|
131
|
+
<option value="auto">Auto</option>
|
|
132
|
+
</select>
|
|
133
|
+
</SettingsField>
|
|
134
|
+
|
|
135
|
+
<SettingsField label="Position">
|
|
136
|
+
<select
|
|
137
|
+
value={getValue<string>("background_position", "center center")}
|
|
138
|
+
onChange={(e) => update("background_position", e.target.value)}
|
|
139
|
+
className={SELECT_CLASS}
|
|
140
|
+
>
|
|
141
|
+
<option value="center center">Center</option>
|
|
142
|
+
<option value="top center">Top</option>
|
|
143
|
+
<option value="bottom center">Bottom</option>
|
|
144
|
+
<option value="left center">Left</option>
|
|
145
|
+
<option value="right center">Right</option>
|
|
146
|
+
</select>
|
|
147
|
+
</SettingsField>
|
|
148
|
+
|
|
149
|
+
<SettingsField label="Repeat">
|
|
150
|
+
<select
|
|
151
|
+
value={getValue<string>("background_repeat", "no-repeat")}
|
|
152
|
+
onChange={(e) => update("background_repeat", e.target.value)}
|
|
153
|
+
className={SELECT_CLASS}
|
|
154
|
+
>
|
|
155
|
+
<option value="no-repeat">No Repeat</option>
|
|
156
|
+
<option value="repeat">Repeat</option>
|
|
157
|
+
<option value="repeat-x">Repeat X</option>
|
|
158
|
+
<option value="repeat-y">Repeat Y</option>
|
|
159
|
+
</select>
|
|
160
|
+
</SettingsField>
|
|
161
|
+
</>
|
|
162
|
+
)}
|
|
163
|
+
</SettingsSection>
|
|
164
|
+
|
|
165
|
+
{/* Border */}
|
|
166
|
+
<SettingsSection title="Border" icon={<BorderIcon />}>
|
|
167
|
+
<SettingsField label="Color">
|
|
168
|
+
<ColorSwatchPicker
|
|
169
|
+
value={parseColorField(getValue<string>("border_color", ""))}
|
|
170
|
+
onChange={(val) => {
|
|
171
|
+
store.clearColorPickerPreview();
|
|
172
|
+
update("border_color", serializeColorField(val));
|
|
173
|
+
}}
|
|
174
|
+
swatches={paletteSwatches}
|
|
175
|
+
allowGradients
|
|
176
|
+
/>
|
|
177
|
+
</SettingsField>
|
|
178
|
+
|
|
179
|
+
<SettingsField label="Width">
|
|
180
|
+
<div className="flex items-center gap-2">
|
|
181
|
+
<input
|
|
182
|
+
type="range"
|
|
183
|
+
min={0}
|
|
184
|
+
max={20}
|
|
185
|
+
value={parseInt(getValue<string>("border_width", "0"))}
|
|
186
|
+
onChange={(e) => update("border_width", e.target.value)}
|
|
187
|
+
className="flex-1 accent-[#3580f9]"
|
|
188
|
+
/>
|
|
189
|
+
<span className="text-xs text-neutral-900 w-10 text-right">
|
|
190
|
+
{getValue<string>("border_width", "0")}px
|
|
191
|
+
</span>
|
|
192
|
+
</div>
|
|
193
|
+
</SettingsField>
|
|
194
|
+
|
|
195
|
+
<SettingsField label="Style">
|
|
196
|
+
<select
|
|
197
|
+
value={getValue<string>("border_style", "none")}
|
|
198
|
+
onChange={(e) => update("border_style", e.target.value)}
|
|
199
|
+
className={SELECT_CLASS}
|
|
200
|
+
>
|
|
201
|
+
<option value="none">None</option>
|
|
202
|
+
<option value="solid">Solid</option>
|
|
203
|
+
<option value="dashed">Dashed</option>
|
|
204
|
+
<option value="dotted">Dotted</option>
|
|
205
|
+
</select>
|
|
206
|
+
</SettingsField>
|
|
207
|
+
|
|
208
|
+
<SettingsField label="Sides">
|
|
209
|
+
<select
|
|
210
|
+
value={getValue<string>("border_sides", "all")}
|
|
211
|
+
onChange={(e) => update("border_sides", e.target.value)}
|
|
212
|
+
className={SELECT_CLASS}
|
|
213
|
+
>
|
|
214
|
+
<option value="all">All</option>
|
|
215
|
+
<option value="top">Top</option>
|
|
216
|
+
<option value="right">Right</option>
|
|
217
|
+
<option value="bottom">Bottom</option>
|
|
218
|
+
<option value="left">Left</option>
|
|
219
|
+
<option value="top-bottom">Top & Bottom</option>
|
|
220
|
+
<option value="left-right">Left & Right</option>
|
|
221
|
+
</select>
|
|
222
|
+
</SettingsField>
|
|
223
|
+
|
|
224
|
+
<SettingsField label="Radius">
|
|
225
|
+
<div className="flex items-center gap-2">
|
|
226
|
+
<input
|
|
227
|
+
type="range"
|
|
228
|
+
min={0}
|
|
229
|
+
max={50}
|
|
230
|
+
value={parseInt(getValue<string>("border_radius", "0"))}
|
|
231
|
+
onChange={(e) => update("border_radius", e.target.value)}
|
|
232
|
+
className="flex-1 accent-[#3580f9]"
|
|
233
|
+
/>
|
|
234
|
+
<span className="text-xs text-neutral-900 w-10 text-right">
|
|
235
|
+
{getValue<string>("border_radius", "0")}px
|
|
236
|
+
</span>
|
|
237
|
+
</div>
|
|
238
|
+
</SettingsField>
|
|
239
|
+
</SettingsSection>
|
|
240
|
+
</>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
@@ -85,8 +85,8 @@ export default function ColumnV2Settings({
|
|
|
85
85
|
<>
|
|
86
86
|
{isResponsive && (
|
|
87
87
|
<div className="px-4 pt-3">
|
|
88
|
-
<div className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-[#
|
|
89
|
-
<span className="text-[11px] font-medium text-[#
|
|
88
|
+
<div className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-[#3580f9]/8 border border-[#3580f9]/15">
|
|
89
|
+
<span className="text-[11px] font-medium text-[#3580f9]">
|
|
90
90
|
Editing {activeViewport === "tablet" ? "Tablet" : "Phone"} overrides
|
|
91
91
|
</span>
|
|
92
92
|
</div>
|
|
@@ -98,7 +98,7 @@ export default function ColumnV2Settings({
|
|
|
98
98
|
<span>
|
|
99
99
|
Span
|
|
100
100
|
{hasSpanOverride && (
|
|
101
|
-
<span className="ml-1 text-[9px] text-[#
|
|
101
|
+
<span className="ml-1 text-[9px] text-[#3580f9]">overridden</span>
|
|
102
102
|
)}
|
|
103
103
|
</span>
|
|
104
104
|
}>
|
|
@@ -109,7 +109,7 @@ export default function ColumnV2Settings({
|
|
|
109
109
|
max={gridColumns}
|
|
110
110
|
value={effectiveSpan}
|
|
111
111
|
onChange={(e) => handleSpanChange(parseInt(e.target.value))}
|
|
112
|
-
className="flex-1 accent-[#
|
|
112
|
+
className="flex-1 accent-[#3580f9]"
|
|
113
113
|
/>
|
|
114
114
|
<span className="text-xs text-neutral-900 w-12 text-right font-medium">
|
|
115
115
|
{effectiveSpan}/{gridColumns}
|
|
@@ -133,7 +133,7 @@ export default function ColumnV2Settings({
|
|
|
133
133
|
<div
|
|
134
134
|
key={i}
|
|
135
135
|
className={`h-1.5 flex-1 rounded-full transition-colors ${
|
|
136
|
-
isActive ? "bg-[#
|
|
136
|
+
isActive ? "bg-[#3580f9]" : "bg-neutral-200"
|
|
137
137
|
}`}
|
|
138
138
|
/>
|
|
139
139
|
);
|
|
@@ -1,71 +1,71 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useBuilderStore } from "../../../lib/builder/store";
|
|
4
|
-
import type { CoverSection } from "../../../lib/sanity/types";
|
|
5
|
-
import {
|
|
6
|
-
SpacingIcon,
|
|
7
|
-
OffsetIcon,
|
|
8
|
-
BorderIcon,
|
|
9
|
-
} from "../editors/section-icons";
|
|
10
|
-
import { SettingsField, SettingsSection } from "../editors/shared";
|
|
11
|
-
import { TRBLInputs } from "./TRBLInputs";
|
|
12
|
-
|
|
13
|
-
interface CoverSectionLayoutTabProps {
|
|
14
|
-
section: CoverSection;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export default function CoverSectionLayoutTab({ section }: CoverSectionLayoutTabProps) {
|
|
18
|
-
const store = useBuilderStore();
|
|
19
|
-
const s = section.settings;
|
|
20
|
-
|
|
21
|
-
const update = (fields: Record<string, string | undefined>) => {
|
|
22
|
-
store.updateCoverSettings(section._key, fields as Partial<typeof s>);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
return (
|
|
26
|
-
<>
|
|
27
|
-
{/* Spacing (padding) */}
|
|
28
|
-
<SettingsSection title="Spacing" defaultOpen icon={<SpacingIcon />}>
|
|
29
|
-
<TRBLInputs
|
|
30
|
-
top={s.spacing_top || ""}
|
|
31
|
-
right={s.spacing_right || ""}
|
|
32
|
-
bottom={s.spacing_bottom || ""}
|
|
33
|
-
left={s.spacing_left || ""}
|
|
34
|
-
onChange={(field, value) => update({ [`spacing_${field}`]: value || undefined })}
|
|
35
|
-
/>
|
|
36
|
-
</SettingsSection>
|
|
37
|
-
|
|
38
|
-
{/* Offset (margin) */}
|
|
39
|
-
<SettingsSection title="Offset" defaultOpen={false} icon={<OffsetIcon />}>
|
|
40
|
-
<TRBLInputs
|
|
41
|
-
top={s.offset_top || ""}
|
|
42
|
-
right={s.offset_right || ""}
|
|
43
|
-
bottom={s.offset_bottom || ""}
|
|
44
|
-
left={s.offset_left || ""}
|
|
45
|
-
onChange={(field, value) => update({ [`offset_${field}`]: value || undefined })}
|
|
46
|
-
/>
|
|
47
|
-
</SettingsSection>
|
|
48
|
-
|
|
49
|
-
{/* Border Radius */}
|
|
50
|
-
<SettingsSection title="Border" defaultOpen={false} icon={<BorderIcon />}>
|
|
51
|
-
<SettingsField label="Radius">
|
|
52
|
-
<div className="flex items-center gap-2">
|
|
53
|
-
<input
|
|
54
|
-
type="range"
|
|
55
|
-
min={0}
|
|
56
|
-
max={50}
|
|
57
|
-
step={1}
|
|
58
|
-
value={parseInt(s.border_radius || "0", 10) || 0}
|
|
59
|
-
onMouseDown={() => store._pushSnapshot()}
|
|
60
|
-
onChange={(e) => update({ border_radius: e.target.value === "0" ? undefined : e.target.value })}
|
|
61
|
-
className="flex-1 accent-[#
|
|
62
|
-
/>
|
|
63
|
-
<span className="text-xs text-neutral-900 w-10 text-right tabular-nums">
|
|
64
|
-
{parseInt(s.border_radius || "0", 10) || 0}px
|
|
65
|
-
</span>
|
|
66
|
-
</div>
|
|
67
|
-
</SettingsField>
|
|
68
|
-
</SettingsSection>
|
|
69
|
-
</>
|
|
70
|
-
);
|
|
71
|
-
}
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useBuilderStore } from "../../../lib/builder/store";
|
|
4
|
+
import type { CoverSection } from "../../../lib/sanity/types";
|
|
5
|
+
import {
|
|
6
|
+
SpacingIcon,
|
|
7
|
+
OffsetIcon,
|
|
8
|
+
BorderIcon,
|
|
9
|
+
} from "../editors/section-icons";
|
|
10
|
+
import { SettingsField, SettingsSection } from "../editors/shared";
|
|
11
|
+
import { TRBLInputs } from "./TRBLInputs";
|
|
12
|
+
|
|
13
|
+
interface CoverSectionLayoutTabProps {
|
|
14
|
+
section: CoverSection;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default function CoverSectionLayoutTab({ section }: CoverSectionLayoutTabProps) {
|
|
18
|
+
const store = useBuilderStore();
|
|
19
|
+
const s = section.settings;
|
|
20
|
+
|
|
21
|
+
const update = (fields: Record<string, string | undefined>) => {
|
|
22
|
+
store.updateCoverSettings(section._key, fields as Partial<typeof s>);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<>
|
|
27
|
+
{/* Spacing (padding) */}
|
|
28
|
+
<SettingsSection title="Spacing" defaultOpen icon={<SpacingIcon />}>
|
|
29
|
+
<TRBLInputs
|
|
30
|
+
top={s.spacing_top || ""}
|
|
31
|
+
right={s.spacing_right || ""}
|
|
32
|
+
bottom={s.spacing_bottom || ""}
|
|
33
|
+
left={s.spacing_left || ""}
|
|
34
|
+
onChange={(field, value) => update({ [`spacing_${field}`]: value || undefined })}
|
|
35
|
+
/>
|
|
36
|
+
</SettingsSection>
|
|
37
|
+
|
|
38
|
+
{/* Offset (margin) */}
|
|
39
|
+
<SettingsSection title="Offset" defaultOpen={false} icon={<OffsetIcon />}>
|
|
40
|
+
<TRBLInputs
|
|
41
|
+
top={s.offset_top || ""}
|
|
42
|
+
right={s.offset_right || ""}
|
|
43
|
+
bottom={s.offset_bottom || ""}
|
|
44
|
+
left={s.offset_left || ""}
|
|
45
|
+
onChange={(field, value) => update({ [`offset_${field}`]: value || undefined })}
|
|
46
|
+
/>
|
|
47
|
+
</SettingsSection>
|
|
48
|
+
|
|
49
|
+
{/* Border Radius */}
|
|
50
|
+
<SettingsSection title="Border" defaultOpen={false} icon={<BorderIcon />}>
|
|
51
|
+
<SettingsField label="Radius">
|
|
52
|
+
<div className="flex items-center gap-2">
|
|
53
|
+
<input
|
|
54
|
+
type="range"
|
|
55
|
+
min={0}
|
|
56
|
+
max={50}
|
|
57
|
+
step={1}
|
|
58
|
+
value={parseInt(s.border_radius || "0", 10) || 0}
|
|
59
|
+
onMouseDown={() => store._pushSnapshot()}
|
|
60
|
+
onChange={(e) => update({ border_radius: e.target.value === "0" ? undefined : e.target.value })}
|
|
61
|
+
className="flex-1 accent-[#3580f9]"
|
|
62
|
+
/>
|
|
63
|
+
<span className="text-xs text-neutral-900 w-10 text-right tabular-nums">
|
|
64
|
+
{parseInt(s.border_radius || "0", 10) || 0}px
|
|
65
|
+
</span>
|
|
66
|
+
</div>
|
|
67
|
+
</SettingsField>
|
|
68
|
+
</SettingsSection>
|
|
69
|
+
</>
|
|
70
|
+
);
|
|
71
|
+
}
|