Add Python REPL, instant deploy, Gist import, presentation mode, and CSS visual tools

- Python mode via Pyodide WASM runtime with stdout/stderr console integration
- Publish fiddles to clean /p/:slug URLs as standalone HTML pages
- Import code from GitHub Gist URLs with auto-detection of language/mode
- Presentation mode with slide management, fullscreen viewer, and keyboard nav
- Enable Monaco color decorators for inline CSS color pickers
- Extract reusable generateStandaloneHtml from export module
This commit is contained in:
root
2026-02-27 15:50:55 -06:00
parent 26e232fd41
commit ae8dbafb20
11 changed files with 666 additions and 6 deletions

View File

@@ -19,6 +19,7 @@
<option value="svelte">Svelte</option>
<option value="markdown">Markdown</option>
<option value="wasm">WASM</option>
<option value="python">Python</option>
</select>
<input type="text" id="title-input" placeholder="Untitled" spellcheck="false">
<div class="tags-input-wrap">
@@ -54,6 +55,9 @@
<button id="btn-templates" class="btn-icon" title="Starter templates">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
</button>
<button id="btn-import-gist" class="btn-icon" title="Import from GitHub Gist">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
</button>
<button id="btn-resources" class="btn-icon" title="External resources">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>
</button>
@@ -63,12 +67,18 @@
<button id="btn-embed" class="btn-icon" title="Embed code">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
</button>
<button id="btn-publish" class="btn-icon" title="Publish to clean URL">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/><path d="M12 15l-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/></svg>
</button>
<button id="btn-export" class="btn-icon" title="Export HTML">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
</button>
<button id="btn-collection" class="btn-icon" title="Collections">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
</button>
<button id="btn-presentation" class="btn-icon" title="Presentation mode">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21l4-4 4 4"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
</button>
<button id="btn-qr" class="btn-icon" title="QR code">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="2" width="8" height="8" rx="1"/><rect x="14" y="2" width="8" height="8" rx="1"/><rect x="2" y="14" width="8" height="8" rx="1"/><rect x="14" y="14" width="4" height="4"/><line x1="22" y1="14" x2="22" y2="22"/><line x1="14" y1="22" x2="22" y2="22"/></svg>
</button>
@@ -306,6 +316,38 @@
</div>
</div>
<div id="presentation-modal" class="modal-overlay hidden">
<div class="modal-content" style="min-width:380px">
<div class="modal-header">
<span>Presentation Mode</span>
<button id="presentation-modal-close" class="btn-small">&times;</button>
</div>
<div style="padding:8px 16px;display:flex;gap:8px;align-items:center">
<button id="btn-add-slide" class="btn-small">+ Add Current State as Slide</button>
<span id="slide-count" style="color:var(--text-dim);font-size:12px"></span>
</div>
<div id="slide-list" class="slide-list"></div>
<div style="padding:8px 16px">
<button id="btn-start-presentation" style="width:100%">Start Presentation</button>
</div>
</div>
</div>
<div id="presentation-overlay" class="presentation-overlay hidden">
<div class="pres-header">
<span id="pres-counter" class="pres-counter"></span>
<button id="pres-exit" class="pres-exit-btn">Exit (Esc)</button>
</div>
<div class="pres-content">
<iframe id="pres-preview-frame" class="pres-iframe" sandbox="allow-scripts allow-same-origin"></iframe>
</div>
<div class="pres-footer">
<button id="pres-prev" class="pres-nav-btn">&larr; Prev</button>
<div id="pres-notes" class="pres-notes"></div>
<button id="pres-next" class="pres-nav-btn">Next &rarr;</button>
</div>
</div>
<div id="share-toast" class="toast hidden"></div>
<script>