feat(ui): one-time announcement dialog for Plannotator TUI and Herdr Annotate - #1529
Merged
Merged
Conversation
… gate Announces Plannotator TUI and Herdr Annotate. One cookie, plannotator-announce-tui-herdr-seen, covers every surface, read through storage directly rather than the settings registry (configStore seeds registry defaults into cookies on first access, so a registry flag could not tell 'never seen' from 'seeded default'). The shell matches the other first-run announcements. Two departures: the backdrop dismisses, because the panel collects no decision, and the keydown listener runs on the capture phase and swallows Mod+Enter so a keystroke aimed at the announcement cannot approve a plan or post a review behind it.
… first-run chain Both apps gate it through terminalToolsAnnouncementCanShow, behind every dialog that asks the user to decide something, and the destination spotlight and auto-viewed toast now defer behind it too. Last rather than first because none of those dialogs consumes this cookie: a session busy asking setup questions defers the announcement instead of burning it. Archive, read-only shared plans (the share portal), the compact touch shell and the initial load suppress it without consuming the cookie.
…dering Existing App tests seed the new key so the announcement does not open over the surface they exercise.
…ipping them At the card width the Homebrew line was cut mid-path with no affordance.
Six files under apps/marketing/public/assets/, served from https://plannotator.ai/assets/ once the marketing deploy syncs them: the Herdr Annotate Full and Lite demos as 1280px h264 mp4 (5.5MB, 3.5MB) and vp9 webm (9MB, 4.8MB), each with a poster jpg. Same hosting precedent as code-review-demo.mp4 and guided-review-demo.mp4; the in-app terminal-tools announcement streams them.
…tage Replaces the text-and-mock panel with a video-first one: the real Herdr Annotate demo fills the top of the panel edge to edge, muted, looping and autoplaying (poster plus a play button under prefers-reduced-motion), over one headline, one sentence, and one action row (star the two repos, Watch on X, Got it). A Full | Lite segmented switch swaps the footage and the X link together. The mock terminal, install commands, feature paragraphs, the NEW badge and the third star button are gone. Media is hosted on plannotator.ai like GuideIntroDialog's hero image (23MB is far too much to inline); if neither source loads, the frame keeps its place and offers the X post instead. The panel's width follows the viewport height as well as its width so the video never scrolls out of view. Cookie gate, chain ordering, surface suppression, focus trap, Esc and backdrop dismiss are unchanged; tests now also cover the muted/playsinline/autoplay attributes, the reduced-motion branch and the demo switch.
AGENTS.md now documents the hosted media, the reduced-motion and offline behavior, the demo switch and the height-aware panel width; the manual checklist's content and theme steps match the new dialog.
…h label A small uppercase tag in the top-left corner of the video, over the footage, with a slow diagonal sheen. Colors are Herdr Annotate's own badge palette (#312b52 purple, #c9c6f1 lavender text, #B9C0FF periwinkle border), set as --announce-brand* variables on the dialog itself so another product's brand never enters theme.css. The sheen class is dropped under prefers-reduced-motion, with the media query as a backstop, and the tag sits where the posters keep only a sidebar label and a tab marker.
The tag now covers the top-left corner of the footage instead of floating inside it: anchored to the panel edge with no inset, square outer edges (the panel's own radius clips them), a rounded bottom-right, and the periwinkle edge only along the two sides that meet the video. 190x48 with 15px tracked uppercase type over the desktop video, 132x32 with 11px at phone width. The sheen now sweeps the whole block every 4s; reduced motion still drops it.
1 task
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.
A one-time, full-screen-ish panel announcing Plannotator's two terminal clients,
Plannotator TUI and Herdr Annotate. It shows once per browser across plan
review, annotate and code review, then never again.
The design
Video first. The real Herdr Annotate demo fills the top of the panel edge to edge,
muted, looping and autoplaying, and everything under it fits in three rows: one
headline, one sentence, one action row. No mock terminal, no feature bullets, no
install commands, no badges; the repo pages carry all of that.
The panel is 1120px wide at most and follows the viewport height too
(
min(1120px, 100%, (100dvh - 14rem) * 1280/806)), so the footage keeps its aspectratio and never scrolls out of view: at 1440x900 the video is 1072px wide. At 400px
the video spans the panel on top and the headline, switch and actions wrap under it.
Both themes come from
theme.csstokens; the dark footage sits on the card surfacewith a hairline under it, which reads as a hero image in light mode and as one
continuous panel in dark.
The corner block. An uppercase
NEW · WATCH:block covers the top-left cornerof the footage on both demos: flush to the panel edge with no inset, square outer
edges (the panel's own radius clips them), a rounded bottom-right, 190x48 with 15px
tracked type over the desktop video and 132x32 with 11px at 400px, the way a "new"
corner tag sits on a product card. A slow diagonal sheen sweeps the whole block every
4s (dropped under
prefers-reduced-motion, with the media query as a backstop). Itscolors are Herdr Annotate's own badge palette from the repo's SVGs:
#312b52purplebackground,
#c9c6f1lavender text (8:1 on it), and a#B9C0FFperiwinkle 1px edgealong the two sides that meet the video, plus a soft shadow. They are set as
--announce-brand*variables on the dialog element, not tokens in
theme.css, so another product's brandnever enters the app palette. The badge purple was chosen over the hero image's darker
ground (
#10101fto#2c2536), which vanishes into the footage; the poster corner itcovers holds only the sidebar's "spaces" label (Full) and a tab marker (Lite).
Full and Lite. One video is visible at a time; a two-segment
Full | Liteswitch(
role="tablist", arrow keys) on the headline row swaps the footage and the"Watch on X" link together. A switch rather than a second tile because a second tile
would either be a tiny thumbnail nobody can read or would halve the hero, and a
control next to the media is where a viewer expects to change what is playing.
Video treatment.
<video muted playsInline loop preload="auto">with the mp4source first and the webm second,
autoPlayunlessprefers-reduced-motionmatches, in which case the poster waits behind a centered play button. Hovering the
playing footage reveals a small pause control bottom-left; a paused frame shows the
centered play button, so it is never mistaken for a broken player. The player is
keyed per demo, so a switch resets playback and load-failure state. If neither source
can load (offline), the frame keeps its place and offers "Watch on X" over it.
Hosting
The six files are new under
apps/marketing/public/assets/, the same precedent ascode-review-demo.mp4andguided-review-demo.mp4, and the dialog references them athttps://plannotator.ai/assets/...:tui-herdr-full-demo.mp4(1280x806 h264, 40s, silent)tui-herdr-full-demo.webm(vp9)tui-herdr-full-poster.jpgtui-herdr-lite-demo.mp4(1280x808 h264, 39s, silent)tui-herdr-lite-demo.webm(vp9)tui-herdr-lite-poster.jpgThe videos go live on merge, when the Deploy workflow syncs
apps/marketing/dist/to S3 on the push to main. Until then the dialog's poster and video URLs 404 and it
shows its offline state. The screenshots below were taken with the same files served
locally in place of that origin (a temporary constant change, reverted before commit).
Hosted rather than inlined like the Edit Mode recording because the two demos are
~23 MB together;
GuideIntroDialogalready streams its hero from this origin. There isno CSP to widen: the app HTML ships no
Content-Security-Policy, and the servers onlyset one on sandboxed artifact responses.
Gating (unchanged from the first version)
One cookie,
plannotator-announce-tui-herdr-seen(value1), read and written byneedsTerminalToolsAnnouncement()/markTerminalToolsAnnouncementSeen()inpackages/ui/utils/terminalToolsAnnouncement.ts. Dismissing it on any surface retiresit everywhere. A plain storage key rather than a settings-registry entry for the same
reason
lookAndFeelAnnouncement.tsis:configStore.ensureLoadedseeds every registrydefault into a cookie on first access, so a registry-backed flag could never tell
"never seen" from "seeded default".
LAST in each app's first-run chain. Code review gates it through
terminalToolsAnnouncementCanShowon guide intro, look-and-feel, review setup, EditMode and token hover cards; the plan editor on the look-and-feel chooser, goal setup
and permission-mode setup. None of those consumes this cookie, so a session busy
asking setup questions defers the announcement to the next load instead of burning it.
Suppressed, never consumed, on archive browsing, read-only shared plans (the share
portal), the compact touch shell, and while the initial payload loads.
The shell is the shared one (portal,
z-[100],role="dialog", hand-rolled Escape,Tab wrap with the roving-tabindex switch skipped, focus restore) with the two
deliberate departures kept: the backdrop dismisses, and the capture-phase keydown
listener swallows
Mod+Enterso a keystroke aimed at the announcement cannot approvea plan or post a review behind it. Entrance reuses the Vim announcement's keyframes;
under reduced motion the panel fades without travelling.
Test plan
packages/ui/components/TerminalToolsAnnouncementDialog.test.tsx(12): labelled modalwith exactly one completion action and initial focus on it; the footage is
muted+playsinline+loop+autoplaywith mp4 before webm and a hostedposter;
reducedMotionwithholdsautoplay, renders the play button and drops thetag's sheen (which is on by default); the switch
swaps the demo and the X link together; every outbound link is
_blank+noopener noreferrer+https:; button, Escape and backdrop dismiss while a pressinside the panel does not;
Mod+Enternever reaches a listener behind the dialog;Tab wraps at both ends; closed renders no nodes.
packages/ui/utils/terminalToolsAnnouncement.test.ts(4) and the App-level tests inpackages/editor/App.terminalToolsAnnouncement.test.tsxandpackages/review-editor/App.decisionControl.test.tsxare unchanged and still pass.Results:
bun run typecheckclean.DOM_TESTS=1 bun test packages/ui packages/editor packages/review-editor: 2158 pass,5 fail, all five the pre-existing order-dependent
DocBadges/artifactDocumentcases.
bun run --cwd packages/ui smoke:package: packs and installs externally against@plannotator/core@0.25.2.bun run --cwd apps/review build && bun run build:hook && bun run build:opencode && bun run build:marketing: all succeed; the six media files land inapps/marketing/dist/assets/.Verified with Playwright (Chromium) on the review dev server in light and dark at
1440x900 and 400px wide, plus the Lite switch and
prefers-reduced-motion; in everyrun the video reported
readyState 4and was playing (paused at 0 under reducedmotion), so the captures show real frames.
Deploy note
The
theme.cssadditions change the guides.show viewer's bundled CSS, sopackages/core/guide-viewer-manifest.tsis repinned (viewer.Glgcqvv_.css, newintegrity; the JS hash is unchanged). The pinned viewer build must be deployed to
guides.show
/v1/on merge, the same step as PR #1526.Docs
AGENTS.md's "First-run terminal-tools announcement" section describes the hostedmedia, the reduced-motion and offline behavior, the demo switch and the height-aware
width;
tests/UI-TESTING.md's manual checklist covers the video, links and theme steps.