- Dark/light preview theme toggle with localStorage persistence and dark CSS injection in preview, export, and embed - External CSS/JS resources modal with per-fiddle persistence in options column, injected as link/script tags - Keyboard shortcuts cheat sheet modal (? button or ? key) - Mobile-responsive CSS with breakpoints at 768px and 480px for both editor and browse pages
162 lines
6.5 KiB
HTML
162 lines
6.5 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Fiddle</title>
|
|
<link rel="stylesheet" href="/css/style.css">
|
|
</head>
|
|
<body>
|
|
<header class="toolbar">
|
|
<div class="toolbar-left">
|
|
<a href="/" class="logo" title="Browse fiddles">Fiddle</a>
|
|
<select id="framework-mode">
|
|
<option value="html-css-js">HTML / CSS / JS</option>
|
|
<option value="typescript">TypeScript</option>
|
|
<option value="react">React (JSX)</option>
|
|
<option value="react-ts">React + TS</option>
|
|
<option value="vue">Vue</option>
|
|
<option value="svelte">Svelte</option>
|
|
<option value="markdown">Markdown</option>
|
|
<option value="wasm">WASM</option>
|
|
</select>
|
|
<input type="text" id="title-input" placeholder="Untitled" spellcheck="false">
|
|
<select id="layout-mode">
|
|
<option value="default">Default</option>
|
|
<option value="top-bottom">Top / Bottom</option>
|
|
<option value="editor-only">Editor Only</option>
|
|
<option value="preview-only">Preview Only</option>
|
|
</select>
|
|
<select id="keybinding-mode">
|
|
<option value="default">Default</option>
|
|
<option value="vim">Vim</option>
|
|
<option value="emacs">Emacs</option>
|
|
</select>
|
|
</div>
|
|
<div class="toolbar-right">
|
|
<div class="tags-input-wrap">
|
|
<input type="text" id="tags-input" placeholder="Add tags..." list="tags-datalist" spellcheck="false">
|
|
<datalist id="tags-datalist"></datalist>
|
|
<div id="tags-display" class="tags-display"></div>
|
|
</div>
|
|
<select id="preview-theme" title="Preview background theme">
|
|
<option value="light">Light</option>
|
|
<option value="dark">Dark</option>
|
|
</select>
|
|
<button id="btn-resources" class="btn-secondary" title="External CSS/JS resources">Resources</button>
|
|
<button id="btn-shortcuts" class="btn-secondary" title="Keyboard shortcuts (?)" aria-label="Keyboard shortcuts">?</button>
|
|
<label class="tailwind-toggle" title="Enable Tailwind CSS">
|
|
<input type="checkbox" id="tailwind-checkbox">
|
|
Tailwind
|
|
</label>
|
|
<label class="listed-toggle" title="Show in browse page">
|
|
<input type="checkbox" id="listed-checkbox" checked>
|
|
Listed
|
|
</label>
|
|
<label class="auto-run-toggle" title="Auto-run on change">
|
|
<input type="checkbox" id="auto-run-checkbox" checked>
|
|
Auto
|
|
</label>
|
|
<button id="btn-run" title="Run (Ctrl+Enter)">Run</button>
|
|
<button id="btn-save" title="Save (Ctrl+S)">Save</button>
|
|
<button id="btn-fork" title="Fork">Fork</button>
|
|
<button id="btn-export" title="Export standalone HTML" class="btn-secondary">Export</button>
|
|
<button id="btn-qr" title="QR code" class="btn-secondary">QR</button>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="grid">
|
|
<div class="panel panel-editor">
|
|
<div class="tab-bar" id="tab-bar"></div>
|
|
<div id="editor-area" class="editor-area"></div>
|
|
<div id="vim-status-bar" class="vim-status-bar"></div>
|
|
</div>
|
|
<div class="divider divider-col" id="divider-col"></div>
|
|
<div class="panel panel-preview">
|
|
<div class="panel-label">Preview</div>
|
|
<iframe id="preview-frame" sandbox="allow-scripts allow-same-origin"></iframe>
|
|
</div>
|
|
<div class="divider divider-row" id="divider-row"></div>
|
|
<div class="panel panel-console">
|
|
<div class="panel-label">Console <button id="btn-clear-console" class="btn-small">Clear</button></div>
|
|
<div id="console-output"></div>
|
|
</div>
|
|
</main>
|
|
|
|
<div id="resources-modal" class="modal-overlay hidden">
|
|
<div class="modal-content" style="min-width:360px">
|
|
<div class="modal-header">
|
|
<span>External Resources</span>
|
|
<button id="resources-modal-close" class="btn-small">×</button>
|
|
</div>
|
|
<div class="resource-inputs">
|
|
<div class="resource-row">
|
|
<input type="text" id="resource-css-input" placeholder="CSS URL (e.g. https://fonts.googleapis.com/...)">
|
|
<button id="btn-add-css" class="btn-small">+ CSS</button>
|
|
</div>
|
|
<div class="resource-row">
|
|
<input type="text" id="resource-js-input" placeholder="JS URL (e.g. https://cdn.jsdelivr.net/...)">
|
|
<button id="btn-add-js" class="btn-small">+ JS</button>
|
|
</div>
|
|
</div>
|
|
<div id="resource-list" class="resource-list"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="shortcuts-modal" class="modal-overlay hidden">
|
|
<div class="modal-content" style="min-width:380px">
|
|
<div class="modal-header">
|
|
<span>Keyboard Shortcuts</span>
|
|
<button id="shortcuts-modal-close" class="btn-small">×</button>
|
|
</div>
|
|
<table class="shortcuts-table">
|
|
<tbody>
|
|
<tr><td><kbd>Ctrl/Cmd</kbd> + <kbd>Enter</kbd></td><td>Run code</td></tr>
|
|
<tr><td><kbd>Ctrl/Cmd</kbd> + <kbd>S</kbd></td><td>Save fiddle</td></tr>
|
|
<tr><td><kbd>?</kbd></td><td>Show shortcuts</td></tr>
|
|
<tr class="shortcuts-divider"><td colspan="2">Keybinding Modes</td></tr>
|
|
<tr><td><kbd>Vim</kbd></td><td>Full vim keybindings (select in toolbar)</td></tr>
|
|
<tr><td><kbd>Emacs</kbd></td><td>Full emacs keybindings (select in toolbar)</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="qr-modal" class="modal-overlay hidden">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<span>Share via QR Code</span>
|
|
<button id="qr-modal-close" class="btn-small">×</button>
|
|
</div>
|
|
<div id="qr-canvas"></div>
|
|
<div id="qr-url" class="qr-url"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="share-toast" class="toast hidden"></div>
|
|
|
|
<script>
|
|
// Monaco AMD loader
|
|
const MONACO_CDN = 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2';
|
|
const script = document.createElement('script');
|
|
script.src = `${MONACO_CDN}/min/vs/loader.min.js`;
|
|
script.onload = () => {
|
|
require.config({ paths: { vs: `${MONACO_CDN}/min/vs` } });
|
|
// Cross-origin worker proxy
|
|
window.MonacoEnvironment = {
|
|
getWorkerUrl: function (_workerId, label) {
|
|
return `data:text/javascript;charset=utf-8,${encodeURIComponent(`
|
|
self.MonacoEnvironment = { baseUrl: '${MONACO_CDN}/min/' };
|
|
importScripts('${MONACO_CDN}/min/vs/base/worker/workerMain.js');
|
|
`)}`;
|
|
}
|
|
};
|
|
require(['vs/editor/editor.main'], () => {
|
|
import('/js/app.js');
|
|
});
|
|
};
|
|
document.head.appendChild(script);
|
|
</script>
|
|
</body>
|
|
</html>
|