diff --git a/examples/content/button_input_arduino.md b/examples/content/button_input_arduino.md
index ce7a9d0..e979be8 100644
--- a/examples/content/button_input_arduino.md
+++ b/examples/content/button_input_arduino.md
@@ -150,32 +150,20 @@ void loop() {
{
"type": "led",
"id": "led-builtin",
- "x": 956.2066448009604,
- "y": -15.285273464964305,
+ "x": 188,
+ "y": -158,
"rotation": 0,
"props": {
"color": "red",
"pin": 13,
- "state": false,
- "value": false
- }
- },
- {
- "type": "resistor",
- "id": "resistor-1776299815587-z0q0jzny8",
- "x": 808.6031046903261,
- "y": 44.96592399354325,
- "rotation": 0,
- "props": {
- "value": false,
"state": false
}
},
{
"type": "pushbutton",
- "id": "pushbutton-1776299852057-07xh6qh7g",
- "x": 829.2414304859469,
- "y": 230.19576790585754,
+ "id": "pushbutton-1778378142489-v899irppo",
+ "x": 300,
+ "y": 59,
"rotation": 0,
"props": {
"color": "red",
@@ -183,10 +171,33 @@ void loop() {
"label": "",
"xray": false
}
+ },
+ {
+ "type": "resistor",
+ "id": "resistor-1778378159414-9y3d8f1uk",
+ "x": 409,
+ "y": 68,
+ "rotation": 0,
+ "props": {
+ "value": "1000"
+ }
+ },
+ {
+ "type": "resistor",
+ "id": "resistor-1778378205248-h9g1m1wml",
+ "x": 114,
+ "y": -89,
+ "rotation": 0,
+ "props": {
+ "value": "1000"
+ }
}
],
- "wires": []
+ "wires": [
+
+ ]
}
+
---END_VELXIO_CIRCUIT---
---EXPECTED_SERIAL_OUTPUT---
@@ -196,9 +207,9 @@ PRESSED
---EXPECTED_WIRING---
{
"wires": [
- {
+ {
"start": {
- "componentId": "resistor-1776299815587-z0q0jzny8",
+ "componentId": "resistor-1778378205248-h9g1m1wml",
"pinName": "2"
},
"end": {
@@ -206,6 +217,16 @@ PRESSED
"pinName": "A"
}
},
+ {
+ "start": {
+ "componentId": "resistor-1778378205248-h9g1m1wml",
+ "pinName": "1"
+ },
+ "end": {
+ "componentId": "arduino-uno",
+ "pinName": "13"
+ }
+ },
{
"start": {
"componentId": "arduino-uno",
@@ -218,22 +239,22 @@ PRESSED
},
{
"start": {
- "componentId": "resistor-1776299815587-z0q0jzny8",
- "pinName": "1"
+ "componentId": "arduino-uno",
+ "pinName": "5V"
},
"end": {
- "componentId": "arduino-uno",
- "pinName": "13"
+ "componentId": "resistor-1778378159414-9y3d8f1uk",
+ "pinName": "2"
}
},
{
"start": {
- "componentId": "pushbutton-1776299852057-07xh6qh7g",
- "pinName": "1.l"
+ "componentId": "resistor-1778378159414-9y3d8f1uk",
+ "pinName": "1"
},
"end": {
- "componentId": "arduino-uno",
- "pinName": "2"
+ "componentId": "pushbutton-1778378142489-v899irppo",
+ "pinName": "1.r"
}
},
{
@@ -242,8 +263,18 @@ PRESSED
"pinName": "GND.3"
},
"end": {
- "componentId": "pushbutton-1776299852057-07xh6qh7g",
- "pinName": "2.l"
+ "componentId": "pushbutton-1778378142489-v899irppo",
+ "pinName": "2.r"
+ }
+ },
+ {
+ "start": {
+ "componentId": "arduino-uno",
+ "pinName": "2"
+ },
+ "end": {
+ "componentId": "pushbutton-1778378142489-v899irppo",
+ "pinName": "1.r"
}
}
]
diff --git a/frontend/src/lib/components/CodeEditor.svelte b/frontend/src/lib/components/CodeEditor.svelte
index 8afa685..a30a0c2 100644
--- a/frontend/src/lib/components/CodeEditor.svelte
+++ b/frontend/src/lib/components/CodeEditor.svelte
@@ -252,6 +252,7 @@
onDestroy(() => {
cleanupNoPaste?.();
view?.destroy();
+ clearTimeout(saveTimeout);
});
// Recreate editor ONLY when theme actually changes (not on ready/container changes)
diff --git a/frontend/src/routes/lesson/[slug]/+page.svelte b/frontend/src/routes/lesson/[slug]/+page.svelte
index 95b20e0..b3dc0f1 100644
--- a/frontend/src/routes/lesson/[slug]/+page.svelte
+++ b/frontend/src/routes/lesson/[slug]/+page.svelte
@@ -26,9 +26,11 @@
const mgr = new LessonManager();
const float = createFloatingPanel();
- // Sync lesson data when navigating
+ // Initialize manager with lesson data whenever it changes.
$effect(() => {
- if (pageData.lesson) mgr.init(pageData.lesson);
+ if (pageData.lesson) {
+ mgr.init(pageData.lesson);
+ }
});
// Mobile behavior for floating panel
@@ -79,191 +81,193 @@
{mgr.data?.lesson_title ?? 'Pelajaran'} - Elemes LMS
-{#if mgr.data}
-
-
-
e.preventDefault()}
- oncopy={(e) => e.preventDefault()}
- oncut={(e) => e.preventDefault()}
- oncontextmenu={(e) => e.preventDefault()}>
-
- {#if mgr.data.locked}
-
-
🔒
-
-
Pelajaran ini terkunci. Kamu dapat membaca materinya, namun workspace (editor) dinonaktifkan hingga prasyarat selesai.
- {#if mgr.data.missing_prerequisites?.length}
-
- Belum selesai:
- {#each mgr.data.missing_prerequisites as p, i}
-
{mgr.getLessonTitle(p)} {i < mgr.data.missing_prerequisites.length - 1 ? ', ' : ''}
- {/each}
+{#if pageData.lesson}
+ {#key pageData.lesson.filename}
+
+
+
e.preventDefault()}
+ oncopy={(e) => e.preventDefault()}
+ oncut={(e) => e.preventDefault()}
+ oncontextmenu={(e) => e.preventDefault()}>
+
+ {#if mgr.data?.locked}
+
+
🔒
+
+
Pelajaran ini terkunci. Kamu dapat membaca materinya, namun workspace (editor) dinonaktifkan hingga prasyarat selesai.
+ {#if mgr.data.missing_prerequisites?.length}
+
+ Belum selesai:
+ {#each mgr.data.missing_prerequisites as p, i}
+
{mgr.getLessonTitle(p)} {i < mgr.data.missing_prerequisites.length - 1 ? ', ' : ''}
+ {/each}
+
+ {/if}
+
+
+ {/if}
+
+ {#if mgr.isQuizMode}
+
+
+
🫣
+
Materi Disembunyikan
+
Selesaikan atau batalkan kuis untuk melihat materi kembali.
+
mgr.isQuizMode = false}>Batal Kuis
+
+
+ {:else}
+
{@html mgr.data?.lesson_content ?? ''}
+
+ {/if}
+
+
+ {#if float.floating && float.minimized && !mgr.isMobile}
+
▶ Editor
+ {/if}
+
+
+
+
+
+
+
+ {#if mgr.data?.locked}
+
+
+
🔒
+
Workspace Terkunci
+
Selesaikan materi sebelumnya untuk mulai mengerjakan latihan ini.
+
+
+ {/if}
+
+
+ {#if mgr.data?.lesson_info}
+
{@html mgr.data.lesson_info}
+ {/if}
+
+
+
+ {#if mgr.data?.exercise_content}
+
+
Latihan
+ {@html mgr.data.exercise_content}
{/if}
-
- {/if}
- {#if mgr.isQuizMode}
-
-
-
🫣
-
Materi Disembunyikan
-
Selesaikan atau batalkan kuis untuk melihat materi kembali.
-
mgr.isQuizMode = false}>Batal Kuis
-
-
- {:else}
-
{@html mgr.data.lesson_content}
-
- {/if}
-
-
- {#if float.floating && float.minimized && !mgr.isMobile}
-
▶ Editor
- {/if}
-
-
-
-
-
-
-
- {#if mgr.data.locked}
-
-
-
🔒
-
Workspace Terkunci
-
Selesaikan materi sebelumnya untuk mulai mengerjakan latihan ini.
-
-
- {/if}
-
-
- {#if mgr.data.lesson_info}
-
{@html mgr.data.lesson_info}
- {/if}
-
-
-
- {#if mgr.data.exercise_content}
-
-
Latihan
- {@html mgr.data.exercise_content}
+ {#if mgr.data?.active_tabs?.includes('circuit')}
+
+
{/if}
+
+ {#if mgr.isVelxio}
+
+
+
+ {/if}
+
+ {#if mgr.isFlowchart}
+
+
+
+ {/if}
+
+ {#if !mgr.data?.active_tabs?.length || mgr.data.active_tabs.includes('c') || mgr.data.active_tabs.includes('python')}
+
+
+
+ {/if}
+
+ {#if mgr.data?.active_tabs?.includes('quiz')}
+
+ mgr.completeLesson(status)}
+ />
+
+ {/if}
+
+
+
+ {#snippet actions()}
+ mgr.handleRunAll()} disabled={mgr.compiling}>
+ {mgr.compiling ? 'Mengevaluasi...' : 'â–¶ Run Keseluruhan'}
+
+ {/snippet}
+
+
- {#if mgr.data.active_tabs?.includes('circuit')}
-
-
-
- {/if}
-
- {#if mgr.isVelxio}
-
-
-
- {/if}
-
- {#if mgr.isFlowchart}
-
-
-
- {/if}
-
- {#if !mgr.data.active_tabs?.length || mgr.data.active_tabs.includes('c') || mgr.data.active_tabs.includes('python')}
-
-
-
- {/if}
-
- {#if mgr.data.active_tabs?.includes('quiz')}
-
- mgr.completeLesson(status)}
- />
-
- {/if}
-
-
-
- {#snippet actions()}
- mgr.handleRunAll()} disabled={mgr.compiling}>
- {mgr.compiling ? 'Mengevaluasi...' : 'â–¶ Run Keseluruhan'}
-
- {/snippet}
-
-
+
-
-
-
+ {/key}
{/if}
diff --git a/frontend/src/routes/lesson/[slug]/CodeTab.svelte b/frontend/src/routes/lesson/[slug]/CodeTab.svelte
index 062ff83..8a351f2 100644
--- a/frontend/src/routes/lesson/[slug]/CodeTab.svelte
+++ b/frontend/src/routes/lesson/[slug]/CodeTab.svelte
@@ -36,7 +36,7 @@
{compiling ? 'Compiling...' : 'â–¶ Run'}
Reset
- {#if data.solution_code && authLoggedIn && lessonCompleted}
+ {#if data?.solution_code && authLoggedIn && lessonCompleted}
{showSolution ? 'Sembunyikan Solusi' : 'Lihat Solusi'}
@@ -57,9 +57,9 @@
{/key}
-{#if (currentLanguage === 'python' ? (data.expected_output_python || data.expected_output) : data.expected_output)}
+{#if (currentLanguage === 'python' ? (data?.expected_output_python || data?.expected_output) : data?.expected_output)}
Expected Output
- {currentLanguage === 'python' ? (data.expected_output_python || data.expected_output) : data.expected_output}
+ {currentLanguage === 'python' ? (data?.expected_output_python || data?.expected_output) : data?.expected_output}
{/if}
diff --git a/frontend/src/routes/lesson/[slug]/lesson.svelte.ts b/frontend/src/routes/lesson/[slug]/lesson.svelte.ts
index c6f521d..423fee1 100644
--- a/frontend/src/routes/lesson/[slug]/lesson.svelte.ts
+++ b/frontend/src/routes/lesson/[slug]/lesson.svelte.ts
@@ -54,7 +54,7 @@ export class LessonManager {
circuitEditor = $state
(null);
flowchartTab = $state(null);
- slug = $derived(get(page).params.slug);
+ get slug() { return get(page).params.slug; }
isVelxio = $derived(this.data?.active_tabs?.includes('velxio') ?? false);
isFlowchart = $derived(this.data?.active_tabs?.includes('flowchart') ?? false);