@morphika/webframe 0.1.0
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 +46 -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 +210 -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,869 @@
|
|
|
1
|
+
// ============================================
|
|
2
|
+
// Primitives / shared
|
|
3
|
+
// ============================================
|
|
4
|
+
|
|
5
|
+
export type NavColorVariant =
|
|
6
|
+
| "yellow-lime"
|
|
7
|
+
| "yellow"
|
|
8
|
+
| "red-coral"
|
|
9
|
+
| "blue"
|
|
10
|
+
| "green"
|
|
11
|
+
| "white";
|
|
12
|
+
|
|
13
|
+
/** Minimal Portable Text block shape (Sanity block content). */
|
|
14
|
+
export interface PortableTextBlock {
|
|
15
|
+
_type: string;
|
|
16
|
+
_key: string;
|
|
17
|
+
children?: Array<{ _type: string; _key: string; text?: string; marks?: string[] }>;
|
|
18
|
+
markDefs?: Array<{ _type: string; _key: string; [key: string]: unknown }>;
|
|
19
|
+
style?: string;
|
|
20
|
+
level?: number;
|
|
21
|
+
listItem?: string;
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type PortableTextContent = PortableTextBlock[];
|
|
26
|
+
|
|
27
|
+
export interface SanitySlug {
|
|
28
|
+
current: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ============================================
|
|
32
|
+
// Responsive Overrides
|
|
33
|
+
// ============================================
|
|
34
|
+
// Blocks store their base properties (= desktop).
|
|
35
|
+
// Tablet and phone can override any visual/layout property.
|
|
36
|
+
// At render time we merge: { ...base, ...overrides[viewport] }.
|
|
37
|
+
// This keeps desktop as source of truth; smaller viewports only
|
|
38
|
+
// store what differs.
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Per-viewport overrides for a block.
|
|
42
|
+
* Each key holds a partial set of the block's own properties.
|
|
43
|
+
* `_type` and `_key` are never overridden.
|
|
44
|
+
*/
|
|
45
|
+
export interface ResponsiveOverrides<T> {
|
|
46
|
+
tablet?: Partial<Omit<T, "_type" | "_key" | "responsive">>;
|
|
47
|
+
phone?: Partial<Omit<T, "_type" | "_key" | "responsive">>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ============================================
|
|
51
|
+
// Enter Animation Config (Session 116)
|
|
52
|
+
// ============================================
|
|
53
|
+
// Unified "enter" trigger with above-the-fold detection.
|
|
54
|
+
// No intensity/range/trigger fields.
|
|
55
|
+
|
|
56
|
+
export { type EnterAnimationConfig, type TypewriterConfig } from "../../lib/animation/enter-types";
|
|
57
|
+
|
|
58
|
+
// ============================================
|
|
59
|
+
// Hover Effect Config — NEW (Session 116)
|
|
60
|
+
// ============================================
|
|
61
|
+
// Replaces both HoverAnimationConfig and ShaderEffectConfig.
|
|
62
|
+
// Block-level only (no cascade).
|
|
63
|
+
|
|
64
|
+
export { type HoverEffectConfig } from "../../lib/animation/hover-effect-types";
|
|
65
|
+
|
|
66
|
+
// ============================================
|
|
67
|
+
// Block Layout — shared styling for all blocks
|
|
68
|
+
// ============================================
|
|
69
|
+
// Same properties as Row layout (Semplice Module styling):
|
|
70
|
+
// Spacing (padding TRBL), Background, Offset (margin TRBL), Border.
|
|
71
|
+
|
|
72
|
+
export interface BlockLayout {
|
|
73
|
+
// Alignment
|
|
74
|
+
align_h?: "left" | "center" | "right";
|
|
75
|
+
align_v?: "top" | "center" | "bottom";
|
|
76
|
+
// Spacing (padding TRBL, px)
|
|
77
|
+
spacing_top?: string;
|
|
78
|
+
spacing_right?: string;
|
|
79
|
+
spacing_bottom?: string;
|
|
80
|
+
spacing_left?: string;
|
|
81
|
+
// Background
|
|
82
|
+
background_color?: string;
|
|
83
|
+
background_opacity?: number; // 0–100
|
|
84
|
+
background_image?: string; // asset path
|
|
85
|
+
background_size?: "cover" | "contain" | "auto";
|
|
86
|
+
background_position?: string;
|
|
87
|
+
background_repeat?: "no-repeat" | "repeat" | "repeat-x" | "repeat-y";
|
|
88
|
+
// Offset (margin TRBL, px)
|
|
89
|
+
offset_top?: string;
|
|
90
|
+
offset_right?: string;
|
|
91
|
+
offset_bottom?: string;
|
|
92
|
+
offset_left?: string;
|
|
93
|
+
// Border
|
|
94
|
+
border_color?: string;
|
|
95
|
+
border_width?: string;
|
|
96
|
+
border_style?: "none" | "solid" | "dashed" | "dotted";
|
|
97
|
+
border_sides?: "all" | "top" | "right" | "bottom" | "left" | "top-bottom" | "left-right";
|
|
98
|
+
border_radius?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ============================================
|
|
102
|
+
// Block Types (7)
|
|
103
|
+
// ============================================
|
|
104
|
+
|
|
105
|
+
export interface TextBlock {
|
|
106
|
+
_type: "textBlock";
|
|
107
|
+
_key: string;
|
|
108
|
+
text?: PortableTextContent;
|
|
109
|
+
/** Optional reference to a global typography level (h1, h2, body, etc.) */
|
|
110
|
+
textStyle?: string;
|
|
111
|
+
/** Number of CSS columns (1 = default, 2–4 = multi-column).
|
|
112
|
+
* Column gap inherits the global grid gutter via var(--grid-gutter). */
|
|
113
|
+
columns?: number;
|
|
114
|
+
style?: {
|
|
115
|
+
fontSize?: number | string; // px value (number) or legacy string enum
|
|
116
|
+
color?: string;
|
|
117
|
+
alignment?: "left" | "center" | "right" | "justify";
|
|
118
|
+
fontWeight?: string; // "300" | "400" | "500" | "700" etc.
|
|
119
|
+
lineHeight?: string;
|
|
120
|
+
letterSpacing?: string;
|
|
121
|
+
maxWidth?: string;
|
|
122
|
+
opacity?: number;
|
|
123
|
+
textTransform?: "none" | "uppercase" | "lowercase" | "capitalize";
|
|
124
|
+
};
|
|
125
|
+
enter_animation?: import("@/lib/animation/enter-types").EnterAnimationConfig;
|
|
126
|
+
hover_effect?: import("@/lib/animation/hover-effect-types").HoverEffectConfig;
|
|
127
|
+
typewriter_config?: import("@/lib/animation/enter-types").TypewriterConfig;
|
|
128
|
+
layout?: BlockLayout;
|
|
129
|
+
responsive?: ResponsiveOverrides<TextBlock>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface ImageBlock {
|
|
133
|
+
_type: "imageBlock";
|
|
134
|
+
_key: string;
|
|
135
|
+
asset_path: string;
|
|
136
|
+
alt?: string;
|
|
137
|
+
caption?: string;
|
|
138
|
+
width?: "full" | "contained" | "small";
|
|
139
|
+
aspect_ratio?: "auto" | "16:9" | "4:3" | "1:1" | "21:9";
|
|
140
|
+
lazy?: boolean;
|
|
141
|
+
border_radius?: string;
|
|
142
|
+
shadow?: boolean;
|
|
143
|
+
enter_animation?: import("@/lib/animation/enter-types").EnterAnimationConfig;
|
|
144
|
+
hover_effect?: import("@/lib/animation/hover-effect-types").HoverEffectConfig;
|
|
145
|
+
layout?: BlockLayout;
|
|
146
|
+
responsive?: ResponsiveOverrides<ImageBlock>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface ImageGridBlock {
|
|
150
|
+
_type: "imageGridBlock";
|
|
151
|
+
_key: string;
|
|
152
|
+
images?: Array<{ asset_path: string; alt?: string }>;
|
|
153
|
+
h_gutter?: number;
|
|
154
|
+
v_gutter?: number;
|
|
155
|
+
images_per_row?: 1 | 2 | 4 | 6 | 12;
|
|
156
|
+
random_grid?: "disabled" | "small2-big4" | "small3-big6" | "small4-big8";
|
|
157
|
+
random_seed?: number;
|
|
158
|
+
lightbox?: boolean;
|
|
159
|
+
object_fit?: "cover" | "contain";
|
|
160
|
+
border_radius?: string;
|
|
161
|
+
enter_animation?: import("@/lib/animation/enter-types").EnterAnimationConfig;
|
|
162
|
+
hover_effect?: import("@/lib/animation/hover-effect-types").HoverEffectConfig;
|
|
163
|
+
layout?: BlockLayout;
|
|
164
|
+
responsive?: ResponsiveOverrides<ImageGridBlock>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export interface VideoBlock {
|
|
168
|
+
_type: "videoBlock";
|
|
169
|
+
_key: string;
|
|
170
|
+
video_type: "vimeo" | "youtube" | "mp4" | "url";
|
|
171
|
+
url_or_path: string;
|
|
172
|
+
poster?: string;
|
|
173
|
+
autoplay?: boolean;
|
|
174
|
+
loop?: boolean;
|
|
175
|
+
muted?: boolean;
|
|
176
|
+
controls?: boolean;
|
|
177
|
+
width?: "full" | "contained";
|
|
178
|
+
aspect_ratio?: "16:9" | "21:9" | "4:3" | "auto";
|
|
179
|
+
border_radius?: string;
|
|
180
|
+
enter_animation?: import("@/lib/animation/enter-types").EnterAnimationConfig;
|
|
181
|
+
hover_effect?: import("@/lib/animation/hover-effect-types").HoverEffectConfig;
|
|
182
|
+
layout?: BlockLayout;
|
|
183
|
+
responsive?: ResponsiveOverrides<VideoBlock>;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface SpacerBlock {
|
|
187
|
+
_type: "spacerBlock";
|
|
188
|
+
_key: string;
|
|
189
|
+
height?: "small" | "medium" | "large" | "xlarge" | "custom";
|
|
190
|
+
custom_height?: number;
|
|
191
|
+
enter_animation?: import("@/lib/animation/enter-types").EnterAnimationConfig;
|
|
192
|
+
hover_effect?: import("@/lib/animation/hover-effect-types").HoverEffectConfig;
|
|
193
|
+
layout?: BlockLayout;
|
|
194
|
+
responsive?: ResponsiveOverrides<SpacerBlock>;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export interface ButtonBlock {
|
|
198
|
+
_type: "buttonBlock";
|
|
199
|
+
_key: string;
|
|
200
|
+
text: string;
|
|
201
|
+
url: string;
|
|
202
|
+
style?: "primary" | "secondary" | "outline" | "text";
|
|
203
|
+
size?: "small" | "medium" | "large";
|
|
204
|
+
target?: boolean;
|
|
205
|
+
full_width?: boolean;
|
|
206
|
+
alignment?: "left" | "center" | "right";
|
|
207
|
+
enter_animation?: import("@/lib/animation/enter-types").EnterAnimationConfig;
|
|
208
|
+
hover_effect?: import("@/lib/animation/hover-effect-types").HoverEffectConfig;
|
|
209
|
+
layout?: BlockLayout;
|
|
210
|
+
responsive?: ResponsiveOverrides<ButtonBlock>;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface CoverBlock {
|
|
214
|
+
_type: "coverBlock";
|
|
215
|
+
_key: string;
|
|
216
|
+
// Content
|
|
217
|
+
headline?: string;
|
|
218
|
+
subheadline?: string;
|
|
219
|
+
cta_button?: {
|
|
220
|
+
text?: string;
|
|
221
|
+
url?: string;
|
|
222
|
+
target_blank?: boolean;
|
|
223
|
+
style?: "primary" | "secondary" | "outline" | "text";
|
|
224
|
+
};
|
|
225
|
+
// Media
|
|
226
|
+
media_type?: "image" | "video";
|
|
227
|
+
media_path?: string;
|
|
228
|
+
video_poster?: string;
|
|
229
|
+
background_size?: "cover" | "contain" | "none";
|
|
230
|
+
background_position?: string;
|
|
231
|
+
background_repeat?: "no-repeat" | "repeat" | "repeat-x" | "repeat-y";
|
|
232
|
+
// Overlay
|
|
233
|
+
overlay?: "none" | "dark" | "light" | "gradient-bottom" | "gradient-top";
|
|
234
|
+
overlay_opacity?: number;
|
|
235
|
+
// Layout
|
|
236
|
+
content_align_h?: "left" | "center" | "right";
|
|
237
|
+
content_align_v?: "top" | "center" | "bottom";
|
|
238
|
+
content_max_width?: string;
|
|
239
|
+
height?: "100vh" | "80vh" | "60vh" | "40vh" | "custom";
|
|
240
|
+
custom_height?: string;
|
|
241
|
+
mobile_height?: "same" | "100vh" | "80vh" | "60vh" | "500px" | "400px";
|
|
242
|
+
// Appearance
|
|
243
|
+
text_color?: string;
|
|
244
|
+
show_scroll_indicator?: boolean;
|
|
245
|
+
enter_animation?: import("@/lib/animation/enter-types").EnterAnimationConfig;
|
|
246
|
+
hover_effect?: import("@/lib/animation/hover-effect-types").HoverEffectConfig;
|
|
247
|
+
layout?: BlockLayout;
|
|
248
|
+
responsive?: ResponsiveOverrides<CoverBlock>;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// ============================================
|
|
252
|
+
// Project Grid Block v2 (template-only, Session 105)
|
|
253
|
+
// ============================================
|
|
254
|
+
|
|
255
|
+
export interface ProjectGridItemOverrides {
|
|
256
|
+
aspect_ratio_override?: "16/9" | "1/1" | "9/16" | null;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export interface ProjectGridItem {
|
|
260
|
+
_key: string;
|
|
261
|
+
project_slug: string;
|
|
262
|
+
custom_thumbnail?: string;
|
|
263
|
+
custom_subtitle?: string;
|
|
264
|
+
/** Per-card aspect ratio override — null/undefined = inherit grid-level ratios */
|
|
265
|
+
aspect_ratio_override?: "16/9" | "1/1" | "9/16" | null;
|
|
266
|
+
/** Viewport-specific per-card overrides (tablet/phone) */
|
|
267
|
+
responsive?: {
|
|
268
|
+
tablet?: ProjectGridItemOverrides;
|
|
269
|
+
phone?: ProjectGridItemOverrides;
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Card entrance animation config for Project Grid */
|
|
274
|
+
export interface CardEntranceConfig {
|
|
275
|
+
enabled?: boolean; // default false
|
|
276
|
+
preset?: "fade" | "slide-up" | "scale"; // default "slide-up"
|
|
277
|
+
stagger_delay?: number; // ms between cards, default 80
|
|
278
|
+
duration?: number; // ms, default 500
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export interface ProjectGridBlock {
|
|
282
|
+
_type: "projectGridBlock";
|
|
283
|
+
_key: string;
|
|
284
|
+
// ─── Grid Settings ───
|
|
285
|
+
columns: number; // 1–6, default 3
|
|
286
|
+
aspect_ratios: string[]; // ["16/9", "1/1", "9/16"] multi-select, min 1
|
|
287
|
+
gap_v: number; // Vertical gap in px, default 16
|
|
288
|
+
gap_h: number; // Horizontal gap in px, default 16
|
|
289
|
+
// ─── Appearance ───
|
|
290
|
+
hover_effect: "3d" | "scale" | "none"; // default "scale"
|
|
291
|
+
show_subtitle: boolean; // default true
|
|
292
|
+
border_radius: number; // px, default 0
|
|
293
|
+
// ─── Video ───
|
|
294
|
+
video_mode: "off" | "hover" | "autoloop"; // default "off"
|
|
295
|
+
// ─── Card Entrance Animation ───
|
|
296
|
+
card_entrance?: CardEntranceConfig;
|
|
297
|
+
// ─── Projects ───
|
|
298
|
+
projects: ProjectGridItem[];
|
|
299
|
+
// ─── Standard block fields ───
|
|
300
|
+
enter_animation?: import("@/lib/animation/enter-types").EnterAnimationConfig;
|
|
301
|
+
layout?: BlockLayout;
|
|
302
|
+
responsive?: ResponsiveOverrides<ProjectGridBlock>;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ============================================
|
|
306
|
+
// Parallax V2 — Group + Slide types (Session 123)
|
|
307
|
+
// ============================================
|
|
308
|
+
|
|
309
|
+
export type NavEntrancePreset = "" | "fade-in" | "slide-down" | "blur-in";
|
|
310
|
+
|
|
311
|
+
/** A single parallax slide — contains a full V2 section (columns + blocks) with background media */
|
|
312
|
+
export interface ParallaxSlideV2 {
|
|
313
|
+
_key: string;
|
|
314
|
+
_type: "parallaxSlide";
|
|
315
|
+
|
|
316
|
+
// Background
|
|
317
|
+
background_type: "image" | "video"; // default "image"
|
|
318
|
+
background_image?: string; // asset path
|
|
319
|
+
background_video?: string; // asset path
|
|
320
|
+
background_position?: string; // CSS background-position, default "center center"
|
|
321
|
+
background_overlay_color?: string; // hex, default "#000000"
|
|
322
|
+
background_overlay_opacity?: number; // 0–100, default 0
|
|
323
|
+
|
|
324
|
+
// Nav color override — hex color applied to navbar while this slide is active
|
|
325
|
+
nav_color?: string; // hex, e.g. "#ffffff"
|
|
326
|
+
|
|
327
|
+
// V2 section data (same structure as PageSectionV2 internals)
|
|
328
|
+
columns: SectionColumn[];
|
|
329
|
+
section_settings: SectionV2Settings;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** A group of parallax slides — lives inline in a page's content_rows */
|
|
333
|
+
export interface ParallaxGroup {
|
|
334
|
+
_type: "parallaxGroup";
|
|
335
|
+
_key: string;
|
|
336
|
+
|
|
337
|
+
// Slides
|
|
338
|
+
slides: ParallaxSlideV2[];
|
|
339
|
+
|
|
340
|
+
// Group-level settings
|
|
341
|
+
transition_effect: "parallax" | "crossfade" | "reveal"; // default "parallax"
|
|
342
|
+
snap_enabled: boolean; // default true
|
|
343
|
+
parallax_intensity: number; // 0.2–0.6, default 0.4 (hidden from UI, hardcoded)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// ============================================
|
|
347
|
+
// Page Section — first-class section type (Session 76)
|
|
348
|
+
// ============================================
|
|
349
|
+
// Replaces the old "matryoshka" approach where section blocks were
|
|
350
|
+
// wrapped in row → column → block. Sections are direct entries in
|
|
351
|
+
// content_rows alongside regular rows.
|
|
352
|
+
|
|
353
|
+
export type PageSectionType = "projectGrid";
|
|
354
|
+
|
|
355
|
+
export interface SectionSettings {
|
|
356
|
+
// Background
|
|
357
|
+
background_color?: string;
|
|
358
|
+
background_opacity?: number;
|
|
359
|
+
background_image?: string;
|
|
360
|
+
background_size?: "cover" | "contain" | "auto";
|
|
361
|
+
background_position?: string;
|
|
362
|
+
background_repeat?: "no-repeat" | "repeat" | "repeat-x" | "repeat-y";
|
|
363
|
+
// Spacing (padding TRBL)
|
|
364
|
+
spacing_top?: string;
|
|
365
|
+
spacing_right?: string;
|
|
366
|
+
spacing_bottom?: string;
|
|
367
|
+
spacing_left?: string;
|
|
368
|
+
// Offset (margin TRBL)
|
|
369
|
+
offset_top?: string;
|
|
370
|
+
offset_right?: string;
|
|
371
|
+
offset_bottom?: string;
|
|
372
|
+
offset_left?: string;
|
|
373
|
+
// Border
|
|
374
|
+
border_color?: string;
|
|
375
|
+
border_width?: string;
|
|
376
|
+
border_style?: "none" | "solid" | "dashed" | "dotted";
|
|
377
|
+
border_sides?: "all" | "top" | "right" | "bottom" | "left" | "top-bottom" | "left-right";
|
|
378
|
+
border_radius?: string;
|
|
379
|
+
// Animation
|
|
380
|
+
enter_animation?: import("@/lib/animation/enter-types").EnterAnimationConfig;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/** Section block types that can appear inside a PageSection */
|
|
384
|
+
export type SectionBlock = ProjectGridBlock;
|
|
385
|
+
|
|
386
|
+
/** Section settings that can be overridden per-viewport */
|
|
387
|
+
export type SectionSettingsOverridable = Pick<SectionSettings,
|
|
388
|
+
"background_color" | "background_opacity" | "background_image" | "background_size" | "background_position" | "background_repeat" |
|
|
389
|
+
"spacing_top" | "spacing_right" | "spacing_bottom" | "spacing_left" |
|
|
390
|
+
"offset_top" | "offset_right" | "offset_bottom" | "offset_left" |
|
|
391
|
+
"border_color" | "border_width" | "border_style" | "border_sides" | "border_radius"
|
|
392
|
+
>;
|
|
393
|
+
|
|
394
|
+
export interface PageSection {
|
|
395
|
+
_type: "pageSection";
|
|
396
|
+
_key: string;
|
|
397
|
+
section_type: PageSectionType;
|
|
398
|
+
/** The actual section content — single block */
|
|
399
|
+
block: [SectionBlock];
|
|
400
|
+
settings?: SectionSettings;
|
|
401
|
+
/** BUG-013 fix: Per-viewport responsive overrides for section settings */
|
|
402
|
+
responsive?: {
|
|
403
|
+
tablet?: Partial<SectionSettingsOverridable>;
|
|
404
|
+
phone?: Partial<SectionSettingsOverridable>;
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// ============================================
|
|
409
|
+
// Page Section V2 — V2 Grid System (Session 83)
|
|
410
|
+
// ============================================
|
|
411
|
+
// Flat list of columns with explicit grid positions.
|
|
412
|
+
// No "row" objects — rows are a visual artifact derived from grid_row values.
|
|
413
|
+
|
|
414
|
+
export type SectionV2Preset = "full" | "halves" | "thirds" | "quarters" | "1/3+2/3" | "2/3+1/3" | "custom";
|
|
415
|
+
|
|
416
|
+
export interface SectionV2Settings {
|
|
417
|
+
// Grid
|
|
418
|
+
preset: SectionV2Preset;
|
|
419
|
+
grid_columns: number; // default 12
|
|
420
|
+
col_gap: number; // px, horizontal
|
|
421
|
+
row_gap: number; // px, vertical
|
|
422
|
+
// Spacing (padding TRBL, px)
|
|
423
|
+
spacing_top?: string;
|
|
424
|
+
spacing_right?: string;
|
|
425
|
+
spacing_bottom?: string;
|
|
426
|
+
spacing_left?: string;
|
|
427
|
+
// Offset (margin TRBL, px)
|
|
428
|
+
offset_top?: string;
|
|
429
|
+
offset_right?: string;
|
|
430
|
+
offset_bottom?: string;
|
|
431
|
+
offset_left?: string;
|
|
432
|
+
// Background
|
|
433
|
+
background_color?: string;
|
|
434
|
+
background_opacity?: number;
|
|
435
|
+
background_image?: string;
|
|
436
|
+
background_size?: "cover" | "contain" | "auto";
|
|
437
|
+
background_position?: string;
|
|
438
|
+
background_repeat?: "no-repeat" | "repeat" | "repeat-x" | "repeat-y";
|
|
439
|
+
// Border
|
|
440
|
+
border_color?: string;
|
|
441
|
+
border_width?: string;
|
|
442
|
+
border_style?: "none" | "solid" | "dashed" | "dotted";
|
|
443
|
+
border_sides?: "all" | "top" | "right" | "bottom" | "left" | "top-bottom" | "left-right";
|
|
444
|
+
border_radius?: string;
|
|
445
|
+
// Animation (cascade: page → section → column → block)
|
|
446
|
+
enter_animation?: import("@/lib/animation/enter-types").EnterAnimationConfig;
|
|
447
|
+
stagger?: {
|
|
448
|
+
enabled?: boolean;
|
|
449
|
+
delayPerChild?: number; // 50–300ms
|
|
450
|
+
direction?: "left-to-right" | "right-to-left";
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export interface SectionColumn {
|
|
455
|
+
_key: string;
|
|
456
|
+
grid_column: number; // 1-based start position (1–12)
|
|
457
|
+
grid_row: number; // 1-based, computed by builder
|
|
458
|
+
span: number; // how many grid columns (1–grid_columns)
|
|
459
|
+
blocks: ContentBlock[]; // same block types as today
|
|
460
|
+
// NEW (Session 116) — column-level enter animation for 4-level cascade
|
|
461
|
+
enter_animation?: import("@/lib/animation/enter-types").EnterAnimationConfig;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
export interface ColumnOverride {
|
|
465
|
+
_key: string; // matches SectionColumn._key
|
|
466
|
+
grid_column?: number;
|
|
467
|
+
grid_row?: number;
|
|
468
|
+
span?: number;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/** V2 section settings that can be overridden per-viewport */
|
|
472
|
+
export type SectionV2SettingsOverridable = Pick<SectionV2Settings,
|
|
473
|
+
"col_gap" | "row_gap" |
|
|
474
|
+
"spacing_top" | "spacing_right" | "spacing_bottom" | "spacing_left" |
|
|
475
|
+
"offset_top" | "offset_right" | "offset_bottom" | "offset_left" |
|
|
476
|
+
"background_color" | "background_opacity" |
|
|
477
|
+
"border_color" | "border_width" | "border_style" | "border_sides" | "border_radius" |
|
|
478
|
+
"enter_animation" | "stagger"
|
|
479
|
+
>;
|
|
480
|
+
|
|
481
|
+
export interface SectionV2ResponsiveOverride {
|
|
482
|
+
columns?: ColumnOverride[]; // per-column layout overrides
|
|
483
|
+
settings?: Partial<SectionV2SettingsOverridable>; // section-level overrides
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
export interface PageSectionV2 {
|
|
487
|
+
_type: "pageSectionV2";
|
|
488
|
+
_key: string;
|
|
489
|
+
section_type: "empty-v2";
|
|
490
|
+
columns: SectionColumn[];
|
|
491
|
+
settings: SectionV2Settings;
|
|
492
|
+
responsive?: {
|
|
493
|
+
tablet?: SectionV2ResponsiveOverride;
|
|
494
|
+
phone?: SectionV2ResponsiveOverride;
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// ============================================
|
|
499
|
+
// Custom Section — reusable V2 section (Session 107)
|
|
500
|
+
// ============================================
|
|
501
|
+
|
|
502
|
+
/** Full custom section document (for editing) */
|
|
503
|
+
export interface CustomSection {
|
|
504
|
+
_id: string;
|
|
505
|
+
title: string;
|
|
506
|
+
slug: SanitySlug;
|
|
507
|
+
description?: string;
|
|
508
|
+
section: PageSectionV2;
|
|
509
|
+
thumbnail_path?: string;
|
|
510
|
+
updated_at?: string;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/** Lightweight list item (for picker) */
|
|
514
|
+
export interface CustomSectionListItem {
|
|
515
|
+
_id: string;
|
|
516
|
+
title: string;
|
|
517
|
+
slug: SanitySlug;
|
|
518
|
+
description?: string;
|
|
519
|
+
thumbnail_path?: string;
|
|
520
|
+
updated_at?: string;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/** Instance reference stored inside a page's content_rows */
|
|
524
|
+
export interface CustomSectionInstance {
|
|
525
|
+
_type: "customSectionInstance";
|
|
526
|
+
_key: string;
|
|
527
|
+
custom_section_id: string; // Sanity _id of the customSection document
|
|
528
|
+
custom_section_slug: string;
|
|
529
|
+
custom_section_title: string; // cached for display
|
|
530
|
+
/** Per-instance section settings overrides (spacing, background, border, animation).
|
|
531
|
+
* Merged on top of the custom section's base settings at render time.
|
|
532
|
+
* Content (columns/blocks) remains shared; only the "embedding" settings vary per-instance. */
|
|
533
|
+
settings_overrides?: Partial<SectionV2Settings>;
|
|
534
|
+
/** Per-instance responsive overrides (tablet/phone viewport-specific settings).
|
|
535
|
+
* Same structure as PageSectionV2.responsive but only affects this instance. */
|
|
536
|
+
responsive_overrides?: PageSectionV2["responsive"];
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// ============================================
|
|
540
|
+
// Content Item — union of PageSection, PageSectionV2, and CustomSectionInstance
|
|
541
|
+
// ============================================
|
|
542
|
+
// Used in content_rows and the builder store.
|
|
543
|
+
|
|
544
|
+
export type ContentItem = PageSection | PageSectionV2 | CustomSectionInstance | ParallaxGroup;
|
|
545
|
+
|
|
546
|
+
/** Type guard: check if a content item is a PageSection (V1) */
|
|
547
|
+
export function isPageSection(item: ContentItem): item is PageSection {
|
|
548
|
+
return (item as PageSection)._type === "pageSection";
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/** Type guard: check if a content item is a PageSectionV2 */
|
|
552
|
+
export function isPageSectionV2(item: ContentItem): item is PageSectionV2 {
|
|
553
|
+
return (item as PageSectionV2)._type === "pageSectionV2";
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/** Type guard: check if a content item is a CustomSectionInstance */
|
|
557
|
+
export function isCustomSectionInstance(item: ContentItem): item is CustomSectionInstance {
|
|
558
|
+
return (item as CustomSectionInstance)._type === "customSectionInstance";
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/** Type guard: check if a content item is a ParallaxGroup (Session 123) */
|
|
562
|
+
export function isParallaxGroup(item: ContentItem): item is ParallaxGroup {
|
|
563
|
+
return (item as ParallaxGroup)._type === "parallaxGroup";
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// ============================================
|
|
567
|
+
// Shared references
|
|
568
|
+
// ============================================
|
|
569
|
+
|
|
570
|
+
export interface PageRef {
|
|
571
|
+
_id: string;
|
|
572
|
+
title: string;
|
|
573
|
+
slug: SanitySlug;
|
|
574
|
+
page_type: PageType;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// ============================================
|
|
578
|
+
// Union type for all blocks
|
|
579
|
+
// ============================================
|
|
580
|
+
|
|
581
|
+
export type ContentBlock =
|
|
582
|
+
| TextBlock
|
|
583
|
+
| ImageBlock
|
|
584
|
+
| ImageGridBlock
|
|
585
|
+
| VideoBlock
|
|
586
|
+
| SpacerBlock
|
|
587
|
+
| ButtonBlock
|
|
588
|
+
| CoverBlock
|
|
589
|
+
| ProjectGridBlock;
|
|
590
|
+
|
|
591
|
+
// ============================================
|
|
592
|
+
// Structural types
|
|
593
|
+
// ============================================
|
|
594
|
+
|
|
595
|
+
// ============================================
|
|
596
|
+
// Page types
|
|
597
|
+
// ============================================
|
|
598
|
+
|
|
599
|
+
export type PageType = "page" | "project";
|
|
600
|
+
|
|
601
|
+
export interface PageMetadata {
|
|
602
|
+
seo_title?: string;
|
|
603
|
+
seo_description?: string;
|
|
604
|
+
og_image_path?: string;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
export interface Page {
|
|
608
|
+
_id: string;
|
|
609
|
+
title: string;
|
|
610
|
+
slug: SanitySlug;
|
|
611
|
+
page_type: PageType;
|
|
612
|
+
is_home?: boolean;
|
|
613
|
+
content_rows?: ContentItem[];
|
|
614
|
+
metadata?: PageMetadata;
|
|
615
|
+
published_at?: string;
|
|
616
|
+
draft_mode?: boolean;
|
|
617
|
+
thumbnail_path?: string;
|
|
618
|
+
cover_video?: string;
|
|
619
|
+
page_settings?: {
|
|
620
|
+
background_color?: string;
|
|
621
|
+
text_color?: string;
|
|
622
|
+
nav_color?: string;
|
|
623
|
+
enter_animation?: import("@/lib/animation/enter-types").EnterAnimationConfig;
|
|
624
|
+
// ── Per-page nav entrance override ──
|
|
625
|
+
nav_entrance_animation?: NavEntrancePreset;
|
|
626
|
+
nav_entrance_duration?: number;
|
|
627
|
+
nav_entrance_delay?: number;
|
|
628
|
+
nav_entrance_disabled?: boolean;
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
export interface PageListItem {
|
|
633
|
+
_id: string;
|
|
634
|
+
title: string;
|
|
635
|
+
slug: SanitySlug;
|
|
636
|
+
page_type: PageType;
|
|
637
|
+
is_home?: boolean;
|
|
638
|
+
draft_mode?: boolean;
|
|
639
|
+
published_at?: string;
|
|
640
|
+
thumbnail_path?: string;
|
|
641
|
+
cover_video?: string;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// ============================================
|
|
645
|
+
// Site Settings
|
|
646
|
+
// ============================================
|
|
647
|
+
|
|
648
|
+
export interface NavItemStyleOverrides {
|
|
649
|
+
font_size?: number;
|
|
650
|
+
font_weight?: string;
|
|
651
|
+
font_family?: string;
|
|
652
|
+
color?: string; // hex
|
|
653
|
+
text_transform?: "none" | "uppercase" | "lowercase" | "capitalize";
|
|
654
|
+
vertical_align?: "top" | "middle" | "bottom";
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
export interface NavItem {
|
|
658
|
+
_key: string;
|
|
659
|
+
type: "logo" | "menu-item"; // NEW — item type
|
|
660
|
+
label: string;
|
|
661
|
+
logo_image?: string; // NEW — asset path for logo (optional)
|
|
662
|
+
link_type: "internal" | "external" | "content";
|
|
663
|
+
internal_page?: PageRef;
|
|
664
|
+
external_url?: string;
|
|
665
|
+
/** Content link: type of media shown in lightbox */
|
|
666
|
+
content_type?: "image" | "video-file" | "video-embed";
|
|
667
|
+
/** Content link: asset path for image or video file */
|
|
668
|
+
content_asset?: string;
|
|
669
|
+
/** Content link: embed URL for YouTube/Vimeo */
|
|
670
|
+
content_url?: string;
|
|
671
|
+
visible: boolean;
|
|
672
|
+
grid_column: number; // 1–12, required
|
|
673
|
+
column_span: number; // NEW — how many columns this item occupies (1–12)
|
|
674
|
+
style_overrides?: NavItemStyleOverrides; // NEW — per-item style overrides
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
export interface NavDesign {
|
|
678
|
+
logo_text?: string;
|
|
679
|
+
color?: NavColorVariant;
|
|
680
|
+
position?: "fixed" | "sticky" | "static";
|
|
681
|
+
hide_on_scroll?: boolean;
|
|
682
|
+
font_size?: number;
|
|
683
|
+
font_weight?: string;
|
|
684
|
+
font_family?: string;
|
|
685
|
+
text_align?: "left" | "center" | "right";
|
|
686
|
+
text_transform?: "none" | "uppercase" | "lowercase" | "capitalize";
|
|
687
|
+
vertical_align?: "top" | "middle" | "bottom";
|
|
688
|
+
padding_h?: number;
|
|
689
|
+
padding_v?: number;
|
|
690
|
+
margin_h?: number;
|
|
691
|
+
margin_v?: number;
|
|
692
|
+
background_color?: string;
|
|
693
|
+
background_opacity?: number;
|
|
694
|
+
backdrop_blur?: boolean;
|
|
695
|
+
items_gap?: number;
|
|
696
|
+
logo_columns?: number; // 1–6, how many grid columns the logo spans
|
|
697
|
+
// ── Entrance animation ──
|
|
698
|
+
entrance_animation?: NavEntrancePreset;
|
|
699
|
+
entrance_duration?: number; // ms, default 600
|
|
700
|
+
entrance_delay?: number; // ms, default 0
|
|
701
|
+
entrance_stagger?: boolean; // stagger items, default false
|
|
702
|
+
entrance_stagger_delay?: number; // ms between items, default 80
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// ============================================
|
|
706
|
+
// Storage Provider
|
|
707
|
+
// ============================================
|
|
708
|
+
|
|
709
|
+
export type StorageProviderType = "r2";
|
|
710
|
+
|
|
711
|
+
// ============================================
|
|
712
|
+
// Asset Registry
|
|
713
|
+
// ============================================
|
|
714
|
+
|
|
715
|
+
export interface RegisteredAsset {
|
|
716
|
+
_key: string;
|
|
717
|
+
path: string;
|
|
718
|
+
filename: string;
|
|
719
|
+
extension: string;
|
|
720
|
+
file_size?: number;
|
|
721
|
+
mime_type?: string;
|
|
722
|
+
width?: number;
|
|
723
|
+
height?: number;
|
|
724
|
+
file_hash?: string;
|
|
725
|
+
has_thumbnail?: boolean;
|
|
726
|
+
status: "active" | "missing" | "moved" | "new";
|
|
727
|
+
last_checked_at?: string;
|
|
728
|
+
used_in?: string[];
|
|
729
|
+
previous_paths?: string[];
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
export interface RelinkLogEntry {
|
|
733
|
+
_key: string;
|
|
734
|
+
date: string;
|
|
735
|
+
old_seed: string;
|
|
736
|
+
new_seed: string;
|
|
737
|
+
assets_relinked: number;
|
|
738
|
+
assets_missing: number;
|
|
739
|
+
details?: string;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
export interface AssetRegistry {
|
|
743
|
+
_id: string;
|
|
744
|
+
/** Active storage provider. Defaults to "r2". */
|
|
745
|
+
storage_provider?: StorageProviderType;
|
|
746
|
+
seed_url?: string;
|
|
747
|
+
scan_status?: "ready" | "scanning" | "error";
|
|
748
|
+
last_scanned_at?: string;
|
|
749
|
+
scan_error?: string;
|
|
750
|
+
assets?: RegisteredAsset[];
|
|
751
|
+
relink_log?: RelinkLogEntry[];
|
|
752
|
+
// R2 configuration
|
|
753
|
+
r2_bucket_url?: string;
|
|
754
|
+
r2_access_key_id?: string;
|
|
755
|
+
r2_secret_access_key?: string;
|
|
756
|
+
r2_endpoint?: string;
|
|
757
|
+
r2_bucket_name?: string;
|
|
758
|
+
r2_connected_at?: string;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// ============================================
|
|
762
|
+
// Site Settings
|
|
763
|
+
// ============================================
|
|
764
|
+
|
|
765
|
+
export interface SiteSettings {
|
|
766
|
+
nav_items?: NavItem[];
|
|
767
|
+
nav_design?: NavDesign;
|
|
768
|
+
default_title?: string;
|
|
769
|
+
default_description?: string;
|
|
770
|
+
default_og_image?: string;
|
|
771
|
+
favicon_path?: string;
|
|
772
|
+
analytics_id?: string;
|
|
773
|
+
seed_url?: string;
|
|
774
|
+
last_scanned_at?: string;
|
|
775
|
+
asset_status?: "ok" | "scanning" | "error";
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// ============================================
|
|
779
|
+
// Site Styles — Global design system
|
|
780
|
+
// ============================================
|
|
781
|
+
|
|
782
|
+
export interface FontVariant {
|
|
783
|
+
_key: string;
|
|
784
|
+
weight: string; // "300", "400", "500", "700", etc.
|
|
785
|
+
style: "normal" | "italic";
|
|
786
|
+
file_url: string; // Sanity CDN URL
|
|
787
|
+
file_id?: string; // Sanity asset ID (for deletion)
|
|
788
|
+
original_filename: string;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
export interface FontFamily {
|
|
792
|
+
_key: string;
|
|
793
|
+
family: string; // e.g. "Inter", "Space Grotesk"
|
|
794
|
+
is_builtin?: boolean; // true for fonts already in /public/fonts/
|
|
795
|
+
variants: FontVariant[];
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
export interface TypographyLevel {
|
|
799
|
+
font_family?: string; // References FontFamily.family
|
|
800
|
+
font_size: string; // e.g. "3rem", "48px"
|
|
801
|
+
font_weight: string; // e.g. "700"
|
|
802
|
+
line_height: string; // e.g. "1.1"
|
|
803
|
+
letter_spacing: string; // e.g. "-0.02em"
|
|
804
|
+
text_transform?: "none" | "uppercase" | "lowercase" | "capitalize";
|
|
805
|
+
color?: string; // Override page text color
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
export interface ColorSwatch {
|
|
809
|
+
_key?: string;
|
|
810
|
+
name: string;
|
|
811
|
+
hex: string;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
export interface ColorPalette {
|
|
815
|
+
swatches: ColorSwatch[];
|
|
816
|
+
// Legacy fields (backward compat, may be empty)
|
|
817
|
+
background?: string;
|
|
818
|
+
text?: string;
|
|
819
|
+
primary?: string;
|
|
820
|
+
secondary?: string;
|
|
821
|
+
accent?: string;
|
|
822
|
+
muted?: string;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
export interface SpacingScale {
|
|
826
|
+
section_padding: string; // e.g. "80px"
|
|
827
|
+
content_gap: string; // e.g. "24px"
|
|
828
|
+
border_radius: string; // e.g. "8px"
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
export interface LinkStyle {
|
|
832
|
+
color: string;
|
|
833
|
+
hover_color: string;
|
|
834
|
+
underline: boolean;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
export interface ButtonStyle {
|
|
838
|
+
primary_bg: string;
|
|
839
|
+
primary_text: string;
|
|
840
|
+
secondary_bg: string;
|
|
841
|
+
secondary_text: string;
|
|
842
|
+
border_radius: string;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
export interface GridSettings {
|
|
846
|
+
width: string; // e.g. "1445"
|
|
847
|
+
outer_padding: string; // e.g. "30"
|
|
848
|
+
gutter_desktop: string; // e.g. "30"
|
|
849
|
+
gutter_responsive: string; // e.g. "30" (tablet)
|
|
850
|
+
gutter_phone?: string; // e.g. "16" (phone, ≤640px)
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
export interface SiteStyles {
|
|
854
|
+
grid?: GridSettings;
|
|
855
|
+
fonts?: FontFamily[];
|
|
856
|
+
typography?: {
|
|
857
|
+
h1?: TypographyLevel;
|
|
858
|
+
h2?: TypographyLevel;
|
|
859
|
+
h3?: TypographyLevel;
|
|
860
|
+
h4?: TypographyLevel;
|
|
861
|
+
body?: TypographyLevel;
|
|
862
|
+
small?: TypographyLevel;
|
|
863
|
+
};
|
|
864
|
+
colors?: ColorPalette;
|
|
865
|
+
link_style?: LinkStyle;
|
|
866
|
+
button_style?: ButtonStyle;
|
|
867
|
+
/** When true, disables all scroll animations on viewports ≤768px */
|
|
868
|
+
disable_scroll_animations_mobile?: boolean;
|
|
869
|
+
}
|