c18510b3c3
The drag-and-drop workspace for building BI122G exercise sheets, served by the Workshop at /projects/exercise-builder. Plain HTML, CSS and ES modules; no build step. It runs entirely in the browser — work in progress lives in localStorage and finished sheets leave as downloads, so nothing is written on the server. This directory is canonical. It began as a deployment target for deploy_builder.sh syncing from the BI122G course folder, and that arrangement has ended; see the README. Includes the sheet's light/dark switch: the stylesheet already carried both themes and followed the reader's system setting, so this adds the control that overrides it — a corner toggle built by sheet.js, applied before first paint by a head script the exporter writes, and hidden in print. The builder's toolbar previews the same attribute on the canvas. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ed5kU3HfZq9dfj7EYj5J2v
69 lines
3.0 KiB
JavaScript
69 lines
3.0 KiB
JavaScript
/* =====================================================================
|
|
Inline markup — a deliberately small syntax, chosen over contenteditable
|
|
because it round-trips exactly and cannot carry pasted styling.
|
|
|
|
`code` → <code>
|
|
[[Ctrl]] → <kbd>
|
|
**strong** → <strong>
|
|
*emphasis* → <em>
|
|
[text](url) → <a href>
|
|
{{part:id}} → "Part 5", resolved from the live numbering
|
|
|
|
parse() and serialise() are inverses; the round-trip test relies on it.
|
|
===================================================================== */
|
|
|
|
const ESC = { '&': '&', '<': '<', '>': '>' };
|
|
const escape = (s) => s.replace(/[&<>]/g, (c) => ESC[c]);
|
|
|
|
/** markup → HTML. `refs` maps a part id to its number. */
|
|
export function parse(text, refs = new Map()) {
|
|
const slots = [];
|
|
const stash = (html) => ` |