@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.
Files changed (319) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +46 -0
  3. package/admin/assets.ts +4 -0
  4. package/admin/database.ts +4 -0
  5. package/admin/index.ts +6 -0
  6. package/admin/login.ts +4 -0
  7. package/admin/navigation.ts +4 -0
  8. package/admin/pages-editor.ts +4 -0
  9. package/admin/pages.ts +4 -0
  10. package/admin/projects-editor.ts +4 -0
  11. package/admin/projects.ts +4 -0
  12. package/admin/settings.ts +4 -0
  13. package/admin/setup.ts +4 -0
  14. package/admin/storage.ts +4 -0
  15. package/admin/styles.ts +4 -0
  16. package/app/(site)/[slug]/loading.tsx +20 -0
  17. package/app/(site)/[slug]/page.tsx +83 -0
  18. package/app/(site)/error.tsx +32 -0
  19. package/app/(site)/layout.tsx +53 -0
  20. package/app/(site)/loading.tsx +20 -0
  21. package/app/(site)/not-found.tsx +41 -0
  22. package/app/(site)/page.tsx +43 -0
  23. package/app/(site)/preview/page.tsx +99 -0
  24. package/app/(site)/work/[slug]/loading.tsx +23 -0
  25. package/app/(site)/work/[slug]/page.tsx +84 -0
  26. package/app/admin/assets/page.tsx +573 -0
  27. package/app/admin/database/page.tsx +302 -0
  28. package/app/admin/error.tsx +53 -0
  29. package/app/admin/layout.tsx +273 -0
  30. package/app/admin/login/page.tsx +88 -0
  31. package/app/admin/navigation/page.tsx +157 -0
  32. package/app/admin/page.tsx +17 -0
  33. package/app/admin/pages/[slug]/page.tsx +849 -0
  34. package/app/admin/pages/page.tsx +588 -0
  35. package/app/admin/projects/[slug]/page.tsx +3 -0
  36. package/app/admin/projects/page.tsx +669 -0
  37. package/app/admin/settings/page.tsx +132 -0
  38. package/app/admin/setup/page.tsx +64 -0
  39. package/app/admin/storage/page.tsx +518 -0
  40. package/app/admin/styles/page.tsx +243 -0
  41. package/app/api/admin/assets/file/route.ts +81 -0
  42. package/app/api/admin/assets/health/route.ts +170 -0
  43. package/app/api/admin/assets/register/route.ts +163 -0
  44. package/app/api/admin/assets/registry/route.ts +98 -0
  45. package/app/api/admin/assets/relink/confirm/route.ts +242 -0
  46. package/app/api/admin/assets/relink/route.ts +202 -0
  47. package/app/api/admin/assets/scan/route.ts +271 -0
  48. package/app/api/admin/auth/route.ts +160 -0
  49. package/app/api/admin/custom-sections/[slug]/route.ts +159 -0
  50. package/app/api/admin/custom-sections/route.ts +127 -0
  51. package/app/api/admin/database/route.ts +53 -0
  52. package/app/api/admin/pages/[slug]/duplicate/route.ts +91 -0
  53. package/app/api/admin/pages/[slug]/route.ts +617 -0
  54. package/app/api/admin/pages/[slug]/set-home/route.ts +76 -0
  55. package/app/api/admin/pages/route.ts +129 -0
  56. package/app/api/admin/preview/route.ts +53 -0
  57. package/app/api/admin/r2/connect/route.ts +181 -0
  58. package/app/api/admin/r2/delete/route.ts +198 -0
  59. package/app/api/admin/r2/disconnect/route.ts +42 -0
  60. package/app/api/admin/r2/rename/route.ts +265 -0
  61. package/app/api/admin/r2/status/route.ts +106 -0
  62. package/app/api/admin/r2/upload-url/route.ts +148 -0
  63. package/app/api/admin/revalidate/route.ts +55 -0
  64. package/app/api/admin/settings/route.ts +279 -0
  65. package/app/api/admin/setup/complete/route.ts +51 -0
  66. package/app/api/admin/setup/route.ts +118 -0
  67. package/app/api/admin/storage/switch/route.ts +117 -0
  68. package/app/api/admin/styles/fonts/route.ts +97 -0
  69. package/app/api/admin/styles/route.ts +304 -0
  70. package/app/api/assets/[...path]/route.ts +98 -0
  71. package/app/api/custom-sections/[id]/route.ts +43 -0
  72. package/app/api/draft-mode/disable/route.ts +10 -0
  73. package/app/api/draft-mode/enable/route.ts +26 -0
  74. package/app/api/projects/route.ts +42 -0
  75. package/app/api/styles/route.ts +88 -0
  76. package/app/favicon.ico +0 -0
  77. package/app/globals.css +7 -0
  78. package/app/layout.tsx +53 -0
  79. package/app/robots.ts +17 -0
  80. package/app/sitemap.ts +48 -0
  81. package/app/studio/[[...index]]/page.tsx +8 -0
  82. package/components/admin/MetadataEditor.tsx +173 -0
  83. package/components/admin/PublishToggle.tsx +130 -0
  84. package/components/admin/icons.tsx +40 -0
  85. package/components/admin/nav-builder/NavBuilder.tsx +182 -0
  86. package/components/admin/nav-builder/NavBuilderGrid.tsx +326 -0
  87. package/components/admin/nav-builder/NavGeneralSettings.tsx +275 -0
  88. package/components/admin/nav-builder/NavGridCell.tsx +48 -0
  89. package/components/admin/nav-builder/NavGridItem.tsx +189 -0
  90. package/components/admin/nav-builder/NavItemSettings.tsx +288 -0
  91. package/components/admin/nav-builder/NavItemTypePicker.tsx +102 -0
  92. package/components/admin/nav-builder/NavLivePreview.tsx +125 -0
  93. package/components/admin/nav-builder/NavSettingsFields.tsx +248 -0
  94. package/components/admin/nav-builder/NavSettingsPanel.tsx +127 -0
  95. package/components/admin/nav-builder/index.ts +10 -0
  96. package/components/admin/nav-builder/nav-builder-utils.ts +238 -0
  97. package/components/admin/setup-wizard/BrandingStep.tsx +218 -0
  98. package/components/admin/setup-wizard/DatabaseStep.tsx +331 -0
  99. package/components/admin/setup-wizard/DoneStep.tsx +187 -0
  100. package/components/admin/setup-wizard/SetupWizard.tsx +166 -0
  101. package/components/admin/setup-wizard/StorageStep.tsx +308 -0
  102. package/components/admin/setup-wizard/WelcomeStep.tsx +96 -0
  103. package/components/admin/setup-wizard/index.ts +9 -0
  104. package/components/admin/styles/ColorsEditor.tsx +214 -0
  105. package/components/admin/styles/FontsEditor.tsx +258 -0
  106. package/components/admin/styles/GridLayoutEditor.tsx +292 -0
  107. package/components/admin/styles/LinksButtonsEditor.tsx +120 -0
  108. package/components/admin/styles/TypographyEditor.tsx +266 -0
  109. package/components/admin/styles/index.ts +9 -0
  110. package/components/admin/styles/shared.tsx +68 -0
  111. package/components/blocks/BlockRenderer.tsx +404 -0
  112. package/components/blocks/ButtonBlockRenderer.tsx +52 -0
  113. package/components/blocks/CoverBlockRenderer.tsx +239 -0
  114. package/components/blocks/CustomSectionInstanceRenderer.tsx +82 -0
  115. package/components/blocks/EnterAnimationWrapper.tsx +140 -0
  116. package/components/blocks/HoverAnimationWrapper.tsx +308 -0
  117. package/components/blocks/ImageBlockRenderer.tsx +61 -0
  118. package/components/blocks/ImageGridBlockRenderer.tsx +545 -0
  119. package/components/blocks/PageBackground.tsx +28 -0
  120. package/components/blocks/PageNavAnimation.tsx +35 -0
  121. package/components/blocks/PageNavColor.tsx +24 -0
  122. package/components/blocks/PageRenderer.tsx +142 -0
  123. package/components/blocks/ParallaxGroupRenderer.tsx +448 -0
  124. package/components/blocks/ParallaxSlideRenderer.tsx +175 -0
  125. package/components/blocks/ProjectGridBlockRenderer.tsx +556 -0
  126. package/components/blocks/SectionRenderer.tsx +170 -0
  127. package/components/blocks/SectionV2Renderer.tsx +330 -0
  128. package/components/blocks/ShaderCanvas.tsx +392 -0
  129. package/components/blocks/SpacerBlockRenderer.tsx +17 -0
  130. package/components/blocks/TextBlockRenderer.tsx +87 -0
  131. package/components/blocks/TypewriterRichText.tsx +464 -0
  132. package/components/blocks/TypewriterWrapper.tsx +149 -0
  133. package/components/blocks/VideoBlockRenderer.tsx +304 -0
  134. package/components/blocks/index.ts +2 -0
  135. package/components/builder/AssetBrowser.tsx +2 -0
  136. package/components/builder/BlockLivePreview.tsx +101 -0
  137. package/components/builder/BlockTypePicker.tsx +178 -0
  138. package/components/builder/BuilderCanvas.tsx +354 -0
  139. package/components/builder/CanvasMinimap.tsx +200 -0
  140. package/components/builder/CanvasToolbar.tsx +202 -0
  141. package/components/builder/ColorPicker.tsx +243 -0
  142. package/components/builder/ColorSwatchPicker.tsx +274 -0
  143. package/components/builder/ColumnDragContext.tsx +51 -0
  144. package/components/builder/ColumnDragOverlay.tsx +110 -0
  145. package/components/builder/CustomSectionInstanceCard.tsx +97 -0
  146. package/components/builder/DeviceFrame.tsx +123 -0
  147. package/components/builder/DndWrapper.tsx +337 -0
  148. package/components/builder/InsertionLines.tsx +186 -0
  149. package/components/builder/ParallaxGroupCanvas.tsx +228 -0
  150. package/components/builder/ParallaxSlideHeader.tsx +113 -0
  151. package/components/builder/ReadOnlyFrame.tsx +417 -0
  152. package/components/builder/SectionEditorBar.tsx +288 -0
  153. package/components/builder/SectionTypePicker.tsx +422 -0
  154. package/components/builder/SectionV2Canvas.tsx +297 -0
  155. package/components/builder/SectionV2Column.tsx +488 -0
  156. package/components/builder/SettingsPanel.tsx +911 -0
  157. package/components/builder/SortableBlock.tsx +230 -0
  158. package/components/builder/SortableRow.tsx +362 -0
  159. package/components/builder/VirtualAssetGrid.tsx +397 -0
  160. package/components/builder/asset-browser/AssetBrowser.tsx +178 -0
  161. package/components/builder/asset-browser/FileLightbox.tsx +116 -0
  162. package/components/builder/asset-browser/FolderTreeItem.tsx +55 -0
  163. package/components/builder/asset-browser/R2BrowserContent.tsx +436 -0
  164. package/components/builder/asset-browser/R2ContextMenu.tsx +98 -0
  165. package/components/builder/asset-browser/VideoThumbnail.tsx +63 -0
  166. package/components/builder/asset-browser/helpers.ts +88 -0
  167. package/components/builder/asset-browser/index.ts +1 -0
  168. package/components/builder/asset-browser/types.ts +49 -0
  169. package/components/builder/asset-browser/useAssetBrowser.ts +344 -0
  170. package/components/builder/asset-browser/useR2DragDrop.ts +116 -0
  171. package/components/builder/asset-browser/useR2Operations.ts +189 -0
  172. package/components/builder/blockStyles.tsx +295 -0
  173. package/components/builder/editors/ButtonBlockEditor.tsx +184 -0
  174. package/components/builder/editors/CoverBlockEditor.tsx +488 -0
  175. package/components/builder/editors/EnterAnimationPicker.tsx +297 -0
  176. package/components/builder/editors/HoverEffectPicker.tsx +209 -0
  177. package/components/builder/editors/ImageBlockEditor.tsx +206 -0
  178. package/components/builder/editors/ImageGridBlockEditor.tsx +386 -0
  179. package/components/builder/editors/ProjectGridEditor.tsx +648 -0
  180. package/components/builder/editors/SpacerBlockEditor.tsx +167 -0
  181. package/components/builder/editors/StaggerSettings.tsx +108 -0
  182. package/components/builder/editors/TextAlignmentIcons.tsx +39 -0
  183. package/components/builder/editors/TextBlockEditor.tsx +462 -0
  184. package/components/builder/editors/TextStylePicker.tsx +183 -0
  185. package/components/builder/editors/VideoBlockEditor.tsx +278 -0
  186. package/components/builder/editors/index.ts +10 -0
  187. package/components/builder/editors/shared.tsx +345 -0
  188. package/components/builder/hooks/useColumnDrag.ts +472 -0
  189. package/components/builder/hooks/useColumnResize.ts +221 -0
  190. package/components/builder/index.ts +12 -0
  191. package/components/builder/live-preview/LiveButtonPreview.tsx +38 -0
  192. package/components/builder/live-preview/LiveCoverPreview.tsx +146 -0
  193. package/components/builder/live-preview/LiveImageGridPreview.tsx +123 -0
  194. package/components/builder/live-preview/LiveImagePreview.tsx +107 -0
  195. package/components/builder/live-preview/LiveProjectGridPreview.tsx +1010 -0
  196. package/components/builder/live-preview/LiveSpacerPreview.tsx +9 -0
  197. package/components/builder/live-preview/LiveTextEditor.tsx +198 -0
  198. package/components/builder/live-preview/LiveVideoPreview.tsx +98 -0
  199. package/components/builder/live-preview/index.ts +10 -0
  200. package/components/builder/live-preview/shared.tsx +153 -0
  201. package/components/builder/settings-panel/BlockLayoutTab.tsx +532 -0
  202. package/components/builder/settings-panel/BlockSettings.tsx +94 -0
  203. package/components/builder/settings-panel/ColumnV2Settings.tsx +160 -0
  204. package/components/builder/settings-panel/LayoutTab.tsx +310 -0
  205. package/components/builder/settings-panel/PageSettings.tsx +200 -0
  206. package/components/builder/settings-panel/ParallaxGroupSettings.tsx +118 -0
  207. package/components/builder/settings-panel/ParallaxSlideSettings.tsx +178 -0
  208. package/components/builder/settings-panel/SectionV2AnimationTab.tsx +103 -0
  209. package/components/builder/settings-panel/SectionV2LayoutTab.tsx +312 -0
  210. package/components/builder/settings-panel/SectionV2Settings.tsx +323 -0
  211. package/components/builder/settings-panel/TRBLInputs.tsx +51 -0
  212. package/components/builder/settings-panel/index.ts +19 -0
  213. package/components/builder/settings-panel/responsive-helpers.ts +524 -0
  214. package/components/ui/CustomCursor.tsx +118 -0
  215. package/components/ui/NavContentLightbox.tsx +152 -0
  216. package/components/ui/Navbar.tsx +582 -0
  217. package/components/ui/PortfolioTracker.tsx +87 -0
  218. package/components/ui/ScrollToTop.tsx +47 -0
  219. package/lib/animation/enter-presets.ts +147 -0
  220. package/lib/animation/enter-resolve.ts +90 -0
  221. package/lib/animation/enter-types.ts +128 -0
  222. package/lib/animation/hover-effect-presets.ts +210 -0
  223. package/lib/animation/hover-effect-types.ts +126 -0
  224. package/lib/asset-retry.ts +111 -0
  225. package/lib/assets.ts +92 -0
  226. package/lib/audit.ts +35 -0
  227. package/lib/auth-token.ts +94 -0
  228. package/lib/auth.ts +13 -0
  229. package/lib/builder/cascade-helpers.ts +51 -0
  230. package/lib/builder/cascade.ts +533 -0
  231. package/lib/builder/constants.ts +103 -0
  232. package/lib/builder/defaults.ts +182 -0
  233. package/lib/builder/history.ts +48 -0
  234. package/lib/builder/index.ts +21 -0
  235. package/lib/builder/layout-styles.ts +344 -0
  236. package/lib/builder/masonry.ts +166 -0
  237. package/lib/builder/responsive.ts +156 -0
  238. package/lib/builder/serializer.ts +845 -0
  239. package/lib/builder/store-blocks.ts +193 -0
  240. package/lib/builder/store-canvas.ts +319 -0
  241. package/lib/builder/store-helpers.ts +490 -0
  242. package/lib/builder/store-sections.ts +709 -0
  243. package/lib/builder/store.ts +333 -0
  244. package/lib/builder/templates.ts +297 -0
  245. package/lib/builder/types.ts +374 -0
  246. package/lib/builder/utils.ts +37 -0
  247. package/lib/color-utils.ts +116 -0
  248. package/lib/config/index.ts +57 -0
  249. package/lib/config/types.ts +122 -0
  250. package/lib/contexts/AssetContext.tsx +79 -0
  251. package/lib/contexts/NavAnimationContext.tsx +44 -0
  252. package/lib/contexts/NavColorContext.tsx +38 -0
  253. package/lib/contexts/PageExitContext.tsx +194 -0
  254. package/lib/contexts/ThumbStatusContext.tsx +83 -0
  255. package/lib/csrf-client.ts +34 -0
  256. package/lib/csrf.ts +68 -0
  257. package/lib/format-utils.ts +24 -0
  258. package/lib/hooks/useViewport.ts +42 -0
  259. package/lib/logger.ts +81 -0
  260. package/lib/revalidate.ts +23 -0
  261. package/lib/sanitize.ts +91 -0
  262. package/lib/sanity/client.ts +8 -0
  263. package/lib/sanity/queries.ts +486 -0
  264. package/lib/sanity/types.ts +869 -0
  265. package/lib/sanity/writeClient.ts +24 -0
  266. package/lib/security.ts +402 -0
  267. package/lib/setup/detect.ts +156 -0
  268. package/lib/shader/glsl/index.ts +27 -0
  269. package/lib/shader/glsl/pixelate.ts +51 -0
  270. package/lib/shader/glsl/rgb-shift.ts +45 -0
  271. package/lib/shader/glsl/ripple.ts +46 -0
  272. package/lib/shader/glsl/vertex.ts +14 -0
  273. package/lib/storage/index.ts +211 -0
  274. package/lib/storage/r2-adapter.ts +286 -0
  275. package/lib/storage/types.ts +125 -0
  276. package/lib/styles/provider.tsx +267 -0
  277. package/lib/thumbnails/generate.ts +151 -0
  278. package/lib/utils.ts +6 -0
  279. package/package.json +212 -0
  280. package/sanity/compose.ts +65 -0
  281. package/sanity/sanity.config.ts +126 -0
  282. package/sanity/schemas/assetRegistry.ts +301 -0
  283. package/sanity/schemas/blocks/blockLayout.ts +90 -0
  284. package/sanity/schemas/blocks/buttonBlock.ts +82 -0
  285. package/sanity/schemas/blocks/coverBlock.ts +229 -0
  286. package/sanity/schemas/blocks/imageBlock.ts +58 -0
  287. package/sanity/schemas/blocks/imageGridBlock.ts +112 -0
  288. package/sanity/schemas/blocks/index.ts +9 -0
  289. package/sanity/schemas/blocks/projectGridBlock.ts +251 -0
  290. package/sanity/schemas/blocks/spacerBlock.ts +41 -0
  291. package/sanity/schemas/blocks/textBlock.ts +139 -0
  292. package/sanity/schemas/blocks/videoBlock.ts +80 -0
  293. package/sanity/schemas/customSection.ts +69 -0
  294. package/sanity/schemas/customSectionInstance.ts +163 -0
  295. package/sanity/schemas/index.ts +111 -0
  296. package/sanity/schemas/objects/enterAnimationConfig.ts +72 -0
  297. package/sanity/schemas/objects/hoverEffectConfig.ts +90 -0
  298. package/sanity/schemas/objects/parallaxGroup.ts +66 -0
  299. package/sanity/schemas/objects/parallaxSlide.ts +217 -0
  300. package/sanity/schemas/objects/typewriterConfig.ts +38 -0
  301. package/sanity/schemas/page.ts +162 -0
  302. package/sanity/schemas/pageSection.ts +157 -0
  303. package/sanity/schemas/pageSectionV2.ts +269 -0
  304. package/sanity/schemas/siteSettings.ts +256 -0
  305. package/sanity/schemas/siteStyles.ts +210 -0
  306. package/site/error.ts +4 -0
  307. package/site/index.ts +8 -0
  308. package/site/not-found.ts +4 -0
  309. package/site/page.ts +4 -0
  310. package/site/preview.ts +4 -0
  311. package/site/robots.ts +4 -0
  312. package/site/sitemap.ts +4 -0
  313. package/site/work.ts +4 -0
  314. package/studio/index.ts +4 -0
  315. package/styles/admin.css +85 -0
  316. package/styles/animations.css +237 -0
  317. package/styles/base.css +148 -0
  318. package/styles/globals.css +10 -0
  319. package/tsconfig.json +25 -0
@@ -0,0 +1,217 @@
1
+ import { defineField, defineType } from "sanity";
2
+
3
+ /**
4
+ * parallaxSlide — A single slide in a ParallaxGroup.
5
+ *
6
+ * Contains a background (image or video) with overlay controls,
7
+ * plus full V2 section data (columns + blocks) for content.
8
+ *
9
+ * Session 123: Parallax V2 rewrite.
10
+ */
11
+ export default defineType({
12
+ name: "parallaxSlide",
13
+ title: "Parallax Slide",
14
+ type: "object",
15
+ fields: [
16
+ // ---- Background ----
17
+ defineField({
18
+ name: "background_type",
19
+ title: "Background Type",
20
+ type: "string",
21
+ options: {
22
+ list: [
23
+ { title: "Image", value: "image" },
24
+ { title: "Video", value: "video" },
25
+ ],
26
+ },
27
+ initialValue: "image",
28
+ }),
29
+ defineField({
30
+ name: "background_image",
31
+ title: "Background Image",
32
+ type: "string",
33
+ description: "Asset path for background image",
34
+ }),
35
+ defineField({
36
+ name: "background_video",
37
+ title: "Background Video",
38
+ type: "string",
39
+ description: "Asset path for background video",
40
+ }),
41
+ defineField({
42
+ name: "background_position",
43
+ title: "Background Position",
44
+ type: "string",
45
+ description: "CSS background-position value",
46
+ initialValue: "center center",
47
+ }),
48
+ defineField({
49
+ name: "background_overlay_color",
50
+ title: "Overlay Color",
51
+ type: "string",
52
+ description: "Hex color for background overlay",
53
+ initialValue: "#000000",
54
+ }),
55
+ defineField({
56
+ name: "background_overlay_opacity",
57
+ title: "Overlay Opacity",
58
+ type: "number",
59
+ description: "0–100",
60
+ initialValue: 0,
61
+ validation: (Rule) => Rule.min(0).max(100),
62
+ }),
63
+
64
+ // ---- Navbar Color Override ----
65
+ defineField({
66
+ name: "nav_color",
67
+ title: "Navbar Color",
68
+ type: "string",
69
+ description: "Hex color for navbar while this slide is active (optional)",
70
+ }),
71
+
72
+ // ---- V2 Section Content (same structure as pageSectionV2 internals) ----
73
+ defineField({
74
+ name: "columns",
75
+ title: "Columns",
76
+ type: "array",
77
+ of: [
78
+ {
79
+ type: "object",
80
+ name: "sectionColumn",
81
+ fields: [
82
+ defineField({
83
+ name: "grid_column",
84
+ title: "Grid Column",
85
+ type: "number",
86
+ validation: (Rule) => Rule.required().min(1).max(12),
87
+ }),
88
+ defineField({
89
+ name: "grid_row",
90
+ title: "Grid Row",
91
+ type: "number",
92
+ validation: (Rule) => Rule.required().min(1),
93
+ }),
94
+ defineField({
95
+ name: "span",
96
+ title: "Column Span",
97
+ type: "number",
98
+ validation: (Rule) => Rule.required().min(1).max(12),
99
+ }),
100
+ defineField({
101
+ name: "blocks",
102
+ title: "Blocks",
103
+ type: "array",
104
+ of: [
105
+ { type: "textBlock" },
106
+ { type: "imageBlock" },
107
+ { type: "imageGridBlock" },
108
+ { type: "videoBlock" },
109
+ { type: "spacerBlock" },
110
+ { type: "buttonBlock" },
111
+ { type: "coverBlock" },
112
+ ],
113
+ }),
114
+ defineField({
115
+ name: "enter_animation",
116
+ title: "Enter Animation",
117
+ type: "enterAnimationConfig",
118
+ }),
119
+ ],
120
+ },
121
+ ],
122
+ }),
123
+
124
+ // ---- Section Settings ----
125
+ defineField({
126
+ name: "section_settings",
127
+ title: "Section Settings",
128
+ type: "object",
129
+ fields: [
130
+ defineField({
131
+ name: "preset",
132
+ title: "Layout Preset",
133
+ type: "string",
134
+ options: {
135
+ list: ["full", "halves", "thirds", "quarters", "1/3+2/3", "2/3+1/3", "custom"],
136
+ },
137
+ }),
138
+ defineField({ name: "grid_columns", title: "Grid Columns", type: "number" }),
139
+ defineField({ name: "col_gap", title: "Column Gap", type: "number" }),
140
+ defineField({ name: "row_gap", title: "Row Gap", type: "number" }),
141
+ // Spacing
142
+ defineField({ name: "spacing_top", title: "Spacing Top", type: "string" }),
143
+ defineField({ name: "spacing_right", title: "Spacing Right", type: "string" }),
144
+ defineField({ name: "spacing_bottom", title: "Spacing Bottom", type: "string" }),
145
+ defineField({ name: "spacing_left", title: "Spacing Left", type: "string" }),
146
+ // Offset
147
+ defineField({ name: "offset_top", title: "Offset Top", type: "string" }),
148
+ defineField({ name: "offset_right", title: "Offset Right", type: "string" }),
149
+ defineField({ name: "offset_bottom", title: "Offset Bottom", type: "string" }),
150
+ defineField({ name: "offset_left", title: "Offset Left", type: "string" }),
151
+ // Background
152
+ defineField({ name: "background_color", title: "Background Color", type: "string" }),
153
+ defineField({ name: "background_opacity", title: "Background Opacity", type: "number" }),
154
+ defineField({ name: "background_image", title: "Background Image", type: "string" }),
155
+ defineField({
156
+ name: "background_size",
157
+ title: "Background Size",
158
+ type: "string",
159
+ options: { list: ["cover", "contain", "auto"] },
160
+ }),
161
+ defineField({ name: "background_position", title: "Background Position", type: "string" }),
162
+ defineField({
163
+ name: "background_repeat",
164
+ title: "Background Repeat",
165
+ type: "string",
166
+ options: { list: ["no-repeat", "repeat", "repeat-x", "repeat-y"] },
167
+ }),
168
+ // Border
169
+ defineField({ name: "border_color", title: "Border Color", type: "string" }),
170
+ defineField({ name: "border_width", title: "Border Width", type: "string" }),
171
+ defineField({
172
+ name: "border_style",
173
+ title: "Border Style",
174
+ type: "string",
175
+ options: { list: ["none", "solid", "dashed", "dotted"] },
176
+ }),
177
+ defineField({
178
+ name: "border_sides",
179
+ title: "Border Sides",
180
+ type: "string",
181
+ options: { list: ["all", "top", "right", "bottom", "left", "top-bottom", "left-right"] },
182
+ }),
183
+ defineField({ name: "border_radius", title: "Border Radius", type: "string" }),
184
+ // Animation
185
+ defineField({
186
+ name: "enter_animation",
187
+ title: "Enter Animation",
188
+ type: "enterAnimationConfig",
189
+ }),
190
+ defineField({
191
+ name: "stagger",
192
+ title: "Stagger",
193
+ type: "object",
194
+ fields: [
195
+ defineField({ name: "enabled", title: "Enabled", type: "boolean" }),
196
+ defineField({ name: "delayPerChild", title: "Delay Per Child", type: "number" }),
197
+ defineField({
198
+ name: "direction",
199
+ title: "Direction",
200
+ type: "string",
201
+ options: { list: ["left-to-right", "right-to-left"] },
202
+ }),
203
+ ],
204
+ }),
205
+ ],
206
+ }),
207
+ ],
208
+ preview: {
209
+ select: { bg_type: "background_type", bg_image: "background_image" },
210
+ prepare({ bg_type, bg_image }) {
211
+ return {
212
+ title: `Slide (${bg_type || "image"})`,
213
+ subtitle: bg_image || "No background set",
214
+ };
215
+ },
216
+ },
217
+ });
@@ -0,0 +1,38 @@
1
+ import { defineType, defineField } from "sanity";
2
+
3
+ /**
4
+ * Typewriter config — extra settings for the "typewriter" enter animation.
5
+ *
6
+ * Only relevant for textBlock when enter_animation.preset === "typewriter".
7
+ *
8
+ * Session 117 — Animation UX Refactor.
9
+ */
10
+ const typewriterConfig = defineType({
11
+ name: "typewriterConfig",
12
+ title: "Typewriter",
13
+ type: "object",
14
+ fields: [
15
+ defineField({
16
+ name: "speed",
17
+ title: "Speed (chars/sec)",
18
+ type: "number",
19
+ description: "Characters per second (10–100)",
20
+ initialValue: 40,
21
+ validation: (Rule) => Rule.min(10).max(100),
22
+ }),
23
+ defineField({
24
+ name: "mode",
25
+ title: "Mode",
26
+ type: "string",
27
+ options: {
28
+ list: [
29
+ { title: "Character", value: "character" },
30
+ { title: "Word", value: "word" },
31
+ ],
32
+ },
33
+ initialValue: "character",
34
+ }),
35
+ ],
36
+ });
37
+
38
+ export default typewriterConfig;
@@ -0,0 +1,162 @@
1
+ import { defineField, defineType } from "sanity";
2
+
3
+ export default defineType({
4
+ name: "page",
5
+ title: "Page",
6
+ type: "document",
7
+ fields: [
8
+ defineField({
9
+ name: "title",
10
+ title: "Title",
11
+ type: "string",
12
+ validation: (Rule) => Rule.required(),
13
+ }),
14
+ defineField({
15
+ name: "slug",
16
+ title: "Slug",
17
+ type: "slug",
18
+ options: { source: "title", maxLength: 96 },
19
+ validation: (Rule) => Rule.required(),
20
+ }),
21
+ defineField({
22
+ name: "page_type",
23
+ title: "Page Type",
24
+ type: "string",
25
+ options: {
26
+ list: [
27
+ { title: "Page", value: "page" },
28
+ { title: "Project", value: "project" },
29
+ ],
30
+ },
31
+ validation: (Rule) => Rule.required(),
32
+ initialValue: "page",
33
+ }),
34
+ defineField({
35
+ name: "is_home",
36
+ title: "Is Home Page",
37
+ type: "boolean",
38
+ description: "Mark this page as the home page. Only one page can be home at a time.",
39
+ initialValue: false,
40
+ }),
41
+ defineField({
42
+ name: "content_rows",
43
+ title: "Content Rows",
44
+ type: "array",
45
+ of: [{ type: "pageSection" }, { type: "pageSectionV2" }, { type: "parallaxGroup" }, { type: "customSectionInstance" }],
46
+ }),
47
+ defineField({
48
+ name: "metadata",
49
+ title: "Metadata",
50
+ type: "object",
51
+ fields: [
52
+ defineField({
53
+ name: "seo_title",
54
+ title: "SEO Title",
55
+ type: "string",
56
+ }),
57
+ defineField({
58
+ name: "seo_description",
59
+ title: "SEO Description",
60
+ type: "text",
61
+ rows: 3,
62
+ }),
63
+ defineField({
64
+ name: "og_image_path",
65
+ title: "OG Image Path",
66
+ type: "string",
67
+ description: "Relative path to the Open Graph image",
68
+ }),
69
+ ],
70
+ }),
71
+ defineField({
72
+ name: "page_settings",
73
+ title: "Page Settings",
74
+ type: "object",
75
+ fields: [
76
+ defineField({
77
+ name: "background_color",
78
+ title: "Background Color",
79
+ type: "string",
80
+ }),
81
+ defineField({
82
+ name: "text_color",
83
+ title: "Text Color",
84
+ type: "string",
85
+ }),
86
+ defineField({
87
+ name: "nav_color",
88
+ title: "Nav Color",
89
+ type: "string",
90
+ description: "Override navigation color for this page",
91
+ }),
92
+ defineField({
93
+ name: "enter_animation",
94
+ title: "Default Enter Animation",
95
+ type: "enterAnimationConfig",
96
+ description: "Page-level default enter animation applied to all sections/columns/blocks unless overridden",
97
+ }),
98
+ // ── Per-page nav entrance override ──
99
+ defineField({
100
+ name: "nav_entrance_animation",
101
+ title: "Nav Entrance Override",
102
+ type: "string",
103
+ description: "Override the global nav entrance animation for this page",
104
+ options: {
105
+ list: [
106
+ { title: "Use Global", value: "" },
107
+ { title: "Fade In", value: "fade-in" },
108
+ { title: "Slide Down", value: "slide-down" },
109
+ { title: "Blur In", value: "blur-in" },
110
+ ],
111
+ },
112
+ }),
113
+ defineField({ name: "nav_entrance_duration", title: "Nav Entrance Duration (ms)", type: "number" }),
114
+ defineField({ name: "nav_entrance_delay", title: "Nav Entrance Delay (ms)", type: "number" }),
115
+ defineField({
116
+ name: "nav_entrance_disabled",
117
+ title: "Disable Nav Animation",
118
+ type: "boolean",
119
+ description: "Completely disable nav entrance animation on this page",
120
+ initialValue: false,
121
+ }),
122
+ ],
123
+ }),
124
+ defineField({
125
+ name: "thumbnail_path",
126
+ title: "Thumbnail",
127
+ type: "string",
128
+ description: "Asset path for the project card preview image",
129
+ }),
130
+ defineField({
131
+ name: "cover_video",
132
+ title: "Cover Video",
133
+ type: "string",
134
+ description: "Asset path for a cover video shown on hover in project grids",
135
+ }),
136
+ defineField({
137
+ name: "published_at",
138
+ title: "Published At",
139
+ type: "datetime",
140
+ }),
141
+ defineField({
142
+ name: "draft_mode",
143
+ title: "Draft Mode",
144
+ type: "boolean",
145
+ initialValue: true,
146
+ }),
147
+ ],
148
+ preview: {
149
+ select: {
150
+ title: "title",
151
+ isHome: "is_home",
152
+ pageType: "page_type",
153
+ },
154
+ prepare({ title, isHome, pageType }) {
155
+ const label = pageType === "project" ? "Project" : isHome ? "Home" : "Page";
156
+ return {
157
+ title: title || "Untitled",
158
+ subtitle: label,
159
+ };
160
+ },
161
+ },
162
+ });
@@ -0,0 +1,157 @@
1
+ import { defineField, defineType } from "sanity";
2
+
3
+ /**
4
+ * pageSection — First-class page section type.
5
+ *
6
+ * Unlike regular rows (which contain columns → blocks), page sections are
7
+ * direct, flat entities in the content_rows array. Each section wraps a single
8
+ * section-level block (projectGridBlock) with its own
9
+ * layout settings — no row/column matryoshka.
10
+ *
11
+ * Session 76: Refactored from the old "section row" approach where section
12
+ * blocks were wrapped in row → column → block.
13
+ */
14
+ export default defineType({
15
+ name: "pageSection",
16
+ title: "Page Section",
17
+ type: "object",
18
+ fields: [
19
+ defineField({
20
+ name: "section_type",
21
+ title: "Section Type",
22
+ type: "string",
23
+ options: {
24
+ list: [
25
+ { title: "Project Grid", value: "projectGrid" },
26
+ ],
27
+ },
28
+ validation: (Rule) => Rule.required(),
29
+ }),
30
+ defineField({
31
+ name: "block",
32
+ title: "Section Content",
33
+ type: "array",
34
+ of: [{ type: "projectGridBlock" }],
35
+ validation: (Rule) => Rule.max(1).required(),
36
+ description: "The section block content (one block per section)",
37
+ }),
38
+ defineField({
39
+ name: "settings",
40
+ title: "Section Settings",
41
+ type: "object",
42
+ fields: [
43
+ // Background
44
+ defineField({ name: "background_color", title: "Background Color", type: "string" }),
45
+ defineField({ name: "background_opacity", title: "Background Opacity", type: "number" }),
46
+ defineField({ name: "background_image", title: "Background Image", type: "string" }),
47
+ defineField({
48
+ name: "background_size",
49
+ title: "Background Size",
50
+ type: "string",
51
+ options: { list: ["cover", "contain", "auto"] },
52
+ }),
53
+ defineField({ name: "background_position", title: "Background Position", type: "string" }),
54
+ defineField({
55
+ name: "background_repeat",
56
+ title: "Background Repeat",
57
+ type: "string",
58
+ options: { list: ["no-repeat", "repeat", "repeat-x", "repeat-y"] },
59
+ }),
60
+ // Spacing (padding TRBL)
61
+ defineField({ name: "spacing_top", title: "Spacing Top", type: "string" }),
62
+ defineField({ name: "spacing_right", title: "Spacing Right", type: "string" }),
63
+ defineField({ name: "spacing_bottom", title: "Spacing Bottom", type: "string" }),
64
+ defineField({ name: "spacing_left", title: "Spacing Left", type: "string" }),
65
+ // Offset (margin TRBL)
66
+ defineField({ name: "offset_top", title: "Offset Top", type: "string" }),
67
+ defineField({ name: "offset_right", title: "Offset Right", type: "string" }),
68
+ defineField({ name: "offset_bottom", title: "Offset Bottom", type: "string" }),
69
+ defineField({ name: "offset_left", title: "Offset Left", type: "string" }),
70
+ // Border
71
+ defineField({ name: "border_color", title: "Border Color", type: "string" }),
72
+ defineField({ name: "border_width", title: "Border Width", type: "string" }),
73
+ defineField({
74
+ name: "border_style",
75
+ title: "Border Style",
76
+ type: "string",
77
+ options: { list: ["none", "solid", "dashed", "dotted"] },
78
+ }),
79
+ defineField({
80
+ name: "border_sides",
81
+ title: "Border Sides",
82
+ type: "string",
83
+ options: { list: ["all", "top", "right", "bottom", "left", "top-bottom", "left-right"] },
84
+ }),
85
+ defineField({ name: "border_radius", title: "Border Radius", type: "string" }),
86
+ // Animation
87
+ defineField({
88
+ name: "enter_animation",
89
+ title: "Enter Animation",
90
+ type: "enterAnimationConfig",
91
+ }),
92
+ ],
93
+ }),
94
+ // BUG-013 fix: Per-viewport responsive overrides for section settings
95
+ defineField({
96
+ name: "responsive",
97
+ title: "Responsive Overrides",
98
+ type: "object",
99
+ hidden: true, // Managed by the visual builder
100
+ fields: [
101
+ defineField({
102
+ name: "tablet",
103
+ title: "Tablet",
104
+ type: "object",
105
+ fields: [
106
+ defineField({ name: "background_color", type: "string", title: "Background Color" }),
107
+ defineField({ name: "background_opacity", type: "number", title: "Background Opacity" }),
108
+ defineField({ name: "spacing_top", type: "string", title: "Spacing Top" }),
109
+ defineField({ name: "spacing_right", type: "string", title: "Spacing Right" }),
110
+ defineField({ name: "spacing_bottom", type: "string", title: "Spacing Bottom" }),
111
+ defineField({ name: "spacing_left", type: "string", title: "Spacing Left" }),
112
+ defineField({ name: "offset_top", type: "string", title: "Offset Top" }),
113
+ defineField({ name: "offset_right", type: "string", title: "Offset Right" }),
114
+ defineField({ name: "offset_bottom", type: "string", title: "Offset Bottom" }),
115
+ defineField({ name: "offset_left", type: "string", title: "Offset Left" }),
116
+ defineField({ name: "border_color", type: "string", title: "Border Color" }),
117
+ defineField({ name: "border_width", type: "string", title: "Border Width" }),
118
+ defineField({ name: "border_style", type: "string", title: "Border Style" }),
119
+ defineField({ name: "border_sides", type: "string", title: "Border Sides" }),
120
+ defineField({ name: "border_radius", type: "string", title: "Border Radius" }),
121
+ ],
122
+ }),
123
+ defineField({
124
+ name: "phone",
125
+ title: "Phone",
126
+ type: "object",
127
+ fields: [
128
+ defineField({ name: "background_color", type: "string", title: "Background Color" }),
129
+ defineField({ name: "background_opacity", type: "number", title: "Background Opacity" }),
130
+ defineField({ name: "spacing_top", type: "string", title: "Spacing Top" }),
131
+ defineField({ name: "spacing_right", type: "string", title: "Spacing Right" }),
132
+ defineField({ name: "spacing_bottom", type: "string", title: "Spacing Bottom" }),
133
+ defineField({ name: "spacing_left", type: "string", title: "Spacing Left" }),
134
+ defineField({ name: "offset_top", type: "string", title: "Offset Top" }),
135
+ defineField({ name: "offset_right", type: "string", title: "Offset Right" }),
136
+ defineField({ name: "offset_bottom", type: "string", title: "Offset Bottom" }),
137
+ defineField({ name: "offset_left", type: "string", title: "Offset Left" }),
138
+ defineField({ name: "border_color", type: "string", title: "Border Color" }),
139
+ defineField({ name: "border_width", type: "string", title: "Border Width" }),
140
+ defineField({ name: "border_style", type: "string", title: "Border Style" }),
141
+ defineField({ name: "border_sides", type: "string", title: "Border Sides" }),
142
+ defineField({ name: "border_radius", type: "string", title: "Border Radius" }),
143
+ ],
144
+ }),
145
+ ],
146
+ }),
147
+ ],
148
+ preview: {
149
+ select: { section_type: "section_type" },
150
+ prepare({ section_type }) {
151
+ const labels: Record<string, string> = {
152
+ projectGrid: "Project Grid",
153
+ };
154
+ return { title: labels[section_type] || "Section" };
155
+ },
156
+ },
157
+ });