Skip to content

refactor(ui): one empty state, and loading is not one of them - #85

Merged
youhide merged 1 commit into
mainfrom
c3a-one-empty-state
Aug 21, 2026
Merged

refactor(ui): one empty state, and loading is not one of them#85
youhide merged 1 commit into
mainfrom
c3a-one-empty-state

Conversation

@youhide

@youhide youhide commented Aug 21, 2026

Copy link
Copy Markdown
Owner

C3 was planned as one item and is two. The dedup is mechanical; giving empty states the next action UI_SPEC.md asks for is a change of copy and behaviour with new catalogue strings. This is the first half, and it changes no pixels.

The dedup

Three helpers rendered the same centred muted line three ways:

Where Name How
diff.rs empty .center(Fill)
detail.rs placeholder .center(Fill)
staging.rs placeholder .center_x(Fill).center_y(Fill)

What reading the call sites turned up

Two of the seven are not empty states at all. "Loading…" and "Reading the conflicted file…" are a pane that has not finished looking — a different thing from a pane with nothing in it.

The difference is about to matter: an empty state is getting a next action, and a loading state has none to offer. Folding them together now would have cemented the confusion exactly when it starts to cost something.

So there are two functions with one body, for the same reason cherry_pick and revert are separate despite their near-identical shape: the distinction lives in what the caller means, and collapsing it is how it gets lost.

A smaller thing

Three diff call sites passed &format!(…) and relied on the old helper calling to_owned for them. They pass the String now, so the allocation is visible at the call site rather than hidden behind a &str parameter that could not actually borrow.

The audit, recorded rather than implied

UI_SPEC.md now says which empty states carry an action — the welcome screen and the PR panel — and that the rest only describe the absence. Naming the gap is what makes the second half a defined piece of work rather than a vague intention.

While counting them I also noticed "Select a file to see its changes" is written out in two files. That is copy duplication rather than code duplication, and it belongs with the ~690 inline literals the i18n migration still has to move, so it is left alone here.

Testing

The migration is covered by the render tests that already exist — they assert these exact strings reach the screen, so a broken call site fails them. No new assertion is honest here: empty and loading render identically today, and a test claiming to tell them apart would be testing a name.

Sabotage: re-adding fn placeholder to detail.rs fails no_view_file_draws_its_own_rule_or_button with "widget/detail.rs defines its own fn placeholder". The guard grew fn placeholder alongside the rules and button roles it already refused.

Gate

cargo fmt --all -- --check, cargo clippy --workspace --all-targets --all-features --locked -- -D warnings, cargo test --workspace --all-features --locked — 900 tests, all green.

C3 was planned as one item and is two. The dedup is mechanical; giving empty
states the next action `UI_SPEC.md` asks them for is a change of copy and
behaviour with new catalogue strings. This is the first half, and it changes no
pixels.

Three helpers rendered the same centred muted line three ways — `empty` in the
diff, `placeholder` in the detail pane, and a third `placeholder` in staging
that reached the same result through `center_x` and `center_y` instead of
`center`. They are one function now.

Reading the seven call sites turned up something the dedup would otherwise have
cemented: two of them are not empty states at all. "Loading…" and "Reading the
conflicted file…" are a pane that has not finished looking, which is a different
thing from a pane with nothing in it — and the difference is about to matter,
because an empty state is getting a next action and a loading state has none to
offer. So there are two functions with one body, for the same reason
`cherry_pick` and `revert` are separate despite their near-identical shape: the
distinction is in what the caller means, and folding it away is how it gets
lost.

Three diff call sites passed `&format!(…)` and relied on the old helper calling
`to_owned` for them. They pass the `String` now, so the allocation is visible at
the call site rather than hidden behind a `&str` parameter that could not
actually borrow.

The audit is recorded in `UI_SPEC.md` rather than left implicit: most empty
states still only describe the absence, and only the welcome screen and the PR
panel carry an action. Naming the gap is what makes the second half a defined
piece of work instead of a vague intention.
@youhide
youhide merged commit 2e96fd4 into main Aug 21, 2026
7 checks passed
@youhide
youhide deleted the c3a-one-empty-state branch August 21, 2026 11:57
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