6f9cd6cad5
A user reported "I can't expand categories, and the Tile + View UIs don't
work". Driving the assembled site under Chromium separates three different
answers, and the useful finding is that two of the three were missing only
their last layer.
Category expand already worked, by keyboard: Shift-C, j, Enter folds
Command::ToggleCatExpand client-side and the items appear. What does not work
is the mouse, because categoryList builds plain <li>s with no listener — the
whole page's pointer model, filed as improvise-7ybz rather than guessed at.
The tile bar and the view panel had the cache, the keymap, the resolver and
the host round trip, and no DOM. Before this commit the browser held five
TileBarCache entries and both ViewListCache views; Shift-T entered TileSelect,
ArrowRight moved tile_cat_idx, and r/c/p really did move a category between
axes — with nothing on screen to aim them at. RenderModel had no field for
either and index.html had no element. The formula panel was the third of
Panel::ALL in the same state, and is fixed by the same mechanism rather than
left arbitrarily behind.
So RenderModel grows `tiles`, `views` and `formulas`. The two panels follow
the help overlay's rule — an empty list is what says a widget is closed, so
the page asks no question about the mode — and the tile bar is drawn always
with only its *selection* conditional, exactly as src/ui/tile_bar.rs makes it
conditional on AppMode::TileSelect.
The view panel's axis line would have been a second derivation, so
ViewContent::axis_summary moves to improvise_protocol::viewmodel as
view_axis_summary and the TUI's own panel now calls it: one home, both ends
(design-principles §5).
Tests: harness/tests/widgets.spec.js, proved by running it against the
unfixed bundle, where the four new assertions fail on zero elements and the
category one passes — the control that says the keyboard really is being
driven. Two draft assertions were wrong and both corrections are recorded:
Axis::short_label is three columns ("Quarter Pag"), and switching views
leaves the panel open as the TUI does.
Not fixed, filed: improvise-7ybz (no pointer affordance anywhere on the page),
improvise-wsaw (app.js has never read category_panel_open, so #categories is
drawn unconditionally and is now inconsistent with the two panels added here).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
275 lines
4.3 KiB
CSS
275 lines
4.3 KiB
CSS
/* Legibility only. Styling the browser client properly is not improvise-cr3. */
|
|
|
|
:root {
|
|
--bg: #fbfaf7;
|
|
--fg: #1c1b19;
|
|
--line: #d8d4cc;
|
|
--accent: #2f6f4f;
|
|
--selected: #e8e2d4;
|
|
--error: #a8322d;
|
|
color-scheme: light dark;
|
|
}
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
:root {
|
|
--bg: #17181a;
|
|
--fg: #e7e4de;
|
|
--line: #35373b;
|
|
--accent: #7fc4a0;
|
|
--selected: #2c2f33;
|
|
--error: #e2827c;
|
|
}
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: var(--bg);
|
|
color: var(--fg);
|
|
font: 14px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
}
|
|
|
|
header {
|
|
display: flex;
|
|
gap: 1rem;
|
|
align-items: baseline;
|
|
padding: 0.5rem 1rem;
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
|
|
header h1 {
|
|
margin: 0;
|
|
font-size: 1rem;
|
|
color: var(--accent);
|
|
}
|
|
|
|
#mode {
|
|
color: var(--accent);
|
|
}
|
|
|
|
#status {
|
|
margin-left: auto;
|
|
opacity: 0.75;
|
|
}
|
|
|
|
main {
|
|
flex: 1;
|
|
display: flex;
|
|
min-height: 0;
|
|
}
|
|
|
|
#categories {
|
|
width: 15rem;
|
|
flex: none;
|
|
overflow: auto;
|
|
padding: 0.5rem;
|
|
border-right: 1px solid var(--line);
|
|
}
|
|
|
|
#formulas,
|
|
#views {
|
|
width: 18rem;
|
|
flex: none;
|
|
overflow: auto;
|
|
padding: 0.5rem;
|
|
border-right: 1px solid var(--line);
|
|
}
|
|
|
|
#categories ul,
|
|
#formulas ul,
|
|
#views ul {
|
|
margin: 0;
|
|
padding: 0;
|
|
list-style: none;
|
|
}
|
|
|
|
#views .axes {
|
|
margin-left: 0.5rem;
|
|
opacity: 0.6;
|
|
font-size: 0.85em;
|
|
}
|
|
|
|
#views .active .name {
|
|
color: var(--accent);
|
|
}
|
|
|
|
/* The tile bar. One line above the grid, as the TUI draws it. */
|
|
#tiles {
|
|
display: flex;
|
|
gap: 0.25rem;
|
|
padding: 0.25rem 0.5rem;
|
|
border-bottom: 1px solid var(--line);
|
|
overflow-x: auto;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
#tiles .tile {
|
|
padding: 0 0.4rem;
|
|
border: 1px solid var(--line);
|
|
border-radius: 3px;
|
|
font-size: 0.85em;
|
|
}
|
|
|
|
#categories .item {
|
|
padding-left: 1.5rem;
|
|
opacity: 0.85;
|
|
}
|
|
|
|
#categories .selected,
|
|
#formulas .selected,
|
|
#views .selected,
|
|
#tiles .selected,
|
|
td.selected {
|
|
background: var(--selected);
|
|
outline: 1px solid var(--accent);
|
|
}
|
|
|
|
#hint {
|
|
opacity: 0.7;
|
|
font-size: 0.85em;
|
|
}
|
|
|
|
/* A keyboard edit in progress. Left-aligned even in a numeric column,
|
|
because what is drawn is the text being typed rather than a value. */
|
|
td.typing {
|
|
text-align: left;
|
|
outline: 2px solid var(--accent);
|
|
}
|
|
|
|
#grid {
|
|
flex: 1;
|
|
overflow: auto;
|
|
padding: 0.5rem;
|
|
}
|
|
|
|
table {
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
th,
|
|
td {
|
|
border: 1px solid var(--line);
|
|
padding: 0.25rem 0.5rem;
|
|
min-width: 6rem;
|
|
height: 1.75rem;
|
|
text-align: left;
|
|
font-weight: normal;
|
|
}
|
|
|
|
th {
|
|
background: color-mix(in srgb, var(--line) 35%, transparent);
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* A group header, on either axis. The TUI draws these green and bold; the
|
|
glyph is already in the text (`indicator` in app.js). */
|
|
th.group {
|
|
color: var(--accent, inherit);
|
|
font-weight: 700;
|
|
}
|
|
|
|
td.numeric {
|
|
text-align: right;
|
|
}
|
|
|
|
td.error {
|
|
color: var(--error);
|
|
}
|
|
|
|
/* The only affordance that matters: a cell the server said is settable. */
|
|
td.editable {
|
|
cursor: text;
|
|
}
|
|
|
|
td:not(.editable) {
|
|
opacity: 0.7;
|
|
}
|
|
|
|
td input {
|
|
width: 100%;
|
|
border: none;
|
|
padding: 0;
|
|
font: inherit;
|
|
color: inherit;
|
|
background: transparent;
|
|
}
|
|
|
|
/* The page cannot reach a server from a static host, and says so. */
|
|
#backend-notice {
|
|
margin: 0;
|
|
padding: 0.5rem 1rem;
|
|
border-bottom: 1px solid var(--line);
|
|
background: color-mix(in srgb, var(--accent) 10%, transparent);
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
#backend-notice code {
|
|
background: color-mix(in srgb, var(--line) 45%, transparent);
|
|
padding: 0 0.25rem;
|
|
}
|
|
|
|
/* The help overlay. Content is improvise_protocol::help's; this is paint. */
|
|
#help {
|
|
position: fixed;
|
|
inset: 2rem;
|
|
overflow: auto;
|
|
padding: 1rem;
|
|
border: 1px solid var(--accent);
|
|
background: var(--bg);
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.help-tabs {
|
|
display: flex;
|
|
gap: 0.75rem;
|
|
border-bottom: 1px solid var(--line);
|
|
padding-bottom: 0.5rem;
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
|
|
.help-tab.active {
|
|
color: var(--accent);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.help-body {
|
|
display: grid;
|
|
grid-template-columns: 16rem 1fr;
|
|
gap: 0 1rem;
|
|
margin: 0;
|
|
}
|
|
|
|
.help-body dt,
|
|
.help-body dd {
|
|
margin: 0;
|
|
min-height: 1.2em;
|
|
}
|
|
|
|
.help-heading {
|
|
grid-column: 1 / -1;
|
|
font-weight: 600;
|
|
color: var(--accent);
|
|
}
|
|
|
|
.help-banner {
|
|
grid-column: 1 / -1;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.help-text,
|
|
.help-accent,
|
|
.help-blank {
|
|
grid-column: 1 / -1;
|
|
white-space: pre;
|
|
}
|
|
|
|
.help-dim {
|
|
opacity: 0.7;
|
|
}
|