5.7.1 Design — bell + unread badge in the shell header + the notification drawer + the per-user notification-preferences settings page (`design/notifications/`)
Estimate: 45m
The design asset every UI subtask of this story builds against. design/shell/ draws the header (desktop.pen) but NO bell, NO unread badge, NO notification drawer/feed, and no notification-preferences settings page — those are whole elements NO design specifies, which under the design gate == no design exists, so this subtask produces them FIRST (mirrors 5.1.3 and the sibling HTML-mockup design subtasks). Output, under a NEW design/notifications/ area: bell.mock.html (the header bell + badge states), drawer.mock.html (the feed/drawer), and preferences.mock.html (the settings page) — each built from the real design system (components/ui/* + --el-* colour + element-semantic shape tokens, no Pencil→code gap) + PNG exports + a new design/notifications/design-notes.md naming primitives, copy, and placement. Passes the design-mockup render checklist (render + screenshot every panel; icon viewBoxes; no nested interactive elements; prettier; AA). Mirror: the Jira Cloud header notification bell + drawer (Direct/Watching split, blue-dot, Mark all as read in the overflow) and the Linear Inbox feed model; the Jira Personal settings → Notification settings page.
Specify, panel by panel:
- Bell + badge (in the header) — placement in
TopNav(desktop) and theSidebarHeader/mobile drawer affordance, beside the existing header controls. The bellIconButton(a labelled control, the--radius-controlaffordance), with the unread/seen badge as a small count pill anchored to the bell (the count = NEW since last open, per the Jira mirror; 99+ cap). States: zero (no badge), 1–99, 99+, and the open (drawer-anchored) state. - The drawer/feed — a header-anchored popover/drawer (the shipped popover grammar; on mobile, a sheet) with: a Direct / Watching segmented filter (Direct default — "mentions first"; Watching drawn DISABLED as the documented 5.4 seam, the way 2.5.3 drew the disabled view-switcher), the overflow (three-dots) menu carrying "Mark all as read", and the scrollable feed below.
- Notification row — actor
Avatar· a one-line summary (e.g. "Zhu Yue mentioned you on PROD-42: …") · relative time (absolute on hover/title) · the unread blue-dot leading indicator. Unread vs read treatment (read = no dot, muted via--el-text-muted, NOT removed from the feed). The whole row is ONE clickable target that deep-links to the issue (no nested interactive elements). Per-row hover affordance to toggle read (the LinearUmodel, surfaced as a control). - Feed states — the loading skeleton rows; the empty state ("You're all caught up — no notifications yet", never blank); the
ErrorState+ retry; the "Show more" affordance at the older edge (cursor paging, finding #57) + the at-scale long feed. - The preferences page (
preferences.mock.html) — a section on the/settings/accountpersonal-settings area: a matrix of event types (rows: Mentioned · Commented on an item you're involved in · Assigned to you · [Watching: item transitioned — the 5.4 seam, drawn disabled] · …) × channels (columns: Email · In-app) of toggles, with section copy, the saving/saved/error inline states, and the defaults annotated (both channels ON for direct/mention events). Mirror Jira's Notification-settings layout.
Acceptance criteria
design/notifications/{bell,drawer,preferences}.mock.html+ PNGs + thedesign-notes.mdexist; built fromcomponents/ui/*+--el-*/element-shape tokens only (no Tier-0--color-*, no rawrounded-*/fixed control padding); pass the render checklist; AA-safe; light + dark parity.- Panels cover: the bell + badge (zero / 1–99 / 99+ / open), the drawer (Direct default + Watching-disabled seam + overflow "Mark all as read"), the row (actor/summary/time/ blue-dot, unread vs read, single clickable deep-link target, toggle-read affordance), loading / empty / error / "Show more" + at-scale, and the preferences matrix (event × channel toggles + saving/saved/error + annotated defaults + the Watching-event seam).
design-notes.mdnames the composing primitives (IconButton, the count-pill /Badge, the popover/drawer grammar,Avatar, the segmented filter, the overflow menu, the toggle/Switch,ContentSectionCardfor the settings section), the copy strings, the Direct-default + Watching-disabled decision, the "badge = seen-since-open" vs "row = readAt" distinction, and records the realtime non-feature (poll/navigation refresh) + any new--el-*/shape token need for 5.7.5/5.7.6 to add.- No improvised primitive: every element composes the shipped design system; no nested interactive elements inside the clickable row (the portal-popover / nested-button lessons).
Context refs
design/shell/desktop.pen+desktop.png— the header this adds the bell to;app/(authed)/_components/TopNav.tsx/SidebarHeader.tsx/SidebarNav.tsx— the shell header components the bell mounts indesign/work-items/comments.mock.html+design-notes.md(5.1.3) — the sibling Activity/notification surface conventions + the mention-row vocabulary to echocomponents/ui/*—IconButton,Badge/count-pill, the popover + overflow-menu grammar,Avatar,Switch,ContentSectionCard, theErrorState/empty/skeleton patterns- The Jira Cloud header notification bell + drawer (Direct/Watching, blue-dot, "Mark all as read" in the overflow) and the Personal settings → Notification settings page; the Linear Inbox feed model — the mirror surfaces
- Findings #35 (AA: hue in tint bg + strong text), #54 (use the palette); the design-mockup render checklist + portal-popover/nested-button memories