Spaces:
Sleeping
Sleeping
| import React, { useState, useEffect, useCallback } from 'react'; | |
| import NLtoSQL from './NLtoSQL'; | |
| import TriggerSim from './TriggerSim'; | |
| import HybridSearch from './HybridSearch'; | |
| import Dashboard from './Dashboard'; | |
| const TABS = [ | |
| { id: 'nl2sql', label: 'Natural Language → SQL' }, | |
| { id: 'trigger', label: 'AI Trigger Simulator' }, | |
| { id: 'search', label: 'Hybrid Search' }, | |
| { id: 'dashboard', label: 'AI Dashboard' }, | |
| ]; | |
| export default function LiveDemo({ initialTab }) { | |
| const [activeTab, setActiveTab] = useState(initialTab || 'nl2sql'); | |
| // Listen for hash changes to switch tabs | |
| useEffect(() => { | |
| const handleHashChange = () => { | |
| const hash = window.location.hash.replace('#', ''); | |
| const parts = hash.split('/'); | |
| if (parts[0] === 'demo' && parts[1]) { | |
| const validTab = TABS.find(t => t.id === parts[1]); | |
| if (validTab) setActiveTab(validTab.id); | |
| } | |
| }; | |
| window.addEventListener('hashchange', handleHashChange); | |
| return () => window.removeEventListener('hashchange', handleHashChange); | |
| }, []); | |
| const switchTab = useCallback((tabId) => { | |
| setActiveTab(tabId); | |
| window.history.replaceState(null, '', `#demo/${tabId}`); | |
| }, []); | |
| return ( | |
| <div className="nv-section" data-testid="live-demo-section"> | |
| <div className="nv-container"> | |
| <div style={{ textAlign: 'center', marginBottom: 40 }}> | |
| <span className="nv-badge nv-badge-purple" style={{ marginBottom: 12, display: 'inline-block' }}>Live Demo</span> | |
| <h2 style={{ fontFamily: 'var(--font-heading)', fontWeight: 700, fontSize: 'clamp(28px, 4vw, 42px)', color: 'var(--text)', marginBottom: 12 }}> | |
| See It In Action | |
| </h2> | |
| <p style={{ color: 'var(--text2)', maxWidth: 520, margin: '0 auto', fontSize: 15 }}> | |
| All demos powered by Google Gemini 2.0 Flash. Real AI responses, not hardcoded. | |
| </p> | |
| </div> | |
| {/* Tab strip with ARIA roles */} | |
| <div | |
| className="nv-tabs" | |
| data-testid="live-demo-tabs" | |
| role="tablist" | |
| aria-label="Live demo tabs" | |
| style={{ maxWidth: 650, margin: '0 auto 32px', justifyContent: 'center' }} | |
| > | |
| {TABS.map((tab) => ( | |
| <button | |
| key={tab.id} | |
| className={`nv-tab ${activeTab === tab.id ? 'active' : ''}`} | |
| onClick={() => switchTab(tab.id)} | |
| data-testid={`live-demo-tab-${tab.id}`} | |
| role="tab" | |
| aria-selected={activeTab === tab.id} | |
| aria-controls={`tabpanel-${tab.id}`} | |
| id={`tab-${tab.id}`} | |
| > | |
| {tab.label} | |
| </button> | |
| ))} | |
| </div> | |
| {/* Tab content with ARIA roles */} | |
| <div | |
| role="tabpanel" | |
| id={`tabpanel-${activeTab}`} | |
| aria-labelledby={`tab-${activeTab}`} | |
| > | |
| {activeTab === 'nl2sql' && <NLtoSQL />} | |
| {activeTab === 'trigger' && <TriggerSim />} | |
| {activeTab === 'search' && <HybridSearch />} | |
| {activeTab === 'dashboard' && <Dashboard />} | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |