ajhahn.de
← Flash
HTML 167 lines
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content">
    <title>Flash — Language Tutorial</title>
    <!-- Favicon: the brand bolt in Flash amber (#FBBF24) -->
    <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23FBBF24' d='M13 2 3 14h7l-1 8 10-12h-7l1-8z'/%3E%3C/svg%3E">
    <!-- Fonts: Inter (UI), JetBrains Mono (code), Orbitron (wordmark only) -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Orbitron:wght@400;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
    <!-- CSS Style -->
    <link rel="stylesheet" href="index.css">
    <!-- Marked library for parsing Markdown -->
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
    <!-- Lucide Icons -->
    <script src="https://unpkg.com/lucide@latest"></script>
    <!-- Monaco Editor Loader -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.39.0/min/vs/loader.min.js"></script>
</head>
<body>
    <!-- Pick theme before first paint: 'auto' follows the OS, else the saved manual mode. -->
    <script>
        (function () {
            var mode = localStorage.getItem('theme') || 'auto';
            var theme = mode === 'auto'
                ? (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark')
                : mode;
            document.body.className = theme + '-theme';
        })();
    </script>
    <header class="app-header">
        <div class="header-logo-section">
            <!-- Chapters drawer toggle: only visible on narrow screens -->
            <button id="sidebar-toggle" class="sidebar-toggle-btn" aria-label="Toggle chapters" aria-expanded="false">
                <i data-lucide="menu"></i>
            </button>
            <!-- Brand wordmark: bold neutral "F" + regular gold "lash", set in Orbitron -->
            <h1 class="wordmark"><span class="wordmark-f">F</span><span class="wordmark-lash">lash</span></h1>
            <span class="sub-badge">Tutorial</span>
        </div>
        <div class="header-actions">
            <a href="https://github.com/ajhahnde/Flash" target="_blank" class="github-btn" title="View Source on GitHub">
                <i data-lucide="github"></i><span class="github-label"> GitHub</span>
            </a>
            <button id="theme-toggle" class="theme-toggle-btn" aria-label="Toggle theme">
                <i data-lucide="monitor" class="auto-icon"></i>
                <i data-lucide="sun" class="light-icon"></i>
                <i data-lucide="moon" class="dark-icon"></i>
            </button>
            <button id="layout-toggle" class="layout-toggle-btn" title="Toggle full-width reader / split editor">
                <i data-lucide="columns"></i>
            </button>
        </div>
    </header>

    <div class="app-layout">
        <!-- Dim layer behind the off-canvas chapters drawer (narrow screens) -->
        <div class="sidebar-backdrop" id="sidebar-backdrop"></div>

        <!-- Sidebar Navigation -->
        <aside class="app-sidebar" id="sidebar">
            <div class="sidebar-header">
                <h3>Chapters</h3>
            </div>
            <nav class="sidebar-nav" id="chapters-list">
                <!-- Chapters will be injected dynamically -->
                <div class="nav-loading">Loading chapters...</div>
            </nav>
        </aside>

        <!-- Main Workspace Pane (Split Screen) -->
        <main class="workspace-pane">
            <!-- Left Pane: Content Reader -->
            <section class="content-panel" id="content-panel">
                <div class="content-body" id="chapter-content">
                    <!-- Chapter Markdown content will load here -->
                    <div class="content-loading">
                        <div class="spinner"></div>
                        <p>Loading chapter content...</p>
                    </div>
                </div>
                <div class="content-nav-buttons">
                    <button id="prev-btn" class="nav-btn" disabled>
                        <i data-lucide="arrow-left"></i> Previous
                    </button>
                    <button id="next-btn" class="nav-btn">
                        Next <i data-lucide="arrow-right"></i>
                    </button>
                </div>
            </section>

            <!-- Right Pane: Interactive Live Playground -->
            <section class="playground-panel" id="playground-panel">
                <div class="playground-header">
                    <div class="tab-selectors">
                        <button class="tab-btn active" data-tab="editor">
                            <i data-lucide="edit-3"></i> Flash Editor
                        </button>
                        <button class="tab-btn" data-tab="output">
                            <i data-lucide="file-code"></i> Lowered Zig
                        </button>
                    </div>
                    <div class="playground-actions">
                        <button id="transpile-btn" class="action-btn primary" title="Compile Flash to Zig">
                            <i data-lucide="zap"></i> Transpile
                        </button>
                    </div>
                </div>

                <div class="playground-body">
                    <!-- Flash Code Editor Container -->
                    <div class="tab-content active" id="tab-editor">
                        <div id="editor-container"></div>
                    </div>

                    <!-- Transpiled Output Container -->
                    <div class="tab-content" id="tab-output">
                        <div id="output-container"></div>
                    </div>
                </div>

                <!-- Terminal drawer for warnings/errors -->
                <div class="playground-terminal" id="terminal-drawer">
                    <div class="terminal-header" id="terminal-header">
                        <span class="terminal-title">
                            <i data-lucide="terminal"></i> Compiler Console
                        </span>
                        <div class="terminal-controls">
                            <span id="terminal-status" class="status-indicator idle">Idle</span>
                            <button id="clear-terminal" class="control-btn" title="Clear console">
                                <i data-lucide="trash-2"></i>
                            </button>
                            <i data-lucide="chevron-down" class="terminal-chevron"></i>
                        </div>
                    </div>
                    <div class="terminal-output" id="terminal-body">
                        Welcome to the Flash compiler environment. Write Flash code in the editor and click "Transpile" to lower it to Zig.
                    </div>
                </div>
            </section>
        </main>
    </div>

    <!-- Main Client-Side JS -->
    <script src="index.js"></script>

    <!-- Live reload (dev only): refresh on any change under public/. Probe the
         backend first so a static build (GitHub Pages) never opens an
         EventSource against a 404 and loops on reconnect. -->
    <script>
      (function () {
        fetch('/api/chapters', { method: 'HEAD' })
          .then((res) => {
            if (!res.ok) return;
            const es = new EventSource('/api/livereload');
            es.onmessage = () => location.reload();
            // onerror fires on transient blips; EventSource auto-reconnects via
            // the server's `retry:` hint, so nothing to do here.
          })
          .catch(() => {});
      })();
    </script>
</body>
</html>