Bob AI: Populate the newly-created page at src/pages/MachineWalkthro

This commit is contained in:
kudinDmitriyUp
2026-07-03 17:13:45 +00:00
parent 8d22a47359
commit 067aa9c650

View File

@@ -1,94 +1,241 @@
import { useState } from "react";
import { motion, AnimatePresence } from "motion/react";
import { routes } from "@/routes";
import NavbarCentered from "@/components/ui/NavbarCentered";
import HeroOverlay from "@/components/sections/hero/HeroOverlay";
import FeaturesMediaCards from "@/components/sections/features/FeaturesMediaCards";
import ContactCta from "@/components/sections/contact/ContactCta";
import FooterSimple from "@/components/sections/footer/FooterSimple";
import { Info, MapPin, ChevronLeft } from "lucide-react";
import { cls } from "@/lib/utils";
type ViewKey = 'exterior' | 'cab' | 'machinery' | 'electrical' | 'boom' | 'maintenance';
type Hotspot =
| { id: string; x: number; y: number; label: string; type: 'nav'; target: ViewKey }
| { id: string; x: number; y: number; label: string; type: 'info'; info: string };
type View = {
title: string;
imageSrc: string;
hotspots: Hotspot[];
};
const VIEWS: Record<ViewKey, View> = {
exterior: {
title: "P&H 4200 Exterior",
imageSrc: "https://picsum.photos/seed/1329000375/1200/800",
hotspots: [
{ id: 'enter', x: 50, y: 60, label: "Enter the Machine", target: 'cab', type: 'nav' }
]
},
cab: {
title: "Operator's Cab",
imageSrc: "https://picsum.photos/seed/1496099219/1200/800",
hotspots: [
{ id: 'controls', x: 40, y: 50, label: "Dual Joystick Controls", info: "Ergonomic control center with panoramic visibility.", type: 'info' },
{ id: 'display', x: 60, y: 45, label: "Diagnostic Displays", info: "Real-time operational data and payload monitoring.", type: 'info' }
]
},
machinery: {
title: "Machinery House",
imageSrc: "https://picsum.photos/seed/1110967395/1200/800",
hotspots: [
{ id: 'hoist', x: 30, y: 60, label: "Hoist Motors", info: "Massive hoist motors designed for continuous high-torque output.", type: 'info' },
{ id: 'swing', x: 70, y: 55, label: "Swing Transmissions", info: "Planetary gearboxes for smooth, rapid swing cycles.", type: 'info' }
]
},
electrical: {
title: "Electrical Room",
imageSrc: "https://picsum.photos/seed/1776604305/1200/800",
hotspots: [
{ id: 'ac', x: 50, y: 40, label: "AC Drive Systems", info: "Advanced IGBT AC drives for precise motor control.", type: 'info' },
{ id: 'panels', x: 20, y: 50, label: "Power Distribution", info: "Climate-controlled electronics bays.", type: 'info' }
]
},
boom: {
title: "Boom & Dipper",
imageSrc: "https://picsum.photos/seed/691466050/1200/800",
hotspots: [
{ id: 'dipper', x: 50, y: 70, label: "High-Capacity Dipper", info: "Engineered for maximum payload and optimal dig geometry.", type: 'info' },
{ id: 'crowd', x: 50, y: 30, label: "Crowd Machinery", info: "Rack and pinion crowd for positive digging force.", type: 'info' }
]
},
maintenance: {
title: "Maintenance Deck",
imageSrc: "https://picsum.photos/seed/429735176/1200/800",
hotspots: [
{ id: 'lube', x: 40, y: 60, label: "Auto-Lube System", info: "Centralized lubrication for all major pivot points.", type: 'info' },
{ id: 'access', x: 80, y: 50, label: "Safe Access", info: "Wide walkways and tie-off points for maintenance personnel.", type: 'info' }
]
}
};
export default function MachineWalkthroughPage() {
const [currentView, setCurrentView] = useState<ViewKey>('exterior');
const [activeInfo, setActiveInfo] = useState<string | null>(null);
const [isTransitioning, setIsTransitioning] = useState(false);
const handleNavigate = (target: ViewKey) => {
setIsTransitioning(true);
setActiveInfo(null);
setTimeout(() => {
setCurrentView(target);
setIsTransitioning(false);
}, 800);
};
const view = VIEWS[currentView];
return (
<div className="min-h-screen bg-background text-foreground flex flex-col">
<NavbarCentered
logo="P&H 4200 Tour"
navItems={routes.map((r) => ({ name: r.label, href: r.path }))}
ctaButton={{ text: "Request Specs", href: "/contact" }}
/>
<div
className="min-h-svh flex flex-col font-sans bg-background text-foreground"
style={{
'--background': '#09090b',
'--foreground': '#f4f4f5',
'--card': '#18181b',
'--primary-cta': '#18181b',
'--primary-cta-text': '#f97316',
'--secondary-cta': '#27272a',
'--secondary-cta-text': '#f4f4f5',
'--accent': '#f97316',
'--background-accent': '#c2410c',
} as React.CSSProperties}
>
<main className="relative flex-grow h-[calc(100vh-5rem)] mt-20 overflow-hidden bg-background">
<AnimatePresence mode="wait">
<motion.div
key={currentView}
initial={{ opacity: 0, scale: 1.1 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 1.2 }}
transition={{ duration: 0.8, ease: "easeInOut" }}
className="absolute inset-0"
>
<img
src={view.imageSrc}
alt={view.title}
className="w-full h-full object-cover opacity-60"
/>
{currentView === 'exterior' && (
<motion.img
src={view.imageSrc}
alt={view.title}
initial={{ scale: 1 }}
animate={{ scale: 1.1 }}
transition={{ duration: 20, repeat: Infinity, repeatType: "reverse", ease: "linear" }}
className="absolute inset-0 w-full h-full object-cover opacity-50 mix-blend-overlay"
/>
)}
</motion.div>
</AnimatePresence>
<main className="flex-grow" id="hero">
<HeroOverlay
tag="Virtual Experience"
title="P&H 4200 Electric Rope Shovel"
description="Experience the sheer scale and engineering mastery of the world's premier mining shovel. Step inside the machine."
primaryButton={{ text: "Enter the Machine", href: "#interiors" }}
secondaryButton={{ text: "Watch Exterior Flyby", href: "#" }}
imageSrc="https://images.unsplash.com/photo-1578319439584-104c94d37305?auto=format&fit=crop&q=80"
textAnimation="fade-blur"
/>
<div className="absolute inset-0 bg-gradient-to-t from-background via-background/40 to-transparent pointer-events-none" />
<div id="interiors">
<FeaturesMediaCards
tag="Interior Compartments"
title="Explore the Anatomy"
description="Navigate through the critical zones of the P&H 4200. Select a compartment to view detailed schematics and operational data."
items={[
{
title: "Operator's Cab",
description: "Ergonomic control center with panoramic visibility, dual joystick controls, and advanced diagnostic displays.",
imageSrc: "https://images.unsplash.com/photo-1581092160562-40aa08e78837?auto=format&fit=crop&q=80"
},
{
title: "Machinery House",
description: "The beating heart housing the massive hoist and swing motors, designed for continuous high-torque output.",
imageSrc: "https://images.unsplash.com/photo-1581092335397-9583eb92d232?auto=format&fit=crop&q=80"
},
{
title: "Electrical Room",
description: "Advanced AC drive systems, power distribution panels, and climate-controlled electronics bays.",
imageSrc: "https://images.unsplash.com/photo-1581092580497-e0d23cbdf1dc?auto=format&fit=crop&q=80"
},
{
title: "Boom & Dipper",
description: "High-strength steel structures engineered for maximum payload and optimal dig geometry.",
imageSrc: "https://images.unsplash.com/photo-1504307651254-35680f356dfd?auto=format&fit=crop&q=80"
}
]}
textAnimation="slide-up"
/>
<div className="absolute inset-0 z-10">
<AnimatePresence>
{!isTransitioning && view.hotspots.map((hotspot) => (
<motion.div
key={hotspot.id}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.9 }}
transition={{ delay: 0.5 }}
className="absolute -translate-x-1/2 -translate-y-1/2 flex flex-col items-center gap-2"
style={{ left: `${hotspot.x}%`, top: `${hotspot.y}%` }}
>
{hotspot.type === 'nav' ? (
<button
onClick={() => handleNavigate(hotspot.target)}
className="group relative flex items-center justify-center w-16 h-16 rounded-full bg-accent/20 border-2 border-accent text-accent hover:bg-accent hover:text-background transition-all duration-300 shadow-lg shadow-accent/40 hover:shadow-xl hover:shadow-accent/60"
>
<MapPin className="w-6 h-6" />
<span className="absolute top-full mt-3 whitespace-nowrap text-sm font-bold tracking-wider uppercase text-accent group-hover:text-accent/80 drop-shadow-md">
{hotspot.label}
</span>
</button>
) : (
<div className="relative">
<button
onClick={() => setActiveInfo(activeInfo === hotspot.id ? null : hotspot.id)}
className={cls(
"group relative flex items-center justify-center w-10 h-10 rounded-full border-2 transition-all duration-300",
activeInfo === hotspot.id
? "bg-accent border-accent text-background shadow-lg shadow-accent/60"
: "bg-card/80 border-accent/50 text-accent hover:border-accent hover:bg-accent/20"
)}
>
<Info className="w-5 h-5" />
</button>
<AnimatePresence>
{activeInfo === hotspot.id && (
<motion.div
initial={{ opacity: 0, y: 10, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: 10, scale: 0.95 }}
className="absolute top-full left-1/2 -translate-x-1/2 mt-4 w-64 p-4 rounded-lg bg-card/95 border border-foreground/10 shadow-2xl backdrop-blur-sm"
>
<h4 className="text-accent font-bold mb-2">{hotspot.label}</h4>
<p className="text-sm text-foreground/80 leading-relaxed">{hotspot.info}</p>
</motion.div>
)}
</AnimatePresence>
</div>
)}
</motion.div>
))}
</AnimatePresence>
</div>
<ContactCta
tag="End of Tour"
text="Ready to step back outside or discuss technical specifications?"
primaryButton={{ text: "Back to Exterior", href: "#hero" }}
secondaryButton={{ text: "Contact Engineering", href: "/contact" }}
textAnimation="fade-blur"
/>
<AnimatePresence>
{currentView !== 'exterior' && (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 20 }}
className="absolute bottom-8 left-1/2 -translate-x-1/2 z-20 flex flex-col items-center gap-6 w-full max-w-content-width px-4"
>
<div className="flex flex-wrap justify-center gap-2 p-2 rounded-theme bg-card/80 backdrop-blur-md border border-foreground/10 shadow-2xl">
{(Object.keys(VIEWS) as ViewKey[]).filter(k => k !== 'exterior').map((key) => (
<button
key={key}
onClick={() => handleNavigate(key)}
className={cls(
"px-4 py-2 rounded-xl text-sm font-medium transition-all duration-300",
currentView === key
? "bg-accent text-background shadow-md shadow-accent/40"
: "text-foreground/60 hover:text-accent hover:bg-background/50"
)}
>
{VIEWS[key].title}
</button>
))}
</div>
<button
onClick={() => handleNavigate('exterior')}
className="flex items-center gap-2 px-6 py-3 rounded-full bg-card/80 border border-foreground/20 text-foreground/80 hover:text-foreground hover:border-foreground/50 transition-all backdrop-blur-md"
>
<ChevronLeft className="w-4 h-4" />
Back to Exterior
</button>
</motion.div>
)}
</AnimatePresence>
<div className="absolute top-8 left-8 z-20">
<motion.div
key={currentView}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
className="flex flex-col gap-1"
>
<span className="text-accent text-sm font-bold tracking-widest uppercase">
{currentView === 'exterior' ? 'Virtual Tour' : 'Interior Compartment'}
</span>
<h1 className="text-4xl md:text-5xl font-bold text-white drop-shadow-lg">
{view.title}
</h1>
</motion.div>
</div>
</main>
<FooterSimple
brand="Record Engineering (Pty) Ltd"
copyright="© 2024 Record Engineering (Pty) Ltd. All rights reserved."
columns={[
{
title: "Contact",
items: [
{ label: "sales@recordeng.com", href: "mailto:sales@recordeng.com" },
{ label: "+27 11 555 0198", href: "tel:+27115550198" }
]
},
{
title: "Legal",
items: [
{ label: "Privacy Policy", href: "/privacy" },
{ label: "Terms of Service", href: "/terms" }
]
}
]}
links={[
{ label: "LinkedIn", href: "#" },
{ label: "YouTube", href: "#" }
]}
/>
</div>
);
}