An interactive rebuild of the engagement tray — the right-docked drawer, its notification, community and profile screens, and the in-place Edit Profile form. Controls on the left drive every state; the Components tab above inventories what this proposal reuses, restyles, reworks and needs built.
Click a rail item, the avatar, Follow, or Mute directly to cycle their states — the workbench controls stay in sync.
Tray shell (tray.vue / tray-navigation.vue) — now simulated as the real right-docked drawer it is, full viewport height, not a floating card. No scrim: the drawer slides over an article the reader is still meant to see, so dimming the page states the wrong relationship — a scrim suspends what is behind it, which is true of a modal and false of a panel you open to check one notification. The drawer's box-shadow carries the separation on its own. The trade is that there is no click-out target, so dismissal is the X or Escape. The top tab row is a vertical rail, 56px and icon-only, with an expand/collapse button at its head — per request, replacing a hover reveal. Hovering fired on the way past (crossing the rail to reach the close X opened it), reported no state to assistive tech, and had no touch equivalent; a button carries aria-expanded and stays where you put it. Expanding overlays the content rather than pushing it, per request: the rail's own box stays 56px and the 188px panel floats over the rows on a drop shadow. Nothing downstream reflows, so rows keep their full 480px measure — revealing some labels never re-wraps row text or resizes a thumbnail. The cost is that the left 188px of the content column is covered while it is open, and the same button uncovers it. On mobile that is the only workable choice: at 375px the rows are already down to 317px, and pushing would have left them 185. Notifications carries an unread badge, counted the way notification-list-item.vue defines unread (new or seen), off the live list rather than the seed data. The drawer is 528px — widened by exactly the rail's collapsed width, so rows keep the full 480px measure the real tray gives them. Opening and closing slides the panel its own width; the first paint is deliberately un-animated so a drawer that starts open does not slide in on load. The Notifications and Profile tabs render the real notification and activity components, shared with the Feed & Activity state matrix — same CSS, same row primitives, injected from the same two partials. Every design change that sheet lets you toggle is switched on here, permanently; this is the proposal in situ, not a comparison. Per request, the separate cog-icon Settings tab is gone. Your own profile has no sub-tab row: it shows Comment History under an ordinary section-header.vue heading, and Edit Profile is a header button, left of Sign Out — a toggle (aria-pressed), since with no Comment History control there is nothing else to navigate to and pressing it again is the way back. Edit Profile is four independent <fieldset>s — Profile Picture, Name & Email, Change Password, Notification Preferences — each named by aria-labelledby pointing at its own section header. The first three own a submit, always present, labelled Update and disabled until that fieldset is dirty and valid. Dirty is measured against the values the form mounted with, so clearing a field back to its original is not a change. Pressing it holds a spinner centred on the still-disabled button; on success the spinner morphs into a checkmark and the button turns green at the same moment, with no label under either — that colour and glyph ARE the confirmation now, replacing a separate "Profile updated" message, and after a beat the button reverts to disabled Update. Notification Preferences has no submit, because its switches always saved themselves. Text fields are design-system/primitives/input/InputText.vue — an outlined box with the label above it — replacing settings.html's floating-label field with the expanding blue underline. Contents are otherwise still the whole of settings.html — the shipped 35×18 toggles, all five push-permission messages, loader-button's pending spinner and status.vue's banner — and the real strings (Invalid email address, New passwords do not match) with the offending field going red — which in the primitive means its border going transparent and a 1px error outline taking over, so an invalid field is exactly the same size as a valid one. This is a departure from the code, not a rendering of it: settings.html is one form with one submit, so four submits means splitting tryUpdateProfile() into per-fieldset dispatches — and the API's old_password requirement for email and password changes no longer has one shared field to live in. Flagged in the workbench rather than papered over. Sign Out stays at the tiny Button variant, rightmost, being a destructive action rather than a destination. Includes a real Avatar Picker component (.Avatar Picker, node 23841:9054) the code doesn't visually implement yet. Feed and Community tabs are honest placeholders — not built this pass.
Code reference: src/components/tray/tray-navigation.vue (nav chrome, real i18n copy), src/components/tray_content/profile/header.vue (permutation logic). Change Profile Information is the whole of settings.html: settings.js, avatar_upload.vue, input-list.vue → form/input/{text,input,floating_input_wrapper}.vue, update_password.vue, verify_password.vue, toggle_settings/{toggle_settings.js,constants.js,util.js} → form/toggle/toggle.c.js, status_message.vue, settings_controls.vue → loader-button.vue + status.vue.
Figma reference: Shared Components file hyDu1jEHR3HQY6ZZgAfURL — Button (node 61:347, exact tiny/base tokens via get_variable_defs), Avatar (node 61:341), Avatar Picker (node 23841:9054: Default/Hover/Uploading/Uploaded/Delete/Error).
"Removed", "Reported", "Unauthorised", and the Avatar Picker's upload-progress/delete-overlay states are documented in the shared library but not yet wired into the current code — included here to show what's available. Feed and Community tabs are placeholders, not built this pass.
Note: merging Settings into an in-place "Edit Profile" view on the Profile tab, and the Sign Out placement/size, are this session's proposed reorganization — tray-navigation.vue still ships a separate Settings tab today.
Every path below was read in viafoura-front at master, not inferred from the prototype. Where the prototype and the code disagree the code is quoted, because the point of this page is to price the rebuild rather than to describe the mock. Verdicts: reuse renders as-is; restyle keeps the component and changes only CSS; rework changes its template, props or behaviour; retire stops being rendered; new has no implementation to modify.