diff options
| author | Craig Jennings <c@cjennings.net> | 2026-07-22 15:15:02 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-07-22 15:15:02 -0500 |
| commit | f1c661f50d6af2a115fc1430ae0478f2acef2dec (patch) | |
| tree | b894ea2e14327794bb75671b962f37185cff22ea /docs/prototypes/2026-07-02-desktop-settings-panel-prototype-9.html | |
| parent | f594068bed75302aba50793ccf5e6ce9cf53c7f8 (diff) | |
| download | archsetup-f1c661f50d6af2a115fc1430ae0478f2acef2dec.tar.gz archsetup-f1c661f50d6af2a115fc1430ae0478f2acef2dec.zip | |
docs(settings-panel): seal the prototype arc and open the build
Prototypes P12-P37 land, along with the night-watch and levels-compare pages plus the shared-engine updates and the kit-candidate file. The spec flips from DRAFT through READY to DOING with rewritten implementation phases and seven recorded build findings. The build tasks are filed in todo.org, and phase 1 is closed against the dotfiles commits.
Diffstat (limited to 'docs/prototypes/2026-07-02-desktop-settings-panel-prototype-9.html')
| -rw-r--r-- | docs/prototypes/2026-07-02-desktop-settings-panel-prototype-9.html | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/docs/prototypes/2026-07-02-desktop-settings-panel-prototype-9.html b/docs/prototypes/2026-07-02-desktop-settings-panel-prototype-9.html new file mode 100644 index 0000000..bc15e94 --- /dev/null +++ b/docs/prototypes/2026-07-02-desktop-settings-panel-prototype-9.html @@ -0,0 +1,211 @@ +<!doctype html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<title>Desktop Settings — Prototype 9 (engine room, Dupre Kit)</title> +<link rel="stylesheet" href="desktop-settings-shared.css"> +<style> + /* Dupre Kit token set (from the gallery :root / tokens.json) — the kit + builders read these; they override the shared prototype gold. */ + :root{ + --ground:#151311; --panel:#100f0f; --well:#0a0c0d; --raise:#1a1917; + --silver:#bfc4d0; --cream:#f3e7c5; --steel:#969385; --dim:#7c838a; + --slate:#424f5e; --slate-hi:#54677d; --wash:#2c2f32; + --pass:#74932f; --fail:#cb6b4d; + --phos:#7fe0a0; --phos-dim:#1c3626; --vfd:#63e6c8; + --sevgrn:#57d357; --sevred:#e2543f; --sevoff:#1a1613; + --jewel-r:#ff5b45; --jewel-a:#ffb43a; --jewel-g:#6fce33; + --gold:#e2a038; --gold-hi:#ffbe54; + --amber-grad-top:#f2c76a; --amber-grad-mid:#d29638; --amber-grad-bot:#8f671f; + --amber-edge:#7d5c16; --amber-warn:#f0b552; + --glow-hi:255,190,84; --glow-lo:226,160,56; + --mono:"BerkeleyMono Nerd Font","Berkeley Mono",monospace; + --pulse-rate:1s; + } + .row { display: flex; justify-content: center; align-items: flex-start; gap: 8px; flex-wrap: wrap; } + /* kit spans that carry width/height need block layout outside the gallery */ + .dupre-rotsel, .dupre-keylock { display: inline-block; } + .cellcap { color: var(--steel); font-size: 9px; letter-spacing: 0.14em; text-align: center; margin-top: 2px; } + .flap-well { display: flex; justify-content: center; padding: 6px 0 2px; pointer-events: none; } +</style> +</head> +<body class="ds-stage"> + <div class="ds-caption"> + <b>Direction 9 — Engine room (Dupre Kit).</b> Real kit instruments: the + DRUM ROLLER sets both levels (drag the drums), a split-flap board reads the + scene tuned on the rotary selector, breaker panels carry the toggles, + airplane is a guarded lever, power is an engine-order telegraph (click to + ring the next order). Lock/suspend/wallpaper are arm-to-fire. + </div> + + <div class="ds-bar"><span>19:24</span><span class="gear">⚙</span></div> + + <div class="ds-panel" id="panel"> + <div class="ds-face"> + <span class="glyph">⚙</span> + <span class="title">Settings</span> + <span class="sub" id="scene-sub"></span> + <span class="x">✕</span> + </div> + <div id="body"></div> + <div class="ds-toast" id="toast"></div> + <div class="ds-subview" id="subview"></div> + </div> + +<script src="widgets.js"></script> +<script src="dupre-kit-additions.js"></script> +<script src="desktop-settings-shared.js"></script> +<script> +const h = DS.h; +const body = document.getElementById("body"); +const subview = document.getElementById("subview"); +DS.bindToast(document.getElementById("toast")); + +const SCENES = Object.keys(DS.SCENES); // 4 names +const SEL = ["OFF", "FOCUS", "PRESENT", "BATTERY", "NIGHT"]; // rotary detents +let booting = true; + +function openWallpaper() { + subview.innerHTML = ""; + subview.appendChild(DS.wallpaperSubview(() => subview.classList.remove("open"))); + subview.classList.add("open"); +} + +function sceneOff() { + DS.state.scene = null; + DS.toast("Scene: off", true); + render(); +} + +const debounce = (fn, ms) => { let t; return (...a) => { clearTimeout(t); t = setTimeout(() => fn(...a), ms); }; }; + +// breakerPanel has no set(): sync its hardcoded initial states to DS by +// clicking the transparent hit rects while booting swallows the onChange. +function breakers(names, keys) { + const host = h("div"); + const bp = DUPRE.breakerPanel(host, { + names, + onChange: (states) => { + if (booting) return; + states.forEach((st, i) => { + const on = st === "on"; + if (on !== DS.state[keys[i]]) DS.setToggle(keys[i], host); + }); + }, + }); + const hits = host.querySelectorAll('rect[fill="transparent"]'); + bp.get().forEach((st, i) => { + if ((st === "on") !== DS.state[keys[i]]) + hits[i].dispatchEvent(new MouseEvent("click", { bubbles: true })); + }); + return host; +} + +function render() { + booting = true; + body.innerHTML = ""; + const col = h("div", "ds-col"); + + // Scenes: split-flap reads the tuned scene, rotary selector picks it. + col.appendChild(DS.engrave("Scene board")); + const flapWell = h("div", "flap-well"); + const flap = DUPRE.splitFlap(flapWell, { cells: 8, animate: true, flapMs: 60 }); + const BOARD = { Focus: "FOCUS", Presentation: "PRESENT", Battery: "BATTERY", Night: "NIGHT" }; + flap.setText(DS.state.scene ? BOARD[DS.state.scene] : "STANDBY"); + col.appendChild(flapWell); + const selRow = h("div", "row"); + const selHost = h("div"); + DUPRE.rotarySelector(selHost, { + values: SEL, + index: DS.state.scene ? SCENES.indexOf(DS.state.scene) + 1 : 0, + onChange: (v) => { + if (booting) return; + if (v === "OFF") sceneOff(); + else DS.applyScene(SCENES[SEL.indexOf(v) - 1], selHost); + }, + }); + selRow.appendChild(selHost); + selRow.appendChild(Object.assign(h("div", "cellcap", "SCENE SELECT"), { style: "align-self:center" })); + col.appendChild(selRow); + + // Levels: the drum roller (Craig favorite #1) — drums are 1-10, ×10 = percent. + col.appendChild(DS.engrave("Levels")); + const drumRow = h("div", "row"); + const drumHost = h("div"); + const commitDrums = debounce((vals) => { + const b = Math.round(vals[0]) * 10, k = Math.round(vals[1]) * 10; + if (b !== DS.state.brightness) DS.setSlider("brightness", b, drumHost); + if (k !== DS.state.kbd) DS.setSlider("kbd", k, drumHost); + }, 350); + DUPRE.drumRoller(drumHost, { + title: "LEVELS ×10", + channels: [ + { name: "BRIGHT", v: Math.max(1, Math.round(DS.state.brightness / 10)) }, + { name: "KBD", v: Math.max(1, Math.round(DS.state.kbd / 10)) }, + ], + onChange: (vals) => { if (!booting) commitDrums(vals); }, + }); + drumRow.appendChild(drumHost); + drumRow.appendChild(h("div")); + drumRow.lastChild.appendChild(h("div", "cellcap", "DRAG DRUM")); + col.appendChild(drumRow); + + // Toggles: breaker panels + a guarded lever for airplane. + col.appendChild(DS.engrave("Breakers")); + const brRow = h("div", "row"); + brRow.appendChild(breakers(["DIM", "CAFF", "TPAD", "MOUSE"], ["autodim", "caffeine", "touchpad", "mouse"])); + brRow.appendChild(breakers(["NIGHT", "DND", "WXGEO"], ["nightlight", "dnd", "weathergeo"])); + col.appendChild(brRow); + + if (DS.state.laptop) { + const gRow = h("div", "row"); + const gHost = h("div"); + DUPRE.guardedToggle(gHost, { + on: DS.state.airplane, + onLabel: "AIRPLANE", + offLabel: "RADIO OK", + onChange: (on) => { if (!booting && on !== DS.state.airplane) DS.setToggle("airplane", gHost); }, + }); + gRow.appendChild(gHost); + col.appendChild(gRow); + } + + // Power: engine-order telegraph — ring the next order. + col.appendChild(DS.engrave("Engine order — power")); + const tRow = h("div", "row"); + const tHost = h("div"); + DUPRE.telegraphIndicator(tHost, { + states: ["PERF", "BAL", "SAVER"], + index: DS.PROFILES.findIndex((p) => p.id === DS.state.powerprofile), + onChange: (i) => { if (!booting) DS.setProfile(DS.PROFILES[i].id, tHost); }, + }); + tRow.appendChild(tHost); + col.appendChild(tRow); + + // Actions: arm-to-fire. + col.appendChild(DS.engrave("Actions")); + const aRow = h("div", "row"); + [["LOCK", () => DS.momentary("Lock")], + ["SUSPEND", () => DS.momentary("Suspend")], + ["WALLPAPER", openWallpaper]].forEach(([label, fn]) => { + const host = h("div"); + DUPRE.armButton(host, { + label, + armLabel: label + "?", + onChange: (st) => { if (!booting && st === "fired") fn(); }, + }); + aRow.appendChild(host); + }); + col.appendChild(aRow); + + body.appendChild(col); + document.getElementById("scene-sub").textContent = DS.state.scene ? "▶ " + DS.state.scene : ""; + booting = false; +} + +DS.onChange(render); +render(); +</script> +</body> +</html> |
