fix(nav): numeric inbox badge with active-state contrast

Show the unread count as a number on the collapsed nav rail (not just a dot), and
invert the badge colours on the active row so it isn't an accent-on-accent red blob;
centre the number on the circle.
This commit is contained in:
npeter83 2026-06-18 04:01:19 +02:00
parent ed4194a8d3
commit 00d07b9153

View file

@ -147,31 +147,47 @@ export default function NavSidebar({
"w-full flex items-center gap-3 rounded-lg px-2.5 py-2 text-sm transition";
const name = me.display_name ?? me.email.split("@")[0];
const renderItem = ({ page: p, icon: Icon, label, badge }: NavItem) => (
const renderItem = ({ page: p, icon: Icon, label, badge }: NavItem) => {
const active = page === p;
// On the active row the background is the accent colour, so a same-accent badge would be
// red-on-red. Invert it there (light pill, accent-coloured number) for clean contrast.
const badgeColor = active ? "bg-accent-fg text-accent" : "bg-accent text-accent-fg";
const show = !!badge && badge > 0;
return (
<button
key={p}
onClick={() => setPage(p)}
title={collapsed ? label : undefined}
aria-current={page === p ? "page" : undefined}
aria-current={active ? "page" : undefined}
className={`${rowBase} ${collapsed ? "justify-center px-0" : ""} relative ${
page === p ? "bg-accent text-accent-fg" : "text-muted hover:text-fg hover:bg-card"
active ? "bg-accent text-accent-fg" : "text-muted hover:text-fg hover:bg-card"
}`}
>
<span className="relative shrink-0">
<Icon className="w-[18px] h-[18px]" />
{/* Collapsed rail: a small dot on the icon; expanded: a numeric pill at the row end. */}
{!!badge && badge > 0 && collapsed && (
<span className="absolute -top-1 -right-1 w-2 h-2 rounded-full bg-accent ring-2 ring-bg" />
{/* Collapsed rail: a numeric badge centred on a circle at the icon corner; the ring
matches the row background so it reads cleanly whether the row is active or not. */}
{show && collapsed && (
<span
className={`absolute -top-2 -right-2 min-w-[16px] h-4 px-1 rounded-full text-[10px] font-bold leading-none grid place-items-center ring-2 ${badgeColor} ${
active ? "ring-accent" : "ring-bg"
}`}
>
{badge > 9 ? "9+" : badge}
</span>
)}
</span>
{!collapsed && <span className="truncate">{label}</span>}
{!!badge && badge > 0 && !collapsed && (
<span className="ml-auto min-w-[18px] h-[18px] px-1 rounded-full bg-accent text-accent-fg text-[11px] font-semibold inline-flex items-center justify-center tabular-nums">
{show && !collapsed && (
<span
className={`ml-auto min-w-[18px] h-[18px] px-1.5 rounded-full text-[11px] font-semibold leading-none inline-flex items-center justify-center tabular-nums ${badgeColor}`}
>
{badge > 99 ? "99+" : badge}
</span>
)}
</button>
);
};
return (
<nav