Skip to content

Wrap long toast messages instead of clipping them at both ends - #65

Open
jankarres wants to merge 1 commit into
shellular-org:mainfrom
jankarres:jan/toast-overflow
Open

Wrap long toast messages instead of clipping them at both ends#65
jankarres wants to merge 1 commit into
shellular-org:mainfrom
jankarres:jan/toast-overflow

Conversation

@jankarres

@jankarres jankarres commented Aug 19, 2026

Copy link
Copy Markdown

A toast wider than the screen is cut off at both ends today, so you lose the start and the finish and keep the middle. That hits the messages you most need in full: Update failed: ${message} in ConnectionInfo takes its text from the CLI, and Downloaded to ${localPath} in FileList prints an absolute path.

before-clipped-both-ends

It is white-space: nowrap with no max-width, centred with translateX(-50%), so it overflows evenly on both sides. That example was 471px wide on a 390px viewport, from -40 to 430. Now it is 340px over two lines, from 25 to 365, and a short toast still hugs its content.

after-wrapped-and-stacked

Wrapping alone would have broken the stack, because each toast positioned itself with bottom: 24 + index * (TOAST_HEIGHT + GAP) and that needs a known height. So the stack moves into one flex container, column-reverse and capped at min(calc(100vw - 32px), 420px), carrying the keyboard and safe-area offsets that used to sit on each toast. Same order, newest above oldest.

That also drops toastCount, which was decremented whenever any toast finished animating out rather than when the one holding the index left, so a new toast could land on top of one still on screen. And the message goes in as a text node rather than through innerHTML, since one of its sources is a CLI error string.

pnpm typecheck and pnpm format clean, pnpm test unchanged at 97. Untested on Android and iOS, I did not set up the mobile build toolchain for this; the container inherits 100vw, --sab and --keyboard-height exactly as before, but that is the part worth a glance on a phone.

I let the message wrap freely rather than capping it with an ellipsis, because for an error I would rather see all of it. If that or anything else should be different, tell me and I will take care of it.

`.shellular-toast` was `white-space: nowrap` with no `max-width`, positioned
with `left: 50%` and `translateX(-50%)`. Anything wider than the viewport
therefore overflowed symmetrically and was clipped at BOTH ends, losing the
start and the finish of the message. Measured on a 390px viewport: "Could not
reach <host>: WebSocket closed before session handshake" rendered 471px wide
at x = -40..430.

Toasts carry host names, absolute file paths and raw CLI error text, so this
is reachable today: "Update failed: <message from the CLI>" in ConnectionInfo
and "Downloaded to <localPath>" in FileList both interpolate arbitrary length.

The single line was load-bearing, which is why this is not a one-line change.
Stacking positioned each toast with `bottom: 24 + index * (TOAST_HEIGHT + GAP)`
and so needed a known, fixed height. Moving the stack into a flex container
makes height irrelevant, after which the toast can wrap. Same visual order,
newest above oldest, and the same offsets for the keyboard and safe area.

That also retires an index bug: `toastCount` was decremented when a toast
finished animating out, so a new toast could be handed the slot of one still
on screen.

Message text now goes in through a text node instead of `innerHTML`. It is
interpolated from CLI-supplied strings, which had no business being parsed as
markup.
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