feat(web): dismissable notice, a raised minibuffer, and a styled shell
Three things the user reported after looking at the deployed page, in the order they cost a visitor something. The deployment notice was ten dense lines of configuration reference — ?doc=, ?seed=, ?ws=, wss:// and reverse proxies — above the tile bar, the category tree and the grid on every visit: about 230px of an 820px window. It is now a <details>, so the collapsing is the BROWSER's (keyboard operable, and correct with app.js absent or still loading) and the only thing the page adds is remembering the answer. It starts COLLAPSED, and collapsing withholds nothing: the one fact a first visitor needs — the document lives in this tab, is saved to this browser's private storage and never leaves the machine — is the <summary>, which never collapses. What a stored value means is a decision and lives in shell.js; touching localStorage is a browser API and stays in app.js, wrapped, with every value that is not one of the two spellings read as "unanswered". The minibuffer was a 14px line in the page's bottom-left corner, up to 800px from the cell being typed into. It is now a raised bar over the grid. The CONTENT is untouched — RenderMinibuffer is built from `state.view.mode.minibuffer()`, the same semantic value the TUI draws — so this is position, weight and contrast, and there is no second derivation of what a prompt says. MinibufColor still resolves here exactly as draw.rs::minibuf_fg resolves it for the terminal. style.css stops being "legibility only": layered surfaces, one accent, a filled badge for the mode, chips for the two axis strips, one selection treatment, tabular numerals in the grid, and a focus ring on the one keyboard surface the page has. The palette is the landing page's, so the two read as one product. Asserted (harness/tests/contract.spec.js, Chromium): the notice starts collapsed and remembers, in BOTH directions across a reload; it opens from the keyboard, which the page's own keydown handler must not claim; the minibuffer is inside the viewport, OVERLAPS #grid — the assertion a static bottom bar cannot satisfy — and is larger than body text. Each was proved discriminating by injecting the fault and watching it fail. NOT asserted, and named as such in context/code/clients.md: colour, contrast, spacing, weight, the grouped and multi-level header DOM, either theme, and the localStorage-throws path. Those are argued and read. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
This commit is contained in:
@@ -28,6 +28,30 @@ export function indicator(collapsed) {
|
||||
return collapsed ? "▶" : "▼";
|
||||
}
|
||||
|
||||
/** Where the deployment notice's open/closed state is remembered. Per-viewer
|
||||
* and per-origin by construction: it never reaches Rust and never travels. */
|
||||
export const NOTICE_KEY = "improvise.notice.open";
|
||||
|
||||
/** Whether a visitor who has never answered sees the notice OPEN. It is a
|
||||
* product call and the argument for `false` is in context/code/clients.md. */
|
||||
export const NOTICE_OPEN_BY_DEFAULT = false;
|
||||
|
||||
/** What a stored notice state MEANS. Everything that is not one of the two
|
||||
* spellings — absent, empty, a value from an older page, a string a private
|
||||
* window handed back — is "unanswered", which is the default and not an
|
||||
* error: storage is allowed to forget, and a page that treated forgetting as
|
||||
* a third state would flicker between them. */
|
||||
export function noticeOpen(stored) {
|
||||
if (stored === "open") return true;
|
||||
if (stored === "closed") return false;
|
||||
return NOTICE_OPEN_BY_DEFAULT;
|
||||
}
|
||||
|
||||
/** …and the inverse, so the two spellings have exactly one home. */
|
||||
export function noticeState(open) {
|
||||
return open ? "open" : "closed";
|
||||
}
|
||||
|
||||
// Rough character metrics, used only to turn the window size into an extent.
|
||||
// Being wrong here costs a row of over- or under-fetch, nothing more.
|
||||
export const ROW_PX = 26;
|
||||
|
||||
Reference in New Issue
Block a user