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

43
db.js
View File

@@ -59,6 +59,15 @@ try {
db.exec(`ALTER TABLE fiddles ADD COLUMN screenshot TEXT`);
} catch (_) { /* column already exists */ }
// Migration: add publishing columns
try {
db.exec(`ALTER TABLE fiddles ADD COLUMN published_slug TEXT`);
} catch (_) { /* column already exists */ }
try {
db.exec(`ALTER TABLE fiddles ADD COLUMN published_html TEXT`);
} catch (_) { /* column already exists */ }
db.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_fiddles_published_slug ON fiddles(published_slug) WHERE published_slug IS NOT NULL`);
// Version history table
db.exec(`
CREATE TABLE IF NOT EXISTS fiddle_versions (
@@ -95,6 +104,21 @@ db.exec(`
)
`);
// Presentation slides table
db.exec(`
CREATE TABLE IF NOT EXISTS fiddle_slides (
id TEXT PRIMARY KEY,
fiddle_id TEXT NOT NULL,
slide_order INTEGER NOT NULL,
html TEXT DEFAULT '',
css TEXT DEFAULT '',
js TEXT DEFAULT '',
notes TEXT DEFAULT '',
FOREIGN KEY (fiddle_id) REFERENCES fiddles(id) ON DELETE CASCADE
)
`);
db.exec(`CREATE INDEX IF NOT EXISTS idx_slides_fiddle ON fiddle_slides(fiddle_id, slide_order)`);
export const stmts = {
insert: db.prepare(`
INSERT INTO fiddles (id, title, html, css, css_type, js, js_type, listed, options)
@@ -145,6 +169,12 @@ export const stmts = {
// Screenshot
updateScreenshot: db.prepare('UPDATE fiddles SET screenshot = ? WHERE id = ?'),
// Publishing
publishFiddle: db.prepare('UPDATE fiddles SET published_slug = @slug, published_html = @html WHERE id = @id'),
getPublishedFiddle: db.prepare('SELECT id, title, published_html FROM fiddles WHERE published_slug = ?'),
unpublishFiddle: db.prepare('UPDATE fiddles SET published_slug = NULL, published_html = NULL WHERE id = ?'),
getPublishStatus: db.prepare('SELECT published_slug FROM fiddles WHERE id = ?'),
// Collections
insertCollection: db.prepare(`
INSERT INTO collections (id, name, description) VALUES (@id, @name, @description)
@@ -179,6 +209,19 @@ export const stmts = {
JOIN collection_fiddles cf ON cf.collection_id = c.id
WHERE cf.fiddle_id = ?
`),
// Slides
insertSlide: db.prepare(`
INSERT INTO fiddle_slides (id, fiddle_id, slide_order, html, css, js, notes)
VALUES (@id, @fiddle_id, @slide_order, @html, @css, @js, @notes)
`),
listSlides: db.prepare('SELECT * FROM fiddle_slides WHERE fiddle_id = ? ORDER BY slide_order'),
getSlide: db.prepare('SELECT * FROM fiddle_slides WHERE id = ?'),
updateSlide: db.prepare(`
UPDATE fiddle_slides SET html = @html, css = @css, js = @js, notes = @notes, slide_order = @slide_order WHERE id = @id
`),
deleteSlide: db.prepare('DELETE FROM fiddle_slides WHERE id = ?'),
getMaxSlideOrder: db.prepare('SELECT COALESCE(MAX(slide_order), 0) as max_order FROM fiddle_slides WHERE fiddle_id = ?'),
};
/**