Spaces:
Sleeping
Sleeping
| import React, { useState, useEffect, useRef, useCallback } from 'react'; | |
| import './App.css'; | |
| import Nav from './components/Nav'; | |
| import Hero from './components/Hero'; | |
| import LiveDemo from './components/LiveDemo'; | |
| import Benchmarks from './components/Benchmarks'; | |
| import Architecture from './components/Architecture'; | |
| import WhatBreaks from './components/WhatBreaks'; | |
| import TechStack from './components/TechStack'; | |
| import ResumeBullet from './components/ResumeBullet'; | |
| import Footer from './components/Footer'; | |
| const SECTIONS = ['hero', 'features', 'benchmarks', 'demo', 'failure-analysis', 'tech-stack']; | |
| // Extract initial tab from URL hash (e.g. #demo/trigger) | |
| function getInitialDemoTab() { | |
| const hash = window.location.hash.replace('#', ''); | |
| const parts = hash.split('/'); | |
| if (parts[0] === 'demo' && parts[1]) { | |
| return parts[1]; // nl2sql, trigger, search, dashboard | |
| } | |
| return null; | |
| } | |
| function App() { | |
| const [activeSection, setActiveSection] = useState('hero'); | |
| const [initialDemoTab] = useState(getInitialDemoTab); | |
| const observerRef = useRef(null); | |
| const handleSectionInView = useCallback((sectionId) => { | |
| setActiveSection(sectionId); | |
| }, []); | |
| useEffect(() => { | |
| const observer = new IntersectionObserver( | |
| (entries) => { | |
| entries.forEach((entry) => { | |
| if (entry.isIntersecting) { | |
| handleSectionInView(entry.target.id); | |
| } | |
| }); | |
| }, | |
| { threshold: 0.3, rootMargin: '-80px 0px 0px 0px' } | |
| ); | |
| observerRef.current = observer; | |
| SECTIONS.forEach((id) => { | |
| const el = document.getElementById(id); | |
| if (el) observer.observe(el); | |
| }); | |
| return () => observer.disconnect(); | |
| }, [handleSectionInView]); | |
| // Handle initial hash navigation on mount | |
| useEffect(() => { | |
| const hash = window.location.hash.replace('#', ''); | |
| if (hash) { | |
| const sectionId = hash.split('/')[0]; | |
| const timer = setTimeout(() => { | |
| const el = document.getElementById(sectionId); | |
| if (el) el.scrollIntoView({ behavior: 'smooth' }); | |
| }, 500); | |
| return () => clearTimeout(timer); | |
| } | |
| }, []); | |
| const scrollToSection = (sectionId) => { | |
| const el = document.getElementById(sectionId); | |
| if (el) el.scrollIntoView({ behavior: 'smooth' }); | |
| // Update hash without triggering a scroll | |
| window.history.replaceState(null, '', `#${sectionId}`); | |
| }; | |
| return ( | |
| <div style={{ background: 'var(--bg)', minHeight: '100vh' }}> | |
| <a href="#demo" className="skip-to-content" aria-label="Skip to main content">Skip to content</a> | |
| <Nav activeSection={activeSection} onNavigate={scrollToSection} /> | |
| <main role="main" aria-label="NeuralVault application content"> | |
| <section id="hero" aria-label="Hero introduction"> | |
| <Hero onLaunchDemo={() => scrollToSection('demo')} onViewBenchmarks={() => scrollToSection('benchmarks')} /> | |
| </section> | |
| <section id="features" aria-label="Architecture deep-dive"> | |
| <Architecture /> | |
| </section> | |
| <section id="benchmarks" aria-label="Performance benchmarks"> | |
| <Benchmarks /> | |
| </section> | |
| <section id="demo" aria-label="Live AI demos"> | |
| <LiveDemo initialTab={initialDemoTab} /> | |
| </section> | |
| <section id="failure-analysis" aria-label="Production failure analysis"> | |
| <WhatBreaks /> | |
| </section> | |
| <section id="tech-stack" aria-label="Technology stack and resume"> | |
| <TechStack /> | |
| <ResumeBullet /> | |
| </section> | |
| </main> | |
| <Footer /> | |
| </div> | |
| ); | |
| } | |
| export default App; | |