@morphika/andami 0.2.14 → 0.2.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/blocks/CoverSectionRenderer.tsx +19 -3
- package/components/blocks/SectionV2Renderer.tsx +8 -1
- package/components/builder/ReadOnlyFrame.tsx +27 -6
- package/components/builder/SectionV2Column.tsx +1 -0
- package/components/builder/SettingsPanel.tsx +3 -0
- package/components/builder/SortableBlock.tsx +26 -11
- package/components/builder/live-preview/LiveImagePreview.tsx +1 -1
- package/components/builder/live-preview/LiveVideoPreview.tsx +1 -1
- package/components/builder/settings-panel/CoverSectionLayoutTab.tsx +71 -0
- package/lib/sanity/types.ts +10 -1
- package/lib/version.ts +1 -1
- package/package.json +1 -1
- package/sanity/schemas/objects/coverSection.ts +11 -0
|
@@ -127,12 +127,19 @@ export default function CoverSectionRenderer({ section, pageEnterAnimation }: Co
|
|
|
127
127
|
rowAlignMap[String(i + 1)] = row.vertical_align || "start";
|
|
128
128
|
});
|
|
129
129
|
|
|
130
|
+
const borderRadius = s.border_radius ? `${String(s.border_radius).replace(/[a-z%]+$/i, "")}px` : undefined;
|
|
131
|
+
|
|
130
132
|
const sectionContent = (
|
|
131
133
|
<section
|
|
132
134
|
style={{
|
|
133
135
|
position: "relative",
|
|
134
136
|
height: section.height,
|
|
135
137
|
overflow: "hidden",
|
|
138
|
+
marginTop: s.offset_top ? `${s.offset_top}px` : undefined,
|
|
139
|
+
marginRight: s.offset_right ? `${s.offset_right}px` : undefined,
|
|
140
|
+
marginBottom: s.offset_bottom ? `${s.offset_bottom}px` : undefined,
|
|
141
|
+
marginLeft: s.offset_left ? `${s.offset_left}px` : undefined,
|
|
142
|
+
borderRadius,
|
|
136
143
|
}}
|
|
137
144
|
>
|
|
138
145
|
{responsiveCss && <style dangerouslySetInnerHTML={{ __html: responsiveCss }} />}
|
|
@@ -221,10 +228,13 @@ export default function CoverSectionRenderer({ section, pageEnterAnimation }: Co
|
|
|
221
228
|
style={{
|
|
222
229
|
gridColumn: `${col.grid_column} / span ${col.span}`,
|
|
223
230
|
gridRow: col.grid_row,
|
|
224
|
-
|
|
231
|
+
position: "relative",
|
|
232
|
+
display: "flex",
|
|
233
|
+
flexDirection: "column",
|
|
234
|
+
justifyContent: alignSelf === "center" ? "center" : alignSelf === "end" ? "flex-end" : colJustify || "flex-start",
|
|
235
|
+
height: "100%",
|
|
225
236
|
minWidth: 0,
|
|
226
237
|
overflow: "hidden",
|
|
227
|
-
...(colJustify ? { display: "flex", flexDirection: "column" as const, justifyContent: colJustify } : {}),
|
|
228
238
|
}}
|
|
229
239
|
>
|
|
230
240
|
{(col.blocks || []).map((block) => {
|
|
@@ -237,9 +247,15 @@ export default function CoverSectionRenderer({ section, pageEnterAnimation }: Co
|
|
|
237
247
|
|
|
238
248
|
const layout = (block as ContentBlock & { layout?: BlockLayout }).layout;
|
|
239
249
|
const alignStyles = layout && hasBlockAlignment(layout) ? getBlockAlignmentStyles(layout) : {};
|
|
250
|
+
const isFillBlock = (block._type === "imageBlock" || block._type === "videoBlock") &&
|
|
251
|
+
(block as unknown as { width?: string }).width === "fill";
|
|
240
252
|
|
|
241
253
|
const rendered = (
|
|
242
|
-
<div key={block._key} style={
|
|
254
|
+
<div key={block._key} style={
|
|
255
|
+
isFillBlock
|
|
256
|
+
? { position: "absolute" as const, inset: 0, zIndex: 0 }
|
|
257
|
+
: { position: "relative" as const, zIndex: 1, ...alignStyles }
|
|
258
|
+
}>
|
|
243
259
|
<BlockRenderer block={block} />
|
|
244
260
|
</div>
|
|
245
261
|
);
|
|
@@ -268,6 +268,7 @@ export default function SectionV2Renderer({ section, pageEnterAnimation }: Secti
|
|
|
268
268
|
style={{
|
|
269
269
|
gridColumn: `${col.grid_column} / span ${col.span}`,
|
|
270
270
|
gridRow: col.grid_row,
|
|
271
|
+
position: "relative",
|
|
271
272
|
display: "flex",
|
|
272
273
|
flexDirection: "column",
|
|
273
274
|
...(colJustify ? { justifyContent: colJustify } : {}),
|
|
@@ -280,8 +281,14 @@ export default function SectionV2Renderer({ section, pageEnterAnimation }: Secti
|
|
|
280
281
|
const blockLayout = (block as unknown as Record<string, unknown>).layout as BlockLayout | undefined;
|
|
281
282
|
const alignStyles = hasBlockAlignment(blockLayout) ? getBlockAlignmentStyles(blockLayout) : undefined;
|
|
282
283
|
const hasHAlign = blockLayout?.align_h && blockLayout.align_h !== "left";
|
|
284
|
+
const isFillBlock = (block._type === "imageBlock" || block._type === "videoBlock") &&
|
|
285
|
+
(block as unknown as { width?: string }).width === "fill";
|
|
283
286
|
return (
|
|
284
|
-
<div key={block._key} className={`blk-wrap-${block._key}`} style={
|
|
287
|
+
<div key={block._key} className={`blk-wrap-${block._key}`} style={
|
|
288
|
+
isFillBlock
|
|
289
|
+
? { position: "absolute" as const, inset: 0, zIndex: 0 }
|
|
290
|
+
: { ...(!hasHAlign ? { width: "100%" } : { width: "auto", maxWidth: "100%" }), minWidth: 0, position: "relative" as const, zIndex: 1, ...alignStyles }
|
|
291
|
+
}>
|
|
285
292
|
<BlockRenderer
|
|
286
293
|
block={block}
|
|
287
294
|
columnEnterAnimation={col.enter_animation}
|
|
@@ -25,6 +25,12 @@ import { DEVICE_HEIGHTS } from "../../lib/builder/types";
|
|
|
25
25
|
import { getEffectiveColumnsV2, getSectionV2SettingValue } from "./settings-panel/responsive-helpers";
|
|
26
26
|
import BlockLivePreview from "./BlockLivePreview";
|
|
27
27
|
import { getColumnVerticalAlign, getRowLayoutStyles } from "../../lib/builder/layout-styles";
|
|
28
|
+
import type { ContentBlock } from "../../lib/sanity/types";
|
|
29
|
+
|
|
30
|
+
function isFillBlock(block: ContentBlock): boolean {
|
|
31
|
+
return (block._type === "imageBlock" || block._type === "videoBlock") &&
|
|
32
|
+
(block as unknown as { width?: string }).width === "fill";
|
|
33
|
+
}
|
|
28
34
|
|
|
29
35
|
// Layout keys that support responsive overrides for V2 sections
|
|
30
36
|
const OVERRIDABLE_KEYS = [
|
|
@@ -84,6 +90,7 @@ const ReadOnlySectionV2 = memo(function ReadOnlySectionV2({ section, viewport }:
|
|
|
84
90
|
style={{
|
|
85
91
|
gridColumn: `${gridColumn} / span ${span}`,
|
|
86
92
|
gridRow,
|
|
93
|
+
position: "relative",
|
|
87
94
|
display: "flex",
|
|
88
95
|
flexDirection: "column",
|
|
89
96
|
...(colJustify ? { justifyContent: colJustify } : {}),
|
|
@@ -93,7 +100,11 @@ const ReadOnlySectionV2 = memo(function ReadOnlySectionV2({ section, viewport }:
|
|
|
93
100
|
}}
|
|
94
101
|
>
|
|
95
102
|
{(col.blocks || []).map((block) => (
|
|
96
|
-
<div key={block._key} style={
|
|
103
|
+
<div key={block._key} style={
|
|
104
|
+
isFillBlock(block)
|
|
105
|
+
? { flex: "999 1 0%", position: "relative" as const, minHeight: 0, zIndex: 0 }
|
|
106
|
+
: { width: "100%", minWidth: 0, position: "relative" as const, zIndex: 1 }
|
|
107
|
+
}>
|
|
97
108
|
<BlockLivePreview block={block} viewport={viewport} />
|
|
98
109
|
</div>
|
|
99
110
|
))}
|
|
@@ -194,6 +205,7 @@ const ReadOnlyParallaxSlide = memo(function ReadOnlyParallaxSlide({
|
|
|
194
205
|
style={{
|
|
195
206
|
gridColumn: `${col.grid_column} / span ${col.span}`,
|
|
196
207
|
gridRow: col.grid_row,
|
|
208
|
+
position: "relative",
|
|
197
209
|
display: "flex",
|
|
198
210
|
flexDirection: "column",
|
|
199
211
|
...(colJustify ? { justifyContent: colJustify } : {}),
|
|
@@ -203,7 +215,11 @@ const ReadOnlyParallaxSlide = memo(function ReadOnlyParallaxSlide({
|
|
|
203
215
|
}}
|
|
204
216
|
>
|
|
205
217
|
{(col.blocks || []).map((block) => (
|
|
206
|
-
<div key={block._key} style={
|
|
218
|
+
<div key={block._key} style={
|
|
219
|
+
isFillBlock(block)
|
|
220
|
+
? { flex: "999 1 0%", position: "relative" as const, minHeight: 0, zIndex: 0 }
|
|
221
|
+
: { width: "100%", minWidth: 0 }
|
|
222
|
+
}>
|
|
207
223
|
<BlockLivePreview block={block} viewport={viewport} />
|
|
208
224
|
</div>
|
|
209
225
|
))}
|
|
@@ -419,24 +435,29 @@ const ReadOnlyCoverSection = memo(function ReadOnlyCoverSection({
|
|
|
419
435
|
>
|
|
420
436
|
{section.columns.map((col) => {
|
|
421
437
|
const rowAlign = effectiveRows[col.grid_row - 1]?.vertical_align || "start";
|
|
422
|
-
const alignSelf = rowAlign === "center" ? "center" : rowAlign === "end" ? "end" : "start";
|
|
423
438
|
const colJustify = getColumnVerticalAlign(col.blocks || []);
|
|
439
|
+
const justify = rowAlign === "center" ? "center" : rowAlign === "end" ? "flex-end" : colJustify || "flex-start";
|
|
424
440
|
return (
|
|
425
441
|
<div
|
|
426
442
|
key={col._key}
|
|
427
443
|
style={{
|
|
428
444
|
gridColumn: `${col.grid_column} / span ${col.span}`,
|
|
429
445
|
gridRow: col.grid_row,
|
|
430
|
-
|
|
446
|
+
position: "relative",
|
|
431
447
|
display: "flex",
|
|
432
448
|
flexDirection: "column",
|
|
433
|
-
|
|
449
|
+
justifyContent: justify,
|
|
450
|
+
height: "100%",
|
|
434
451
|
minWidth: 0,
|
|
435
452
|
overflow: "hidden",
|
|
436
453
|
}}
|
|
437
454
|
>
|
|
438
455
|
{(col.blocks || []).map((block) => (
|
|
439
|
-
<div key={block._key} style={
|
|
456
|
+
<div key={block._key} style={
|
|
457
|
+
isFillBlock(block)
|
|
458
|
+
? { flex: "999 1 0%", position: "relative" as const, minHeight: 0, zIndex: 0 }
|
|
459
|
+
: { width: "100%", minWidth: 0, position: "relative" as const, zIndex: 1 }
|
|
460
|
+
}>
|
|
440
461
|
<BlockLivePreview block={block} viewport={viewport} />
|
|
441
462
|
</div>
|
|
442
463
|
))}
|
|
@@ -233,6 +233,7 @@ export default function SectionV2Column({
|
|
|
233
233
|
style={{
|
|
234
234
|
gridColumn: `${column.grid_column} / span ${column.span}`,
|
|
235
235
|
gridRow: column.grid_row,
|
|
236
|
+
position: "relative",
|
|
236
237
|
display: "flex",
|
|
237
238
|
flexDirection: "column",
|
|
238
239
|
...(colJustify ? { justifyContent: colJustify } : {}),
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
ParallaxGroupSettings,
|
|
40
40
|
CoverSectionSettings,
|
|
41
41
|
} from "./settings-panel";
|
|
42
|
+
import CoverSectionLayoutTab from "./settings-panel/CoverSectionLayoutTab";
|
|
42
43
|
|
|
43
44
|
type SettingsTab = "settings" | "layout" | "seo" | "animation";
|
|
44
45
|
|
|
@@ -337,6 +338,8 @@ export default function SettingsPanel() {
|
|
|
337
338
|
isCoverSectionOnly && selectedCoverSection ? (
|
|
338
339
|
activeTab === "animation" ? (
|
|
339
340
|
<SectionV2AnimationTab section={effectiveSectionV2!} />
|
|
341
|
+
) : activeTab === "layout" ? (
|
|
342
|
+
<CoverSectionLayoutTab section={selectedCoverSection} />
|
|
340
343
|
) : (
|
|
341
344
|
<CoverSectionSettings section={selectedCoverSection} />
|
|
342
345
|
)
|
|
@@ -7,7 +7,7 @@ import { makeBlockId } from "./DndWrapper";
|
|
|
7
7
|
import { ALL_BLOCK_INFO, isSectionBlockType } from "../../lib/builder/types";
|
|
8
8
|
import type { DeviceViewport } from "../../lib/builder/types";
|
|
9
9
|
import { useBuilderStore } from "../../lib/builder/store";
|
|
10
|
-
import type { ContentBlock } from "../../lib/sanity/types";
|
|
10
|
+
import type { ContentBlock, ImageBlock, VideoBlock } from "../../lib/sanity/types";
|
|
11
11
|
import BlockLivePreview from "./BlockLivePreview";
|
|
12
12
|
import { getBlockAlignmentStyles, hasBlockAlignment } from "../../lib/builder/layout-styles";
|
|
13
13
|
import type { BlockLayout } from "../../lib/sanity/types";
|
|
@@ -65,14 +65,29 @@ export default function SortableBlock({
|
|
|
65
65
|
// Only force width:100% when no horizontal alignment — align-self needs width:auto to shrink
|
|
66
66
|
const hasHAlign = blockLayout?.align_h && blockLayout.align_h !== "left";
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
// Fill-mode blocks act as column backgrounds — absolute positioned behind other blocks
|
|
69
|
+
const isFillBlock =
|
|
70
|
+
(block._type === "imageBlock" && (block as ImageBlock).width === "fill") ||
|
|
71
|
+
(block._type === "videoBlock" && (block as VideoBlock).width === "fill");
|
|
72
|
+
|
|
73
|
+
const style: React.CSSProperties = isFillBlock
|
|
74
|
+
? {
|
|
75
|
+
position: "relative",
|
|
76
|
+
flex: "999 1 0%",
|
|
77
|
+
minHeight: 0,
|
|
78
|
+
zIndex: 0,
|
|
79
|
+
opacity: isDragging ? 0.3 : 1,
|
|
80
|
+
transform: CSS.Transform.toString(transform),
|
|
81
|
+
transition,
|
|
82
|
+
}
|
|
83
|
+
: {
|
|
84
|
+
transform: CSS.Transform.toString(transform),
|
|
85
|
+
transition,
|
|
86
|
+
opacity: isDragging ? 0.3 : 1,
|
|
87
|
+
...(!hasHAlign ? { width: "100%" } : {}),
|
|
88
|
+
minWidth: 0,
|
|
89
|
+
...alignStyles,
|
|
90
|
+
};
|
|
76
91
|
|
|
77
92
|
const showToolbar = isSelected || isHovered;
|
|
78
93
|
|
|
@@ -106,8 +121,8 @@ export default function SortableBlock({
|
|
|
106
121
|
return (
|
|
107
122
|
<div
|
|
108
123
|
ref={setNodeRef}
|
|
109
|
-
style={style}
|
|
110
|
-
className={`
|
|
124
|
+
style={{ ...style, ...(!isFillBlock ? { position: "relative" as const, zIndex: 1 } : {}) }}
|
|
125
|
+
className={`transition-[opacity,box-shadow] ${
|
|
111
126
|
isDragging
|
|
112
127
|
? "ring-2 ring-[#0d9668] ring-offset-1 ring-offset-transparent rounded"
|
|
113
128
|
: ""
|
|
@@ -39,7 +39,7 @@ export default function LiveImagePreview({ block }: { block: ImageBlock }) {
|
|
|
39
39
|
|
|
40
40
|
if (isFill) {
|
|
41
41
|
return (
|
|
42
|
-
<div style={{
|
|
42
|
+
<div style={{ width: "100%", height: "100%", overflow: "hidden", borderRadius: block.border_radius ? `${String(block.border_radius).replace(/px$/i, "")}px` : undefined }}>
|
|
43
43
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
44
44
|
<img
|
|
45
45
|
src={src}
|
|
@@ -61,7 +61,7 @@ export default function LiveVideoPreview({ block }: { block: VideoBlock }) {
|
|
|
61
61
|
const borderRadius = block.border_radius ? `${String(block.border_radius).replace(/px$/i, "")}px` : undefined;
|
|
62
62
|
|
|
63
63
|
const outerStyle: React.CSSProperties = isFill
|
|
64
|
-
? {
|
|
64
|
+
? { width: "100%", height: "100%", minWidth: 0, borderRadius, overflow: "hidden" }
|
|
65
65
|
: { width: widthStyle, margin: block.width === "contained" ? "0 auto" : undefined, minWidth: 0, borderRadius, overflow: borderRadius ? "hidden" : undefined };
|
|
66
66
|
|
|
67
67
|
return (
|
|
@@ -0,0 +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-[#076bff]"
|
|
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
|
+
}
|
package/lib/sanity/types.ts
CHANGED
|
@@ -452,15 +452,24 @@ export interface CoverRow {
|
|
|
452
452
|
vertical_align: "start" | "center" | "end";
|
|
453
453
|
}
|
|
454
454
|
|
|
455
|
-
/** Cover Section settings (subset of SectionV2Settings
|
|
455
|
+
/** Cover Section settings (subset of SectionV2Settings) */
|
|
456
456
|
export interface CoverSectionSettings {
|
|
457
457
|
grid_columns: number; // default 12
|
|
458
458
|
col_gap: number;
|
|
459
459
|
row_gap: number;
|
|
460
|
+
// Spacing (padding TRBL, px)
|
|
460
461
|
spacing_top?: string;
|
|
461
462
|
spacing_right?: string;
|
|
462
463
|
spacing_bottom?: string;
|
|
463
464
|
spacing_left?: string;
|
|
465
|
+
// Offset (margin TRBL, px)
|
|
466
|
+
offset_top?: string;
|
|
467
|
+
offset_right?: string;
|
|
468
|
+
offset_bottom?: string;
|
|
469
|
+
offset_left?: string;
|
|
470
|
+
// Border
|
|
471
|
+
border_radius?: string;
|
|
472
|
+
// Animation
|
|
464
473
|
enter_animation?: import("../../lib/animation/enter-types").EnterAnimationConfig;
|
|
465
474
|
stagger?: {
|
|
466
475
|
enabled?: boolean;
|
package/lib/version.ts
CHANGED
package/package.json
CHANGED
|
@@ -95,6 +95,10 @@ const responsiveSettingsFields = [
|
|
|
95
95
|
defineField({ name: "spacing_right", type: "string", title: "Spacing Right" }),
|
|
96
96
|
defineField({ name: "spacing_bottom", type: "string", title: "Spacing Bottom" }),
|
|
97
97
|
defineField({ name: "spacing_left", type: "string", title: "Spacing Left" }),
|
|
98
|
+
defineField({ name: "offset_top", type: "string", title: "Offset Top" }),
|
|
99
|
+
defineField({ name: "offset_right", type: "string", title: "Offset Right" }),
|
|
100
|
+
defineField({ name: "offset_bottom", type: "string", title: "Offset Bottom" }),
|
|
101
|
+
defineField({ name: "offset_left", type: "string", title: "Offset Left" }),
|
|
98
102
|
];
|
|
99
103
|
|
|
100
104
|
export default defineType({
|
|
@@ -250,6 +254,13 @@ export default defineType({
|
|
|
250
254
|
defineField({ name: "spacing_right", title: "Spacing Right", type: "string" }),
|
|
251
255
|
defineField({ name: "spacing_bottom", title: "Spacing Bottom", type: "string" }),
|
|
252
256
|
defineField({ name: "spacing_left", title: "Spacing Left", type: "string" }),
|
|
257
|
+
// Offset (margin TRBL)
|
|
258
|
+
defineField({ name: "offset_top", title: "Offset Top", type: "string" }),
|
|
259
|
+
defineField({ name: "offset_right", title: "Offset Right", type: "string" }),
|
|
260
|
+
defineField({ name: "offset_bottom", title: "Offset Bottom", type: "string" }),
|
|
261
|
+
defineField({ name: "offset_left", title: "Offset Left", type: "string" }),
|
|
262
|
+
// Border
|
|
263
|
+
defineField({ name: "border_radius", title: "Border Radius", type: "string" }),
|
|
253
264
|
// Animation
|
|
254
265
|
defineField({
|
|
255
266
|
name: "enter_animation",
|