Cdlane4998's picture
Upload components/LiveDemo.js with huggingface_hub
2e6bb43 verified
Raw
History Blame Contribute Delete
7.38 kB
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>
);
}