Skip to content

Add header brand wordmark with superscript unread badge#190

Closed
general-lex wants to merge 4 commits into
mainfrom
claude/add-unread-count-BUcfh
Closed

Add header brand wordmark with superscript unread badge#190
general-lex wants to merge 4 commits into
mainfrom
claude/add-unread-count-BUcfh

Conversation

@general-lex
Copy link
Copy Markdown
Collaborator

@general-lex general-lex commented May 18, 2026

Summary

Adds a "Chat" brand identity to the app header and a live, app-wide unread-message indicator rendered as a superscript badge on the wordmark.

  • Live unread badgeselectUnreadTotal() (pure selector in reducer.js) aggregates per-room unreadCount/hasMention into { total, hasMention }; exposed via the useUnreadTotal() hook. No fetch, no polling, no subscription — the reducer already keeps per-room counts current (MESSAGE_RECEIVED raises non-active rooms, SET_ACTIVE_ROOM zeroes the visited one), so the badge updates live.
  • UnreadBadge component — hidden at 0, caps at 99+, mention-accent variant, accessible singular/plural aria-label. Design-token styling only.
  • "Chat" brand wordmark — bold, accent-colored, pinned top-left of AppHeader (the search bar is an absolutely-positioned centered overlay, so the wordmark anchors left).
  • Superscript placement — the badge nests inside the wordmark and is absolutely positioned at its top-right corner (app-icon notification metaphor); standalone .unread-badge flow styling is overridden only within .app-header-brand.

Test plan

  • selectUnreadTotal unit tests: empty, summation, mention OR, missing fields, recompute after MESSAGE_RECEIVED / SET_ACTIVE_ROOM
  • UnreadBadge tests: zero→null, count, 99+ cap, singular/plural label, mention class
  • AppHeader render test asserts the wordmark + badge are present
  • npm run typecheck clean, full suite green, vite build clean
  • Visual check in npm run dev — confirm wordmark size/color and badge superscript offsets at the "Chat" top-right corner

https://claude.ai/code/session_018Ji3fX1rmVci7HF1uFtbzB


Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Added an unread message badge to the app header displaying the total count of unread messages across all conversations
    • Badge automatically hides when there are no unread messages
    • Counts are capped at "99+" for cleaner visual presentation
    • Special styling applied when unread messages include mentions
    • Full accessibility support with contextual labels and descriptions

Review Change Stack

claude added 4 commits May 15, 2026 06:49
The header had no global indication of unread activity — users had to
scan the sidebar to notice messages in rooms they weren't viewing.

Adds an UnreadBadge in AppHeader backed by a pure selectUnreadTotal
derivation over state.summaries (exposed via the useUnreadTotal hook).
The reducer already keeps per-room unreadCount/hasMention current —
incremented by MESSAGE_RECEIVED for non-active rooms, zeroed by
SET_ACTIVE_ROOM — so the badge updates live (up on new messages, down
on room visit) with no extra fetch, subscription, or polling.

https://claude.ai/code/session_018Ji3fX1rmVci7HF1uFtbzB
CodeRabbit nitpick — assert the UnreadBadge mock renders in the
AppHeader "renders user chip..." test so the integration point is
guarded against accidental unwiring.

Also add a component docstring to UnreadBadge documenting its
conditional-render / cap / mention-variant contract (raises the
PR's docstring coverage).

https://claude.ai/code/session_018Ji3fX1rmVci7HF1uFtbzB
The app had no brand identity in the UI — only the browser tab title.
Adds a bold accent-colored "Chat" wordmark at the top-left of the
AppHeader (first flex child; the search overlay is absolutely
positioned so the wordmark anchors left). Styled with existing design
tokens. Render test asserts it is present.

https://claude.ai/code/session_018Ji3fX1rmVci7HF1uFtbzB
Previously the badge sat as a standalone flex child pinned to the left
next to the wordmark, which read oddly ("Chat 3"). Nest it inside the
brand and absolutely position it at the wordmark's top-right corner so
it reads as an app-icon-style notification count. Standalone
.unread-badge flow styling is overridden only within .app-header-brand.

https://claude.ai/code/session_018Ji3fX1rmVci7HF1uFtbzB
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3af48877-3960-42e8-92eb-370a968868c6

📥 Commits

Reviewing files that changed from the base of the PR and between 035526f and 4be894f.

📒 Files selected for processing (10)
  • chat-frontend/src/components/MainApp/AppHeader/AppHeader.jsx
  • chat-frontend/src/components/MainApp/AppHeader/AppHeader.test.jsx
  • chat-frontend/src/components/MainApp/AppHeader/UnreadBadge/UnreadBadge.jsx
  • chat-frontend/src/components/MainApp/AppHeader/UnreadBadge/UnreadBadge.test.jsx
  • chat-frontend/src/components/MainApp/AppHeader/UnreadBadge/index.jsx
  • chat-frontend/src/components/MainApp/AppHeader/UnreadBadge/style.css
  • chat-frontend/src/components/MainApp/AppHeader/style.css
  • chat-frontend/src/context/RoomEventsContext/RoomEventsContext.tsx
  • chat-frontend/src/context/RoomEventsContext/reducer.js
  • chat-frontend/src/context/RoomEventsContext/reducer.test.js

📝 Walkthrough

Walkthrough

This PR introduces a header-mounted unread message badge that aggregates unread counts and mention indicators from all chat rooms. The change flows from state selection through a context hook, component rendering, visual styling, and integration into the app header.

Changes

Unread Badge Feature

Layer / File(s) Summary
State selection and aggregation logic
chat-frontend/src/context/RoomEventsContext/reducer.js, chat-frontend/src/context/RoomEventsContext/reducer.test.js
selectUnreadTotal(summaries) sums unreadCount across all rooms and ORs hasMention flags; tests verify aggregation, missing-count tolerance, and state mutations after MESSAGE_RECEIVED and SET_ACTIVE_ROOM.
Context hook for unread badge data
chat-frontend/src/context/RoomEventsContext/RoomEventsContext.tsx
useUnreadTotal() hook memoizes the badge aggregate { total, hasMention } by reading state.summaries and computing via selectUnreadTotal().
UnreadBadge component and tests
chat-frontend/src/components/MainApp/AppHeader/UnreadBadge/UnreadBadge.jsx, chat-frontend/src/components/MainApp/AppHeader/UnreadBadge/index.jsx, chat-frontend/src/components/MainApp/AppHeader/UnreadBadge/UnreadBadge.test.jsx
Component reads { total, hasMention } from useUnreadTotal(), renders null when total is non-positive, caps display at 99+, applies mention-specific class modifier, and exposes full (uncapped) count in aria-label and title with singular/plural grammar; tests verify rendering, count capping, aria-labels, and mention styling.
Badge and header brand styling
chat-frontend/src/components/MainApp/AppHeader/UnreadBadge/style.css, chat-frontend/src/components/MainApp/AppHeader/style.css
Base .unread-badge defines pill layout, dimensions, padding, border-radius, accent colors, and typography using design tokens; .unread-badge--mention switches to mention-color background; .app-header-brand adds wordmark styling and absolutely positions the badge as a superscript via top: 0, left: 100%, and transform.
AppHeader integration and tests
chat-frontend/src/components/MainApp/AppHeader/AppHeader.jsx, chat-frontend/src/components/MainApp/AppHeader/AppHeader.test.jsx
Header imports UnreadBadge and renders it inside the brand span alongside the "Chat" text; test suite mocks the badge and verifies it appears in the rendered output.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • hmchangw/chat#187: Implements the same unread-header feature with shared useUnreadTotal() hook and selectUnreadTotal() selector backed by matching tests and styles.
  • hmchangw/chat#188: Updates RoomEventsContext reducer and summary metadata construction; the unread badge aggregation depends on the hasMention field and summary structure produced by this PR.

Suggested reviewers

  • mliu33
  • GITMateuszCharczuk

Poem

🐰 A badge now perches atop the brand so bright,
Counting unread tales throughout the night,
Summaries summed and mentions all tracked,
The header keeps readers perfectly stacked.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: adding a header brand wordmark (the 'Chat' text) and a superscript unread badge component to the AppHeader.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/add-unread-count-BUcfh

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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.

2 participants