@morphika/andami 0.1.8 → 0.1.10
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 +3 -0
- package/components/admin/nav-builder/NavBuilder.tsx +90 -14
- package/components/admin/nav-builder/NavGeneralSettings.tsx +521 -271
- package/components/admin/nav-builder/NavItemSettings.tsx +331 -312
- package/components/admin/nav-builder/NavMobileSettings.tsx +159 -140
- package/components/admin/nav-builder/NavSettingsFields.tsx +287 -21
- package/components/admin/nav-builder/NavSettingsPanel.tsx +137 -127
- package/components/blocks/TextBlockRenderer.tsx +1 -1
- package/components/builder/SettingsPanel.tsx +29 -543
- package/components/builder/editors/ButtonBlockEditor.tsx +8 -3
- package/components/builder/editors/CoverBlockEditor.tsx +14 -6
- package/components/builder/editors/ImageBlockEditor.tsx +8 -3
- package/components/builder/editors/ImageGridBlockEditor.tsx +8 -3
- package/components/builder/editors/ProjectGridEditor.tsx +7 -46
- package/components/builder/editors/SpacerBlockEditor.tsx +4 -1
- package/components/builder/editors/StaggerSettings.tsx +2 -1
- package/components/builder/editors/TextBlockEditor.tsx +8 -3
- package/components/builder/editors/VideoBlockEditor.tsx +10 -4
- package/components/builder/editors/section-icons.tsx +492 -0
- package/components/builder/editors/shared.tsx +23 -4
- package/components/builder/live-preview/GhostCard.tsx +84 -0
- package/components/builder/live-preview/LiveProjectGridPreview.tsx +294 -1010
- package/components/builder/live-preview/LiveTextEditor.tsx +1 -1
- package/components/builder/live-preview/ProjectCardWrapper.tsx +291 -0
- package/components/builder/live-preview/drag-utils.tsx +89 -0
- package/components/builder/live-preview/useDragReorder.ts +370 -0
- package/components/builder/settings-panel/AnimationTab.tsx +152 -0
- package/components/builder/settings-panel/BlockLayoutTab.tsx +13 -58
- package/components/builder/settings-panel/CardEntranceSection.tsx +114 -0
- package/components/builder/settings-panel/ColumnV2AnimationTab.tsx +32 -0
- package/components/builder/settings-panel/ColumnV2Settings.tsx +4 -1
- package/components/builder/settings-panel/CustomSectionSettings.tsx +150 -0
- package/components/builder/settings-panel/LayoutTab.tsx +11 -47
- package/components/builder/settings-panel/PageSettings.tsx +10 -4
- package/components/builder/settings-panel/ParallaxGroupSettings.tsx +6 -2
- package/components/builder/settings-panel/ParallaxSlideSettings.tsx +8 -3
- package/components/builder/settings-panel/SectionV2LayoutTab.tsx +11 -47
- package/components/builder/settings-panel/SectionV2Settings.tsx +6 -27
- package/components/builder/settings-panel/index.ts +6 -0
- package/components/builder/settings-panel/useSettingsPanelSelection.ts +184 -0
- package/components/ui/Navbar.tsx +151 -30
- package/lib/builder/serializer/migrations.ts +107 -0
- package/lib/builder/serializer/normalizers.ts +278 -0
- package/lib/builder/serializer/serializers.ts +393 -0
- package/lib/builder/serializer/shared.ts +102 -0
- package/lib/builder/serializer.ts +11 -846
- package/lib/sanity/types.ts +22 -0
- package/package.json +13 -10
- package/styles/base.css +7 -3
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
A reusable Visual Page Builder framework for Next.js. Build custom websites with a drag-and-drop visual editor, Sanity CMS backend, and zero-config deployment.
|
|
4
4
|
|
|
5
|
+
**Designed for Vercel Hobby tier** — the framework is engineered to run comfortably within Vercel's free/Hobby plan limits (4h Fluid Active CPU, 10 GB Fast Origin Transfer per month). Aggressive ISR caching, Sanity CDN routing, bot mitigation, and Edge-first middleware keep serverless CPU usage minimal even under crawler traffic.
|
|
6
|
+
|
|
5
7
|
## Features
|
|
6
8
|
|
|
7
9
|
- **Visual Page Builder** — Infinite canvas editor with device previews (desktop, tablet, phone)
|
|
@@ -13,6 +15,7 @@ A reusable Visual Page Builder framework for Next.js. Build custom websites with
|
|
|
13
15
|
- **Asset Management** — Cloudflare R2 storage with browser, thumbnails, and CDN serving
|
|
14
16
|
- **Setup Wizard** — Guided onboarding for new sites
|
|
15
17
|
- **Sanity v3 CMS** — Structured content with custom schemas, GROQ queries, and ISR
|
|
18
|
+
- **Vercel-Optimized** — Sanity CDN for public queries, 24h ISR, R2 direct CDN shortcut, bot guard middleware, aggressive robots.txt with crawl-delay — all tuned to minimize serverless CPU on Hobby tier
|
|
16
19
|
|
|
17
20
|
## Quick Start
|
|
18
21
|
|
|
@@ -7,6 +7,44 @@ import NavBuilderGrid from "./NavBuilderGrid";
|
|
|
7
7
|
import NavLivePreview from "./NavLivePreview";
|
|
8
8
|
import NavSettingsPanel from "./NavSettingsPanel";
|
|
9
9
|
|
|
10
|
+
// ── Header icons ──
|
|
11
|
+
|
|
12
|
+
const NAV_HEADER_ICON = (
|
|
13
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="rgba(0,0,0,0.55)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
14
|
+
<line x1="3" y1="6" x2="21" y2="6" /><line x1="3" y1="12" x2="21" y2="12" /><line x1="3" y1="18" x2="21" y2="18" />
|
|
15
|
+
</svg>
|
|
16
|
+
);
|
|
17
|
+
const LOGO_HEADER_ICON = (
|
|
18
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="rgba(0,0,0,0.55)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
19
|
+
<rect x="3" y="3" width="18" height="18" rx="2" ry="2" /><circle cx="8.5" cy="8.5" r="1.5" /><polyline points="21 15 16 10 5 21" />
|
|
20
|
+
</svg>
|
|
21
|
+
);
|
|
22
|
+
const ITEM_HEADER_ICON = (
|
|
23
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="rgba(0,0,0,0.55)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
24
|
+
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
|
|
25
|
+
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
|
|
26
|
+
</svg>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
function getHeaderConfig(selectedItem: NavItem | null) {
|
|
30
|
+
if (!selectedItem) {
|
|
31
|
+
return {
|
|
32
|
+
gradient: "linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 40%, #ddd6fe 100%)",
|
|
33
|
+
icon: NAV_HEADER_ICON,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (selectedItem.type === "logo") {
|
|
37
|
+
return {
|
|
38
|
+
gradient: "linear-gradient(135deg, #fef3c7 0%, #fde68a 40%, #fcd34d 100%)",
|
|
39
|
+
icon: LOGO_HEADER_ICON,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
gradient: "linear-gradient(135deg, #dbeafe 0%, #bfdbfe 40%, #c7d2fe 100%)",
|
|
44
|
+
icon: ITEM_HEADER_ICON,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
10
48
|
interface NavBuilderProps {
|
|
11
49
|
initialItems: NavItem[];
|
|
12
50
|
initialDesign: NavDesign;
|
|
@@ -121,30 +159,68 @@ export default function NavBuilder({
|
|
|
121
159
|
}, [items, design, onSave]);
|
|
122
160
|
|
|
123
161
|
const selectedItem = items.find((i) => i._key === selectedKey) || null;
|
|
162
|
+
const headerConfig = getHeaderConfig(selectedItem);
|
|
163
|
+
|
|
164
|
+
const isItemMode = !!selectedItem;
|
|
165
|
+
const headerTitle = isItemMode
|
|
166
|
+
? selectedItem.type === "logo"
|
|
167
|
+
? "Logo"
|
|
168
|
+
: selectedItem.label || "Untitled"
|
|
169
|
+
: "Navigation";
|
|
170
|
+
const headerSubtitle = isItemMode
|
|
171
|
+
? `${selectedItem.type === "logo" ? "Logo" : "Menu Item"} · Col ${selectedItem.grid_column}${
|
|
172
|
+
selectedItem.column_span > 1
|
|
173
|
+
? `–${selectedItem.grid_column + selectedItem.column_span - 1}`
|
|
174
|
+
: ""
|
|
175
|
+
}`
|
|
176
|
+
: `${items.length} items · 12 columns`;
|
|
124
177
|
|
|
125
178
|
return (
|
|
126
179
|
<div className="bg-white rounded-2xl overflow-hidden border border-neutral-200">
|
|
127
|
-
{/*
|
|
128
|
-
<div
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
180
|
+
{/* ── Gradient header (matches Mobile Menu style) ── */}
|
|
181
|
+
<div
|
|
182
|
+
className="relative flex items-center px-4 py-3.5 overflow-hidden"
|
|
183
|
+
style={{ background: headerConfig.gradient }}
|
|
184
|
+
>
|
|
185
|
+
<div
|
|
186
|
+
className="absolute inset-0 pointer-events-none"
|
|
187
|
+
style={{ background: "linear-gradient(135deg, rgba(255,255,255,0.25) 0%, rgba(255,255,255,0.05) 100%)" }}
|
|
188
|
+
/>
|
|
189
|
+
<div
|
|
190
|
+
className="relative shrink-0 flex items-center justify-center"
|
|
191
|
+
style={{
|
|
192
|
+
width: 34,
|
|
193
|
+
height: 34,
|
|
194
|
+
borderRadius: 10,
|
|
195
|
+
background: "rgba(255,255,255,0.4)",
|
|
196
|
+
backdropFilter: "blur(8px)",
|
|
197
|
+
boxShadow: "0 2px 8px rgba(0,0,0,0.06), inset 0 1px 0 rgba(255,255,255,0.5)",
|
|
198
|
+
}}
|
|
199
|
+
>
|
|
200
|
+
{headerConfig.icon}
|
|
201
|
+
</div>
|
|
202
|
+
<div className="relative z-10 ml-2.5 min-w-0 flex-1">
|
|
203
|
+
<h3
|
|
204
|
+
className="text-[13px] font-semibold truncate"
|
|
205
|
+
style={{ color: "rgba(0,0,0,0.72)", textShadow: "0 1px 0 rgba(255,255,255,0.3)" }}
|
|
206
|
+
>
|
|
207
|
+
{headerTitle}
|
|
208
|
+
</h3>
|
|
209
|
+
<p className="text-[10px] mt-0.5" style={{ color: "rgba(0,0,0,0.38)" }}>
|
|
210
|
+
{headerSubtitle}
|
|
211
|
+
</p>
|
|
134
212
|
</div>
|
|
135
|
-
<div className="flex items-center gap-3">
|
|
213
|
+
<div className="relative z-10 flex items-center gap-3">
|
|
136
214
|
{hasChanges && (
|
|
137
|
-
<span className="text-[11px] text-amber-
|
|
138
|
-
Unsaved changes
|
|
139
|
-
</span>
|
|
215
|
+
<span className="text-[11px] text-amber-600 font-medium">Unsaved</span>
|
|
140
216
|
)}
|
|
141
217
|
<button
|
|
142
218
|
onClick={handleSave}
|
|
143
219
|
disabled={saving || !hasChanges}
|
|
144
|
-
className={`px-
|
|
220
|
+
className={`px-4 py-1.5 text-[11px] font-medium rounded-lg transition-all ${
|
|
145
221
|
saving || !hasChanges
|
|
146
|
-
? "bg-
|
|
147
|
-
: "bg-[#076bff]
|
|
222
|
+
? "bg-white/40 text-neutral-400 cursor-not-allowed"
|
|
223
|
+
: "bg-white text-[#076bff] shadow-sm hover:shadow-md"
|
|
148
224
|
}`}
|
|
149
225
|
>
|
|
150
226
|
{saving ? "Saving..." : "Save"}
|