Spaces:
Running
Running
File size: 4,055 Bytes
a383d0e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
import { useState, useEffect } from 'react';
export default function DemoSelector({ onDemoSelect, currentDemo }) {
const [demos, setDemos] = useState([]);
const [categories, setCategories] = useState([]);
const [loading, setLoading] = useState(true);
const [selectedCategory, setSelectedCategory] = useState('all');
useEffect(() => {
fetch('/demos.json')
.then(res => res.json())
.then(data => {
setDemos(data.demos);
setCategories(data.categories);
setLoading(false);
})
.catch(err => {
console.error('Failed to load demos:', err);
setLoading(false);
});
}, []);
const filteredDemos = selectedCategory === 'all'
? demos
: demos.filter(demo => demo.category === selectedCategory);
if (loading) {
return (
<div className="flex items-center justify-center h-64">
<div className="text-lg text-gray-600">Loading demos...</div>
</div>
);
}
return (
<div className="p-6">
<h2 className="text-2xl font-bold text-gray-900 mb-6">Choose a Demo</h2>
{/* Category Filter */}
<div className="mb-6">
<div className="flex flex-wrap gap-2">
<button
className={`px-4 py-2 rounded-md text-sm font-medium transition-colors ${
selectedCategory === 'all'
? 'bg-blue-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
onClick={() => setSelectedCategory('all')}
>
All Categories
</button>
{categories.map(category => (
<button
key={category.id}
className={`px-4 py-2 rounded-md text-sm font-medium transition-colors ${
selectedCategory === category.id
? 'bg-blue-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
onClick={() => setSelectedCategory(category.id)}
>
{category.name}
</button>
))}
</div>
</div>
{/* Demo Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredDemos.map(demo => (
<div
key={demo.id}
className={`bg-white rounded-lg shadow-md hover:shadow-lg transition-shadow cursor-pointer border-2 ${
currentDemo?.id === demo.id ? 'border-blue-500' : 'border-transparent'
}`}
onClick={() => onDemoSelect(demo)}
>
<div className="aspect-video bg-gray-200 rounded-t-lg overflow-hidden">
<img
src={demo.thumbnail}
alt={demo.name}
className="w-full h-full object-cover"
onError={(e) => {
e.target.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgdmlld0JveD0iMCAwIDMwMCAyMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIzMDAiIGhlaWdodD0iMjAwIiBmaWxsPSIjRjNGNEY2Ii8+Cjx0ZXh0IHg9IjE1MCIgeT0iMTAwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjOUI5QkEwIiBmb250LWZhbWlseT0iQXJpYWwiIGZvbnQtc2l6ZT0iMTQiPkltYWdlIE5vdCBGb3VuZDwvdGV4dD4KPC9zdmc+';
}}
/>
</div>
<div className="p-4">
<div className="mb-2">
<h3 className="text-lg font-semibold text-gray-900">{demo.name}</h3>
</div>
<p className="text-gray-600 text-sm mb-3">{demo.description}</p>
<div className="flex items-center justify-between text-sm text-gray-500">
<span>⏱️ {demo.estimatedTime}</span>
<span>📋 {demo.steps} steps</span>
</div>
</div>
</div>
))}
</div>
{filteredDemos.length === 0 && (
<div className="text-center py-12">
<div className="text-gray-500 text-lg">No demos found in this category</div>
</div>
)}
</div>
);
} |