@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.
Files changed (319) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +50 -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 +212 -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,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
+ }