@morphika/andami 0.5.1 → 0.5.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/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 +320 -320
- package/app/admin/navigation/page.tsx +255 -255
- package/app/admin/pages/[slug]/page.tsx +6 -6
- package/app/admin/pages/page.tsx +11 -11
- package/app/admin/projects/page.tsx +14 -14
- package/app/admin/setup/page.tsx +1 -1
- package/app/admin/styles/page.tsx +1 -1
- package/components/admin/MetadataEditor.tsx +6 -6
- 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 +4 -4
- 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 +514 -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 +2 -2
- package/components/admin/styles/FontsEditor.tsx +6 -6
- 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/MarqueeBlockRenderer.tsx +316 -0
- package/components/blocks/ProjectCarouselBlockRenderer.tsx +1 -1
- package/components/builder/BlockCardIcons.tsx +316 -316
- package/components/builder/BlockTypePicker.tsx +1 -1
- package/components/builder/BubbleIcons.tsx +90 -0
- package/components/builder/BuilderCanvas.tsx +2 -0
- package/components/builder/CanvasMinimap.tsx +2 -2
- 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 +1 -1
- package/components/builder/SectionTypePicker.tsx +4 -4
- package/components/builder/SectionV2Canvas.tsx +1 -1
- package/components/builder/SectionV2Column.tsx +69 -67
- package/components/builder/SortableBlock.tsx +93 -73
- package/components/builder/SortableRow.tsx +27 -26
- package/components/builder/VirtualAssetGrid.tsx +2 -2
- package/components/builder/asset-browser/R2BrowserContent.tsx +11 -11
- 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 +74 -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 +93 -93
- 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 +4 -4
- package/components/builder/editors/MarqueeBlockEditor.tsx +621 -0
- package/components/builder/editors/ProjectCarouselBlockEditor.tsx +443 -443
- package/components/builder/editors/ProjectGridEditor.tsx +9 -9
- package/components/builder/editors/SpacerBlockEditor.tsx +5 -5
- package/components/builder/editors/StaggerSettings.tsx +109 -109
- package/components/builder/editors/TextBlockEditor.tsx +3 -3
- 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 +6 -6
- 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 +1 -1
- 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 +291 -291
- package/components/builder/settings-panel/AnimationTab.tsx +138 -138
- package/components/builder/settings-panel/BlockLayoutTab.tsx +7 -7
- package/components/builder/settings-panel/CardEntranceSection.tsx +114 -114
- 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 +335 -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 +14 -14
- package/components/builder/settings-panel/TRBLInputs.tsx +1 -1
- 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/store-sections.ts +2 -2
- package/lib/builder/types-slices.ts +414 -414
- package/lib/builder/types.ts +4 -1
- package/lib/config/index.ts +27 -27
- package/lib/sanity/types.ts +98 -1
- package/lib/version.ts +1 -1
- package/package.json +1 -1
- 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/styles/admin.css +85 -85
- package/styles/animations.css +237 -237
- package/styles/base.css +114 -114
|
@@ -135,7 +135,7 @@ function MediaPicker({
|
|
|
135
135
|
<button
|
|
136
136
|
type="button"
|
|
137
137
|
onClick={() => openBrowser()}
|
|
138
|
-
className="w-full aspect-[4/3] rounded-lg border border-dashed border-neutral-300 flex flex-col items-center justify-center gap-2 hover:border-[#
|
|
138
|
+
className="w-full aspect-[4/3] rounded-lg border border-dashed border-neutral-300 flex flex-col items-center justify-center gap-2 hover:border-[#3580f9] hover:bg-neutral-50 transition-colors cursor-pointer"
|
|
139
139
|
>
|
|
140
140
|
{activeTab === "image" ? (
|
|
141
141
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="text-neutral-400">
|
|
@@ -240,13 +240,13 @@ function CreateProjectModal({
|
|
|
240
240
|
<form onSubmit={handleSubmit} className="space-y-4">
|
|
241
241
|
<div>
|
|
242
242
|
<label className="block text-xs text-neutral-500 mb-1">Project Title</label>
|
|
243
|
-
<input type="text" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="My Project" className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 placeholder:text-neutral-400 focus:border-[#
|
|
243
|
+
<input type="text" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="My Project" className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 placeholder:text-neutral-400 focus:border-[#3580f9] focus:outline-none" autoFocus />
|
|
244
244
|
</div>
|
|
245
245
|
<div>
|
|
246
246
|
<label className="block text-xs text-neutral-500 mb-1">URL Slug</label>
|
|
247
247
|
<div className="flex items-center gap-1">
|
|
248
248
|
<span className="text-xs text-neutral-400">/work/</span>
|
|
249
|
-
<input type="text" value={slug} onChange={(e) => { setSlug(e.target.value); setAutoSlug(false); }} placeholder="my-project" className="flex-1 rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 placeholder:text-neutral-400 focus:border-[#
|
|
249
|
+
<input type="text" value={slug} onChange={(e) => { setSlug(e.target.value); setAutoSlug(false); }} placeholder="my-project" className="flex-1 rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 placeholder:text-neutral-400 focus:border-[#3580f9] focus:outline-none" />
|
|
250
250
|
</div>
|
|
251
251
|
</div>
|
|
252
252
|
<MediaPicker
|
|
@@ -259,7 +259,7 @@ function CreateProjectModal({
|
|
|
259
259
|
{error && <p className="text-xs text-[var(--admin-error)]">{error}</p>}
|
|
260
260
|
<div className="flex gap-3 justify-end pt-2">
|
|
261
261
|
<button type="button" onClick={onClose} className="rounded-lg border border-neutral-200 px-5 py-2.5 text-sm text-neutral-500 hover:text-neutral-800 hover:border-neutral-300 transition-colors">Cancel</button>
|
|
262
|
-
<button type="submit" disabled={creating} className="rounded-lg bg-[#
|
|
262
|
+
<button type="submit" disabled={creating} className="rounded-lg bg-[#3580f9] px-5 py-2.5 text-sm font-medium text-white hover:bg-[#2d6dd4] transition-colors disabled:opacity-50">{creating ? "Creating..." : "Create"}</button>
|
|
263
263
|
</div>
|
|
264
264
|
</form>
|
|
265
265
|
</div>
|
|
@@ -344,13 +344,13 @@ function EditProjectModal({
|
|
|
344
344
|
<form onSubmit={handleSave} className="space-y-4">
|
|
345
345
|
<div>
|
|
346
346
|
<label className="block text-xs text-neutral-500 mb-1">Project Title</label>
|
|
347
|
-
<input type="text" value={title} onChange={(e) => setTitle(e.target.value)} className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 placeholder:text-neutral-400 focus:border-[#
|
|
347
|
+
<input type="text" value={title} onChange={(e) => setTitle(e.target.value)} className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 placeholder:text-neutral-400 focus:border-[#3580f9] focus:outline-none" autoFocus />
|
|
348
348
|
</div>
|
|
349
349
|
<div>
|
|
350
350
|
<label className="block text-xs text-neutral-500 mb-1">URL Slug</label>
|
|
351
351
|
<div className="flex items-center gap-1">
|
|
352
352
|
<span className="text-xs text-neutral-400">/work/</span>
|
|
353
|
-
<input type="text" value={slug} onChange={(e) => setSlug(e.target.value)} className="flex-1 rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 placeholder:text-neutral-400 focus:border-[#
|
|
353
|
+
<input type="text" value={slug} onChange={(e) => setSlug(e.target.value)} className="flex-1 rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 placeholder:text-neutral-400 focus:border-[#3580f9] focus:outline-none" />
|
|
354
354
|
</div>
|
|
355
355
|
</div>
|
|
356
356
|
<MediaPicker
|
|
@@ -363,7 +363,7 @@ function EditProjectModal({
|
|
|
363
363
|
{error && <p className="text-xs text-[var(--admin-error)]">{error}</p>}
|
|
364
364
|
<div className="flex gap-3 justify-end pt-2">
|
|
365
365
|
<button type="button" onClick={onClose} className="rounded-lg border border-neutral-200 px-5 py-2.5 text-sm text-neutral-500 hover:text-neutral-800 hover:border-neutral-300 transition-colors">Cancel</button>
|
|
366
|
-
<button type="submit" disabled={saving} className="rounded-lg bg-[#
|
|
366
|
+
<button type="submit" disabled={saving} className="rounded-lg bg-[#3580f9] px-5 py-2.5 text-sm font-medium text-white hover:bg-[#2d6dd4] transition-colors disabled:opacity-50">{saving ? "Saving..." : "Save"}</button>
|
|
367
367
|
</div>
|
|
368
368
|
</form>
|
|
369
369
|
</div>
|
|
@@ -494,7 +494,7 @@ export default function AdminProjectsPage() {
|
|
|
494
494
|
<select
|
|
495
495
|
value={viewMode === "thumb" ? "Thumb View" : "List View"}
|
|
496
496
|
onChange={(e) => setViewMode(e.target.value === "Thumb View" ? "thumb" : "list")}
|
|
497
|
-
className="appearance-none rounded-lg border border-neutral-200 bg-white px-3 py-2.5 pr-8 text-sm text-neutral-700 focus:border-[#
|
|
497
|
+
className="appearance-none rounded-lg border border-neutral-200 bg-white px-3 py-2.5 pr-8 text-sm text-neutral-700 focus:border-[#3580f9] focus:outline-none cursor-pointer"
|
|
498
498
|
>
|
|
499
499
|
<option>List View</option>
|
|
500
500
|
<option>Thumb View</option>
|
|
@@ -505,7 +505,7 @@ export default function AdminProjectsPage() {
|
|
|
505
505
|
</div>
|
|
506
506
|
<button
|
|
507
507
|
onClick={() => setShowCreate(true)}
|
|
508
|
-
className="rounded-lg bg-[#
|
|
508
|
+
className="rounded-lg bg-[#3580f9] px-5 py-2.5 text-sm font-medium text-white hover:bg-[#2d6dd4] transition-colors"
|
|
509
509
|
>
|
|
510
510
|
+ New Project
|
|
511
511
|
</button>
|
|
@@ -519,7 +519,7 @@ export default function AdminProjectsPage() {
|
|
|
519
519
|
value={search}
|
|
520
520
|
onChange={(e) => setSearch(e.target.value)}
|
|
521
521
|
placeholder="Search by title or slug..."
|
|
522
|
-
className="w-full max-w-md rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 placeholder:text-neutral-400 focus:border-[#
|
|
522
|
+
className="w-full max-w-md rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 placeholder:text-neutral-400 focus:border-[#3580f9] focus:outline-none focus:ring-2 focus:ring-[#3580f9]/10 shadow-sm"
|
|
523
523
|
/>
|
|
524
524
|
</div>
|
|
525
525
|
|
|
@@ -534,7 +534,7 @@ export default function AdminProjectsPage() {
|
|
|
534
534
|
{projects.length === 0 ? "No projects yet" : "No projects match your search"}
|
|
535
535
|
</p>
|
|
536
536
|
{projects.length === 0 && (
|
|
537
|
-
<button onClick={() => setShowCreate(true)} className="text-xs text-[#
|
|
537
|
+
<button onClick={() => setShowCreate(true)} className="text-xs text-[#3580f9] hover:underline">
|
|
538
538
|
Create your first project
|
|
539
539
|
</button>
|
|
540
540
|
)}
|
|
@@ -557,7 +557,7 @@ export default function AdminProjectsPage() {
|
|
|
557
557
|
className="group grid grid-cols-[1fr_120px_140px_180px] gap-4 items-center rounded-lg bg-white px-5 py-4 hover:shadow-md transition-all cursor-pointer border border-transparent hover:border-neutral-200"
|
|
558
558
|
onClick={() => router.push(`/admin/projects/${project.slug.current}`)}
|
|
559
559
|
>
|
|
560
|
-
<p className="text-sm text-neutral-900 group-hover:text-[#
|
|
560
|
+
<p className="text-sm text-neutral-900 group-hover:text-[#3580f9] transition-colors">
|
|
561
561
|
{project.title}
|
|
562
562
|
</p>
|
|
563
563
|
|
|
@@ -601,7 +601,7 @@ export default function AdminProjectsPage() {
|
|
|
601
601
|
<div key={project._id} className="group relative">
|
|
602
602
|
{/* Thumbnail card */}
|
|
603
603
|
<div
|
|
604
|
-
className="relative aspect-[4/3] rounded-xl overflow-hidden bg-neutral-200 cursor-pointer border border-neutral-200/80 hover:shadow-md hover:shadow-[#
|
|
604
|
+
className="relative aspect-[4/3] rounded-xl overflow-hidden bg-neutral-200 cursor-pointer border border-neutral-200/80 hover:shadow-md hover:shadow-[#3580f9]/5 transition-all"
|
|
605
605
|
onClick={() => router.push(`/admin/projects/${project.slug.current}`)}
|
|
606
606
|
>
|
|
607
607
|
{project.thumbnail_path ? (
|
|
@@ -628,7 +628,7 @@ export default function AdminProjectsPage() {
|
|
|
628
628
|
{/* Hover overlay with actions */}
|
|
629
629
|
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/20 transition-colors flex items-start justify-end p-2 opacity-0 group-hover:opacity-100">
|
|
630
630
|
<div className="flex gap-1" onClick={(e) => e.stopPropagation()}>
|
|
631
|
-
<button onClick={() => setEditingProject(project)} className="p-1.5 rounded bg-white/90 text-neutral-600 hover:text-[#
|
|
631
|
+
<button onClick={() => setEditingProject(project)} className="p-1.5 rounded bg-white/90 text-neutral-600 hover:text-[#3580f9] transition-colors shadow-sm" title="Edit">
|
|
632
632
|
<EditIcon />
|
|
633
633
|
</button>
|
|
634
634
|
<button onClick={() => handleDuplicate(project)} disabled={duplicating === project._id} className="p-1.5 rounded bg-white/90 text-neutral-600 hover:text-neutral-900 transition-colors shadow-sm" title="Duplicate">
|
package/app/admin/setup/page.tsx
CHANGED
|
@@ -53,7 +53,7 @@ export default function SetupPage() {
|
|
|
53
53
|
style={{ fontFamily: "Inter, system-ui, sans-serif" }}
|
|
54
54
|
>
|
|
55
55
|
<div className="text-center">
|
|
56
|
-
<div className="w-6 h-6 border-2 border-[#
|
|
56
|
+
<div className="w-6 h-6 border-2 border-[#3580f9] border-t-transparent rounded-full animate-spin mx-auto mb-3" />
|
|
57
57
|
<p className="text-xs text-[#999]">Checking setup status...</p>
|
|
58
58
|
</div>
|
|
59
59
|
</div>
|
|
@@ -172,7 +172,7 @@ export default function AdminStylesPage() {
|
|
|
172
172
|
onClick={() => setActiveTab(tab.id)}
|
|
173
173
|
className={`flex items-center gap-1.5 px-4 py-2.5 text-[13px] font-medium transition-colors border-b-2 -mb-px ${
|
|
174
174
|
isActive
|
|
175
|
-
? "text-neutral-900 border-[#
|
|
175
|
+
? "text-neutral-900 border-[#3580f9]"
|
|
176
176
|
: "text-neutral-400 border-transparent hover:text-neutral-600"
|
|
177
177
|
}`}
|
|
178
178
|
>
|
|
@@ -71,7 +71,7 @@ export default function MetadataEditor({
|
|
|
71
71
|
value={title}
|
|
72
72
|
onChange={(e) => setTitle(e.target.value)}
|
|
73
73
|
placeholder={getSiteConfig().defaults.metaTitle}
|
|
74
|
-
className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 focus:border-[#
|
|
74
|
+
className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 focus:border-[#3580f9] focus:outline-none"
|
|
75
75
|
/>
|
|
76
76
|
<p className="text-xs text-neutral-400">
|
|
77
77
|
Shown in browser tabs and search results when no page-specific title is
|
|
@@ -89,7 +89,7 @@ export default function MetadataEditor({
|
|
|
89
89
|
onChange={(e) => setDescription(e.target.value)}
|
|
90
90
|
placeholder="Motion graphics studio based in Barcelona..."
|
|
91
91
|
rows={3}
|
|
92
|
-
className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 focus:border-[#
|
|
92
|
+
className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 focus:border-[#3580f9] focus:outline-none resize-none"
|
|
93
93
|
/>
|
|
94
94
|
<div className="flex justify-between">
|
|
95
95
|
<p className="text-xs text-neutral-400">
|
|
@@ -115,7 +115,7 @@ export default function MetadataEditor({
|
|
|
115
115
|
value={ogImage}
|
|
116
116
|
onChange={(e) => setOgImage(e.target.value)}
|
|
117
117
|
placeholder="meta/og-image.jpg"
|
|
118
|
-
className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 focus:border-[#
|
|
118
|
+
className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 focus:border-[#3580f9] focus:outline-none"
|
|
119
119
|
/>
|
|
120
120
|
<p className="text-xs text-neutral-400">
|
|
121
121
|
Relative path to the default image shown when sharing on social media.
|
|
@@ -133,7 +133,7 @@ export default function MetadataEditor({
|
|
|
133
133
|
value={favicon}
|
|
134
134
|
onChange={(e) => setFavicon(e.target.value)}
|
|
135
135
|
placeholder="meta/favicon.ico"
|
|
136
|
-
className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 focus:border-[#
|
|
136
|
+
className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 focus:border-[#3580f9] focus:outline-none"
|
|
137
137
|
/>
|
|
138
138
|
<p className="text-xs text-neutral-400">
|
|
139
139
|
Relative path to the favicon. Resolved via the asset seed URL.
|
|
@@ -150,7 +150,7 @@ export default function MetadataEditor({
|
|
|
150
150
|
value={analyticsId}
|
|
151
151
|
onChange={(e) => setAnalyticsId(e.target.value)}
|
|
152
152
|
placeholder="G-XXXXXXXXXX or plausible domain"
|
|
153
|
-
className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 focus:border-[#
|
|
153
|
+
className="w-full rounded-lg border border-neutral-200 bg-white px-3 py-2.5 text-sm text-neutral-900 focus:border-[#3580f9] focus:outline-none"
|
|
154
154
|
/>
|
|
155
155
|
<p className="text-xs text-neutral-400">
|
|
156
156
|
Google Analytics measurement ID or Plausible domain. Leave empty to
|
|
@@ -163,7 +163,7 @@ export default function MetadataEditor({
|
|
|
163
163
|
<button
|
|
164
164
|
onClick={handleSave}
|
|
165
165
|
disabled={saving}
|
|
166
|
-
className="rounded-lg bg-[#
|
|
166
|
+
className="rounded-lg bg-[#3580f9] px-5 py-2.5 text-sm font-medium text-white hover:bg-[#2d6dd4] transition-colors disabled:opacity-50"
|
|
167
167
|
>
|
|
168
168
|
{saving ? "Saving..." : "Save Metadata"}
|
|
169
169
|
</button>
|
|
@@ -220,7 +220,7 @@ export default function NavBuilder({
|
|
|
220
220
|
className={`px-4 py-1.5 text-[11px] font-medium rounded-lg transition-all ${
|
|
221
221
|
saving || !hasChanges
|
|
222
222
|
? "bg-white/40 text-neutral-400 cursor-not-allowed"
|
|
223
|
-
: "bg-white text-[#
|
|
223
|
+
: "bg-white text-[#3580f9] shadow-sm hover:shadow-md"
|
|
224
224
|
}`}
|
|
225
225
|
>
|
|
226
226
|
{saving ? "Saving..." : "Save"}
|
|
@@ -87,7 +87,7 @@ function DroppableCell({
|
|
|
87
87
|
<div ref={setNodeRef} style={{ gridColumn: column, gridRow: 1 }}>
|
|
88
88
|
<NavGridCell column={column} onAddItem={onAddItem} />
|
|
89
89
|
{isDragOver && (
|
|
90
|
-
<div className="absolute inset-0 rounded-lg ring-2 ring-[#
|
|
90
|
+
<div className="absolute inset-0 rounded-lg ring-2 ring-[#3580f9] bg-[#3580f9]/10 pointer-events-none" />
|
|
91
91
|
)}
|
|
92
92
|
</div>
|
|
93
93
|
);
|
|
@@ -286,7 +286,7 @@ export default function NavBuilderGrid({
|
|
|
286
286
|
{/* Helper hints */}
|
|
287
287
|
<div className="mt-4 flex gap-4 text-[10px] text-neutral-400">
|
|
288
288
|
<span>
|
|
289
|
-
<span className="text-[#
|
|
289
|
+
<span className="text-[#3580f9]">+</span> Click empty column to add
|
|
290
290
|
</span>
|
|
291
291
|
<span>
|
|
292
292
|
<span className="text-neutral-500">⠇</span> Drag to move
|
|
@@ -301,7 +301,7 @@ export default function NavBuilderGrid({
|
|
|
301
301
|
<DragOverlay>
|
|
302
302
|
{activeItem ? (
|
|
303
303
|
<div
|
|
304
|
-
className="h-14 flex items-center px-3 gap-2 rounded-lg ring-2 ring-[#
|
|
304
|
+
className="h-14 flex items-center px-3 gap-2 rounded-lg ring-2 ring-[#3580f9] bg-white shadow-xl"
|
|
305
305
|
style={{ width: 120, opacity: 0.9 }}
|
|
306
306
|
>
|
|
307
307
|
<div className="text-xs font-mono text-neutral-900 uppercase tracking-wider truncate">
|
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
|
|
5
|
-
interface NavGridCellProps {
|
|
6
|
-
column: number;
|
|
7
|
-
onAddItem: (column: number) => void;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export default function NavGridCell({ column, onAddItem }: NavGridCellProps) {
|
|
11
|
-
const [hovered, setHovered] = useState(false);
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
<div
|
|
15
|
-
onMouseEnter={() => setHovered(true)}
|
|
16
|
-
onMouseLeave={() => setHovered(false)}
|
|
17
|
-
onClick={(e) => {
|
|
18
|
-
e.stopPropagation();
|
|
19
|
-
onAddItem(column);
|
|
20
|
-
}}
|
|
21
|
-
className={`h-14 flex items-center justify-center cursor-pointer transition-all rounded-lg border border-dashed ${
|
|
22
|
-
hovered
|
|
23
|
-
? "border-[#
|
|
24
|
-
: "border-neutral-200 bg-transparent"
|
|
25
|
-
}`}
|
|
26
|
-
data-nav-cell={column}
|
|
27
|
-
>
|
|
28
|
-
<div
|
|
29
|
-
className={`flex flex-col items-center gap-0.5 transition-all ${
|
|
30
|
-
hovered ? "text-[#
|
|
31
|
-
}`}
|
|
32
|
-
style={{
|
|
33
|
-
opacity: hovered ? 1 : 0.5,
|
|
34
|
-
transform: hovered ? "scale(1)" : "scale(0.9)",
|
|
35
|
-
}}
|
|
36
|
-
>
|
|
37
|
-
<svg width="14" height="14" viewBox="0 0 16 16" fill="none">
|
|
38
|
-
<path
|
|
39
|
-
d="M8 3v10M3 8h10"
|
|
40
|
-
stroke="currentColor"
|
|
41
|
-
strokeWidth="1.5"
|
|
42
|
-
strokeLinecap="round"
|
|
43
|
-
/>
|
|
44
|
-
</svg>
|
|
45
|
-
</div>
|
|
46
|
-
</div>
|
|
47
|
-
);
|
|
48
|
-
}
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
|
|
5
|
+
interface NavGridCellProps {
|
|
6
|
+
column: number;
|
|
7
|
+
onAddItem: (column: number) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default function NavGridCell({ column, onAddItem }: NavGridCellProps) {
|
|
11
|
+
const [hovered, setHovered] = useState(false);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div
|
|
15
|
+
onMouseEnter={() => setHovered(true)}
|
|
16
|
+
onMouseLeave={() => setHovered(false)}
|
|
17
|
+
onClick={(e) => {
|
|
18
|
+
e.stopPropagation();
|
|
19
|
+
onAddItem(column);
|
|
20
|
+
}}
|
|
21
|
+
className={`h-14 flex items-center justify-center cursor-pointer transition-all rounded-lg border border-dashed ${
|
|
22
|
+
hovered
|
|
23
|
+
? "border-[#3580f9]/50 bg-[#3580f9]/[0.03]"
|
|
24
|
+
: "border-neutral-200 bg-transparent"
|
|
25
|
+
}`}
|
|
26
|
+
data-nav-cell={column}
|
|
27
|
+
>
|
|
28
|
+
<div
|
|
29
|
+
className={`flex flex-col items-center gap-0.5 transition-all ${
|
|
30
|
+
hovered ? "text-[#3580f9]" : "text-neutral-300"
|
|
31
|
+
}`}
|
|
32
|
+
style={{
|
|
33
|
+
opacity: hovered ? 1 : 0.5,
|
|
34
|
+
transform: hovered ? "scale(1)" : "scale(0.9)",
|
|
35
|
+
}}
|
|
36
|
+
>
|
|
37
|
+
<svg width="14" height="14" viewBox="0 0 16 16" fill="none">
|
|
38
|
+
<path
|
|
39
|
+
d="M8 3v10M3 8h10"
|
|
40
|
+
stroke="currentColor"
|
|
41
|
+
strokeWidth="1.5"
|
|
42
|
+
strokeLinecap="round"
|
|
43
|
+
/>
|
|
44
|
+
</svg>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -94,7 +94,7 @@ export default function NavGridItem({
|
|
|
94
94
|
}}
|
|
95
95
|
className={`h-14 relative flex items-center px-3 gap-2 cursor-pointer rounded-lg transition-all border ${
|
|
96
96
|
isSelected
|
|
97
|
-
? "border-[#
|
|
97
|
+
? "border-[#3580f9] bg-[#3580f9]/5 shadow-sm"
|
|
98
98
|
: hovered
|
|
99
99
|
? "border-neutral-300 bg-neutral-50"
|
|
100
100
|
: "border-neutral-200 bg-white"
|
|
@@ -141,7 +141,7 @@ export default function NavGridItem({
|
|
|
141
141
|
<div
|
|
142
142
|
className="absolute -top-2 -right-2 text-[9px] font-semibold px-1.5 py-0 rounded text-white"
|
|
143
143
|
style={{
|
|
144
|
-
background: isSelected ? "#
|
|
144
|
+
background: isSelected ? "#3580f9" : "#a3a3a3",
|
|
145
145
|
}}
|
|
146
146
|
>
|
|
147
147
|
{item.column_span}/{TOTAL_COLUMNS}
|
|
@@ -175,9 +175,9 @@ export default function NavGridItem({
|
|
|
175
175
|
className="absolute -right-1 top-1/2 -translate-y-1/2 w-2 h-6 rounded cursor-col-resize transition-all"
|
|
176
176
|
style={{
|
|
177
177
|
background: resizing
|
|
178
|
-
? "#
|
|
178
|
+
? "#3580f9"
|
|
179
179
|
: isSelected
|
|
180
|
-
? "#
|
|
180
|
+
? "#3580f9"
|
|
181
181
|
: hovered
|
|
182
182
|
? "#a3a3a3"
|
|
183
183
|
: "transparent",
|