@morphika/andami 0.1.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/LICENSE +21 -0
- package/README.md +50 -0
- package/admin/assets.ts +4 -0
- package/admin/database.ts +4 -0
- package/admin/index.ts +6 -0
- package/admin/login.ts +4 -0
- package/admin/navigation.ts +4 -0
- package/admin/pages-editor.ts +4 -0
- package/admin/pages.ts +4 -0
- package/admin/projects-editor.ts +4 -0
- package/admin/projects.ts +4 -0
- package/admin/settings.ts +4 -0
- package/admin/setup.ts +4 -0
- package/admin/storage.ts +4 -0
- package/admin/styles.ts +4 -0
- package/app/(site)/[slug]/loading.tsx +20 -0
- package/app/(site)/[slug]/page.tsx +83 -0
- package/app/(site)/error.tsx +32 -0
- package/app/(site)/layout.tsx +53 -0
- package/app/(site)/loading.tsx +20 -0
- package/app/(site)/not-found.tsx +41 -0
- package/app/(site)/page.tsx +43 -0
- package/app/(site)/preview/page.tsx +99 -0
- package/app/(site)/work/[slug]/loading.tsx +23 -0
- package/app/(site)/work/[slug]/page.tsx +84 -0
- package/app/admin/assets/page.tsx +573 -0
- package/app/admin/database/page.tsx +302 -0
- package/app/admin/error.tsx +53 -0
- package/app/admin/layout.tsx +273 -0
- package/app/admin/login/page.tsx +88 -0
- package/app/admin/navigation/page.tsx +157 -0
- package/app/admin/page.tsx +17 -0
- package/app/admin/pages/[slug]/page.tsx +849 -0
- package/app/admin/pages/page.tsx +588 -0
- package/app/admin/projects/[slug]/page.tsx +3 -0
- package/app/admin/projects/page.tsx +669 -0
- package/app/admin/settings/page.tsx +132 -0
- package/app/admin/setup/page.tsx +64 -0
- package/app/admin/storage/page.tsx +518 -0
- package/app/admin/styles/page.tsx +243 -0
- package/app/api/admin/assets/file/route.ts +81 -0
- package/app/api/admin/assets/health/route.ts +170 -0
- package/app/api/admin/assets/register/route.ts +163 -0
- package/app/api/admin/assets/registry/route.ts +98 -0
- package/app/api/admin/assets/relink/confirm/route.ts +242 -0
- package/app/api/admin/assets/relink/route.ts +202 -0
- package/app/api/admin/assets/scan/route.ts +271 -0
- package/app/api/admin/auth/route.ts +160 -0
- package/app/api/admin/custom-sections/[slug]/route.ts +159 -0
- package/app/api/admin/custom-sections/route.ts +127 -0
- package/app/api/admin/database/route.ts +53 -0
- package/app/api/admin/pages/[slug]/duplicate/route.ts +91 -0
- package/app/api/admin/pages/[slug]/route.ts +617 -0
- package/app/api/admin/pages/[slug]/set-home/route.ts +76 -0
- package/app/api/admin/pages/route.ts +129 -0
- package/app/api/admin/preview/route.ts +53 -0
- package/app/api/admin/r2/connect/route.ts +181 -0
- package/app/api/admin/r2/delete/route.ts +198 -0
- package/app/api/admin/r2/disconnect/route.ts +42 -0
- package/app/api/admin/r2/rename/route.ts +265 -0
- package/app/api/admin/r2/status/route.ts +106 -0
- package/app/api/admin/r2/upload-url/route.ts +148 -0
- package/app/api/admin/revalidate/route.ts +55 -0
- package/app/api/admin/settings/route.ts +279 -0
- package/app/api/admin/setup/complete/route.ts +51 -0
- package/app/api/admin/setup/route.ts +118 -0
- package/app/api/admin/storage/switch/route.ts +117 -0
- package/app/api/admin/styles/fonts/route.ts +97 -0
- package/app/api/admin/styles/route.ts +304 -0
- package/app/api/assets/[...path]/route.ts +98 -0
- package/app/api/custom-sections/[id]/route.ts +43 -0
- package/app/api/draft-mode/disable/route.ts +10 -0
- package/app/api/draft-mode/enable/route.ts +26 -0
- package/app/api/projects/route.ts +42 -0
- package/app/api/styles/route.ts +88 -0
- package/app/favicon.ico +0 -0
- package/app/globals.css +7 -0
- package/app/layout.tsx +53 -0
- package/app/robots.ts +17 -0
- package/app/sitemap.ts +48 -0
- package/app/studio/[[...index]]/page.tsx +8 -0
- package/components/admin/MetadataEditor.tsx +173 -0
- package/components/admin/PublishToggle.tsx +130 -0
- package/components/admin/icons.tsx +40 -0
- package/components/admin/nav-builder/NavBuilder.tsx +182 -0
- package/components/admin/nav-builder/NavBuilderGrid.tsx +326 -0
- package/components/admin/nav-builder/NavGeneralSettings.tsx +275 -0
- package/components/admin/nav-builder/NavGridCell.tsx +48 -0
- package/components/admin/nav-builder/NavGridItem.tsx +189 -0
- package/components/admin/nav-builder/NavItemSettings.tsx +288 -0
- package/components/admin/nav-builder/NavItemTypePicker.tsx +102 -0
- package/components/admin/nav-builder/NavLivePreview.tsx +125 -0
- package/components/admin/nav-builder/NavSettingsFields.tsx +248 -0
- package/components/admin/nav-builder/NavSettingsPanel.tsx +127 -0
- package/components/admin/nav-builder/index.ts +10 -0
- package/components/admin/nav-builder/nav-builder-utils.ts +238 -0
- package/components/admin/setup-wizard/BrandingStep.tsx +218 -0
- package/components/admin/setup-wizard/DatabaseStep.tsx +331 -0
- package/components/admin/setup-wizard/DoneStep.tsx +187 -0
- package/components/admin/setup-wizard/SetupWizard.tsx +166 -0
- package/components/admin/setup-wizard/StorageStep.tsx +308 -0
- package/components/admin/setup-wizard/WelcomeStep.tsx +96 -0
- package/components/admin/setup-wizard/index.ts +9 -0
- package/components/admin/styles/ColorsEditor.tsx +214 -0
- package/components/admin/styles/FontsEditor.tsx +258 -0
- package/components/admin/styles/GridLayoutEditor.tsx +292 -0
- package/components/admin/styles/LinksButtonsEditor.tsx +120 -0
- package/components/admin/styles/TypographyEditor.tsx +266 -0
- package/components/admin/styles/index.ts +9 -0
- package/components/admin/styles/shared.tsx +68 -0
- package/components/blocks/BlockRenderer.tsx +404 -0
- package/components/blocks/ButtonBlockRenderer.tsx +52 -0
- package/components/blocks/CoverBlockRenderer.tsx +239 -0
- package/components/blocks/CustomSectionInstanceRenderer.tsx +82 -0
- package/components/blocks/EnterAnimationWrapper.tsx +140 -0
- package/components/blocks/HoverAnimationWrapper.tsx +308 -0
- package/components/blocks/ImageBlockRenderer.tsx +61 -0
- package/components/blocks/ImageGridBlockRenderer.tsx +545 -0
- package/components/blocks/PageBackground.tsx +28 -0
- package/components/blocks/PageNavAnimation.tsx +35 -0
- package/components/blocks/PageNavColor.tsx +24 -0
- package/components/blocks/PageRenderer.tsx +142 -0
- package/components/blocks/ParallaxGroupRenderer.tsx +448 -0
- package/components/blocks/ParallaxSlideRenderer.tsx +175 -0
- package/components/blocks/ProjectGridBlockRenderer.tsx +556 -0
- package/components/blocks/SectionRenderer.tsx +170 -0
- package/components/blocks/SectionV2Renderer.tsx +330 -0
- package/components/blocks/ShaderCanvas.tsx +392 -0
- package/components/blocks/SpacerBlockRenderer.tsx +17 -0
- package/components/blocks/TextBlockRenderer.tsx +87 -0
- package/components/blocks/TypewriterRichText.tsx +464 -0
- package/components/blocks/TypewriterWrapper.tsx +149 -0
- package/components/blocks/VideoBlockRenderer.tsx +304 -0
- package/components/blocks/index.ts +2 -0
- package/components/builder/AssetBrowser.tsx +2 -0
- package/components/builder/BlockLivePreview.tsx +101 -0
- package/components/builder/BlockTypePicker.tsx +178 -0
- package/components/builder/BuilderCanvas.tsx +354 -0
- package/components/builder/CanvasMinimap.tsx +200 -0
- package/components/builder/CanvasToolbar.tsx +202 -0
- package/components/builder/ColorPicker.tsx +243 -0
- package/components/builder/ColorSwatchPicker.tsx +274 -0
- package/components/builder/ColumnDragContext.tsx +51 -0
- package/components/builder/ColumnDragOverlay.tsx +110 -0
- package/components/builder/CustomSectionInstanceCard.tsx +97 -0
- package/components/builder/DeviceFrame.tsx +123 -0
- package/components/builder/DndWrapper.tsx +337 -0
- package/components/builder/InsertionLines.tsx +186 -0
- package/components/builder/ParallaxGroupCanvas.tsx +228 -0
- package/components/builder/ParallaxSlideHeader.tsx +113 -0
- package/components/builder/ReadOnlyFrame.tsx +417 -0
- package/components/builder/SectionEditorBar.tsx +288 -0
- package/components/builder/SectionTypePicker.tsx +422 -0
- package/components/builder/SectionV2Canvas.tsx +297 -0
- package/components/builder/SectionV2Column.tsx +488 -0
- package/components/builder/SettingsPanel.tsx +911 -0
- package/components/builder/SortableBlock.tsx +230 -0
- package/components/builder/SortableRow.tsx +362 -0
- package/components/builder/VirtualAssetGrid.tsx +397 -0
- package/components/builder/asset-browser/AssetBrowser.tsx +178 -0
- package/components/builder/asset-browser/FileLightbox.tsx +116 -0
- package/components/builder/asset-browser/FolderTreeItem.tsx +55 -0
- package/components/builder/asset-browser/R2BrowserContent.tsx +436 -0
- package/components/builder/asset-browser/R2ContextMenu.tsx +98 -0
- package/components/builder/asset-browser/VideoThumbnail.tsx +63 -0
- package/components/builder/asset-browser/helpers.ts +88 -0
- package/components/builder/asset-browser/index.ts +1 -0
- package/components/builder/asset-browser/types.ts +49 -0
- package/components/builder/asset-browser/useAssetBrowser.ts +344 -0
- package/components/builder/asset-browser/useR2DragDrop.ts +116 -0
- package/components/builder/asset-browser/useR2Operations.ts +189 -0
- package/components/builder/blockStyles.tsx +295 -0
- package/components/builder/editors/ButtonBlockEditor.tsx +184 -0
- package/components/builder/editors/CoverBlockEditor.tsx +488 -0
- package/components/builder/editors/EnterAnimationPicker.tsx +297 -0
- package/components/builder/editors/HoverEffectPicker.tsx +209 -0
- package/components/builder/editors/ImageBlockEditor.tsx +206 -0
- package/components/builder/editors/ImageGridBlockEditor.tsx +386 -0
- package/components/builder/editors/ProjectGridEditor.tsx +648 -0
- package/components/builder/editors/SpacerBlockEditor.tsx +167 -0
- package/components/builder/editors/StaggerSettings.tsx +108 -0
- package/components/builder/editors/TextAlignmentIcons.tsx +39 -0
- package/components/builder/editors/TextBlockEditor.tsx +462 -0
- package/components/builder/editors/TextStylePicker.tsx +183 -0
- package/components/builder/editors/VideoBlockEditor.tsx +278 -0
- package/components/builder/editors/index.ts +10 -0
- package/components/builder/editors/shared.tsx +345 -0
- package/components/builder/hooks/useColumnDrag.ts +472 -0
- package/components/builder/hooks/useColumnResize.ts +221 -0
- package/components/builder/index.ts +12 -0
- package/components/builder/live-preview/LiveButtonPreview.tsx +38 -0
- package/components/builder/live-preview/LiveCoverPreview.tsx +146 -0
- package/components/builder/live-preview/LiveImageGridPreview.tsx +123 -0
- package/components/builder/live-preview/LiveImagePreview.tsx +107 -0
- package/components/builder/live-preview/LiveProjectGridPreview.tsx +1010 -0
- package/components/builder/live-preview/LiveSpacerPreview.tsx +9 -0
- package/components/builder/live-preview/LiveTextEditor.tsx +198 -0
- package/components/builder/live-preview/LiveVideoPreview.tsx +98 -0
- package/components/builder/live-preview/index.ts +10 -0
- package/components/builder/live-preview/shared.tsx +153 -0
- package/components/builder/settings-panel/BlockLayoutTab.tsx +532 -0
- package/components/builder/settings-panel/BlockSettings.tsx +94 -0
- package/components/builder/settings-panel/ColumnV2Settings.tsx +160 -0
- package/components/builder/settings-panel/LayoutTab.tsx +310 -0
- package/components/builder/settings-panel/PageSettings.tsx +200 -0
- package/components/builder/settings-panel/ParallaxGroupSettings.tsx +118 -0
- package/components/builder/settings-panel/ParallaxSlideSettings.tsx +178 -0
- package/components/builder/settings-panel/SectionV2AnimationTab.tsx +103 -0
- package/components/builder/settings-panel/SectionV2LayoutTab.tsx +312 -0
- package/components/builder/settings-panel/SectionV2Settings.tsx +323 -0
- package/components/builder/settings-panel/TRBLInputs.tsx +51 -0
- package/components/builder/settings-panel/index.ts +19 -0
- package/components/builder/settings-panel/responsive-helpers.ts +524 -0
- package/components/ui/CustomCursor.tsx +118 -0
- package/components/ui/NavContentLightbox.tsx +152 -0
- package/components/ui/Navbar.tsx +582 -0
- package/components/ui/PortfolioTracker.tsx +87 -0
- package/components/ui/ScrollToTop.tsx +47 -0
- package/lib/animation/enter-presets.ts +147 -0
- package/lib/animation/enter-resolve.ts +90 -0
- package/lib/animation/enter-types.ts +128 -0
- package/lib/animation/hover-effect-presets.ts +210 -0
- package/lib/animation/hover-effect-types.ts +126 -0
- package/lib/asset-retry.ts +111 -0
- package/lib/assets.ts +92 -0
- package/lib/audit.ts +35 -0
- package/lib/auth-token.ts +94 -0
- package/lib/auth.ts +13 -0
- package/lib/builder/cascade-helpers.ts +51 -0
- package/lib/builder/cascade.ts +533 -0
- package/lib/builder/constants.ts +103 -0
- package/lib/builder/defaults.ts +182 -0
- package/lib/builder/history.ts +48 -0
- package/lib/builder/index.ts +21 -0
- package/lib/builder/layout-styles.ts +344 -0
- package/lib/builder/masonry.ts +166 -0
- package/lib/builder/responsive.ts +156 -0
- package/lib/builder/serializer.ts +845 -0
- package/lib/builder/store-blocks.ts +193 -0
- package/lib/builder/store-canvas.ts +319 -0
- package/lib/builder/store-helpers.ts +490 -0
- package/lib/builder/store-sections.ts +709 -0
- package/lib/builder/store.ts +333 -0
- package/lib/builder/templates.ts +297 -0
- package/lib/builder/types.ts +374 -0
- package/lib/builder/utils.ts +37 -0
- package/lib/color-utils.ts +116 -0
- package/lib/config/index.ts +57 -0
- package/lib/config/types.ts +122 -0
- package/lib/contexts/AssetContext.tsx +79 -0
- package/lib/contexts/NavAnimationContext.tsx +44 -0
- package/lib/contexts/NavColorContext.tsx +38 -0
- package/lib/contexts/PageExitContext.tsx +194 -0
- package/lib/contexts/ThumbStatusContext.tsx +83 -0
- package/lib/csrf-client.ts +34 -0
- package/lib/csrf.ts +68 -0
- package/lib/format-utils.ts +24 -0
- package/lib/hooks/useViewport.ts +42 -0
- package/lib/logger.ts +81 -0
- package/lib/revalidate.ts +23 -0
- package/lib/sanitize.ts +91 -0
- package/lib/sanity/client.ts +8 -0
- package/lib/sanity/queries.ts +486 -0
- package/lib/sanity/types.ts +869 -0
- package/lib/sanity/writeClient.ts +24 -0
- package/lib/security.ts +402 -0
- package/lib/setup/detect.ts +156 -0
- package/lib/shader/glsl/index.ts +27 -0
- package/lib/shader/glsl/pixelate.ts +51 -0
- package/lib/shader/glsl/rgb-shift.ts +45 -0
- package/lib/shader/glsl/ripple.ts +46 -0
- package/lib/shader/glsl/vertex.ts +14 -0
- package/lib/storage/index.ts +211 -0
- package/lib/storage/r2-adapter.ts +286 -0
- package/lib/storage/types.ts +125 -0
- package/lib/styles/provider.tsx +267 -0
- package/lib/thumbnails/generate.ts +151 -0
- package/lib/utils.ts +6 -0
- package/package.json +212 -0
- package/sanity/compose.ts +65 -0
- package/sanity/sanity.config.ts +126 -0
- package/sanity/schemas/assetRegistry.ts +301 -0
- package/sanity/schemas/blocks/blockLayout.ts +90 -0
- package/sanity/schemas/blocks/buttonBlock.ts +82 -0
- package/sanity/schemas/blocks/coverBlock.ts +229 -0
- package/sanity/schemas/blocks/imageBlock.ts +58 -0
- package/sanity/schemas/blocks/imageGridBlock.ts +112 -0
- package/sanity/schemas/blocks/index.ts +9 -0
- package/sanity/schemas/blocks/projectGridBlock.ts +251 -0
- package/sanity/schemas/blocks/spacerBlock.ts +41 -0
- package/sanity/schemas/blocks/textBlock.ts +139 -0
- package/sanity/schemas/blocks/videoBlock.ts +80 -0
- package/sanity/schemas/customSection.ts +69 -0
- package/sanity/schemas/customSectionInstance.ts +163 -0
- package/sanity/schemas/index.ts +111 -0
- package/sanity/schemas/objects/enterAnimationConfig.ts +72 -0
- package/sanity/schemas/objects/hoverEffectConfig.ts +90 -0
- package/sanity/schemas/objects/parallaxGroup.ts +66 -0
- package/sanity/schemas/objects/parallaxSlide.ts +217 -0
- package/sanity/schemas/objects/typewriterConfig.ts +38 -0
- package/sanity/schemas/page.ts +162 -0
- package/sanity/schemas/pageSection.ts +157 -0
- package/sanity/schemas/pageSectionV2.ts +269 -0
- package/sanity/schemas/siteSettings.ts +256 -0
- package/sanity/schemas/siteStyles.ts +212 -0
- package/site/error.ts +4 -0
- package/site/index.ts +8 -0
- package/site/not-found.ts +4 -0
- package/site/page.ts +4 -0
- package/site/preview.ts +4 -0
- package/site/robots.ts +4 -0
- package/site/sitemap.ts +4 -0
- package/site/work.ts +4 -0
- package/studio/index.ts +4 -0
- package/styles/admin.css +85 -0
- package/styles/animations.css +237 -0
- package/styles/base.css +148 -0
- package/styles/globals.css +10 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ParallaxGroupSettings — Settings panel for a parallax group (group-level).
|
|
5
|
+
*
|
|
6
|
+
* Displays:
|
|
7
|
+
* - Transition effect picker (parallax / crossfade / reveal)
|
|
8
|
+
* with description text explaining each effect
|
|
9
|
+
*
|
|
10
|
+
* Shown when the parallax group header is selected (not a specific slide).
|
|
11
|
+
*
|
|
12
|
+
* Session 124: Parallax V2 Phase 3
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { useBuilderStore } from "../../../lib/builder/store";
|
|
16
|
+
import type { ParallaxGroup } from "../../../lib/sanity/types";
|
|
17
|
+
import {
|
|
18
|
+
SettingsSection,
|
|
19
|
+
} from "../editors/shared";
|
|
20
|
+
|
|
21
|
+
// ============================================
|
|
22
|
+
// Transition effect definitions
|
|
23
|
+
// ============================================
|
|
24
|
+
|
|
25
|
+
const TRANSITION_EFFECTS = [
|
|
26
|
+
{
|
|
27
|
+
value: "parallax" as const,
|
|
28
|
+
label: "Parallax",
|
|
29
|
+
description: "Background moves slower than content as you scroll, creating depth.",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
value: "crossfade" as const,
|
|
33
|
+
label: "Crossfade",
|
|
34
|
+
description: "Backgrounds fade in and out as slides enter and leave the viewport.",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
value: "reveal" as const,
|
|
38
|
+
label: "Reveal",
|
|
39
|
+
description: "Each slide reveals over the previous one with a clip-path wipe effect.",
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
// ============================================
|
|
44
|
+
// Component
|
|
45
|
+
// ============================================
|
|
46
|
+
|
|
47
|
+
interface ParallaxGroupSettingsProps {
|
|
48
|
+
group: ParallaxGroup;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default function ParallaxGroupSettings({
|
|
52
|
+
group,
|
|
53
|
+
}: ParallaxGroupSettingsProps) {
|
|
54
|
+
const store = useBuilderStore();
|
|
55
|
+
const activeEffect = group.transition_effect || "parallax";
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<>
|
|
59
|
+
<SettingsSection title="Transition Effect" defaultOpen>
|
|
60
|
+
<div className="space-y-1.5">
|
|
61
|
+
{TRANSITION_EFFECTS.map((effect) => {
|
|
62
|
+
const isActive = activeEffect === effect.value;
|
|
63
|
+
return (
|
|
64
|
+
<button
|
|
65
|
+
key={effect.value}
|
|
66
|
+
onClick={() =>
|
|
67
|
+
store.updateParallaxGroupSettings(group._key, {
|
|
68
|
+
transition_effect: effect.value,
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
className={`w-full text-left rounded-lg border p-3 transition-all ${
|
|
72
|
+
isActive
|
|
73
|
+
? "border-[#8b5cf6] bg-[#8b5cf6]/5"
|
|
74
|
+
: "border-neutral-200 bg-white hover:border-neutral-300 hover:bg-neutral-50"
|
|
75
|
+
}`}
|
|
76
|
+
>
|
|
77
|
+
<div className="flex items-center gap-2 mb-0.5">
|
|
78
|
+
{/* Radio indicator */}
|
|
79
|
+
<div
|
|
80
|
+
className={`w-3.5 h-3.5 rounded-full border-2 flex items-center justify-center transition-colors ${
|
|
81
|
+
isActive ? "border-[#8b5cf6]" : "border-neutral-300"
|
|
82
|
+
}`}
|
|
83
|
+
>
|
|
84
|
+
{isActive && (
|
|
85
|
+
<div className="w-1.5 h-1.5 rounded-full bg-[#8b5cf6]" />
|
|
86
|
+
)}
|
|
87
|
+
</div>
|
|
88
|
+
<span
|
|
89
|
+
className={`text-xs font-medium ${
|
|
90
|
+
isActive ? "text-[#8b5cf6]" : "text-neutral-700"
|
|
91
|
+
}`}
|
|
92
|
+
>
|
|
93
|
+
{effect.label}
|
|
94
|
+
</span>
|
|
95
|
+
</div>
|
|
96
|
+
<p className="text-[10px] text-neutral-400 ml-[22px] leading-relaxed">
|
|
97
|
+
{effect.description}
|
|
98
|
+
</p>
|
|
99
|
+
</button>
|
|
100
|
+
);
|
|
101
|
+
})}
|
|
102
|
+
</div>
|
|
103
|
+
</SettingsSection>
|
|
104
|
+
|
|
105
|
+
{/* Group info */}
|
|
106
|
+
<SettingsSection title="Info">
|
|
107
|
+
<div className="text-[11px] text-neutral-500 space-y-1">
|
|
108
|
+
<p>
|
|
109
|
+
{group.slides.length} slide{group.slides.length !== 1 ? "s" : ""}
|
|
110
|
+
</p>
|
|
111
|
+
<p className="text-[10px] text-neutral-400">
|
|
112
|
+
Click a slide to edit its background and content layout.
|
|
113
|
+
</p>
|
|
114
|
+
</div>
|
|
115
|
+
</SettingsSection>
|
|
116
|
+
</>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ParallaxSlideSettings — Settings panel for an individual parallax slide.
|
|
5
|
+
*
|
|
6
|
+
* Displays:
|
|
7
|
+
* - Background type segmented control (Image / Video)
|
|
8
|
+
* - AssetBrowser picker for image or video
|
|
9
|
+
* - Background position dropdown
|
|
10
|
+
* - Overlay color (ColorSwatchPicker) + overlay opacity slider
|
|
11
|
+
*
|
|
12
|
+
* The parent SettingsPanel handles tab routing:
|
|
13
|
+
* - Settings tab → this component
|
|
14
|
+
* - Layout tab → SectionV2Settings (delegated)
|
|
15
|
+
* - Animation tab → SectionV2AnimationTab (delegated)
|
|
16
|
+
*
|
|
17
|
+
* Session 124: Parallax V2 Phase 3
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { useBuilderStore } from "../../../lib/builder/store";
|
|
21
|
+
import type { ParallaxSlideV2, ParallaxGroup, PageSectionV2 } from "../../../lib/sanity/types";
|
|
22
|
+
import {
|
|
23
|
+
SettingsField,
|
|
24
|
+
SettingsSection,
|
|
25
|
+
AssetPathInput,
|
|
26
|
+
} from "../editors/shared";
|
|
27
|
+
import ColorSwatchPicker, { usePaletteSwatches } from "../ColorSwatchPicker";
|
|
28
|
+
|
|
29
|
+
// ============================================
|
|
30
|
+
// Background position options
|
|
31
|
+
// ============================================
|
|
32
|
+
|
|
33
|
+
const BG_POSITION_OPTIONS = [
|
|
34
|
+
{ value: "center center", label: "Center" },
|
|
35
|
+
{ value: "top center", label: "Top" },
|
|
36
|
+
{ value: "bottom center", label: "Bottom" },
|
|
37
|
+
{ value: "center left", label: "Left" },
|
|
38
|
+
{ value: "center right", label: "Right" },
|
|
39
|
+
{ value: "top left", label: "Top Left" },
|
|
40
|
+
{ value: "top right", label: "Top Right" },
|
|
41
|
+
{ value: "bottom left", label: "Bottom Left" },
|
|
42
|
+
{ value: "bottom right", label: "Bottom Right" },
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
// ============================================
|
|
46
|
+
// Component
|
|
47
|
+
// ============================================
|
|
48
|
+
|
|
49
|
+
interface ParallaxSlideSettingsProps {
|
|
50
|
+
group: ParallaxGroup;
|
|
51
|
+
slide: ParallaxSlideV2;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default function ParallaxSlideSettings({
|
|
55
|
+
group,
|
|
56
|
+
slide,
|
|
57
|
+
}: ParallaxSlideSettingsProps) {
|
|
58
|
+
const store = useBuilderStore();
|
|
59
|
+
const paletteSwatches = usePaletteSwatches();
|
|
60
|
+
|
|
61
|
+
const updateBg = (fields: Partial<ParallaxSlideV2>) => {
|
|
62
|
+
store.updateParallaxSlideBackground(group._key, slide._key, fields);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const bgType = slide.background_type || "image";
|
|
66
|
+
const bgPosition = slide.background_position || "center center";
|
|
67
|
+
const overlayColor = slide.background_overlay_color || "#000000";
|
|
68
|
+
const overlayOpacity = slide.background_overlay_opacity ?? 0;
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<>
|
|
72
|
+
{/* Background Type */}
|
|
73
|
+
<SettingsSection title="Background" defaultOpen>
|
|
74
|
+
{/* Segmented control: Image / Video */}
|
|
75
|
+
<SettingsField label="Type">
|
|
76
|
+
<div className="flex rounded-lg bg-[#f0f0f0] p-[3px]">
|
|
77
|
+
{(["image", "video"] as const).map((type) => (
|
|
78
|
+
<button
|
|
79
|
+
key={type}
|
|
80
|
+
onClick={() => updateBg({ background_type: type })}
|
|
81
|
+
className={`flex-1 py-1.5 rounded-md text-[11px] font-medium transition-all ${
|
|
82
|
+
bgType === type
|
|
83
|
+
? "bg-white text-neutral-900 shadow-sm border border-[#e5e5e5]"
|
|
84
|
+
: "text-neutral-400 hover:text-neutral-500"
|
|
85
|
+
}`}
|
|
86
|
+
>
|
|
87
|
+
{type === "image" ? "Image" : "Video"}
|
|
88
|
+
</button>
|
|
89
|
+
))}
|
|
90
|
+
</div>
|
|
91
|
+
</SettingsField>
|
|
92
|
+
|
|
93
|
+
{/* Asset picker — switches between image and video filter */}
|
|
94
|
+
<SettingsField label={bgType === "image" ? "Image" : "Video"}>
|
|
95
|
+
<AssetPathInput
|
|
96
|
+
value={bgType === "image" ? (slide.background_image || "") : (slide.background_video || "")}
|
|
97
|
+
onChange={(path) => {
|
|
98
|
+
if (bgType === "image") {
|
|
99
|
+
updateBg({ background_image: path });
|
|
100
|
+
} else {
|
|
101
|
+
updateBg({ background_video: path });
|
|
102
|
+
}
|
|
103
|
+
}}
|
|
104
|
+
filterType={bgType === "image" ? "image" : "video"}
|
|
105
|
+
placeholder={bgType === "image" ? "path/to/image.jpg" : "path/to/video.mp4"}
|
|
106
|
+
/>
|
|
107
|
+
</SettingsField>
|
|
108
|
+
|
|
109
|
+
{/* Background position */}
|
|
110
|
+
<SettingsField label="Position">
|
|
111
|
+
<select
|
|
112
|
+
value={bgPosition}
|
|
113
|
+
onChange={(e) => updateBg({ background_position: e.target.value })}
|
|
114
|
+
className="w-full rounded-lg border border-transparent bg-[#f5f5f5] px-2.5 py-[7px] text-xs text-neutral-900 font-normal outline-none transition-all hover:bg-[#efefef] focus:bg-white focus:border-[#076bff] focus:shadow-[0_0_0_3px_rgba(7,107,255,0.06)]"
|
|
115
|
+
>
|
|
116
|
+
{BG_POSITION_OPTIONS.map((opt) => (
|
|
117
|
+
<option key={opt.value} value={opt.value}>
|
|
118
|
+
{opt.label}
|
|
119
|
+
</option>
|
|
120
|
+
))}
|
|
121
|
+
</select>
|
|
122
|
+
</SettingsField>
|
|
123
|
+
</SettingsSection>
|
|
124
|
+
|
|
125
|
+
{/* Navbar Color Override */}
|
|
126
|
+
<SettingsSection title="Navbar Color" defaultOpen={false}>
|
|
127
|
+
<SettingsField label="Color">
|
|
128
|
+
<div className="flex items-center gap-2">
|
|
129
|
+
<ColorSwatchPicker
|
|
130
|
+
value={slide.nav_color || ""}
|
|
131
|
+
onChange={(hex) => updateBg({ nav_color: hex })}
|
|
132
|
+
swatches={paletteSwatches}
|
|
133
|
+
/>
|
|
134
|
+
{slide.nav_color && (
|
|
135
|
+
<button
|
|
136
|
+
onClick={() => updateBg({ nav_color: undefined })}
|
|
137
|
+
className="text-[10px] text-neutral-400 hover:text-neutral-600 transition-colors shrink-0"
|
|
138
|
+
>
|
|
139
|
+
Clear
|
|
140
|
+
</button>
|
|
141
|
+
)}
|
|
142
|
+
</div>
|
|
143
|
+
</SettingsField>
|
|
144
|
+
<p className="text-[10px] text-neutral-400 leading-snug px-0.5">
|
|
145
|
+
Override the navbar text color while this slide is active. Color interpolates smoothly between slides on scroll.
|
|
146
|
+
</p>
|
|
147
|
+
</SettingsSection>
|
|
148
|
+
|
|
149
|
+
{/* Overlay */}
|
|
150
|
+
<SettingsSection title="Overlay" defaultOpen>
|
|
151
|
+
<SettingsField label="Color">
|
|
152
|
+
<ColorSwatchPicker
|
|
153
|
+
value={overlayColor}
|
|
154
|
+
onChange={(hex) => updateBg({ background_overlay_color: hex })}
|
|
155
|
+
swatches={paletteSwatches}
|
|
156
|
+
/>
|
|
157
|
+
</SettingsField>
|
|
158
|
+
|
|
159
|
+
<SettingsField label="Opacity">
|
|
160
|
+
<div className="flex items-center gap-2">
|
|
161
|
+
<input
|
|
162
|
+
type="range"
|
|
163
|
+
min={0}
|
|
164
|
+
max={100}
|
|
165
|
+
step={5}
|
|
166
|
+
value={overlayOpacity}
|
|
167
|
+
onChange={(e) => updateBg({ background_overlay_opacity: parseInt(e.target.value) })}
|
|
168
|
+
className="flex-1 accent-[#076bff]"
|
|
169
|
+
/>
|
|
170
|
+
<span className="text-xs text-neutral-900 w-10 text-right tabular-nums">
|
|
171
|
+
{overlayOpacity}%
|
|
172
|
+
</span>
|
|
173
|
+
</div>
|
|
174
|
+
</SettingsField>
|
|
175
|
+
</SettingsSection>
|
|
176
|
+
</>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* SectionV2AnimationTab — Animation tab content for V2 grid sections.
|
|
5
|
+
*
|
|
6
|
+
* Session 118: Replaced ScrollAnimationPicker + HoverAnimationPicker with
|
|
7
|
+
* EnterAnimationPicker (generic mode with inherit toggle) + StaggerSettings.
|
|
8
|
+
*
|
|
9
|
+
* Session 135: Added responsive override support — tablet/phone write to
|
|
10
|
+
* responsive overrides instead of base settings.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { useBuilderStore } from "../../../lib/builder/store";
|
|
14
|
+
import type { PageSectionV2, SectionV2Settings as SectionV2SettingsType } from "../../../lib/sanity/types";
|
|
15
|
+
import type { EnterAnimationConfig } from "../../../lib/animation/enter-types";
|
|
16
|
+
import EnterAnimationPicker from "../editors/EnterAnimationPicker";
|
|
17
|
+
import StaggerSettings from "../editors/StaggerSettings";
|
|
18
|
+
import {
|
|
19
|
+
getSectionV2SettingValue,
|
|
20
|
+
hasSectionV2SettingOverride,
|
|
21
|
+
buildSectionV2SettingOverride,
|
|
22
|
+
} from "./responsive-helpers";
|
|
23
|
+
|
|
24
|
+
export function SectionV2AnimationTab({ section }: { section: PageSectionV2 }) {
|
|
25
|
+
const store = useBuilderStore();
|
|
26
|
+
const activeViewport = store.activeViewport;
|
|
27
|
+
const isResponsive = activeViewport !== "desktop";
|
|
28
|
+
|
|
29
|
+
/** Viewport-aware update: desktop writes to settings, tablet/phone to responsive */
|
|
30
|
+
const updateAnimSetting = (property: "enter_animation" | "stagger", value: unknown) => {
|
|
31
|
+
if (activeViewport === "desktop") {
|
|
32
|
+
store.updateSectionV2Settings(section._key, { [property]: value } as Partial<SectionV2SettingsType>);
|
|
33
|
+
} else {
|
|
34
|
+
const responsive = buildSectionV2SettingOverride(section, activeViewport, property, value);
|
|
35
|
+
store.updateSectionV2Responsive(section._key, responsive ?? undefined);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const effectiveEnterAnim = getSectionV2SettingValue<EnterAnimationConfig | undefined>(
|
|
40
|
+
section, activeViewport, "enter_animation", undefined
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const effectiveStagger = getSectionV2SettingValue<SectionV2SettingsType["stagger"] | undefined>(
|
|
44
|
+
section, activeViewport, "stagger", undefined
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const hasEnterOverride = isResponsive && hasSectionV2SettingOverride(section, activeViewport, "enter_animation");
|
|
48
|
+
const hasStaggerOverride = isResponsive && hasSectionV2SettingOverride(section, activeViewport, "stagger");
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
{/* Responsive info banner */}
|
|
53
|
+
{isResponsive && (
|
|
54
|
+
<div className="px-4 pt-3">
|
|
55
|
+
<div className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-[#076bff]/8 border border-[#076bff]/15">
|
|
56
|
+
<span className="text-[11px] font-medium text-[#076bff]">
|
|
57
|
+
Editing {activeViewport === "tablet" ? "Tablet" : "Phone"} overrides
|
|
58
|
+
</span>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
)}
|
|
62
|
+
|
|
63
|
+
<div className="relative">
|
|
64
|
+
{hasEnterOverride && (
|
|
65
|
+
<div className="flex items-center justify-between px-4 pt-2">
|
|
66
|
+
<span className="text-[9px] text-[#076bff] font-medium">overridden</span>
|
|
67
|
+
<button
|
|
68
|
+
onClick={() => updateAnimSetting("enter_animation", undefined)}
|
|
69
|
+
className="text-[10px] text-neutral-400 hover:text-[var(--admin-error)] transition-colors"
|
|
70
|
+
>
|
|
71
|
+
Reset
|
|
72
|
+
</button>
|
|
73
|
+
</div>
|
|
74
|
+
)}
|
|
75
|
+
<EnterAnimationPicker
|
|
76
|
+
mode={{ level: "section", parentConfig: store.pageSettings.enter_animation }}
|
|
77
|
+
config={effectiveEnterAnim}
|
|
78
|
+
onChange={(cfg) => updateAnimSetting("enter_animation", cfg)}
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div className="border-t border-neutral-200 my-1" />
|
|
83
|
+
|
|
84
|
+
<div className="relative">
|
|
85
|
+
{hasStaggerOverride && (
|
|
86
|
+
<div className="flex items-center justify-between px-4 pt-2">
|
|
87
|
+
<span className="text-[9px] text-[#076bff] font-medium">overridden</span>
|
|
88
|
+
<button
|
|
89
|
+
onClick={() => updateAnimSetting("stagger", undefined)}
|
|
90
|
+
className="text-[10px] text-neutral-400 hover:text-[var(--admin-error)] transition-colors"
|
|
91
|
+
>
|
|
92
|
+
Reset
|
|
93
|
+
</button>
|
|
94
|
+
</div>
|
|
95
|
+
)}
|
|
96
|
+
<StaggerSettings
|
|
97
|
+
stagger={effectiveStagger}
|
|
98
|
+
onChange={(staggerCfg) => updateAnimSetting("stagger", staggerCfg)}
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
</>
|
|
102
|
+
);
|
|
103
|
+
}
|