diff options
| author | Craig Jennings <c@cjennings.net> | 2026-07-19 23:45:24 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-07-19 23:45:24 -0500 |
| commit | 0468fedb23ae34a140b6a5a903adedb4e9873ca5 (patch) | |
| tree | 188151ac2e0e9a27b205cd523c7872028795e5ca /docs/prototypes/2026-07-02-desktop-settings-panel-prototype-4.html | |
| parent | c4b3710b14a47d4c8297322297f217be264349ea (diff) | |
| download | archsetup-0468fedb23ae34a140b6a5a903adedb4e9873ca5.tar.gz archsetup-0468fedb23ae34a140b6a5a903adedb4e9873ca5.zip | |
docs: expand desktop-settings spec and add panel prototypes
I folded the home-handoff control-set decisions into the desktop-settings panel spec. The controls table gains night-light, Do Not Disturb, power profile, lock/suspend actions, scenes, and a wallpaper sub-view. Volume and theme are out of scope, with reasons, and the format pickers move to their own display-format sibling spec (stubbed). The scenes and wallpaper-shape decisions close. The spec stays DRAFT pending UI prototyping.
I added five direction prototypes over a shared engine (tile grid, sectioned rack, scenes-first, instrument cluster, expandable rows) so the layout gets picked against working behavior.
I closed the shipped Next Session Focus work in todo.org: notification loudness, clock right-click dismiss, date-only scrolling, the wired-interface indicator, and best-saved WiFi connect, plus velox boot recovery. The three design-blocked network and audio items stay TODO with their open question recorded.
Diffstat (limited to 'docs/prototypes/2026-07-02-desktop-settings-panel-prototype-4.html')
| -rw-r--r-- | docs/prototypes/2026-07-02-desktop-settings-panel-prototype-4.html | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/docs/prototypes/2026-07-02-desktop-settings-panel-prototype-4.html b/docs/prototypes/2026-07-02-desktop-settings-panel-prototype-4.html new file mode 100644 index 0000000..23d72fb --- /dev/null +++ b/docs/prototypes/2026-07-02-desktop-settings-panel-prototype-4.html @@ -0,0 +1,166 @@ +<!doctype html> +<html lang="en"> +<head> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<title>Desktop Settings — Prototype 4 (instrument cluster)</title> +<link rel="stylesheet" href="desktop-settings-shared.css"> +<style> + /* Instrument cluster: ring gauges for the levels, a rotary deck for power. */ + .gauge-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } + .gauge { + background: var(--well); border: 1px solid var(--line); border-radius: 12px; + padding: 10px; display: flex; flex-direction: column; align-items: center; gap: 6px; + } + .g-ring { + width: 92px; height: 92px; border-radius: 50%; + display: flex; align-items: center; justify-content: center; + position: relative; + } + .g-ring::before { + content: ""; position: absolute; inset: 9px; border-radius: 50%; + background: var(--ground); border: 1px solid var(--plate-edge); + } + .g-val { position: relative; z-index: 1; color: var(--cream); font-size: 20px; font-weight: 700; font-variant-numeric: tabular-nums; } + .g-val .u { color: var(--dim); font-size: 11px; } + .g-name { color: var(--steel); font-size: 10px; text-transform: uppercase; letter-spacing: 0.1em; } + .g-fader { width: 100%; } + .g-fader input[type=range] { + -webkit-appearance:none; appearance:none; width: 100%; height: 5px; border-radius: 5px; + background: var(--ground); border: 1px solid var(--line); outline: none; + } + .g-fader input[type=range]::-webkit-slider-thumb { + -webkit-appearance:none; width: 12px; height: 12px; border-radius: 50%; + background: var(--cream); border: 1px solid var(--gold); cursor: pointer; + } + .rotary { display: flex; align-items: center; gap: 10px; background: var(--well); border: 1px solid var(--line); border-radius: 12px; padding: 8px 12px; } + .rotary .dial { width: 40px; height: 40px; border-radius: 50%; border: 2px solid var(--key-edge); position: relative; background: linear-gradient(180deg,#23211e,#191715); } + .rotary .dial .tick { position: absolute; top: 3px; left: 50%; width: 2px; height: 12px; background: var(--gold); transform-origin: 50% 17px; } + .rotary .opts { display: flex; gap: 6px; flex: 1; } + .rotary .opt { flex: 1; text-align: center; font-size: 11px; color: var(--dim); cursor: pointer; padding: 4px 2px; border-radius: 6px; } + .rotary .opt.cur { color: var(--gold); font-weight: 700; } + .rotary .opt:hover { color: var(--silver); } +</style> +</head> +<body class="ds-stage"> + <div class="ds-caption"> + <b>Direction 4 — Instrument cluster.</b> The most literal control panel: + brightness and keyboard read as needle-ring gauges, power profile is a rotary + selector, toggles are lamp rows. Leans hardest into the faceplate aesthetic. + </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="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")); + +function openWallpaper() { + subview.innerHTML = ""; + subview.appendChild(DS.wallpaperSubview(() => subview.classList.remove("open"))); + subview.classList.add("open"); +} + +function gauge(key) { + const meta = DS.SLIDERS[key]; + const v = DS.state[key]; + const g = h("div", "gauge"); + const ring = h("div", "g-ring"); + ring.style.background = `conic-gradient(var(--gold) ${v * 3.6}deg, #1a1917 0)`; + ring.innerHTML = `<span class="g-val">${v}<span class="u">%</span></span>`; + g.appendChild(ring); + g.appendChild(h("div", "g-name", meta.name)); + const fw = h("div", "g-fader"); + const inp = h("input"); inp.type = "range"; inp.min = meta.floor; inp.max = 100; inp.value = v; + inp.oninput = () => { ring.style.background = `conic-gradient(var(--gold) ${inp.value*3.6}deg, #1a1917 0)`; ring.querySelector(".g-val").innerHTML = `${inp.value}<span class="u">%</span>`; }; + inp.onchange = () => DS.setSlider(key, +inp.value, g); + fw.appendChild(inp); g.appendChild(fw); + return g; +} + +function rotary() { + const r = h("div", "rotary"); + const idx = DS.PROFILES.findIndex((p) => p.id === DS.state.powerprofile); + const dial = h("div", "dial"); + const angle = -50 + idx * 50; // three positions + dial.innerHTML = `<span class="tick" style="transform:translateX(-50%) rotate(${angle}deg)"></span>`; + r.appendChild(dial); + const opts = h("div", "opts"); + DS.PROFILES.forEach((p) => { + const o = h("div", "opt" + (p.id === DS.state.powerprofile ? " cur" : ""), p.label); + o.onclick = () => DS.setProfile(p.id, r); + opts.appendChild(o); + }); + r.appendChild(opts); + return r; +} + +function lampRow(key) { + const meta = DS.TOGGLES[key]; + const on = DS.state[key]; + const el = h("div", "ds-key" + (on ? " on" : "")); + el.innerHTML = + `<span class="ds-lamp ${on ? "gold" : "off"}"></span>` + + `<span class="k-glyph">${meta.glyph}</span>` + + `<span class="k-name">${meta.name}</span>` + + `<span class="k-state">${on ? meta.on : meta.off}</span>`; + el.onclick = () => DS.setToggle(key, el); + return el; +} + +function render() { + body.innerHTML = ""; + const col = h("div", "ds-col"); + + col.appendChild(DS.engrave("Levels")); + const gr = h("div", "gauge-row"); + gr.appendChild(gauge("brightness")); + gr.appendChild(gauge("kbd")); + col.appendChild(gr); + + col.appendChild(DS.engrave("Power profile")); + col.appendChild(rotary()); + + col.appendChild(DS.engrave("Toggles")); + const well = h("div", "ds-well ds-col"); + ["autodim", "nightlight", "touchpad", "mouse", "dnd"].forEach((k) => well.appendChild(lampRow(k))); + if (DS.state.laptop) well.appendChild(lampRow("airplane")); + well.appendChild(lampRow("caffeine")); + col.appendChild(well); + + col.appendChild(DS.engrave("Scenes")); + const scenes = h("div", "ds-grid4"); + Object.keys(DS.SCENES).forEach((n) => scenes.appendChild(DS.sceneKey(n))); + col.appendChild(scenes); + + col.appendChild(DS.engrave("Actions")); + const acts = h("div", "ds-grid3"); + acts.appendChild(DS.actionBtn("Lock", "\u{f033e}", false)); + acts.appendChild(DS.actionBtn("Suspend", "\u{f04b2}", false)); + acts.appendChild(DS.actionBtn("Wallpaper", "\u{f021c}", false, openWallpaper)); + col.appendChild(acts); + + body.appendChild(col); + document.getElementById("scene-sub").textContent = DS.state.scene ? "▶ " + DS.state.scene : ""; +} + +DS.onChange(render); +render(); +</script> +</body> +</html> |
