Files
fiddle/public/js/api.js
root ae8dbafb20 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
2026-02-27 15:50:55 -06:00

121 lines
3.3 KiB
JavaScript

const BASE = '/api/fiddles';
async function request(url, opts = {}) {
const res = await fetch(url, {
headers: { 'Content-Type': 'application/json' },
...opts,
});
if (!res.ok) {
const err = await res.json().catch(() => ({ error: res.statusText }));
throw new Error(err.error || res.statusText);
}
return res.json();
}
export function createFiddle(data) {
return request(BASE, { method: 'POST', body: JSON.stringify(data) });
}
export function loadFiddle(id) {
return request(`${BASE}/${id}`);
}
export function updateFiddle(id, data) {
return request(`${BASE}/${id}`, { method: 'PUT', body: JSON.stringify(data) });
}
export function listFiddles({ q, js_type, tag, page, limit, sort } = {}) {
const params = new URLSearchParams();
if (q) params.set('q', q);
if (js_type) params.set('js_type', js_type);
if (tag) params.set('tag', tag);
if (page) params.set('page', String(page));
if (limit) params.set('limit', String(limit));
if (sort) params.set('sort', sort);
const qs = params.toString();
return request(`${BASE}${qs ? '?' + qs : ''}`);
}
export function listTags() {
return request('/api/tags');
}
// Version history
export function listVersions(id) {
return request(`${BASE}/${id}/versions`);
}
export function getVersion(id, ver) {
return request(`${BASE}/${id}/versions/${ver}`);
}
export function revertVersion(id, ver) {
return request(`${BASE}/${id}/revert/${ver}`, { method: 'POST' });
}
// Slides (presentation mode)
export function listSlides(fiddleId) {
return request(`${BASE}/${fiddleId}/slides`);
}
export function createSlide(fiddleId, data) {
return request(`${BASE}/${fiddleId}/slides`, { method: 'POST', body: JSON.stringify(data) });
}
export function updateSlide(slideId, data) {
return request(`/api/slides/${slideId}`, { method: 'PUT', body: JSON.stringify(data) });
}
export function deleteSlide(slideId) {
return request(`/api/slides/${slideId}`, { method: 'DELETE' });
}
// Gist import
export function importGist(url) {
return request('/api/import/gist', { method: 'POST', body: JSON.stringify({ url }) });
}
// Publishing
export function publishFiddle(id, html) {
return request(`${BASE}/${id}/publish`, { method: 'POST', body: JSON.stringify({ html }) });
}
export function unpublishFiddle(id) {
return request(`${BASE}/${id}/publish`, { method: 'DELETE' });
}
export function getPublishStatus(id) {
return request(`${BASE}/${id}/publish`);
}
// Collections
export function createCollection(data) {
return request('/api/collections', { method: 'POST', body: JSON.stringify(data) });
}
export function listCollections() {
return request('/api/collections');
}
export function getCollection(id) {
return request(`/api/collections/${id}`);
}
export function updateCollection(id, data) {
return request(`/api/collections/${id}`, { method: 'PUT', body: JSON.stringify(data) });
}
export function deleteCollection(id) {
return request(`/api/collections/${id}`, { method: 'DELETE' });
}
export function addToCollection(collectionId, fiddleId) {
return request(`/api/collections/${collectionId}/fiddles`, {
method: 'POST', body: JSON.stringify({ fiddle_id: fiddleId }),
});
}
export function removeFromCollection(collectionId, fiddleId) {
return request(`/api/collections/${collectionId}/fiddles/${fiddleId}`, { method: 'DELETE' });
}