@morphika/andami 0.2.0 → 0.2.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.
- package/app/admin/pages/[slug]/page.tsx +9 -3
- package/components/blocks/TextBlockRenderer.tsx +1 -1
- package/components/builder/ReadOnlyFrame.tsx +2 -2
- package/components/builder/SectionV2Column.tsx +22 -5
- package/components/builder/SettingsPanel.tsx +0 -3
- package/components/builder/SortableBlock.tsx +13 -9
- package/components/builder/SortableRow.tsx +16 -10
- package/components/builder/live-preview/LiveTextEditor.tsx +1 -1
- package/package.json +1 -1
- package/styles/base.css +2 -9
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
verticalListSortingStrategy,
|
|
20
20
|
} from "@dnd-kit/sortable";
|
|
21
21
|
import type { Page, PageSectionV2, ParallaxGroup, SectionColumn, CustomSectionInstance, CustomSectionListItem } from "../../../../lib/sanity/types";
|
|
22
|
-
import { isPageSectionV2, isCustomSectionInstance,
|
|
22
|
+
import { isPageSectionV2, isCustomSectionInstance, isParallaxGroup } from "../../../../lib/sanity/types";
|
|
23
23
|
import SectionEditorBar from "../../../../components/builder/SectionEditorBar";
|
|
24
24
|
import CustomSectionInstanceCard from "../../../../components/builder/CustomSectionInstanceCard";
|
|
25
25
|
import { ColumnDragProvider } from "../../../../components/builder/ColumnDragContext";
|
|
@@ -666,7 +666,7 @@ export default function PageEditorPage() {
|
|
|
666
666
|
{store.rows.map((item, rowIndex) => {
|
|
667
667
|
const isV2Section = isPageSectionV2(item);
|
|
668
668
|
const isInstance = isCustomSectionInstance(item);
|
|
669
|
-
const isParallax =
|
|
669
|
+
const isParallax = isParallaxGroup(item);
|
|
670
670
|
const v2Section = isV2Section ? (item as PageSectionV2) : null;
|
|
671
671
|
|
|
672
672
|
// Custom Section Instance — rendered directly without SortableRow chrome
|
|
@@ -783,7 +783,13 @@ export default function PageEditorPage() {
|
|
|
783
783
|
e.stopPropagation();
|
|
784
784
|
setShowSectionPicker(true);
|
|
785
785
|
}}
|
|
786
|
-
className="w-full rounded-xl py-3 text-xs font-medium
|
|
786
|
+
className="w-full rounded-xl py-3 text-xs font-medium transition-colors"
|
|
787
|
+
style={{
|
|
788
|
+
background: "linear-gradient(170deg, rgba(38,38,48,0.95) 0%, rgba(28,28,36,0.97) 100%)",
|
|
789
|
+
color: "rgba(200,160,220,0.8)",
|
|
790
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.04)",
|
|
791
|
+
border: "1px solid rgba(255,255,255,0.06)",
|
|
792
|
+
}}
|
|
787
793
|
>
|
|
788
794
|
+ Add Section
|
|
789
795
|
</button>
|
|
@@ -87,7 +87,7 @@ export default function TextBlockRenderer({ block }: { block: TextBlock }) {
|
|
|
87
87
|
return (
|
|
88
88
|
<div
|
|
89
89
|
className={`${className} space-y-[0.75em]`}
|
|
90
|
-
style={
|
|
90
|
+
style={style}
|
|
91
91
|
>
|
|
92
92
|
<PortableText value={block.text} />
|
|
93
93
|
</div>
|
|
@@ -20,11 +20,11 @@ import { memo, useMemo, useState, useEffect } from "react";
|
|
|
20
20
|
import { useBuilderStore } from "../../lib/builder/store";
|
|
21
21
|
import type { DeviceViewport } from "../../lib/builder/types";
|
|
22
22
|
import type { ContentItem, PageSectionV2, CustomSectionInstance, ParallaxGroup, ParallaxSlideV2 } from "../../lib/sanity/types";
|
|
23
|
-
import { isPageSectionV2, isCustomSectionInstance,
|
|
23
|
+
import { isPageSectionV2, isCustomSectionInstance, isParallaxGroup } from "../../lib/sanity/types";
|
|
24
24
|
import { DEVICE_HEIGHTS } from "../../lib/builder/types";
|
|
25
25
|
import { getEffectiveColumnsV2, getSectionV2SettingValue } from "./settings-panel/responsive-helpers";
|
|
26
26
|
import BlockLivePreview from "./BlockLivePreview";
|
|
27
|
-
import { getColumnVerticalAlign } from "../../lib/builder/layout-styles";
|
|
27
|
+
import { getColumnVerticalAlign, getRowLayoutStyles } from "../../lib/builder/layout-styles";
|
|
28
28
|
|
|
29
29
|
// Layout keys that support responsive overrides for V2 sections
|
|
30
30
|
const OVERRIDABLE_KEYS = [
|
|
@@ -450,12 +450,23 @@ export default function SectionV2Column({
|
|
|
450
450
|
aria-label="Add block to empty column"
|
|
451
451
|
className={`w-full py-2 rounded-lg text-xs font-medium transition-all flex items-center justify-center ${
|
|
452
452
|
showChrome
|
|
453
|
-
? "
|
|
453
|
+
? "opacity-100"
|
|
454
454
|
: showFaintOutline
|
|
455
|
-
? "
|
|
455
|
+
? "opacity-40"
|
|
456
456
|
: "bg-transparent text-transparent opacity-0 pointer-events-none"
|
|
457
457
|
}`}
|
|
458
|
-
style={{
|
|
458
|
+
style={{
|
|
459
|
+
pointerEvents: showChrome || showFaintOutline ? "auto" : "none",
|
|
460
|
+
...(showChrome ? {
|
|
461
|
+
background: "linear-gradient(170deg, rgba(38,38,48,0.95) 0%, rgba(28,28,36,0.97) 100%)",
|
|
462
|
+
color: "rgba(100,220,170,0.8)",
|
|
463
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.04)",
|
|
464
|
+
border: "1px solid rgba(255,255,255,0.06)",
|
|
465
|
+
} : showFaintOutline ? {
|
|
466
|
+
background: "rgba(38,38,48,0.3)",
|
|
467
|
+
color: "rgba(100,220,170,0.4)",
|
|
468
|
+
} : {}),
|
|
469
|
+
}}
|
|
459
470
|
>
|
|
460
471
|
+ Add Block
|
|
461
472
|
</button>
|
|
@@ -476,8 +487,14 @@ export default function SectionV2Column({
|
|
|
476
487
|
<button
|
|
477
488
|
onClick={handleAddBlockBelow}
|
|
478
489
|
aria-label="Add block below existing blocks"
|
|
479
|
-
className="w-full py-1.5 text-[11px] font-medium rounded
|
|
480
|
-
style={{
|
|
490
|
+
className="w-full py-1.5 text-[11px] font-medium rounded transition-all"
|
|
491
|
+
style={{
|
|
492
|
+
pointerEvents: showChrome ? "auto" : "none",
|
|
493
|
+
background: "linear-gradient(170deg, rgba(38,38,48,0.95) 0%, rgba(28,28,36,0.97) 100%)",
|
|
494
|
+
color: "rgba(100,220,170,0.8)",
|
|
495
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.04)",
|
|
496
|
+
border: "1px solid rgba(255,255,255,0.06)",
|
|
497
|
+
}}
|
|
481
498
|
>
|
|
482
499
|
+ Add Block
|
|
483
500
|
</button>
|
|
@@ -144,9 +144,6 @@ export default function SettingsPanel() {
|
|
|
144
144
|
} else if (selectedSectionV2) {
|
|
145
145
|
onDelete = () => store.deleteSection(selectedSectionV2._key);
|
|
146
146
|
deleteTitle = "Delete Section";
|
|
147
|
-
} else if (selectedSection) {
|
|
148
|
-
onDelete = () => store.deleteSection(selectedSection._key);
|
|
149
|
-
deleteTitle = "Delete Section";
|
|
150
147
|
}
|
|
151
148
|
|
|
152
149
|
if (!onDelete) return null;
|
|
@@ -149,14 +149,18 @@ export default function SortableBlock({
|
|
|
149
149
|
className="flex items-center gap-1.5"
|
|
150
150
|
style={{ transform: `scale(${Math.min(2, 1 / canvasZoom)})`, transformOrigin: "top center" }}
|
|
151
151
|
>
|
|
152
|
-
<div className="flex items-center
|
|
152
|
+
<div className="flex items-center rounded-[5px] overflow-hidden" style={{
|
|
153
|
+
background: "linear-gradient(170deg, rgba(38,38,48,0.97) 0%, rgba(28,28,36,0.98) 100%)",
|
|
154
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.06)",
|
|
155
|
+
border: "1px solid rgba(255,255,255,0.06)",
|
|
156
|
+
}}>
|
|
153
157
|
{/* Move up arrow */}
|
|
154
158
|
<button
|
|
155
159
|
onClick={() => canMoveUp && reorderBlocks(rowKey, colKey, blockIndex, blockIndex - 1)}
|
|
156
160
|
className={`transition-colors px-1 py-0.5 text-[11px] ${
|
|
157
161
|
canMoveUp
|
|
158
|
-
? "text-white/
|
|
159
|
-
: "text-white/
|
|
162
|
+
? "text-white/45 hover:text-white/80 hover:bg-white/10 cursor-pointer"
|
|
163
|
+
: "text-white/20 cursor-default"
|
|
160
164
|
}`}
|
|
161
165
|
title="Move block up"
|
|
162
166
|
aria-label="Move block up"
|
|
@@ -169,10 +173,10 @@ export default function SortableBlock({
|
|
|
169
173
|
{/* Move down arrow */}
|
|
170
174
|
<button
|
|
171
175
|
onClick={() => canMoveDown && reorderBlocks(rowKey, colKey, blockIndex, blockIndex + 1)}
|
|
172
|
-
className={`transition-colors px-1 py-0.5 text-[11px] border-l border-white/
|
|
176
|
+
className={`transition-colors px-1 py-0.5 text-[11px] border-l border-white/10 ${
|
|
173
177
|
canMoveDown
|
|
174
|
-
? "text-white/
|
|
175
|
-
: "text-white/
|
|
178
|
+
? "text-white/45 hover:text-white/80 hover:bg-white/10 cursor-pointer"
|
|
179
|
+
: "text-white/20 cursor-default"
|
|
176
180
|
}`}
|
|
177
181
|
title="Move block down"
|
|
178
182
|
aria-label="Move block down"
|
|
@@ -183,12 +187,12 @@ export default function SortableBlock({
|
|
|
183
187
|
</svg>
|
|
184
188
|
</button>
|
|
185
189
|
{/* Block type label */}
|
|
186
|
-
<span className="text-[11px]
|
|
190
|
+
<span className="text-[11px] px-1.5 py-0.5 border-l border-white/10 font-medium" style={{ color: "rgba(100,220,170,0.9)" }}>
|
|
187
191
|
{info?.icon || "▪"} {info?.label || block._type}
|
|
188
192
|
</span>
|
|
189
193
|
{/* Enter animation badge */}
|
|
190
194
|
{block.enter_animation?.preset && block.enter_animation.preset !== "none" && (
|
|
191
|
-
<span className="text-[10px] text-white/
|
|
195
|
+
<span className="text-[10px] text-white/35 px-1 py-0.5 border-l border-white/10" title={`Animation: ${block.enter_animation.preset}`}>
|
|
192
196
|
✦
|
|
193
197
|
</span>
|
|
194
198
|
)}
|
|
@@ -196,7 +200,7 @@ export default function SortableBlock({
|
|
|
196
200
|
{onDuplicate && (
|
|
197
201
|
<button
|
|
198
202
|
onClick={onDuplicate}
|
|
199
|
-
className="text-white/
|
|
203
|
+
className="text-white/45 hover:text-white/80 transition-colors px-1.5 py-0.5 text-[11px] border-l border-white/10 hover:bg-white/10"
|
|
200
204
|
title="Duplicate block (Ctrl+D)"
|
|
201
205
|
aria-label="Duplicate block"
|
|
202
206
|
>
|
|
@@ -253,12 +253,18 @@ export default function SortableRow({
|
|
|
253
253
|
>
|
|
254
254
|
{/* Main toolbar — drag + actions */}
|
|
255
255
|
<div
|
|
256
|
-
className="flex flex-col items-stretch
|
|
256
|
+
className="flex flex-col items-stretch rounded-l-lg py-2 px-2.5 gap-1 cursor-grab active:cursor-grabbing"
|
|
257
|
+
style={{
|
|
258
|
+
background: "linear-gradient(170deg, rgba(38,38,48,0.97) 0%, rgba(28,28,36,0.98) 100%)",
|
|
259
|
+
boxShadow: "0 4px 16px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.06)",
|
|
260
|
+
border: "1px solid rgba(255,255,255,0.06)",
|
|
261
|
+
borderRight: "none",
|
|
262
|
+
}}
|
|
257
263
|
{...attributes}
|
|
258
264
|
{...listeners}
|
|
259
265
|
>
|
|
260
266
|
{/* Section label — shows specific type for page sections */}
|
|
261
|
-
<span className="text-[11px]
|
|
267
|
+
<span className="text-[11px] select-none leading-tight pointer-events-none font-medium tracking-wide" style={{ color: "rgba(200,160,220,0.9)" }}>
|
|
262
268
|
{sectionLabel || "Section"}
|
|
263
269
|
</span>
|
|
264
270
|
|
|
@@ -267,7 +273,7 @@ export default function SortableRow({
|
|
|
267
273
|
<button
|
|
268
274
|
onClick={(e) => { e.stopPropagation(); onDuplicate(); }}
|
|
269
275
|
onPointerDown={(e) => e.stopPropagation()}
|
|
270
|
-
className="flex items-center justify-center text-[12px] text-white/
|
|
276
|
+
className="flex items-center justify-center text-[12px] text-white/50 hover:text-white/85 transition-colors"
|
|
271
277
|
title="Duplicate section"
|
|
272
278
|
aria-label="Duplicate section"
|
|
273
279
|
>
|
|
@@ -277,7 +283,7 @@ export default function SortableRow({
|
|
|
277
283
|
onClick={(e) => { e.stopPropagation(); onMoveUp(); }}
|
|
278
284
|
onPointerDown={(e) => e.stopPropagation()}
|
|
279
285
|
disabled={isFirst}
|
|
280
|
-
className="flex items-center justify-center text-[12px] text-white/
|
|
286
|
+
className="flex items-center justify-center text-[12px] text-white/50 hover:text-white/85 transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
|
|
281
287
|
title="Move up"
|
|
282
288
|
aria-label="Move section up"
|
|
283
289
|
>
|
|
@@ -287,7 +293,7 @@ export default function SortableRow({
|
|
|
287
293
|
onClick={(e) => { e.stopPropagation(); onMoveDown(); }}
|
|
288
294
|
onPointerDown={(e) => e.stopPropagation()}
|
|
289
295
|
disabled={isLast}
|
|
290
|
-
className="flex items-center justify-center text-[12px] text-white/
|
|
296
|
+
className="flex items-center justify-center text-[12px] text-white/50 hover:text-white/85 transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
|
|
291
297
|
title="Move down"
|
|
292
298
|
aria-label="Move section down"
|
|
293
299
|
>
|
|
@@ -300,11 +306,11 @@ export default function SortableRow({
|
|
|
300
306
|
<button
|
|
301
307
|
onClick={(e) => { e.stopPropagation(); onAddColumn(); }}
|
|
302
308
|
onPointerDown={(e) => e.stopPropagation()}
|
|
303
|
-
className="flex items-center gap-1 text-[11px] text-white/
|
|
309
|
+
className="flex items-center gap-1 text-[11px] text-white/50 hover:text-white/85 transition-colors py-0.5"
|
|
304
310
|
title="Add column"
|
|
305
311
|
aria-label="Add column"
|
|
306
312
|
>
|
|
307
|
-
<span className="text-white/
|
|
313
|
+
<span className="text-white/30">+</span> Col
|
|
308
314
|
</button>
|
|
309
315
|
)}
|
|
310
316
|
|
|
@@ -312,11 +318,11 @@ export default function SortableRow({
|
|
|
312
318
|
<button
|
|
313
319
|
onClick={(e) => { e.stopPropagation(); onDelete(); }}
|
|
314
320
|
onPointerDown={(e) => e.stopPropagation()}
|
|
315
|
-
className="flex items-center gap-1 text-[11px] text-white/
|
|
321
|
+
className="flex items-center gap-1 text-[11px] text-white/50 hover:text-red-300 transition-colors py-0.5"
|
|
316
322
|
title="Delete section"
|
|
317
323
|
aria-label="Delete section"
|
|
318
324
|
>
|
|
319
|
-
<span className="text-white/
|
|
325
|
+
<span className="text-white/30">-</span> Delete
|
|
320
326
|
</button>
|
|
321
327
|
</div>
|
|
322
328
|
</div>
|
|
@@ -333,7 +339,7 @@ export default function SortableRow({
|
|
|
333
339
|
)}
|
|
334
340
|
|
|
335
341
|
{/* Content — same layout as Preview */}
|
|
336
|
-
<div style={coverRow ? undefined : { maxWidth, margin: "0 auto", paddingLeft: maxWidth !== "100%" ? gridPadding : undefined, paddingRight: maxWidth !== "100%" ? gridPadding : undefined }} className="relative
|
|
342
|
+
<div style={coverRow ? undefined : { maxWidth, margin: "0 auto", paddingLeft: maxWidth !== "100%" ? gridPadding : undefined, paddingRight: maxWidth !== "100%" ? gridPadding : undefined }} className="relative">
|
|
337
343
|
{children}
|
|
338
344
|
</div>
|
|
339
345
|
</div>
|
|
@@ -149,7 +149,7 @@ export default function LiveTextEditor({ block, editable = false }: { block: Tex
|
|
|
149
149
|
fontFamily: "inherit",
|
|
150
150
|
outline: "none",
|
|
151
151
|
whiteSpace: "pre-wrap",
|
|
152
|
-
wordBreak: "
|
|
152
|
+
wordBreak: "break-word",
|
|
153
153
|
minHeight: "1em",
|
|
154
154
|
// Multi-column layout: gap inherits global grid gutter
|
|
155
155
|
...(cols ? {
|
package/package.json
CHANGED
package/styles/base.css
CHANGED
|
@@ -57,21 +57,14 @@ body {
|
|
|
57
57
|
overflow-x: clip;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
/* Prevent text overflow in grid columns on narrow viewports
|
|
61
|
-
* overflow-wrap: break-word — breaks mid-word ONLY when the entire word
|
|
62
|
-
* cannot fit on a fresh line. Does NOT affect min-content intrinsic sizing,
|
|
63
|
-
* so CSS Grid columns keep their proper width (unlike 'anywhere' which
|
|
64
|
-
* collapses min-content to a single character width).
|
|
65
|
-
* word-break: normal — wraps at natural word boundaries first, preventing
|
|
66
|
-
* ugly mid-word splits like "Collecti" + "on". */
|
|
60
|
+
/* Prevent text overflow in grid columns on narrow viewports */
|
|
67
61
|
[data-site] p,
|
|
68
62
|
[data-site] h1,
|
|
69
63
|
[data-site] h2,
|
|
70
64
|
[data-site] h3,
|
|
71
65
|
[data-site] h4,
|
|
72
66
|
[data-site] span {
|
|
73
|
-
|
|
74
|
-
word-break: normal;
|
|
67
|
+
word-break: break-word;
|
|
75
68
|
}
|
|
76
69
|
|
|
77
70
|
[data-custom-cursor] {
|