/** * Examples Gallery Component * * Displays a gallery of example Arduino projects that users can load and run */ import React, { useState } from 'react'; import { exampleProjects, type ExampleProject } from '../../data/examples'; import './ExamplesGallery.css'; interface ExamplesGalleryProps { onLoadExample: (example: ExampleProject) => void; } // ── Board config ─────────────────────────────────────────────────────────── interface BoardTab { id: string; label: string; color: string; bg: string; } const BOARD_TABS: BoardTab[] = [ { id: 'all', label: 'All Boards', color: '#ffffff', bg: '#444444' }, { id: 'arduino-uno', label: 'Arduino Uno', color: '#ffffff', bg: '#007acc' }, { id: 'arduino-nano', label: 'Arduino Nano', color: '#ffffff', bg: '#0055aa' }, { id: 'arduino-mega', label: 'Arduino Mega', color: '#ffffff', bg: '#003388' }, { id: 'raspberry-pi-pico', label: 'Pico', color: '#ffffff', bg: '#c11c31' }, { id: 'esp32', label: 'ESP32 (Xtensa)', color: '#ffffff', bg: '#e77d11' }, { id: 'esp32-c3', label: 'ESP32-C3 (RISC-V)', color: '#ffffff', bg: '#27ae60' }, { id: 'multi', label: 'Multi-Board', color: '#ffffff', bg: '#7b2d8b' }, ]; function getBoardFilter(example: ExampleProject): string { if (example.boards) return 'multi'; if ((example as any).boardFilter) return (example as any).boardFilter; return example.boardType ?? 'arduino-uno'; } export const ExamplesGallery: React.FC = ({ onLoadExample }) => { const [selectedBoard, setSelectedBoard] = useState('all'); const [selectedCategory, setSelectedCategory] = useState('all'); const [selectedDifficulty, setSelectedDifficulty] = useState('all'); const filteredExamples = exampleProjects.filter((example) => { const boardMatch = selectedBoard === 'all' || getBoardFilter(example) === selectedBoard; const catMatch = selectedCategory === 'all' || example.category === selectedCategory; const diffMatch = selectedDifficulty === 'all' || example.difficulty === selectedDifficulty; return boardMatch && catMatch && diffMatch; }); // Count per board for tab badges const boardCounts: Record = { all: exampleProjects.length }; exampleProjects.forEach((ex) => { const b = getBoardFilter(ex); boardCounts[b] = (boardCounts[b] ?? 0) + 1; }); const getCategoryIcon = (category: ExampleProject['category']): React.ReactNode => { const svgProps = { width: 16, height: 16, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round' as const, strokeLinejoin: 'round' as const, style: { display: 'inline-block', verticalAlign: 'middle', flexShrink: 0 }, }; const icons: Record = { basics: ( ), sensors: ( ), displays: ( ), communication: ( ), games: ( ), robotics: ( ), }; return icons[category]; }; const getDifficultyColor = (difficulty: ExampleProject['difficulty']): string => ({ beginner: '#4ade80', intermediate: '#fbbf24', advanced: '#f87171', }[difficulty]); const getBoardBadge = (example: ExampleProject): { label: string; color: string; bg: string } | null => { const bf = getBoardFilter(example); const tab = BOARD_TABS.find((t) => t.id === bf); if (!tab || tab.id === 'all') return null; return { label: tab.label, color: tab.color, bg: tab.bg }; }; return (

Featured Projects

Explore and run example projects — organized by board

{/* Board tabs */}
{BOARD_TABS.map((tab) => ( ))}
{/* Category + Difficulty filters */}
{(['all', 'basics', 'sensors', 'displays', 'communication', 'games', 'robotics'] as const).map((cat) => ( ))}
{(['all', 'beginner', 'intermediate', 'advanced'] as const).map((diff) => ( ))}
{/* Examples Grid */}
{filteredExamples.map((example) => { const boardBadge = getBoardBadge(example); return (
onLoadExample(example)} >
{example.thumbnail ? ( {example.title} ) : (
{getCategoryIcon(example.category)}
{example.components.length} component{example.components.length !== 1 ? 's' : ''}
{example.wires.length} wire{example.wires.length !== 1 ? 's' : ''}
)}

{example.title}

{example.description}

{example.difficulty} {getCategoryIcon(example.category)} {example.category} {boardBadge && ( {boardBadge.label} )}
); })}
{filteredExamples.length === 0 && (

No examples found with the selected filters

)}
); };