/** * ExampleDetailPage — SEO landing page for a single example. * * Route: /examples/:exampleId * * Shows example title, description, category, difficulty and board type with * a CTA to open the example in the simulator. Fully prerenderable at build * time (no browser-only APIs on first render) so every example gets its own * statically-served HTML for search engines. */ import React from 'react'; import { useParams, useNavigate, Link } from 'react-router-dom'; import { exampleProjects } from '../data/examples'; import { AppHeader } from '../components/layout/AppHeader'; import { ExampleThumbnail } from '../components/examples/ExampleThumbnail'; import { useSEO } from '../utils/useSEO'; const DOMAIN = 'https://velxio.dev'; const BOARD_LABELS: Record = { 'arduino-uno': 'Arduino Uno', 'arduino-nano': 'Arduino Nano', 'arduino-mega': 'Arduino Mega', 'raspberry-pi-pico': 'Raspberry Pi Pico (RP2040)', esp32: 'ESP32', 'esp32-c3': 'ESP32-C3', }; const CATEGORY_LABELS: Record = { basics: 'Basics', sensors: 'Sensors', displays: 'Displays', communication: 'Communication', games: 'Games', robotics: 'Robotics', }; const DIFFICULTY_COLOR: Record = { beginner: '#4caf50', intermediate: '#ff9800', advanced: '#f44336', }; export const ExampleDetailPage: React.FC = () => { const { exampleId } = useParams<{ exampleId: string }>(); const navigate = useNavigate(); const example = exampleId ? exampleProjects.find((e) => e.id === exampleId) : null; // SEO — called unconditionally (hooks must not be inside conditionals). const seoTitle = example ? `${example.title} — Free Arduino Simulator Example | Velxio` : 'Example Not Found | Velxio'; const boardLabel = example ? (BOARD_LABELS[example.boardType ?? 'arduino-uno'] ?? example.boardType ?? 'Arduino Uno') : ''; const seoDescription = example ? `${example.description}. Run this ${boardLabel} example free in your browser — no install, no account required.` : 'This example was not found.'; useSEO({ title: seoTitle, description: seoDescription, url: `${DOMAIN}/examples/${exampleId ?? ''}`, }); const handleOpen = () => { if (!example) return; // Navigate to the live editor URL — ExampleEditorPage owns the load. // Pinning the URL means the user can refresh / share the link and // keep the example loaded. navigate(`/example/${example.id}`); }; // ── 404 state ─────────────────────────────────────────────────────────────── if (!example) { return (
404
Example "{exampleId}" not found.
Browse all examples
); } const diffColor = DIFFICULTY_COLOR[example.difficulty] ?? '#999'; const categoryLabel = CATEGORY_LABELS[example.category] ?? example.category; return (
{/* Breadcrumb */} {/* Card */}
{/* Circuit preview */}
{/* Badges */}
{categoryLabel} {example.difficulty} {boardLabel}
{/* Title */}

{example.title}

{/* Description */}

{example.description}

{/* What you'll learn section */}

What you'll simulate

  • Real {boardLabel} emulation — cycle-accurate, no hardware needed
  • {example.components.length > 0 ? `${example.components.length} interactive component${example.components.length > 1 ? 's' : ''} on the canvas` : 'Interactive simulation canvas'}
  • {example.libraries && example.libraries.length > 0 && (
  • Auto-installs: {example.libraries.join(', ')}
  • )}
  • Serial Monitor included — see output in real time
{/* CTA */}
← Back to examples
{/* JSON-LD structured data */}