feat(help): add interactive student tutorial with video and integrated help page
- Create student tutorial documentation in Markdown with updated asset paths - Add backend routes to serve rendered help content and assets via JSON API - Implement frontend /help route using SvelteKit for professional rendering - Add "Bantuan" link to the navigation bar with custom styling - Generate tutorial screenshots and a demo video with virtual cursor and subtitles - Configure Tailscale and Vite proxies to support the new help routing - Add automated video generation scripts and assetsmaster
2
app.py
|
|
@ -32,11 +32,13 @@ def create_app():
|
||||||
from routes.compile import compile_bp
|
from routes.compile import compile_bp
|
||||||
from routes.lessons import lessons_bp
|
from routes.lessons import lessons_bp
|
||||||
from routes.progress import progress_bp
|
from routes.progress import progress_bp
|
||||||
|
from routes.help import help_bp
|
||||||
|
|
||||||
app.register_blueprint(auth_bp)
|
app.register_blueprint(auth_bp)
|
||||||
app.register_blueprint(compile_bp)
|
app.register_blueprint(compile_bp)
|
||||||
app.register_blueprint(lessons_bp)
|
app.register_blueprint(lessons_bp)
|
||||||
app.register_blueprint(progress_bp)
|
app.register_blueprint(progress_bp)
|
||||||
|
app.register_blueprint(help_bp)
|
||||||
|
|
||||||
# ── Startup tasks ─────────────────────────────────────────────────
|
# ── Startup tasks ─────────────────────────────────────────────────
|
||||||
initialize_tokens_file(get_lesson_names())
|
initialize_tokens_file(get_lesson_names())
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,10 @@
|
||||||
{$themeDark ? '\u2600\uFE0F' : '\uD83C\uDF19'}
|
{$themeDark ? '\u2600\uFE0F' : '\uD83C\uDF19'}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<a href="/help" target="_blank" class="nav-help-link" title="Panduan Penggunaan">
|
||||||
|
Bantuan
|
||||||
|
</a>
|
||||||
|
|
||||||
{#if $authLoggedIn}
|
{#if $authLoggedIn}
|
||||||
<span class="user-label">{$authStudentName}</span>
|
<span class="user-label">{$authStudentName}</span>
|
||||||
<button class="btn btn-danger btn-xs" onclick={() => auth.logout()}>Keluar</button>
|
<button class="btn btn-danger btn-xs" onclick={() => auth.logout()}>Keluar</button>
|
||||||
|
|
@ -202,6 +206,21 @@
|
||||||
padding: 0.25rem 0.6rem;
|
padding: 0.25rem 0.6rem;
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
|
.nav-help-link {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.25rem 0.6rem;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background 0.15s;
|
||||||
|
}
|
||||||
|
.nav-help-link:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.15);
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Modal ──────────────────────────────────────── */
|
/* ── Modal ──────────────────────────────────────── */
|
||||||
.modal-overlay {
|
.modal-overlay {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<script lang="ts">
|
||||||
|
let { data } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>{data.help.title} - Elemes LMS</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<div class="help-container">
|
||||||
|
<header class="help-header">
|
||||||
|
<h1>{data.help.title}</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="help-content prose">
|
||||||
|
{@html data.help.content}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.help-container {
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem 1rem;
|
||||||
|
}
|
||||||
|
.help-header {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
border-bottom: 2px solid var(--color-border);
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
.help-header h1 {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.help-content {
|
||||||
|
background: var(--color-bg-secondary);
|
||||||
|
padding: 2rem;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.help-header h1 {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
}
|
||||||
|
.help-content {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
export async function load({ fetch }) {
|
||||||
|
const res = await fetch('/api/help');
|
||||||
|
if (!res.ok) {
|
||||||
|
throw error(res.status, 'Gagal memuat panduan');
|
||||||
|
}
|
||||||
|
const data = await res.json();
|
||||||
|
return {
|
||||||
|
help: data
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
# Panduan Penggunaan LMS Elemes (Sinau-C)
|
||||||
|
|
||||||
|
Selamat datang di LMS Elemes! Panduan ini akan membantu kamu memahami cara menggunakan platform ini untuk belajar pemrograman C, elektronika, dan Arduino secara interaktif.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Memasukkan Token
|
||||||
|
Untuk mulai belajar, kamu perlu masuk menggunakan token yang diberikan oleh gurumu.
|
||||||
|
- Buka halaman utama LMS
|
||||||
|
- Klik tombol **"Masuk"** di pojok kanan atas.
|
||||||
|
- Masukkan token kamu (contoh: `dummy_token_12345`) dan klik **"Masuk"**.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Navigasi ke Kursus
|
||||||
|
Setelah berhasil masuk, nama kamu akan muncul di pojok kanan atas. Kamu bisa melihat daftar materi yang tersedia di halaman Home.
|
||||||
|
- Klik pada **Kartu Materi** (misalnya: "Hello, World!") untuk masuk ke halaman pelajaran.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Pengoperasian Halaman Lesson (Mode Desktop)
|
||||||
|
Halaman pelajaran terbagi menjadi dua bagian utama: **Materi** di sisi kiri dan **Workspace** di sisi kanan.
|
||||||
|
|
||||||
|
### Tab Workspace
|
||||||
|
Workspace memiliki beberapa tab sesuai dengan materi yang sedang dipelajari:
|
||||||
|
- **Info**: Menampilkan tujuan pembelajaran dan prasyarat.
|
||||||
|
- **Exercise**: Instruksi tugas yang harus diselesaikan.
|
||||||
|
- **C / Python**: Editor kode untuk menulis program.
|
||||||
|
- **Circuit / Arduino**: Simulator rangkaian atau mikrokontroler.
|
||||||
|
- **Output**: Hasil eksekusi program kamu.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Floating & Docked Mode
|
||||||
|
Kamu bisa merubah tampilan Workspace agar lebih fleksibel:
|
||||||
|
- **Floating Mode**: Klik ikon kotak bertumpuk (**⊞**) di pojok kanan atas Workspace untuk menjadikannya jendela melayang.
|
||||||
|
- **Docker Workspace**: Klik ikon panah bawah (**▽**) untuk meminimalkan Workspace, atau klik ikon kotak (**⊡**) untuk mengembalikannya ke posisi semula (docked).
|
||||||
|
- **Resize**: Tarik ikon di pojok kiri atas jendela melayang (**◳**) untuk mengubah ukuran Workspace.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Pemrograman C dan Python
|
||||||
|
Di tab **C** atau **Python**, kamu bisa langsung menulis kode.
|
||||||
|
- Klik tombol **"▶ Run"** untuk menjalankan kodemu.
|
||||||
|
- Hasilnya akan muncul di tab **Output**.
|
||||||
|
- Gunakan tombol **"Reset"** jika ingin mengulang kode ke kondisi awal.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Simulasi CircuitJS
|
||||||
|
Untuk materi elektronika, kamu bisa menggunakan simulator **CircuitJS**.
|
||||||
|
- Pilih tab **"Circuit"**.
|
||||||
|
- Kamu bisa melihat simulasi aliran arus secara *real-time*.
|
||||||
|
- Kamu bisa berinteraksi dengan komponen (seperti saklar) langsung di dalam simulator.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Simulasi Velxio (Arduino)
|
||||||
|
Untuk materi Arduino, platform ini menyediakan simulator **Velxio**.
|
||||||
|
- Pilih tab **"Arduino"**.
|
||||||
|
- Tulis kode `.ino` kamu di sisi kiri editor.
|
||||||
|
- Klik tombol **"Run"** (ikon petir/play) untuk mengunggah kode ke Arduino virtual.
|
||||||
|
- Perhatikan komponen di sisi kanan (seperti LED) yang akan bereaksi sesuai kodemu.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Memantau Keberhasilan Exercise
|
||||||
|
Platform ini akan otomatis mendeteksi jika kamu telah berhasil menyelesaikan tugas.
|
||||||
|
- Jika tugas selesai, akan muncul tanda centang hijau (**✓ Selesai**) di samping judul materi.
|
||||||
|
- Kamu juga bisa melihat status penyelesaian di halaman Home (Dashboard) pada setiap kartu materi.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
*Selamat belajar dan selamat bereksperimen!*
|
||||||
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
|
@ -20,8 +20,8 @@ services:
|
||||||
elemes-frontend:
|
elemes-frontend:
|
||||||
build: ./frontend
|
build: ./frontend
|
||||||
image: lms-c-frontend:latest
|
image: lms-c-frontend:latest
|
||||||
ports:
|
# ports:
|
||||||
- 3000:3000
|
# - 3000:3000
|
||||||
environment:
|
environment:
|
||||||
- ORIGIN=http://localhost:3000
|
- ORIGIN=http://localhost:3000
|
||||||
- API_BACKEND=http://elemes:5000
|
- API_BACKEND=http://elemes:5000
|
||||||
|
|
@ -77,3 +77,4 @@ volumes:
|
||||||
networks:
|
networks:
|
||||||
main_network:
|
main_network:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
network_mode: service:elemes-ts
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import os
|
||||||
|
import markdown as md
|
||||||
|
from flask import Blueprint, jsonify, send_from_directory
|
||||||
|
from services.lesson_service import MD_EXTENSIONS
|
||||||
|
|
||||||
|
help_bp = Blueprint('help_api', __name__)
|
||||||
|
|
||||||
|
HELP_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'help')
|
||||||
|
|
||||||
|
@help_bp.route('/help')
|
||||||
|
def get_help_content():
|
||||||
|
file_path = os.path.join(HELP_DIR, 'TUTORIAL_SISWA.md')
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
return jsonify({'error': 'Help content not found'}), 404
|
||||||
|
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
# Render markdown to HTML
|
||||||
|
html_content = md.markdown(content, extensions=MD_EXTENSIONS)
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'title': 'Panduan Penggunaan',
|
||||||
|
'content': html_content
|
||||||
|
})
|
||||||
|
|
||||||
|
@help_bp.route('/help/asset/<path:filename>')
|
||||||
|
def serve_help_asset(filename):
|
||||||
|
return send_from_directory(os.path.join(HELP_DIR, 'asset'), filename)
|
||||||