Chat tagging:
- Any @user is a visible tag in chat bubbles (the .mention-tag CSS never
existed, so highlighting was invisible); self/alias mentions get a gold
emphasis. Fixes cross-room tags not being highlighted.
Mentions window:
- Redesigned: unread count in the header, restyled filter chips + a refresh
button, CSS-driven list/date-groups, adaptive height (compact when few,
capped + scroll when many), polished empty state.
- Rows: framed avatar (friends-list head crop so the face is never clipped),
per-row unread dot, type marker, icon action buttons (goto / remove).
- Re-requests from the server each time it opens.
Autocomplete:
- Never suggests the viewer themselves; suggests room users + online friends +
aliases.
Notifications:
- Mention toast removed; mentions flow through the client's standard
notification stream via a dedicated mention bubble (avatar + actions) in the
default position. EVERY received mention surfaces (independent of the generic
info-feed toggle, gated only by mentions_ui.enabled).
Refactor (behaviour-preserving):
- Centralised @-token classification in api/mentions/mentionTokens.
- Moved mentionsFormat -> api/mentions, useMentionActions -> hooks/mentions.
- Extracted ChatInputView @-autocomplete into a tested useChatMentions hook +
pure helper; removed the dead duplicate useMentionAutocomplete.
useNotification is consumed by ~44 sites in the codebase but most of
them only need a single imperative entry point (typically simpleAlert
or showConfirm). The hook also runs ~24 useMessageEvent listeners
internally to translate server events into queued notifications.
Same singleton-filter pattern as useWiredTools / useTranslation:
- useNotificationStore (internal, was useNotificationState) — the
previous body unchanged. ~30 listeners + 5 state slices + 8 actions
in one closure.
- useNotificationState (public, read-only) — useBetween filter
exposing only the three queue arrays (alerts, bubbleAlerts,
confirms). Used by the global NotificationView renderer.
- useNotificationActions (public, imperative) — useBetween filter
exposing the 8 entry points: simpleAlert / showNitroAlert /
showTradeAlert / showConfirm / showSingleBubble +
closeAlert / closeBubbleAlert / closeConfirm.
- useNotification (deprecated shim) — composes the singleton via
useBetween, preserving the historical return shape so the 44
existing call sites keep working.
Also brings CLAUDE.md's 'What's wired up' table up to date with the
splits done this session (chat-input doorbell-style, wired-tools +
translation singleton-filter, plus this notification one) and the
8 useCatalog fetch migrations to TanStack queries.
Block NotificationDialogMessageEvent badge types to prevent duplicate
bubbles. Wrap bubble content in stopPropagation div so button clicks
don't close the notification before toggleBadge runs. Request badge
data on mount so Wear works even if inventory was never opened.
Both events fire for the same badge, causing two notifications. Track
recently notified badge codes in a Set so only the first event shows
the notification bubble, the second is silently skipped.
Read user.badges.max.slots from config instead of hardcoded 5. InfoStand
layout adapts: 5 slots shows group badge, 6 slots replaces group with
6th badge. Double-click on InfoStand badge removes it. Badge received
toast now directly equips the badge via toggleBadge and closes.
New unseen badges pulse with a gold glow instead of a flat green
background. When a badge is received, a bubble notification appears
with the badge image, name, and a "Wear" button that opens inventory.