feat: add ConfigurePage with back button and ConfiguratorSection integration
This commit is contained in:
parent
11ab8908fa
commit
1788df79e1
43
src/app/configure/page.tsx
Normal file
43
src/app/configure/page.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { ConfiguratorSection } from '@/components/ConfiguratorSection';
|
||||||
|
|
||||||
|
export default function ConfigurePage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Back button */}
|
||||||
|
<Link
|
||||||
|
href="/"
|
||||||
|
style={{
|
||||||
|
position: 'fixed',
|
||||||
|
top: '1rem',
|
||||||
|
left: '1rem',
|
||||||
|
zIndex: 100,
|
||||||
|
display: 'inline-flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '0.5rem',
|
||||||
|
padding: '0.5rem 1rem',
|
||||||
|
borderRadius: '2rem',
|
||||||
|
background: 'rgba(255, 255, 255, 0.9)',
|
||||||
|
backdropFilter: 'blur(12px)',
|
||||||
|
WebkitBackdropFilter: 'blur(12px)',
|
||||||
|
border: '1px solid rgba(0, 0, 0, 0.08)',
|
||||||
|
boxShadow: '0 2px 12px rgba(0, 0, 0, 0.06)',
|
||||||
|
color: '#374151',
|
||||||
|
fontSize: '0.8rem',
|
||||||
|
fontWeight: 500,
|
||||||
|
textDecoration: 'none',
|
||||||
|
transition: 'all 0.2s ease',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<line x1="19" y1="12" x2="5" y2="12" /><polyline points="12 19 5 12 12 5" />
|
||||||
|
</svg>
|
||||||
|
Back
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<ConfiguratorSection />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -4,7 +4,6 @@ import { useRef } from "react";
|
|||||||
import { ClientOnly } from "@/components/ClientOnly";
|
import { ClientOnly } from "@/components/ClientOnly";
|
||||||
import { ScrollScene } from "@/components/ScrollScene";
|
import { ScrollScene } from "@/components/ScrollScene";
|
||||||
import { ScrollOverlays } from "@/components/ScrollOverlays";
|
import { ScrollOverlays } from "@/components/ScrollOverlays";
|
||||||
import { ConfiguratorSection } from "@/components/ConfiguratorSection";
|
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||||
@ -29,11 +28,6 @@ export default function HomePage() {
|
|||||||
<div className="snap-section" />
|
<div className="snap-section" />
|
||||||
<div className="snap-section" />
|
<div className="snap-section" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Configurator section */}
|
|
||||||
<div style={{ position: "relative", zIndex: 20 }}>
|
|
||||||
<ConfiguratorSection />
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { useScroll, useTransform, motion } from 'framer-motion';
|
import { useScroll, useTransform, motion } from 'framer-motion';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
interface SectionProps {
|
interface SectionProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@ -253,6 +254,51 @@ export function ScrollOverlays() {
|
|||||||
</div>
|
</div>
|
||||||
</OverlaySection>
|
</OverlaySection>
|
||||||
|
|
||||||
|
{/* Configure CTA — appears at the very end of scroll */}
|
||||||
|
<motion.div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: '8vh',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translateX(-50%)',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '1rem',
|
||||||
|
opacity: useTransform(scrollYProgress, [0.88, 0.95], [0, 1]),
|
||||||
|
pointerEvents: 'auto',
|
||||||
|
zIndex: 20,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Link
|
||||||
|
href="/configure/"
|
||||||
|
style={{
|
||||||
|
display: 'inline-flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '0.75rem',
|
||||||
|
padding: '1rem 2.5rem',
|
||||||
|
borderRadius: '3rem',
|
||||||
|
background: 'linear-gradient(135deg, #c4a265, #d4b47a)',
|
||||||
|
color: '#ffffff',
|
||||||
|
fontSize: '0.95rem',
|
||||||
|
fontWeight: 600,
|
||||||
|
letterSpacing: '0.1em',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
textDecoration: 'none',
|
||||||
|
boxShadow: '0 8px 32px rgba(196, 162, 101, 0.3)',
|
||||||
|
transition: 'all 0.3s ease',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Configure Your G1
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<line x1="5" y1="12" x2="19" y2="12" /><polyline points="12 5 19 12 12 19" />
|
||||||
|
</svg>
|
||||||
|
</Link>
|
||||||
|
<span style={{ fontSize: '0.7rem', color: '#94a3b8', letterSpacing: '0.15em', textTransform: 'uppercase' }}>
|
||||||
|
Build & Order Your Robot
|
||||||
|
</span>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
{/* Scroll indicator mapped to vanish rapidly when scrolled */}
|
{/* Scroll indicator mapped to vanish rapidly when scrolled */}
|
||||||
<motion.div
|
<motion.div
|
||||||
className="overlay-scroll-hint"
|
className="overlay-scroll-hint"
|
||||||
|
|||||||
@ -128,7 +128,7 @@ export const pricingStore = createStore<PricingStore>((set, get) => ({
|
|||||||
// Merge: server wins for label/price, but keep local modelPath if server doesn't have one
|
// Merge: server wins for label/price, but keep local modelPath if server doesn't have one
|
||||||
const localItems = get().items;
|
const localItems = get().items;
|
||||||
const localMap = new Map(localItems.map((l) => [l.id, l]));
|
const localMap = new Map(localItems.map((l) => [l.id, l]));
|
||||||
const merged = serverItems.map((s) => {
|
const merged: PricingItem[] = serverItems.map((s) => {
|
||||||
const local = localMap.get(s.id);
|
const local = localMap.get(s.id);
|
||||||
return {
|
return {
|
||||||
...s,
|
...s,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user