a11y: announce live updates for notifications, wallet balance, DMs (U3)

Add aria-live="polite" to the three dynamic surfaces screen-reader
users otherwise miss:
- Notification bell unread-count badge (with an "N unread notifications"
  label so the number is announced meaningfully, not read as bare digits)
- Cashu wallet balance value (announces the new balance after a
  send/receive completes)
- Direct-message conversation thread: role="log" + aria-live so
  incoming messages are announced as they arrive

ToastViewport already announces via the Radix default and was left
untouched.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy 2026-09-24 19:39:09 +07:00
parent 0b83749aa1
commit 01d35823cc
3 changed files with 16 additions and 3 deletions

View file

@ -291,7 +291,11 @@ export function NotificationBell({ className }: { className?: string }) {
)} )}
/> />
{badgeTotal > 0 && ( {badgeTotal > 0 && (
<span className="absolute -right-1 -top-1 flex min-w-[18px] items-center justify-center rounded-full bg-[#ccff00] px-1 text-[10px] font-black leading-[18px] text-black shadow-[0_0_8px_rgba(204,255,0,0.6)] ring-2 ring-black"> <span
aria-live="polite"
aria-label={`${badgeTotal} unread notifications`}
className="absolute -right-1 -top-1 flex min-w-[18px] items-center justify-center rounded-full bg-[#ccff00] px-1 text-[10px] font-black leading-[18px] text-black shadow-[0_0_8px_rgba(204,255,0,0.6)] ring-2 ring-black"
>
{badgeTotal > 9 ? '9+' : badgeTotal} {badgeTotal > 9 ? '9+' : badgeTotal}
</span> </span>
)} )}

View file

@ -380,7 +380,11 @@ function CashuWalletCardNative() {
<div className="flex items-center justify-between py-3 px-4 rounded-xl bg-orange-500/10 border border-orange-500/20"> <div className="flex items-center justify-between py-3 px-4 rounded-xl bg-orange-500/10 border border-orange-500/20">
<div> <div>
<div className="text-[10px] text-orange-400/80 uppercase tracking-widest font-bold mb-0.5">Balance</div> <div className="text-[10px] text-orange-400/80 uppercase tracking-widest font-bold mb-0.5">Balance</div>
<div className="text-2xl font-black tabular-nums leading-none"> <div
className="text-2xl font-black tabular-nums leading-none"
aria-live="polite"
aria-label={`Wallet balance ${totalBalance.toLocaleString()} sats`}
>
{totalBalance.toLocaleString()} {totalBalance.toLocaleString()}
<span className="text-sm font-semibold text-muted-foreground ml-1.5">sats</span> <span className="text-sm font-semibold text-muted-foreground ml-1.5">sats</span>
</div> </div>

View file

@ -231,7 +231,12 @@ export default function ConversationPage() {
</div> </div>
{/* Messages Area */} {/* Messages Area */}
<div className="flex-1 overflow-y-auto py-3 sm:py-4 space-y-2 sm:space-y-3 min-h-0"> <div
className="flex-1 overflow-y-auto py-3 sm:py-4 space-y-2 sm:space-y-3 min-h-0"
role="log"
aria-live="polite"
aria-label="Message conversation"
>
{isLoading ? ( {isLoading ? (
<> <>
<MessageSkeleton isFromMe={false} /> <MessageSkeleton isFromMe={false} />