feat: rotating composer hints and time-of-day greetings - #1096
Merged
Merged
Conversation
`@` and `/` are the two shortcuts nothing on the page advertises: each one only reveals itself once you have already typed the character that opens its menu. The empty composer is where a user looks when they do not yet know what to type, so that is where the hint goes. Three rules keep it from being the kind of animation people file bugs about: - It is decoration, not information. The native `placeholder` attribute never rotates, so assistive tech reads one stable string; the visible line is an `aria-hidden` overlay painted over a placeholder that is transparent but still there. A placeholder that re-announced itself every few seconds would be a screen-reader defect, not a feature. - It stops. Three passes and it comes to rest on the idle line, and the first keystroke settles it on the spot. Nothing auto-updates indefinitely, so WCAG 2.2.2 asks for no pause control we would then have to fit into the composer's chrome. - It honours `prefers-reduced-motion`. Reduce means no rotation at all, not the same rotation with the fade taken off. The rotation comes to rest *in the overlay* rather than unmounting back to the native placeholder: unmounting would exit-animate a copy of the idle line straight off the placeholder underneath, which spells the same words — a ghost double-image on the one transition every user sees. Hints are offered only for surfaces this composer actually has, so an environment with Agents switched off, or a user with no skills enabled, is never told to type a character that opens an empty menu. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds twenty greetings bucketed into morning (05:00-11:59), afternoon (12:00-16:59), evening (17:00-21:59) and night (22:00-04:59), each with a no-name fallback for signed-out users. They pool *with* the existing five rather than replacing them, so a morning visitor draws from morning plus the any-time list: about half of what anyone sees knows what time it is, and half is the familiar copy. Replacing instead of pooling would leave the app with exactly one thing to say each morning. The clock is the viewer's own, read once at resolve time, so "Good evening" means evening where the person actually is and the heading does not re-write itself out from under someone mid-conversation. `DEFAULT_GREETING_TEMPLATES` and `DEFAULT_FALLBACK_GREETINGS` are left untouched: `brand.defaults.golden.spec.ts` pins them verbatim as the pre-branding-refactor greetings, and that guard is worth more than tidiness. The new copy lives in its own constants. Greetings are Brand_Config territory, so this stays rebrandable. `timeOfDayGreetings` / `timeOfDayFallbackGreetings` are optional: omit either, or any single bucket, and the defaults apply. An explicitly empty bucket is honoured as "stay quiet at that hour" — the one place these differ from the flat lists, where empty means "have the defaults" — and each bucket normalizes independently, so one bad hour never costs a rebrand the other three. 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.
Two small additions to the empty-chat surface: the composer teaches the two shortcuts nothing else advertises, and the greeting above it knows what time it is.
Rotating discovery hints in the composer
@and/only reveal themselves once you have already typed the character that opens their menu. The empty composer is where a user looks when they do not yet know what to type, so the hint goes there — cyclingHow can I help you today?→Type @ to hand this turn to one of your agents→Type / to run one of your skills, cross-faded with Angular 21'sanimate.enter/animate.leave.Three rules keep it from being the kind of animation people file bugs about:
placeholderattribute never rotates, so assistive tech reads one stable string; the visible line is anaria-hiddenoverlay painted over a placeholder that is transparent but still present. A placeholder that re-announced itself every few seconds would be a screen-reader defect, not a feature.prefers-reduced-motion. Reduce means no rotation at all, not the same rotation with the fade taken off.Two details worth a reviewer's eye:
showAgentMentionsand a non-empty mentionable list;showSkillCommandsand at least one enabled skill), so nobody is told to type a character that opens an empty menu.Time-of-day greetings
Twenty new greetings, bucketed on the viewer's own clock, each with a no-name fallback for signed-out users:
morningafternooneveningnightThey pool with the existing five rather than replacing them, so a morning visitor draws from morning ∪ any-time: about half of what anyone sees knows what time it is, half is the familiar copy. The clock is the browser's, read once at resolve time, so "Good evening" means evening where the person actually is and the heading does not re-write itself out from under someone mid-conversation.
DEFAULT_GREETING_TEMPLATES/DEFAULT_FALLBACK_GREETINGSare untouched —brand.defaults.golden.spec.tspins them verbatim as the pre-branding-refactor greetings, and that guard is worth more than tidiness. The new copy lives in its own constants.Still rebrandable
Greetings are Brand_Config territory, so
timeOfDayGreetings/timeOfDayFallbackGreetingsare new optional fields onBrandConfig:night: []) is honoured as "stay quiet at that hour". This is the one place these differ from the flat lists, where an empty array means "you gave me nothing usable, have the defaults" — without it a rebrand would have no way to turn a bucket off.Documented in
src/branding/README.mdwith the hours table, and the worked example config now shows a gym that greets by session time and says nothing at 3am.Caveat for reviewers
Because the fields are optional and pooled, a rebrand that edits only
greetingTemplateswill still show stock time-of-day lines about half the time. That is called out in the guide and in a comment directly above the field inbrand.config.ts, but it is a real behaviour change for a forker reading neither.Testing
BrandingServiceby hand and predate the field.npx tsc --noEmitclean.localhost:4200: the cross-fade measured with both nodes coexisting ~300ms (outgoing 1.00 → 0.43 → gone, incoming 0.00 → 0.45 → 1.00), rotation continuing into pass 2 and 3, and greetings resolved at 07:15 / 14:15 / 19:15 / 23:15 / 02:15.🤖 Generated with Claude Code