Skip to content

Overview state rides the CLI tile too - #100

Merged
lvwerra merged 1 commit into
mainfrom
design/overview-state-frame
Aug 20, 2026
Merged

Overview state rides the CLI tile too#100
lvwerra merged 1 commit into
mainfrom
design/overview-state-frame

Conversation

@lvwerra

@lvwerra lvwerra commented Aug 20, 2026

Copy link
Copy Markdown
Member

in the overview the spinning widget is still next to the icon, when it should be the animation around the icon like in the sidebar

Before/after, sizes and reduced-motion behaviour →

#92 shipped the frame to the sidebar, both pane headers and the install mock, and deliberately left Overview on the standalone mark — the argument being that Overview is denser. The operator has decided the other way, so all three of Overview's state slots move onto the tile:

  • the card's row and the tile's head drop the separate mark; their plain Logo becomes a StateLogo
  • the group's peek strip has no icon to frame, so it uses the frame-only form the sidebar and install legends already use

Density was the objection, so here are the numbers

before after
card / tile 15×13 mark + 18×18 logo 18×18 frame
sidebar frame 18×18 18×18 — unchanged, and identical
group strip mark 15px wide 12px frame-only
old marks left in Overview 6 0

The frame is not a shrunken version of the sidebar's — it is the same object at the same size, and on the card and tile it replaces a mark and a logo that sat side by side, so those two rows get narrower. The strip's marks get smaller. No new size was invented: both come from StateLogo's own size prop.

The tile keeps its word and loses its spinner

.ovt-state.running::before drew an animated braille glyph in the line under the icon — so with the frame now animating a few pixels above it, one small tile carried two motions saying the same thing. The glyph is gone.

The word stays, because it says what a four-state frame cannot: needs input, ✓ done, and running in the wider digest sense (atWork, which covers a session whose transcript is mid-task while its state reads waiting). In the sidebar the frame is all you get; on a tile the word still earns its place. Flagging the one consequence: in that atWork-but-not-working case the tile no longer animates at all — the accent word is the whole signal. Say if you would rather keep the glyph.

The bare .status block, checked before touching

After this change .status is rendered nowhere with a state class — only bare, by the provider dots in UsagePanel.tsx:92 and the ready dot in SettingsView.tsx:358. Both still work and both are still asserted in statusMark.render.test.mjs (provider still shows rgb(214, 69, 69), ready still shows rgb(46, 158, 91)) — the pair I broke in #82 and do not intend to break again.

The .status.<state> rules stay. They look dead but are not: statusMark.test.mjs and statusMark.render.test.mjs measure .status.working::before as the reference for the spinner family that .ov-busy and .cx-running are checked against. Removing them means rewriting those two suites, which is a separate change. I left a note rather than a trap.

Four states, both themes, no motion

All four stay distinguishable at Overview's sizes (the screenshots force real states through the API, so the working dash is genuine rather than a class swap). Under prefers-reduced-motion the working frame keeps stroke-dasharray: 20px, 4px with animation-name: none and 0 running animations, while waiting has no dash rect at all — so working is still dashed against waiting's solid when nothing may move.

Tests

  • stateLogo.test.mjs gains the assertion the brief asked for. The old declaration that Overview keeps the standalone mark was already gone — that suite was rewritten after my Move agent status onto CLI icon frames #92 review to pin structure rather than source text — so instead of editing it I added its opposite: every state slot is a frame, the strip uses the frame-only form, and no component renders a state-classed .status. Verified it fails if any one of the three sites is reverted.
  • statusMark.render.test.mjs loses its overview-group-working fixture, which existed only to measure the tile spinner this removes.

One thing that was already broken

server/reader-info.test.mjs asserted "the state mark leads the centred name" — the pane header's standalone dot. #92 moved that onto the tile, so this has been failing on main since #92 merged; I confirmed it fails identically with my changes stashed:

FAIL  the state mark leads the centred name  {"statusInTitle":false,"statusLeftOfName":false}

It now pins the arrangement #92 actually shipped (state on the tile, at the head of the row, no dot left behind). npm run test:ui goes from red to green — 74 checks.

Web suite: 15 suites. npm run test:render: all checks. npm run test:ui: all three suites green.

🤖 Generated with Claude Code

From prod: "in the overview the spinning widget is still next to the icon, when
it should be the animation around the icon like in the sidebar."

#92 shipped the frame to the sidebar, both pane headers and the install mock,
and deliberately left Overview on the standalone mark — the argument being that
Overview is denser. The operator has decided the other way, so all three of its
state slots move:

- the card's row (`ov-id`) and the tile's head (`ovt-head`) drop the separate
  mark and hand the state to the `StateLogo` that replaces their plain `Logo`
- the group's peek strip has no icon to frame, so it uses the frame-only form
  the legends already use

Density was the original objection, so it is worth stating what actually
happens: the card and tile frames measure **18x18, exactly the sidebar's**, and
they replace a 15px mark plus an 18px tile sitting side by side. Those two rows
get *narrower*, not denser. The strip's marks go from 15px wide to 12px. No new
size was invented: both come from `StateLogo`'s own `size` prop.

**The tile keeps its state word and loses its spinner.** `.ovt-state.running`
drew an animated braille glyph next to the frame that is now animating a few
pixels away — one small tile carrying two motions saying the same thing. The
word stays because it says what the four-state frame cannot: `needs input`,
`✓ done`, and `running` in the wider digest sense (`atWork`) that a frame
reading `waiting` does not cover.

`.status` is now rendered nowhere with a state class — only bare, by the
provider dots in `UsagePanel` and the ready dot in `SettingsView`. Both keep
working and both are still asserted. The `.status.<state>` rules stay: they are
the reference implementation the mark-parity tests measure the spinner family
against, so they are exercised even though the app no longer draws them.

Tests: `stateLogo.test.mjs` gains the assertion that every state slot is a
frame and no component renders a state-classed `.status` — verified to fail if
any one site is reverted. `statusMark.render.test.mjs` loses its
`overview-group-working` fixture, which measured the tile spinner this removes.

Also fixed, and failing on main before this branch: `reader-info.test.mjs`
asserted the pane header's state dot leads the centred name. #92 moved that
onto the tile, so the assertion has been red since it merged; it now pins the
new arrangement instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lvwerra
lvwerra merged commit 894a64d into main Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant