Spaces:
Build error
Build error
| import { useState } from 'react'; | |
| import { Send, Loader2, Code2, Eye, Copy, Check } from 'lucide-react'; | |
| const samplePrompts = [ | |
| 'Build a todo app with drag and drop', | |
| 'Create a weather dashboard with charts', | |
| 'Make an analytics dashboard with KPI cards', | |
| ]; | |
| export default function LiveDemo() { | |
| const [prompt, setPrompt] = useState(''); | |
| const [loading, setLoading] = useState(false); | |
| const [result, setResult] = useState(null); | |
| const [activeTab, setActiveTab] = useState('code'); | |
| const [copied, setCopied] = useState(false); | |
| const handleGenerate = async () => { | |
| if (!prompt.trim() || loading) return; | |
| setLoading(true); | |
| setResult(null); | |
| try { | |
| const res = await fetch('/api/generate', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ prompt }), | |
| }); | |
| const data = await res.json(); | |
| setResult(data); | |
| setActiveTab('code'); | |
| } catch (err) { | |
| setResult({ | |
| code: '// Error generating code. Please try again.', | |
| explanation: 'Something went wrong. Please try another prompt.', | |
| }); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| const handleCopy = () => { | |
| if (result?.code) { | |
| navigator.clipboard.writeText(result.code); | |
| setCopied(true); | |
| setTimeout(() => setCopied(false), 2000); | |
| } | |
| }; | |
| return ( | |
| <section id="demo" className="py-24 px-4 sm:px-6 lg:px-8 relative"> | |
| <div className="absolute inset-0 pointer-events-none"> | |
| <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[800px] h-[400px] bg-brand-500/5 rounded-full blur-3xl" /> | |
| </div> | |
| <div className="max-w-5xl mx-auto relative"> | |
| <div className="text-center mb-12"> | |
| <div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-brand-500/10 border border-brand-500/20 mb-4"> | |
| <span className="text-xs font-medium text-brand-300 uppercase tracking-wider">Live Demo</span> | |
| </div> | |
| <h2 className="text-4xl sm:text-5xl font-bold tracking-tight mb-4"> | |
| Try it <span className="gradient-text">right now</span> | |
| </h2> | |
| <p className="text-lg text-surface-300 max-w-2xl mx-auto"> | |
| Describe what you want to build and watch the AI generate production-ready code in real-time. | |
| </p> | |
| </div> | |
| {/* Input area */} | |
| <div className="glass-card p-6 mb-6"> | |
| <div className="flex flex-col sm:flex-row gap-3"> | |
| <div className="flex-1 relative"> | |
| <input | |
| type="text" | |
| value={prompt} | |
| onChange={(e) => setPrompt(e.target.value)} | |
| onKeyDown={(e) => e.key === 'Enter' && handleGenerate()} | |
| placeholder="Describe the app you want to build..." | |
| className="w-full px-4 py-3 bg-surface-800 border border-white/10 rounded-xl text-white placeholder-surface-300 focus:outline-none focus:border-brand-500 focus:ring-1 focus:ring-brand-500 transition-all" | |
| /> | |
| </div> | |
| <button | |
| onClick={handleGenerate} | |
| disabled={loading || !prompt.trim()} | |
| className="px-6 py-3 bg-gradient-to-r from-brand-500 to-brand-600 hover:from-brand-600 hover:to-brand-700 disabled:opacity-50 disabled:cursor-not-allowed rounded-xl font-semibold transition-all duration-200 flex items-center justify-center gap-2 shadow-lg shadow-brand-500/25 whitespace-nowrap" | |
| > | |
| {loading ? ( | |
| <> | |
| <Loader2 className="w-4 h-4 animate-spin" /> | |
| Generating... | |
| </> | |
| ) : ( | |
| <> | |
| <Send className="w-4 h-4" /> | |
| Generate | |
| </> | |
| )} | |
| </button> | |
| </div> | |
| <div className="flex flex-wrap gap-2 mt-4"> | |
| {samplePrompts.map((sp) => ( | |
| <button | |
| key={sp} | |
| onClick={() => setPrompt(sp)} | |
| className="px-3 py-1.5 text-xs bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg text-surface-300 hover:text-white transition-all" | |
| > | |
| {sp} | |
| </button> | |
| ))} | |
| </div> | |
| </div> | |
| {/* Result area */} | |
| {result && ( | |
| <div className="glass-card overflow-hidden animate-slide-up"> | |
| {/* Tabs */} | |
| <div className="flex items-center justify-between border-b border-white/5 px-4"> | |
| <div className="flex"> | |
| <button | |
| onClick={() => setActiveTab('code')} | |
| className={`px-4 py-3 text-sm font-medium transition-colors flex items-center gap-2 ${ | |
| activeTab === 'code' ? 'text-brand-400 border-b-2 border-brand-400' : 'text-surface-300 hover:text-white' | |
| }`} | |
| > | |
| <Code2 className="w-4 h-4" /> | |
| Code | |
| </button> | |
| <button | |
| onClick={() => setActiveTab('preview')} | |
| className={`px-4 py-3 text-sm font-medium transition-colors flex items-center gap-2 ${ | |
| activeTab === 'preview' ? 'text-brand-400 border-b-2 border-brand-400' : 'text-surface-300 hover:text-white' | |
| }`} | |
| > | |
| <Eye className="w-4 h-4" /> | |
| Explanation | |
| </button> | |
| </div> | |
| {activeTab === 'code' && ( | |
| <button | |
| onClick={handleCopy} | |
| className="flex items-center gap-1.5 px-3 py-1.5 text-xs text-surface-300 hover:text-white bg-white/5 hover:bg-white/10 rounded-md transition-all" | |
| > | |
| {copied ? <Check className="w-3.5 h-3.5 text-green-400" /> : <Copy className="w-3.5 h-3.5" />} | |
| {copied ? 'Copied!' : 'Copy'} | |
| </button> | |
| )} | |
| </div> | |
| <div className="p-6"> | |
| {activeTab === 'code' ? ( | |
| <pre className="font-mono text-sm leading-relaxed text-surface-200 overflow-x-auto whitespace-pre-wrap"> | |
| {result.code} | |
| </pre> | |
| ) : ( | |
| <div className="space-y-4"> | |
| <div className="flex items-start gap-3"> | |
| <div className="w-8 h-8 rounded-lg bg-brand-500/20 flex items-center justify-center flex-shrink-0 mt-0.5"> | |
| <Code2 className="w-4 h-4 text-brand-400" /> | |
| </div> | |
| <div> | |
| <h4 className="font-semibold text-white mb-1">AI Explanation</h4> | |
| <p className="text-surface-300 leading-relaxed">{result.explanation}</p> | |
| </div> | |
| </div> | |
| <div className="p-4 bg-green-500/10 border border-green-500/20 rounded-xl"> | |
| <p className="text-sm text-green-300"> | |
| ✨ This code is production-ready and includes TypeScript types, responsive design, and accessibility features. | |
| </p> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| </section> | |
| ); | |
| } |