feat(announcements): move the banner to the chat composer, on whichever side it leaves free - #981
Merged
Conversation
The banner sat at the top of the shell. What it announces — a new model, a new capability — is acted on in the composer, so the notice now lives where the decision is made rather than in a corner the eye has already left. It mounts from `chat-input` beside `quota-warning-banner`, which is where users already look for ambient notices. It still floats rather than stacking in flow. `bottom-full` against a `relative` chat-input host puts it clear of the quota tabs, which stay attached to the input, and keeps the property from the previous change: measured before and after a dismissal, the composer, greeting and scroll container all move by exactly 0px. Restyled to match the sibling it now sits beside — a compact shrink-to-fit pill rather than a bar spanning the composer, which also shrinks how much it overlays. **It is now a chat-view surface only.** That is the real consequence of the move and it is deliberate: What's New remains the everywhere-record, which is why `panel` is forced onto every announcement server-side. The spec's §D1 is updated to say so rather than leaving the doc describing a placement that no longer exists, and the two admin help strings that told authors "a strip below the top nav" now describe where a banner actually appears. `chat-input` is reused by the agent-preview and marketplace test-drive panes, where a platform-wide notice would read as a bug rather than an announcement. A `showAnnouncements` input gates it, following the same opt-out shape as the `show*` controls beside it: default true, explicitly false at those two call sites, and threaded through `chat-container` so its embedded mode is off too. The shell mount and its `isAuthenticated()` gate are gone with it — the composer only exists inside an authenticated chat route, so the 401-on-login hazard that gate existed for is now structural rather than guarded. Three real test failures found and fixed on the way: two `chat-container` specs stub `app-chat-input` and needed the new input added to the stub, and one of the banner's own assertions was stale after the restyle. Full frontend suite 2486 passed, only the known `submission-review` flake outstanding. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The composer is not always in the same place. A conversation pins it to the bottom of the viewport, where a pill below it would be off the edge. The empty state centres it with the greeting immediately above, where a pill above it floats over that greeting — visibly so at 375px, where the greeting wraps and the pill covered its second line. So the placement follows the composer: `below` on the empty state, `above` otherwise. Derived, not measured. `isEmptyState()` is the same computed that already picks which layout branch renders — the centred composer or the bottom-pinned one — so reading it makes the two impossible to drift apart. Measuring the composer's viewport position would re-derive that same fact less reliably and would have to be recomputed on resize, on scroll, and when the artifact pane opens. The banner takes a `placement` input and swaps `bottom-full`/`mb-2` for `top-full`/`mt-2`; `chat-container` supplies it through `chat-input` alongside the `showAnnouncements` gate. Verified on the empty state at desktop and 375px: the pill sits below the composer in clear space and `coversGreeting` is false in both, where it was true before. Full frontend suite 2490 passed — a clean run, including the `submission-review` spec that has been flaking. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #979. The banner sat at the top of the shell. What it announces — a new model, a new capability — is acted on in the composer, so the notice now lives where the decision is made rather than in a corner the eye has already left. It mounts from
chat-inputbesidequota-warning-banner, which is where users already look for ambient notices.It follows the composer, and the composer moves
A conversation pins the composer to the bottom of the viewport, where a pill below it would be off the edge. The empty state centres it with the greeting immediately above, where a pill above it floats over that greeting — visibly so at 375px, where the greeting wraps and the pill covered its second line.
So placement switches:
belowon the empty state,aboveotherwise.Derived, not measured.
isEmptyState()is the same computed that already picks which layout branch renders — the centred composer or the bottom-pinned one — so reading it makes the two impossible to drift apart. Measuring the composer's viewport position would re-derive that same fact less reliably, and would have to be recomputed on resize, on scroll, and when the artifact pane opens.It still floats
bottom-full/top-fullagainst arelativechat-input host keeps it clear of the quota tabs, which stay attached to the input, and preserves the property from #979 — measured before and after a dismissal:app-chat-input#app-scroll-containerRestyled to match the sibling it now sits beside — a compact shrink-to-fit pill (
inline-flex,text-xs) rather than a bar spanning the composer.The consequence worth agreeing on
The banner is now a chat-view surface only. It no longer appears on admin pages, settings, agents, or anywhere without a composer. That is deliberate — What's New remains the everywhere-record, which is why
panelis forced onto every announcement server-side — but it is a real narrowing and worth a second opinion.Rather than leave the design doc describing a placement that no longer exists, §D1 now says what shipped and why, and the two admin help strings that told authors "a strip below the top nav" now describe where a banner actually appears. An author choosing the banner surface should not be told the wrong thing.
Embedded panes are gated off
chat-inputis reused by the agent-preview and marketplace test-drive panes, where a platform-wide "new models are available" pill would read as a bug rather than an announcement. AshowAnnouncementsinput gates it, following the same opt-out shape as theshow*controls beside it: default true, explicitlyfalseat those two call sites, and threaded throughchat-containerso its embedded mode is off too.The shell mount and its
isAuthenticated()gate are gone with it — the composer only exists inside an authenticated chat route, so the 401-on-login hazard that gate existed for is now structural rather than guarded.Verification
Browser-verified against dev data with a local app-api: light, dark, desktop and 375px, no horizontal overflow, dismiss still writing its durable server-side ack. On the empty state the pill sits below the composer in clear space and
coversGreetingis false at both widths, where it was true before this change.Three real test failures surfaced and were fixed, none of which a typecheck would have caught: two
chat-containerspecs stubapp-chat-inputand needed the new inputs added to the stub (NG0303: Can't bind to 'showAnnouncements'), and one of the banner's own assertions was stale after the restyle. Full frontend suite 2490 passed on a clean run — including thesubmission-review.page.spec.tsspec that has been flaking.One case not verified in a browser: the
aboveplacement inside a real conversation. The local stack has no inference-api, so I could not produce a loaded session; both host-class branches are covered by unit tests and theabovestyling was verified live on the empty state before this commit flipped it. Worth a glance on dev.Independent of any other open PR — no shared files.
🤖 Generated with Claude Code