Skip to content

feat(announcements): move the banner to the chat composer, on whichever side it leaves free - #981

Merged
philmerrell merged 2 commits into
developfrom
feature/announcement-banner-near-composer
Sep 6, 2026
Merged

feat(announcements): move the banner to the chat composer, on whichever side it leaves free#981
philmerrell merged 2 commits into
developfrom
feature/announcement-banner-near-composer

Conversation

@philmerrell

@philmerrell philmerrell commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

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-input beside quota-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: 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.

It still floats

bottom-full / top-full against a relative chat-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:

Δtop Δleft Δheight
app-chat-input 0 0 0
greeting 0 0 0
#app-scroll-container 0 0 0

Restyled 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 panel is 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-input is 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. 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.

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 coversGreeting is 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-container specs stub app-chat-input and 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 the submission-review.page.spec.ts spec that has been flaking.

One case not verified in a browser: the above placement 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 the above styling 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

philmerrell and others added 2 commits September 6, 2026 10:34
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>
@philmerrell philmerrell changed the title feat(announcements): move the banner above the chat composer feat(announcements): move the banner to the chat composer, on whichever side it leaves free Sep 6, 2026
@philmerrell
philmerrell merged commit 9db5bc0 into develop Sep 6, 2026
4 checks passed
@philmerrell
philmerrell deleted the feature/announcement-banner-near-composer branch September 6, 2026 16:52
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