@morphika/andami 0.4.2 → 0.5.1
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 +151 -36
- package/app/admin/layout.tsx +145 -152
- package/components/blocks/AudioBlockRenderer.tsx +286 -0
- package/components/blocks/BeforeAfterBlockRenderer.tsx +274 -0
- package/components/builder/BlockCardIcons.tsx +89 -0
- package/components/builder/BlockTypePicker.tsx +2 -0
- package/components/builder/ColumnDragContext.tsx +5 -0
- package/components/builder/ColumnDragOverlay.tsx +38 -11
- package/components/builder/CoverSectionCanvas.tsx +90 -2
- package/components/builder/InsertionLines.tsx +9 -1
- package/components/builder/SectionV2Canvas.tsx +32 -6
- package/components/builder/SectionV2Column.tsx +5 -1
- package/components/builder/asset-browser/R2BrowserContent.tsx +23 -6
- package/components/builder/asset-browser/helpers.ts +4 -0
- package/components/builder/asset-browser/types.ts +2 -1
- package/components/builder/blockStyles.tsx +12 -0
- package/components/builder/editors/AudioBlockEditor.tsx +242 -0
- package/components/builder/editors/BeforeAfterBlockEditor.tsx +360 -0
- package/components/builder/editors/shared.tsx +1 -1
- package/components/builder/hooks/useColumnDrag.ts +206 -132
- package/components/builder/live-preview/LiveAudioPreview.tsx +120 -0
- package/components/builder/live-preview/LiveBeforeAfterPreview.tsx +176 -0
- package/lib/animation/enter-types.ts +2 -0
- package/lib/animation/hover-effect-types.ts +2 -0
- package/lib/builder/block-registrations.ts +83 -1
- package/lib/builder/store-helpers.ts +302 -1
- package/lib/builder/store-sections.ts +60 -0
- package/lib/builder/types-slices.ts +27 -0
- package/lib/builder/types.ts +2 -0
- package/lib/sanity/types.ts +75 -0
- package/lib/version.ts +1 -1
- package/package.json +1 -1
- package/sanity/schemas/blocks/audioBlock.ts +69 -0
- package/sanity/schemas/blocks/beforeAfterBlock.ts +121 -0
- package/sanity/schemas/blocks/index.ts +3 -1
- package/sanity/schemas/index.ts +7 -1
package/lib/version.ts
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { defineField, defineType } from "sanity";
|
|
2
|
+
import { blockLayoutField, blockAnimationFields } from "./blockLayout";
|
|
3
|
+
|
|
4
|
+
export const audioBlock = defineType({
|
|
5
|
+
name: "audioBlock",
|
|
6
|
+
title: "Audio Block",
|
|
7
|
+
type: "object",
|
|
8
|
+
fields: [
|
|
9
|
+
// ── Source ──
|
|
10
|
+
defineField({
|
|
11
|
+
name: "asset_path",
|
|
12
|
+
title: "Audio File",
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "Relative path to the audio file (mp3, wav, ogg, m4a, aac, flac)",
|
|
15
|
+
validation: (Rule) => Rule.required(),
|
|
16
|
+
}),
|
|
17
|
+
defineField({ name: "alt", title: "Alt Text", type: "string" }),
|
|
18
|
+
|
|
19
|
+
// ── Metadata ──
|
|
20
|
+
defineField({ name: "title", title: "Title", type: "string" }),
|
|
21
|
+
defineField({ name: "artist", title: "Artist", type: "string" }),
|
|
22
|
+
defineField({
|
|
23
|
+
name: "cover_path",
|
|
24
|
+
title: "Cover Art",
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "Optional relative path to a cover image",
|
|
27
|
+
}),
|
|
28
|
+
|
|
29
|
+
// ── Appearance ──
|
|
30
|
+
defineField({
|
|
31
|
+
name: "accent_color",
|
|
32
|
+
title: "Accent Color",
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "Hex color for the play button + progress fill",
|
|
35
|
+
initialValue: "#4794E2",
|
|
36
|
+
}),
|
|
37
|
+
defineField({
|
|
38
|
+
name: "width",
|
|
39
|
+
title: "Width",
|
|
40
|
+
type: "string",
|
|
41
|
+
options: {
|
|
42
|
+
list: [
|
|
43
|
+
{ title: "Full", value: "full" },
|
|
44
|
+
{ title: "Contained", value: "contained" },
|
|
45
|
+
{ title: "Small", value: "small" },
|
|
46
|
+
{ title: "Fill", value: "fill" },
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
initialValue: "contained",
|
|
50
|
+
}),
|
|
51
|
+
defineField({ name: "border_radius", title: "Border Radius", type: "string" }),
|
|
52
|
+
defineField({ name: "shadow", title: "Shadow", type: "boolean", initialValue: false }),
|
|
53
|
+
|
|
54
|
+
// ── Playback ──
|
|
55
|
+
defineField({ name: "autoplay", title: "Autoplay", type: "boolean", initialValue: false }),
|
|
56
|
+
defineField({ name: "loop", title: "Loop", type: "boolean", initialValue: false }),
|
|
57
|
+
defineField({ name: "muted", title: "Muted", type: "boolean", initialValue: false }),
|
|
58
|
+
|
|
59
|
+
...blockAnimationFields,
|
|
60
|
+
blockLayoutField,
|
|
61
|
+
],
|
|
62
|
+
preview: {
|
|
63
|
+
select: { path: "asset_path", title: "title", artist: "artist" },
|
|
64
|
+
prepare({ path, title, artist }) {
|
|
65
|
+
const label = title ? (artist ? `${title} — ${artist}` : title) : path || "Audio block";
|
|
66
|
+
return { title: label };
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { defineField, defineType } from "sanity";
|
|
2
|
+
import { blockLayoutField, blockAnimationFields } from "./blockLayout";
|
|
3
|
+
|
|
4
|
+
export const beforeAfterBlock = defineType({
|
|
5
|
+
name: "beforeAfterBlock",
|
|
6
|
+
title: "Before / After Block",
|
|
7
|
+
type: "object",
|
|
8
|
+
fields: [
|
|
9
|
+
// ── Before side ──
|
|
10
|
+
defineField({
|
|
11
|
+
name: "before_media_type",
|
|
12
|
+
title: "Before Media Type",
|
|
13
|
+
type: "string",
|
|
14
|
+
options: { list: [{ title: "Image", value: "image" }, { title: "Video", value: "video" }] },
|
|
15
|
+
initialValue: "image",
|
|
16
|
+
}),
|
|
17
|
+
defineField({
|
|
18
|
+
name: "before_asset_path",
|
|
19
|
+
title: "Before Asset Path",
|
|
20
|
+
type: "string",
|
|
21
|
+
description: "Relative path to the image or video file shown before the slider",
|
|
22
|
+
validation: (Rule) => Rule.required(),
|
|
23
|
+
}),
|
|
24
|
+
defineField({ name: "before_alt", title: "Before Alt Text", type: "string" }),
|
|
25
|
+
|
|
26
|
+
// ── After side ──
|
|
27
|
+
defineField({
|
|
28
|
+
name: "after_media_type",
|
|
29
|
+
title: "After Media Type",
|
|
30
|
+
type: "string",
|
|
31
|
+
options: { list: [{ title: "Image", value: "image" }, { title: "Video", value: "video" }] },
|
|
32
|
+
initialValue: "image",
|
|
33
|
+
}),
|
|
34
|
+
defineField({
|
|
35
|
+
name: "after_asset_path",
|
|
36
|
+
title: "After Asset Path",
|
|
37
|
+
type: "string",
|
|
38
|
+
description: "Relative path to the image or video file shown after the slider",
|
|
39
|
+
validation: (Rule) => Rule.required(),
|
|
40
|
+
}),
|
|
41
|
+
defineField({ name: "after_alt", title: "After Alt Text", type: "string" }),
|
|
42
|
+
|
|
43
|
+
// ── Slider behavior ──
|
|
44
|
+
defineField({
|
|
45
|
+
name: "orientation",
|
|
46
|
+
title: "Orientation",
|
|
47
|
+
type: "string",
|
|
48
|
+
options: {
|
|
49
|
+
list: [
|
|
50
|
+
{ title: "Horizontal (slider left-right)", value: "horizontal" },
|
|
51
|
+
{ title: "Vertical (slider top-bottom)", value: "vertical" },
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
initialValue: "horizontal",
|
|
55
|
+
}),
|
|
56
|
+
defineField({
|
|
57
|
+
name: "initial_position",
|
|
58
|
+
title: "Initial Position",
|
|
59
|
+
type: "number",
|
|
60
|
+
description: "Starting split position (0–100%)",
|
|
61
|
+
initialValue: 50,
|
|
62
|
+
validation: (Rule) => Rule.min(0).max(100),
|
|
63
|
+
}),
|
|
64
|
+
defineField({
|
|
65
|
+
name: "handle_color",
|
|
66
|
+
title: "Handle Color",
|
|
67
|
+
type: "string",
|
|
68
|
+
description: "Hex color for the slider line + handle",
|
|
69
|
+
initialValue: "#FFFFFF",
|
|
70
|
+
}),
|
|
71
|
+
|
|
72
|
+
// ── Layout ──
|
|
73
|
+
defineField({
|
|
74
|
+
name: "width",
|
|
75
|
+
title: "Width",
|
|
76
|
+
type: "string",
|
|
77
|
+
options: {
|
|
78
|
+
list: [
|
|
79
|
+
{ title: "Full", value: "full" },
|
|
80
|
+
{ title: "Contained", value: "contained" },
|
|
81
|
+
{ title: "Small", value: "small" },
|
|
82
|
+
{ title: "Fill", value: "fill" },
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
initialValue: "full",
|
|
86
|
+
}),
|
|
87
|
+
defineField({
|
|
88
|
+
name: "aspect_ratio",
|
|
89
|
+
title: "Aspect Ratio",
|
|
90
|
+
type: "string",
|
|
91
|
+
options: {
|
|
92
|
+
list: [
|
|
93
|
+
{ title: "Auto", value: "auto" },
|
|
94
|
+
{ title: "16:9", value: "16:9" },
|
|
95
|
+
{ title: "4:3", value: "4:3" },
|
|
96
|
+
{ title: "1:1", value: "1:1" },
|
|
97
|
+
{ title: "21:9", value: "21:9" },
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
initialValue: "16:9",
|
|
101
|
+
}),
|
|
102
|
+
|
|
103
|
+
// ── Video playback (applies when either side is video) ──
|
|
104
|
+
defineField({ name: "video_autoplay", title: "Video Autoplay", type: "boolean", initialValue: true }),
|
|
105
|
+
defineField({ name: "video_loop", title: "Video Loop", type: "boolean", initialValue: true }),
|
|
106
|
+
defineField({ name: "video_muted", title: "Video Muted", type: "boolean", initialValue: true }),
|
|
107
|
+
|
|
108
|
+
// ── Appearance ──
|
|
109
|
+
defineField({ name: "border_radius", title: "Border Radius", type: "string" }),
|
|
110
|
+
defineField({ name: "shadow", title: "Shadow", type: "boolean", initialValue: false }),
|
|
111
|
+
|
|
112
|
+
...blockAnimationFields,
|
|
113
|
+
blockLayoutField,
|
|
114
|
+
],
|
|
115
|
+
preview: {
|
|
116
|
+
select: { before: "before_asset_path", after: "after_asset_path" },
|
|
117
|
+
prepare({ before, after }) {
|
|
118
|
+
return { title: `Before/After: ${before || "—"} ↔ ${after || "—"}` };
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
});
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
// Block schemas (
|
|
1
|
+
// Block schemas (10)
|
|
2
2
|
export { textBlock } from "./textBlock";
|
|
3
3
|
export { imageBlock } from "./imageBlock";
|
|
4
4
|
export { imageGridBlock } from "./imageGridBlock";
|
|
5
5
|
export { videoBlock } from "./videoBlock";
|
|
6
6
|
export { spacerBlock } from "./spacerBlock";
|
|
7
7
|
export { buttonBlock } from "./buttonBlock";
|
|
8
|
+
export { beforeAfterBlock } from "./beforeAfterBlock";
|
|
9
|
+
export { audioBlock } from "./audioBlock";
|
|
8
10
|
export { projectGridBlock } from "./projectGridBlock";
|
|
9
11
|
export { projectCarouselBlock } from "./projectCarouselBlock";
|
package/sanity/schemas/index.ts
CHANGED
|
@@ -18,6 +18,8 @@ import {
|
|
|
18
18
|
videoBlock,
|
|
19
19
|
spacerBlock,
|
|
20
20
|
buttonBlock,
|
|
21
|
+
beforeAfterBlock,
|
|
22
|
+
audioBlock,
|
|
21
23
|
projectGridBlock,
|
|
22
24
|
projectCarouselBlock,
|
|
23
25
|
} from "./blocks";
|
|
@@ -69,6 +71,8 @@ export {
|
|
|
69
71
|
videoBlock,
|
|
70
72
|
spacerBlock,
|
|
71
73
|
buttonBlock,
|
|
74
|
+
beforeAfterBlock,
|
|
75
|
+
audioBlock,
|
|
72
76
|
projectGridBlock,
|
|
73
77
|
projectCarouselBlock,
|
|
74
78
|
} from "./blocks";
|
|
@@ -93,13 +97,15 @@ export const schemaTypes = [
|
|
|
93
97
|
parallaxGroup, // Parallax V2 group (Session 123)
|
|
94
98
|
coverSection, // Cover Section — proportional rows (Session 176)
|
|
95
99
|
|
|
96
|
-
// Blocks (
|
|
100
|
+
// Blocks (10)
|
|
97
101
|
textBlock,
|
|
98
102
|
imageBlock,
|
|
99
103
|
imageGridBlock,
|
|
100
104
|
videoBlock,
|
|
101
105
|
spacerBlock,
|
|
102
106
|
buttonBlock,
|
|
107
|
+
beforeAfterBlock,
|
|
108
|
+
audioBlock,
|
|
103
109
|
projectGridBlock,
|
|
104
110
|
projectCarouselBlock,
|
|
105
111
|
];
|