Skip to content

fix(chat): centre the empty-chat hero in the reading column - #2153

Merged
Astro-Han merged 1 commit into
mainfrom
fix/chat-empty-state-vertical-centering
Aug 4, 2026
Merged

fix(chat): centre the empty-chat hero in the reading column#2153
Astro-Han merged 1 commit into
mainfrom
fix/chat-empty-state-vertical-centering

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

The empty chat surface rendered its hero — the wordmark plus the time-of-day greeting — noticeably low, sitting against the composer rather than in the middle of the reading column.

The cause is in Astryx's ChatMessageList: it renders a flex: 1 spacer ahead of its rows so a short conversation rests on the composer instead of hanging from the top. That spacer is unconditional, so on the empty surface it split the column with the empty-state holder — which is itself flex: 1 and centres its content — and the hero ended up centred in the bottom half. Measured on main: hero centre 552px against a column centre of 380px, a 172px drop, plus the list's own 16px gap.

This collapses the spacer when the list's last row is an empty state, handing the whole column back to the holder so its centring is true to the surface. The rule is keyed on the empty-state content rather than on "no messages" because a one-message conversation must keep the push-to-bottom.

The accompanying check is a live metric rather than a static CSS read: the selector matches ChatMessageList's internal DOM, so a CSS contract could only prove the rule is written, never that it still matches after an Astryx bump.

Verification

  • apps/desktop Playwright — full e2e/scroll-geometry.spec.ts, 6 passed, including the new the empty-chat hero centres in the reading column.
  • The new test was confirmed to fail for the right reason: with the spacer left visible it reports the 172px offset and goes red.
  • npm run lint, npm run format:check, node scripts/check-dead-css.mjs --check (the allowlist entry is for astryx-empty-state, which Astryx emits through themeProps at runtime and never appears as a className literal in Maka source).
  • Live app on this branch, empty session: hero centre and message-list centre both read 380px. Conversation with rows: the spacer still computes display: block, so push-to-bottom is intact.

Astryx's ChatMessageList renders a `flex: 1` spacer ahead of its rows so
a short conversation rests on the composer instead of hanging from the
top. The spacer is unconditional, so on the empty surface it split the
column with the empty-state holder — itself `flex: 1` and centring — and
the hero landed centred in the bottom half, measured 172px below the
reading column's centre.

Collapse the spacer when the list's last row is an empty state, which
hands the whole column back to the holder. Keyed on the empty-state
content rather than on "no messages" so a one-message conversation keeps
the push-to-bottom.

The invariant is a live metric, not a CSS read: the rule matches
ChatMessageList's internal DOM, so a static check could only prove the
selector is written, never that it still applies.
@Astro-Han
Astro-Han marked this pull request as ready for review August 4, 2026 13:23
@Astro-Han
Astro-Han merged commit 2d37c65 into main Aug 4, 2026
11 checks passed
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