| <!DOCTYPE html> |
| <html lang="en"> |
|
|
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>{{ title }} — Code Example</title> |
|
|
| <link |
| href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Plus+Jakarta+Sans:wght@300;400;600;700;800&display=swap" |
| rel="stylesheet"> |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet" /> |
|
|
| <style> |
| :root { |
| |
| --primary: #4f46e5; |
| --primary-light: #818cf8; |
| --accent: #ec4899; |
| --text-main: #0f172a; |
| --text-muted: #64748b; |
| --glass-bg: rgba(255, 255, 255, 0.75); |
| --editor-bg: #1e293b; |
| |
| --editor-border: rgba(255, 255, 255, 0.1); |
| |
| --font-main: 'Plus Jakarta Sans', sans-serif; |
| --font-code: 'JetBrains Mono', monospace; |
| } |
| |
| * { |
| box-sizing: border-box; |
| margin: 0; |
| padding: 0; |
| } |
| |
| body { |
| font-family: var(--font-main); |
| background: #eef2f6; |
| background-image: |
| radial-gradient(at 0% 0%, rgba(99, 102, 241, 0.15) 0px, transparent 50%), |
| radial-gradient(at 100% 100%, rgba(236, 72, 153, 0.15) 0px, transparent 50%); |
| color: var(--text-main); |
| width: 100vw; |
| height: 100vh; |
| overflow: hidden; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| } |
| |
| .slide-wrap { |
| width: 1920px; |
| height: 1080px; |
| background: var(--glass-bg); |
| backdrop-filter: blur(20px); |
| box-shadow: |
| 0 25px 50px -12px rgba(0, 0, 0, 0.1), |
| 0 0 0 1px rgba(255, 255, 255, 0.5) inset; |
| border-radius: 24px; |
| overflow: hidden; |
| position: relative; |
| display: flex; |
| } |
| |
| |
| .sidebar-decor { |
| width: 12px; |
| height: 100%; |
| background: linear-gradient(180deg, var(--primary) 0%, var(--accent) 100%); |
| flex-shrink: 0; |
| } |
| |
| .slide { |
| flex: 1; |
| padding: 80px 100px; |
| display: flex; |
| flex-direction: column; |
| position: relative; |
| z-index: 10; |
| } |
| |
| |
| .header { |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| margin-bottom: 50px; |
| animation: slideInDown 0.6s ease-out; |
| } |
| |
| @keyframes slideInDown { |
| from { |
| opacity: 0; |
| transform: translateY(-30px); |
| } |
| |
| to { |
| opacity: 1; |
| transform: translateY(0); |
| } |
| } |
| |
| .header-accent { |
| height: 6px; |
| width: 240px; |
| background: linear-gradient(90deg, #4f46e5 0%, #818cf8 50%, transparent 100%); |
| border-radius: 4px; |
| } |
| |
| .title-section { |
| margin-bottom: 40px; |
| animation: slideInLeft 0.7s ease-out 0.2s both; |
| } |
| |
| @keyframes slideInLeft { |
| from { |
| opacity: 0; |
| transform: translateX(-40px); |
| } |
| |
| to { |
| opacity: 1; |
| transform: translateX(0); |
| } |
| } |
| |
| .main-title { |
| font-size: 64px; |
| line-height: 1.1; |
| font-weight: 800; |
| color: var(--text-main); |
| letter-spacing: -0.03em; |
| margin-bottom: 16px; |
| } |
| |
| .subtitle { |
| font-size: 28px; |
| color: var(--text-muted); |
| font-weight: 500; |
| } |
| |
| |
| .code-window { |
| flex: 1; |
| background: var(--editor-bg); |
| border-radius: 16px; |
| border: 1px solid var(--editor-border); |
| box-shadow: |
| 0 20px 40px rgba(0, 0, 0, 0.2), |
| 0 0 0 1px rgba(255, 255, 255, 0.05) inset; |
| overflow: hidden; |
| display: flex; |
| flex-direction: column; |
| animation: fadeIn 0.7s ease-out 0.5s both; |
| } |
| |
| @keyframes fadeIn { |
| from { |
| opacity: 0; |
| transform: translateY(20px); |
| } |
| |
| to { |
| opacity: 1; |
| transform: translateY(0); |
| } |
| } |
| |
| |
| .window-header { |
| padding: 18px 28px; |
| background: rgba(15, 23, 42, 0.6); |
| border-bottom: 1px solid rgba(255, 255, 255, 0.05); |
| display: flex; |
| align-items: center; |
| gap: 16px; |
| } |
| |
| .window-dots { |
| display: flex; |
| gap: 8px; |
| } |
| |
| .dot { |
| width: 12px; |
| height: 12px; |
| border-radius: 50%; |
| } |
| |
| .dot-red { |
| background: #ff5f56; |
| } |
| |
| .dot-yellow { |
| background: #ffbd2e; |
| } |
| |
| .dot-green { |
| background: #27c93f; |
| } |
| |
| .file-name { |
| font-family: var(--font-code); |
| font-size: 14px; |
| color: #94a3b8; |
| font-weight: 500; |
| } |
| |
| .language-badge { |
| margin-left: auto; |
| font-family: var(--font-code); |
| font-size: 12px; |
| color: var(--primary-light); |
| background: rgba(79, 70, 229, 0.15); |
| padding: 4px 12px; |
| border-radius: 6px; |
| text-transform: uppercase; |
| letter-spacing: 0.5px; |
| font-weight: 600; |
| } |
| |
| |
| .code-content { |
| flex: 1; |
| padding: 40px; |
| overflow-y: auto; |
| overflow-x: hidden; |
| position: relative; |
| } |
| |
| |
| .code-content::-webkit-scrollbar { |
| width: 8px; |
| } |
| |
| .code-content::-webkit-scrollbar-track { |
| background: transparent; |
| } |
| |
| .code-content::-webkit-scrollbar-thumb { |
| background: rgba(255, 255, 255, 0.1); |
| border-radius: 4px; |
| } |
| |
| |
| code[class*="language-"], |
| pre[class*="language-"] { |
| font-family: var(--font-code) !important; |
| font-size: 20px !important; |
| line-height: 1.7 !important; |
| text-shadow: none !important; |
| background: transparent !important; |
| margin: 0 !important; |
| padding: 0 !important; |
| } |
| |
| |
| .cursor { |
| display: inline-block; |
| width: 10px; |
| height: 22px; |
| background: var(--accent); |
| vertical-align: middle; |
| margin-left: 3px; |
| opacity: 1; |
| } |
| |
| .cursor.blink { |
| animation: blink 1s infinite; |
| } |
| |
| @keyframes blink { |
| |
| 0%, |
| 49% { |
| opacity: 1; |
| } |
| |
| 50%, |
| 100% { |
| opacity: 0; |
| } |
| } |
| |
| |
| .bg-shape { |
| position: absolute; |
| z-index: 1; |
| opacity: 0.04; |
| pointer-events: none; |
| } |
| |
| .bg-shape-1 { |
| width: 600px; |
| height: 600px; |
| background: radial-gradient(circle, var(--primary) 0%, transparent 70%); |
| top: -200px; |
| right: -200px; |
| } |
| |
| .bg-shape-2 { |
| width: 400px; |
| height: 400px; |
| background: radial-gradient(circle, var(--accent) 0%, transparent 70%); |
| bottom: -150px; |
| left: -100px; |
| } |
| |
| |
| .line-numbers { |
| counter-reset: line; |
| } |
| |
| .line-numbers .line::before { |
| counter-increment: line; |
| content: counter(line); |
| display: inline-block; |
| width: 40px; |
| color: rgba(255, 255, 255, 0.3); |
| text-align: right; |
| margin-right: 24px; |
| user-select: none; |
| } |
| </style> |
| </head> |
|
|
| <body> |
|
|
| <div class="slide-wrap"> |
|
|
| <div class="sidebar-decor"></div> |
|
|
| <div class="bg-shape bg-shape-1"></div> |
| <div class="bg-shape bg-shape-2"></div> |
|
|
| <div class="slide"> |
|
|
| <div class="header"> |
| <div class="header-accent"></div> |
| </div> |
|
|
| <div class="title-section"> |
| <h1 class="main-title">{{ title }}</h1> |
| {% if subtitle %} |
| <p class="subtitle">{{ subtitle }}</p> |
| {% endif %} |
| </div> |
|
|
| <div class="code-window"> |
| <div class="window-header"> |
| <div class="window-dots"> |
| <div class="dot dot-red"></div> |
| <div class="dot dot-yellow"></div> |
| <div class="dot dot-green"></div> |
| </div> |
| <span class="file-name">{{ filename | default('implementation.js') }}</span> |
| <span class="language-badge">{{ language | default('javascript') }}</span> |
| </div> |
|
|
| <div class="code-content" id="scroller"> |
| <pre><code id="code-display" class="language-{{ language | default('javascript') }}"></code><span id="cursor" class="cursor"></span></pre> |
| </div> |
| </div> |
|
|
| </div> |
| </div> |
|
|
| <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script> |
|
|
| <script> |
| |
| const sourceCode = {{ code_source | tojson }}; |
| const typingSpeed = {{ typing_speed | default (25) }}; |
| const highlightInterval = {{ highlight_interval | default (10) }}; |
| |
| |
| const codeDisplay = document.getElementById('code-display'); |
| const scroller = document.getElementById('scroller'); |
| const cursor = document.getElementById('cursor'); |
| |
| let charIndex = 0; |
| let highlightQueued = false; |
| |
| |
| function typeWriter() { |
| if (charIndex < sourceCode.length) { |
| |
| codeDisplay.textContent += sourceCode.charAt(charIndex); |
| |
| |
| |
| const char = sourceCode.charAt(charIndex); |
| const isStructuralChar = ['\n', ';', '{', '}', '(', ')'].includes(char); |
| const isInterval = charIndex % highlightInterval === 0; |
| |
| if ((isStructuralChar || isInterval) && !highlightQueued) { |
| highlightQueued = true; |
| |
| |
| requestAnimationFrame(() => { |
| Prism.highlightElement(codeDisplay); |
| highlightQueued = false; |
| }); |
| } |
| |
| |
| if (scroller.scrollHeight > scroller.clientHeight) { |
| scroller.scrollTop = scroller.scrollHeight; |
| } |
| |
| charIndex++; |
| |
| |
| let delay = typingSpeed; |
| if (char === '\n') delay += 80; |
| if (char === ';') delay += 40; |
| |
| setTimeout(typeWriter, delay); |
| |
| } else { |
| |
| Prism.highlightElement(codeDisplay); |
| |
| |
| cursor.classList.add('blink'); |
| |
| |
| {% if auto_run %} |
| setTimeout(executeCode, 500); |
| {% endif %} |
| } |
| } |
| |
| {% if auto_run %} |
| |
| function executeCode() { |
| console.log("=== Code Execution Started ==="); |
| |
| try { |
| |
| const codeToRun = codeDisplay.textContent; |
| |
| |
| |
| eval(codeToRun); |
| |
| console.log("=== Execution Completed ==="); |
| } catch (error) { |
| console.error("Runtime Error:", error.message); |
| } |
| } |
| {% endif %} |
| |
| |
| window.addEventListener('load', () => { |
| |
| setTimeout(typeWriter, 800); |
| }); |
| |
| |
| if (!{{ auto_run | default ('false') | lower }}) { |
| console.log = () => { }; |
| console.error = () => { }; |
| } |
| </script> |
| </body> |
|
|
| </html> |