diff --git a/README.md b/README.md index f9993b7..fb3846d 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,14 @@ Local Arduino emulator with code editor and visual simulator. +## Support This Project + +If you find this project helpful, please consider giving it a star! Your support helps the project grow and motivates continued development. + +[![GitHub stars](https://img.shields.io/github/stars/yourusername/wokwi_clon?style=social)](https://github.com/yourusername/wokwi_clon/stargazers) + +Every star counts and helps make this project better! + ## Features - ✅ Code editor with syntax highlighting (Monaco Editor) @@ -16,11 +24,11 @@ Local Arduino emulator with code editor and visual simulator. ## Screenshots -Arduino Emulator - Editor and Simulator +![Arduino Emulator - Editor and Simulator](doc/img1.png) *Arduino emulator with Monaco code editor and visual simulator with wokwi-elements* -Arduino Emulator - Component Properties and Wire Editing +![Arduino Emulator - Component Properties and Wire Editing](doc/img2.png) *Interactive component properties dialog and segment-based wire editing* diff --git a/frontend/src/App.css b/frontend/src/App.css index 4dfe18f..96736bf 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -22,6 +22,23 @@ body { border-bottom: 2px solid #007acc; } +.header-content { + display: flex; + justify-content: space-between; + align-items: center; +} + +.header-title h1 { + font-size: 24px; + margin-bottom: 5px; + color: #007acc; +} + +.header-title p { + font-size: 14px; + color: #aaa; +} + .app-header h1 { font-size: 24px; margin-bottom: 5px; @@ -33,6 +50,26 @@ body { color: #aaa; } +.examples-link { + padding: 10px 20px; + background-color: #007acc; + color: #fff; + text-decoration: none; + border-radius: 6px; + font-size: 14px; + font-weight: 500; + transition: all 0.2s; + display: flex; + align-items: center; + gap: 8px; +} + +.examples-link:hover { + background-color: #005a9e; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 122, 204, 0.3); +} + .app-container { flex: 1; display: flex; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index a5d541f..31ca039 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,27 +1,16 @@ -import { CodeEditor } from './components/editor/CodeEditor'; -import { EditorToolbar } from './components/editor/EditorToolbar'; -import { SimulatorCanvas } from './components/simulator/SimulatorCanvas'; +import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom'; +import { EditorPage } from './pages/EditorPage'; +import { ExamplesPage } from './pages/ExamplesPage'; import './App.css'; function App() { return ( -
-
-

Arduino Emulator

-

Local Arduino IDE & Simulator

-
-
-
- -
- -
-
-
- -
-
-
+ + + } /> + } /> + + ); } diff --git a/frontend/src/components/examples/ExamplesGallery.css b/frontend/src/components/examples/ExamplesGallery.css new file mode 100644 index 0000000..316780b --- /dev/null +++ b/frontend/src/components/examples/ExamplesGallery.css @@ -0,0 +1,241 @@ +/** + * Examples Gallery Styles + */ + +.examples-gallery { + min-height: 100vh; + background-color: #1e1e1e; + color: #fff; + padding: 40px 20px; +} + +.examples-nav { + max-width: 1200px; + margin: 0 auto 20px auto; +} + +.back-link { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 8px 16px; + background-color: #2d2d2d; + color: #fff; + text-decoration: none; + border-radius: 6px; + border: 1px solid #444; + font-size: 14px; + transition: all 0.2s; +} + +.back-link:hover { + background-color: #3d3d3d; + border-color: #007acc; + color: #007acc; +} + +.examples-header { + text-align: center; + margin-bottom: 40px; +} + +.examples-header h1 { + font-size: 48px; + margin: 0 0 10px 0; + font-weight: 300; +} + +.examples-header p { + font-size: 20px; + color: #aaa; + margin: 0; +} + +/* Filters */ +.examples-filters { + max-width: 1200px; + margin: 0 auto 40px auto; + display: flex; + flex-direction: column; + gap: 20px; +} + +.filter-group { + display: flex; + align-items: center; + gap: 15px; +} + +.filter-group label { + font-size: 14px; + color: #aaa; + min-width: 80px; +} + +.filter-buttons { + display: flex; + gap: 10px; + flex-wrap: wrap; +} + +.filter-button { + padding: 8px 16px; + border: 1px solid #444; + background-color: #2d2d2d; + color: #fff; + border-radius: 6px; + cursor: pointer; + font-size: 14px; + transition: all 0.2s; +} + +.filter-button:hover { + background-color: #3d3d3d; + border-color: #555; +} + +.filter-button.active { + background-color: #007acc; + border-color: #007acc; + color: #fff; +} + +/* Examples Grid */ +.examples-grid { + max-width: 1200px; + margin: 0 auto; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 24px; +} + +.example-card { + background-color: #2d2d2d; + border: 1px solid #444; + border-radius: 8px; + overflow: hidden; + cursor: pointer; + transition: all 0.3s; + display: flex; + flex-direction: column; +} + +.example-card:hover { + transform: translateY(-4px); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5); + border-color: #007acc; +} + +.example-thumbnail { + width: 100%; + height: 200px; + background-color: #1e1e1e; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} + +.example-thumbnail img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.example-placeholder { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 10px; + width: 100%; + height: 100%; +} + +.example-icon { + font-size: 64px; + opacity: 0.5; +} + +.example-components-count { + font-size: 12px; + color: #888; +} + +.example-info { + padding: 16px; + display: flex; + flex-direction: column; + gap: 8px; + flex: 1; +} + +.example-title { + font-size: 18px; + font-weight: 600; + margin: 0; + color: #fff; +} + +.example-description { + font-size: 14px; + color: #aaa; + margin: 0; + line-height: 1.5; + flex: 1; +} + +.example-meta { + display: flex; + align-items: center; + gap: 10px; + margin-top: auto; +} + +.example-difficulty { + padding: 4px 10px; + border-radius: 12px; + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + color: #1e1e1e; +} + +.example-category { + font-size: 12px; + color: #888; + text-transform: capitalize; +} + +/* Empty State */ +.examples-empty { + max-width: 1200px; + margin: 60px auto; + text-align: center; + color: #888; + font-size: 16px; +} + +/* Responsive */ +@media (max-width: 768px) { + .examples-header h1 { + font-size: 32px; + } + + .examples-header p { + font-size: 16px; + } + + .examples-grid { + grid-template-columns: 1fr; + } + + .filter-group { + flex-direction: column; + align-items: flex-start; + } + + .filter-group label { + min-width: auto; + } +} diff --git a/frontend/src/components/examples/ExamplesGallery.tsx b/frontend/src/components/examples/ExamplesGallery.tsx new file mode 100644 index 0000000..37922c7 --- /dev/null +++ b/frontend/src/components/examples/ExamplesGallery.tsx @@ -0,0 +1,167 @@ +/** + * Examples Gallery Component + * + * Displays a gallery of example Arduino projects that users can load and run + */ + +import React, { useState } from 'react'; +import { Link } from 'react-router-dom'; +import { exampleProjects, getCategories, type ExampleProject } from '../../data/examples'; +import './ExamplesGallery.css'; + +interface ExamplesGalleryProps { + onLoadExample: (example: ExampleProject) => void; +} + +export const ExamplesGallery: React.FC = ({ onLoadExample }) => { + const [selectedCategory, setSelectedCategory] = useState( + 'all' + ); + const [selectedDifficulty, setSelectedDifficulty] = useState< + ExampleProject['difficulty'] | 'all' + >('all'); + + const categories = getCategories(); + + // Filter examples based on selected category and difficulty + const filteredExamples = exampleProjects.filter((example) => { + const categoryMatch = selectedCategory === 'all' || example.category === selectedCategory; + const difficultyMatch = + selectedDifficulty === 'all' || example.difficulty === selectedDifficulty; + return categoryMatch && difficultyMatch; + }); + + const getCategoryIcon = (category: ExampleProject['category']): string => { + const icons: Record = { + basics: '💡', + sensors: '📡', + displays: '📺', + communication: '📶', + games: '🎮', + robotics: '🤖', + }; + return icons[category]; + }; + + const getDifficultyColor = (difficulty: ExampleProject['difficulty']): string => { + const colors: Record = { + beginner: '#4ade80', + intermediate: '#fbbf24', + advanced: '#f87171', + }; + return colors[difficulty]; + }; + + return ( +
+
+ + ← Back to Editor + +
+
+

Featured Projects

+

Explore and run example Arduino projects

+
+ + {/* Filters */} +
+
+ +
+ + {categories.map((category) => ( + + ))} +
+
+ +
+ +
+ + + + +
+
+
+ + {/* Examples Grid */} +
+ {filteredExamples.map((example) => ( +
onLoadExample(example)} + > +
+ {example.thumbnail ? ( + {example.title} + ) : ( +
+ {getCategoryIcon(example.category)} + + {example.components.length} component{example.components.length !== 1 ? 's' : ''} + +
+ )} +
+
+

{example.title}

+

{example.description}

+
+ + {example.difficulty} + + + {getCategoryIcon(example.category)} {example.category} + +
+
+
+ ))} +
+ + {filteredExamples.length === 0 && ( +
+

No examples found with the selected filters

+
+ )} +
+ ); +}; diff --git a/frontend/src/data/examples.ts b/frontend/src/data/examples.ts new file mode 100644 index 0000000..9de1c98 --- /dev/null +++ b/frontend/src/data/examples.ts @@ -0,0 +1,611 @@ +/** + * Arduino Example Projects + * + * Collection of example projects that users can load and run + */ + +export interface ExampleProject { + id: string; + title: string; + description: string; + category: 'basics' | 'sensors' | 'displays' | 'communication' | 'games' | 'robotics'; + difficulty: 'beginner' | 'intermediate' | 'advanced'; + code: string; + components: Array<{ + type: string; + id: string; + x: number; + y: number; + properties: Record; + }>; + wires: Array<{ + id: string; + start: { componentId: string; pinName: string }; + end: { componentId: string; pinName: string }; + color: string; + }>; + thumbnail?: string; +} + +export const exampleProjects: ExampleProject[] = [ + { + id: 'blink-led', + title: 'Blink LED', + description: 'Classic Arduino blink example - toggle an LED on and off', + category: 'basics', + difficulty: 'beginner', + code: `// Blink LED Example +// Toggles the built-in LED on pin 13 + +void setup() { + pinMode(13, OUTPUT); +} + +void loop() { + digitalWrite(13, HIGH); + delay(1000); + digitalWrite(13, LOW); + delay(1000); +}`, + components: [ + { + type: 'wokwi-arduino-uno', + id: 'arduino-uno', + x: 100, + y: 100, + properties: {}, + }, + ], + wires: [], + }, + { + id: 'traffic-light', + title: 'Traffic Light', + description: 'Simulate a traffic light with red, yellow, and green LEDs', + category: 'basics', + difficulty: 'beginner', + code: `// Traffic Light Simulator +// Red -> Yellow -> Green -> Yellow -> Red + +const int RED_PIN = 13; +const int YELLOW_PIN = 12; +const int GREEN_PIN = 11; + +void setup() { + pinMode(RED_PIN, OUTPUT); + pinMode(YELLOW_PIN, OUTPUT); + pinMode(GREEN_PIN, OUTPUT); +} + +void loop() { + // Red light + digitalWrite(RED_PIN, HIGH); + delay(3000); + digitalWrite(RED_PIN, LOW); + + // Yellow light + digitalWrite(YELLOW_PIN, HIGH); + delay(1000); + digitalWrite(YELLOW_PIN, LOW); + + // Green light + digitalWrite(GREEN_PIN, HIGH); + delay(3000); + digitalWrite(GREEN_PIN, LOW); + + // Yellow light again + digitalWrite(YELLOW_PIN, HIGH); + delay(1000); + digitalWrite(YELLOW_PIN, LOW); +}`, + components: [ + { + type: 'wokwi-arduino-uno', + id: 'arduino-uno', + x: 100, + y: 100, + properties: {}, + }, + { + type: 'wokwi-led', + id: 'led-red', + x: 400, + y: 100, + properties: { color: 'red', pin: 13 }, + }, + { + type: 'wokwi-led', + id: 'led-yellow', + x: 400, + y: 200, + properties: { color: 'yellow', pin: 12 }, + }, + { + type: 'wokwi-led', + id: 'led-green', + x: 400, + y: 300, + properties: { color: 'green', pin: 11 }, + }, + ], + wires: [ + { + id: 'wire-red', + start: { componentId: 'arduino-uno', pinName: '13' }, + end: { componentId: 'led-red', pinName: 'A' }, + color: '#ff0000', + }, + { + id: 'wire-yellow', + start: { componentId: 'arduino-uno', pinName: '12' }, + end: { componentId: 'led-yellow', pinName: 'A' }, + color: '#ffaa00', + }, + { + id: 'wire-green', + start: { componentId: 'arduino-uno', pinName: '11' }, + end: { componentId: 'led-green', pinName: 'A' }, + color: '#00ff00', + }, + ], + }, + { + id: 'button-led', + title: 'Button Control', + description: 'Control an LED with a pushbutton', + category: 'basics', + difficulty: 'beginner', + code: `// Button LED Control +// Press button to turn LED on + +const int BUTTON_PIN = 2; +const int LED_PIN = 13; + +void setup() { + pinMode(BUTTON_PIN, INPUT_PULLUP); + pinMode(LED_PIN, OUTPUT); +} + +void loop() { + int buttonState = digitalRead(BUTTON_PIN); + + if (buttonState == LOW) { + digitalWrite(LED_PIN, HIGH); + } else { + digitalWrite(LED_PIN, LOW); + } +}`, + components: [ + { + type: 'wokwi-arduino-uno', + id: 'arduino-uno', + x: 100, + y: 100, + properties: {}, + }, + { + type: 'wokwi-pushbutton', + id: 'button-1', + x: 400, + y: 100, + properties: {}, + }, + { + type: 'wokwi-led', + id: 'led-1', + x: 400, + y: 250, + properties: { color: 'red', pin: 13 }, + }, + ], + wires: [ + { + id: 'wire-button', + start: { componentId: 'arduino-uno', pinName: '2' }, + end: { componentId: 'button-1', pinName: '1.L' }, + color: '#00aaff', + }, + { + id: 'wire-led', + start: { componentId: 'arduino-uno', pinName: '13' }, + end: { componentId: 'led-1', pinName: 'A' }, + color: '#ff0000', + }, + ], + }, + { + id: 'fade-led', + title: 'Fade LED', + description: 'Smoothly fade an LED using PWM', + category: 'basics', + difficulty: 'beginner', + code: `// Fade LED with PWM +// Smoothly fade LED brightness + +const int LED_PIN = 9; // PWM pin + +int brightness = 0; +int fadeAmount = 5; + +void setup() { + pinMode(LED_PIN, OUTPUT); +} + +void loop() { + analogWrite(LED_PIN, brightness); + + brightness += fadeAmount; + + if (brightness <= 0 || brightness >= 255) { + fadeAmount = -fadeAmount; + } + + delay(30); +}`, + components: [ + { + type: 'wokwi-arduino-uno', + id: 'arduino-uno', + x: 100, + y: 100, + properties: {}, + }, + { + type: 'wokwi-led', + id: 'led-1', + x: 400, + y: 150, + properties: { color: 'blue', pin: 9 }, + }, + ], + wires: [ + { + id: 'wire-led', + start: { componentId: 'arduino-uno', pinName: '9' }, + end: { componentId: 'led-1', pinName: 'A' }, + color: '#0000ff', + }, + ], + }, + { + id: 'serial-hello', + title: 'Serial Hello World', + description: 'Send messages through serial communication', + category: 'communication', + difficulty: 'beginner', + code: `// Serial Communication Example +// Send messages to Serial Monitor + +void setup() { + Serial.begin(9600); + Serial.println("Hello, Arduino!"); + Serial.println("System initialized"); +} + +void loop() { + Serial.print("Uptime: "); + Serial.print(millis() / 1000); + Serial.println(" seconds"); + delay(2000); +}`, + components: [ + { + type: 'wokwi-arduino-uno', + id: 'arduino-uno', + x: 100, + y: 100, + properties: {}, + }, + ], + wires: [], + }, + { + id: 'rgb-led', + title: 'RGB LED Colors', + description: 'Cycle through colors with an RGB LED', + category: 'basics', + difficulty: 'intermediate', + code: `// RGB LED Color Cycling +// Display different colors + +const int RED_PIN = 9; +const int GREEN_PIN = 10; +const int BLUE_PIN = 11; + +void setup() { + pinMode(RED_PIN, OUTPUT); + pinMode(GREEN_PIN, OUTPUT); + pinMode(BLUE_PIN, OUTPUT); +} + +void setColor(int red, int green, int blue) { + analogWrite(RED_PIN, red); + analogWrite(GREEN_PIN, green); + analogWrite(BLUE_PIN, blue); +} + +void loop() { + // Red + setColor(255, 0, 0); + delay(1000); + + // Green + setColor(0, 255, 0); + delay(1000); + + // Blue + setColor(0, 0, 255); + delay(1000); + + // Yellow + setColor(255, 255, 0); + delay(1000); + + // Cyan + setColor(0, 255, 255); + delay(1000); + + // Magenta + setColor(255, 0, 255); + delay(1000); + + // White + setColor(255, 255, 255); + delay(1000); +}`, + components: [ + { + type: 'wokwi-arduino-uno', + id: 'arduino-uno', + x: 100, + y: 100, + properties: {}, + }, + { + type: 'wokwi-rgb-led', + id: 'rgb-led-1', + x: 400, + y: 150, + properties: {}, + }, + ], + wires: [ + { + id: 'wire-red', + start: { componentId: 'arduino-uno', pinName: '9' }, + end: { componentId: 'rgb-led-1', pinName: 'R' }, + color: '#ff0000', + }, + { + id: 'wire-green', + start: { componentId: 'arduino-uno', pinName: '10' }, + end: { componentId: 'rgb-led-1', pinName: 'G' }, + color: '#00ff00', + }, + { + id: 'wire-blue', + start: { componentId: 'arduino-uno', pinName: '11' }, + end: { componentId: 'rgb-led-1', pinName: 'B' }, + color: '#0000ff', + }, + ], + }, + { + id: 'simon-says', + title: 'Simon Says Game', + description: 'Memory game with LEDs and buttons', + category: 'games', + difficulty: 'advanced', + code: `// Simon Says Game +// Memory game with 4 LEDs and buttons + +const int LED_PINS[] = {8, 9, 10, 11}; +const int BUTTON_PINS[] = {2, 3, 4, 5}; +const int NUM_LEDS = 4; + +int sequence[100]; +int sequenceLength = 0; +int currentStep = 0; + +void setup() { + Serial.begin(9600); + + for (int i = 0; i < NUM_LEDS; i++) { + pinMode(LED_PINS[i], OUTPUT); + pinMode(BUTTON_PINS[i], INPUT_PULLUP); + } + + randomSeed(analogRead(A0)); + newGame(); +} + +void newGame() { + sequenceLength = 1; + currentStep = 0; + addToSequence(); + playSequence(); +} + +void addToSequence() { + sequence[sequenceLength - 1] = random(0, NUM_LEDS); +} + +void playSequence() { + for (int i = 0; i < sequenceLength; i++) { + flashLED(sequence[i]); + delay(500); + } +} + +void flashLED(int led) { + digitalWrite(LED_PINS[led], HIGH); + delay(300); + digitalWrite(LED_PINS[led], LOW); +} + +void loop() { + for (int i = 0; i < NUM_LEDS; i++) { + if (digitalRead(BUTTON_PINS[i]) == LOW) { + flashLED(i); + + if (i == sequence[currentStep]) { + currentStep++; + if (currentStep == sequenceLength) { + delay(1000); + sequenceLength++; + currentStep = 0; + addToSequence(); + playSequence(); + } + } else { + // Wrong button - game over + for (int j = 0; j < 3; j++) { + for (int k = 0; k < NUM_LEDS; k++) { + digitalWrite(LED_PINS[k], HIGH); + } + delay(200); + for (int k = 0; k < NUM_LEDS; k++) { + digitalWrite(LED_PINS[k], LOW); + } + delay(200); + } + newGame(); + } + + delay(300); + while (digitalRead(BUTTON_PINS[i]) == LOW); + } + } +}`, + components: [ + { + type: 'wokwi-arduino-uno', + id: 'arduino-uno', + x: 100, + y: 100, + properties: {}, + }, + { + type: 'wokwi-led', + id: 'led-red', + x: 450, + y: 100, + properties: { color: 'red', pin: 8 }, + }, + { + type: 'wokwi-led', + id: 'led-green', + x: 550, + y: 100, + properties: { color: 'green', pin: 9 }, + }, + { + type: 'wokwi-led', + id: 'led-blue', + x: 450, + y: 200, + properties: { color: 'blue', pin: 10 }, + }, + { + type: 'wokwi-led', + id: 'led-yellow', + x: 550, + y: 200, + properties: { color: 'yellow', pin: 11 }, + }, + { + type: 'wokwi-pushbutton', + id: 'button-red', + x: 450, + y: 300, + properties: {}, + }, + { + type: 'wokwi-pushbutton', + id: 'button-green', + x: 550, + y: 300, + properties: {}, + }, + { + type: 'wokwi-pushbutton', + id: 'button-blue', + x: 450, + y: 400, + properties: {}, + }, + { + type: 'wokwi-pushbutton', + id: 'button-yellow', + x: 550, + y: 400, + properties: {}, + }, + ], + wires: [ + { + id: 'wire-led-red', + start: { componentId: 'arduino-uno', pinName: '8' }, + end: { componentId: 'led-red', pinName: 'A' }, + color: '#ff0000', + }, + { + id: 'wire-led-green', + start: { componentId: 'arduino-uno', pinName: '9' }, + end: { componentId: 'led-green', pinName: 'A' }, + color: '#00ff00', + }, + { + id: 'wire-led-blue', + start: { componentId: 'arduino-uno', pinName: '10' }, + end: { componentId: 'led-blue', pinName: 'A' }, + color: '#0000ff', + }, + { + id: 'wire-led-yellow', + start: { componentId: 'arduino-uno', pinName: '11' }, + end: { componentId: 'led-yellow', pinName: 'A' }, + color: '#ffaa00', + }, + { + id: 'wire-button-red', + start: { componentId: 'arduino-uno', pinName: '2' }, + end: { componentId: 'button-red', pinName: '1.L' }, + color: '#00aaff', + }, + { + id: 'wire-button-green', + start: { componentId: 'arduino-uno', pinName: '3' }, + end: { componentId: 'button-green', pinName: '1.L' }, + color: '#00aaff', + }, + { + id: 'wire-button-blue', + start: { componentId: 'arduino-uno', pinName: '4' }, + end: { componentId: 'button-blue', pinName: '1.L' }, + color: '#00aaff', + }, + { + id: 'wire-button-yellow', + start: { componentId: 'arduino-uno', pinName: '5' }, + end: { componentId: 'button-yellow', pinName: '1.L' }, + color: '#00aaff', + }, + ], + }, +]; + +// Get examples by category +export function getExamplesByCategory(category: ExampleProject['category']): ExampleProject[] { + return exampleProjects.filter((example) => example.category === category); +} + +// Get example by ID +export function getExampleById(id: string): ExampleProject | undefined { + return exampleProjects.find((example) => example.id === id); +} + +// Get all categories +export function getCategories(): ExampleProject['category'][] { + return ['basics', 'sensors', 'displays', 'communication', 'games', 'robotics']; +} diff --git a/frontend/src/pages/EditorPage.tsx b/frontend/src/pages/EditorPage.tsx new file mode 100644 index 0000000..bfeb389 --- /dev/null +++ b/frontend/src/pages/EditorPage.tsx @@ -0,0 +1,41 @@ +/** + * Editor Page Component + * + * Main editor and simulator page + */ + +import React from 'react'; +import { Link } from 'react-router-dom'; +import { CodeEditor } from '../components/editor/CodeEditor'; +import { EditorToolbar } from '../components/editor/EditorToolbar'; +import { SimulatorCanvas } from '../components/simulator/SimulatorCanvas'; +import '../App.css'; + +export const EditorPage: React.FC = () => { + return ( +
+
+
+
+

Arduino Emulator

+

Local Arduino IDE & Simulator

+
+ + 📚 Browse Examples + +
+
+
+
+ +
+ +
+
+
+ +
+
+
+ ); +}; diff --git a/frontend/src/pages/ExamplesPage.tsx b/frontend/src/pages/ExamplesPage.tsx new file mode 100644 index 0000000..c96f758 --- /dev/null +++ b/frontend/src/pages/ExamplesPage.tsx @@ -0,0 +1,66 @@ +/** + * Examples Page Component + * + * Displays the examples gallery + */ + +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import { ExamplesGallery } from '../components/examples/ExamplesGallery'; +import { useEditorStore } from '../store/useEditorStore'; +import { useSimulatorStore } from '../store/useSimulatorStore'; +import type { ExampleProject } from '../data/examples'; + +export const ExamplesPage: React.FC = () => { + const navigate = useNavigate(); + const { setCode } = useEditorStore(); + const { setComponents, setWires } = useSimulatorStore(); + + const handleLoadExample = (example: ExampleProject) => { + console.log('Loading example:', example.title); + + // Load the code into the editor + setCode(example.code); + + // Load components into the simulator + // Convert component type to metadataId (e.g., 'wokwi-led' -> 'led') + setComponents( + example.components.map((comp) => ({ + id: comp.id, + metadataId: comp.type.replace('wokwi-', ''), + x: comp.x, + y: comp.y, + properties: comp.properties, + })) + ); + + // Load wires (need to convert to full wire format with positions) + // For now, just set empty wires - wire positions will be calculated when components are loaded + const wiresWithPositions = example.wires.map((wire) => ({ + id: wire.id, + start: { + componentId: wire.start.componentId, + pinName: wire.start.pinName, + x: 0, // Will be calculated by SimulatorCanvas + y: 0, + }, + end: { + componentId: wire.end.componentId, + pinName: wire.end.pinName, + x: 0, + y: 0, + }, + color: wire.color, + controlPoints: [], + isValid: true, + signalType: 'digital' as const, + })); + + setWires(wiresWithPositions); + + // Navigate to the editor + navigate('/'); + }; + + return ; +}; diff --git a/frontend/src/store/useSimulatorStore.ts b/frontend/src/store/useSimulatorStore.ts index 81b3ee6..e0c54cb 100644 --- a/frontend/src/store/useSimulatorStore.ts +++ b/frontend/src/store/useSimulatorStore.ts @@ -44,12 +44,14 @@ interface SimulatorState { removeComponent: (id: string) => void; updateComponent: (id: string, updates: Partial) => void; updateComponentState: (id: string, state: boolean) => void; + setComponents: (components: Component[]) => void; // Wire management (Phase 1) addWire: (wire: Wire) => void; removeWire: (wireId: string) => void; updateWire: (wireId: string, updates: Partial) => void; setSelectedWire: (wireId: string | null) => void; + setWires: (wires: Wire[]) => void; // Wire creation (Phase 2) startWireCreation: (endpoint: WireEndpoint) => void; @@ -220,6 +222,10 @@ export const useSimulatorStore = create((set, get) => { })); }, + setComponents: (components) => { + set({ components }); + }, + // Wire management actions addWire: (wire) => { set((state) => ({ @@ -246,6 +252,10 @@ export const useSimulatorStore = create((set, get) => { set({ selectedWireId: wireId }); }, + setWires: (wires) => { + set({ wires }); + }, + // Wire creation actions (Phase 2) startWireCreation: (endpoint) => { set({