Redesign sidebar components for improved accessibility, visual hierarchy, and hover/active state differentiation.

This commit is contained in:
MartinBraquet
2026-07-23 17:44:45 +02:00
parent f168ce2466
commit 8a562a1470
3 changed files with 17 additions and 18 deletions

View File

@@ -18,18 +18,16 @@ export function ProfileSummary(props: {user: User; className?: string; currentPa
href={profile === null ? '/signup' : `/${user.username}`}
onClick={trackCallback('sidebar: profile')}
className={clsx(
'group flex w-full shrink-0 flex-row items-center truncate rounded-xl py-3 transition-all',
'group flex w-full shrink-0 flex-row items-center truncate rounded-lg py-2.5 transition-colors',
className,
isSelected && 'bg-canvas-900',
isSelected && 'bg-primary-500/15',
)}
>
<div className="w-2 shrink" />
<Avatar avatarUrl={profile?.pinned_url ?? ''} username={user.username} noLink />
<div className="mr-1 w-2 shrink-[2]" />
<div className="shrink-0 grow" data-testid="sidebar-username">
<div className="sidebar-text group-hover:text-primary-700 group-hover:translate-x-[2px]">
{user.name}
</div>
<div className={clsx('sidebar-text', isSelected && 'text-primary-500')}>{user.name}</div>
</div>
<div className="w-2 shrink" />
</Link>

View File

@@ -28,11 +28,13 @@ export function SidebarItem(props: {item: Item; currentPage?: string}) {
}
const sidebarClass = clsx(
isCurrentPage
? 'bg-canvas-900 text-primary-600'
: 'sidebar-text hover:text-primary-700 hover:translate-x-[2px]',
'group flex items-center rounded-xl px-3 py-2 text-sm font-medium',
'focus-visible:bg-ink-100 outline-none transition-all',
'group relative flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium',
'outline-none transition-colors duration-150',
// Active is a warm amber-washed pill, not the same neutral fill as hover — the two used to be
// near-identical (both `bg-canvas-900`), so the current page barely stood out. Hover uses the
// canvas-900 "sidebar pressed" token, which is theme-aware on the always-dark rail.
isCurrentPage ? 'bg-primary-500/15 text-primary-500' : 'sidebar-text hover:bg-canvas-900',
'focus-visible:bg-canvas-900',
)
const sidebarItem = (
@@ -40,10 +42,9 @@ export function SidebarItem(props: {item: Item; currentPage?: string}) {
{item.icon && (
<item.icon
className={clsx(
isCurrentPage
? 'text-primary-600'
: 'sidebar-text group-hover:text-primary-700 group-hover:translate-x-[2px]',
'-ml-1 mr-3 h-6 w-6 flex-shrink-0 transition-all',
'h-5 w-5 flex-shrink-0 transition',
// Muted until active/hovered — modern icon hierarchy — but always full-amber when current.
isCurrentPage ? 'text-primary-500' : 'sidebar-text opacity-70 group-hover:opacity-100',
)}
aria-hidden="true"
/>

View File

@@ -56,16 +56,16 @@ export default function Sidebar(props: {
{user && !isMobile && (
<>
<div className="h-px bg-canvas-900 mb-4" />
<div className="h-px bg-white/[0.06] mb-4" />
<ProfileSummary
user={user}
className="mb-3 sidebar-text hover:text-primary-700 hover:translate-x-[2px]"
className="mb-3 sidebar-text transition-colors hover:bg-canvas-900"
currentPage={currentPage}
/>
</>
)}
<div className="h-px bg-canvas-900 mb-4" />
<div className="h-px bg-white/[0.06] mb-4" />
<div className="mb-4 flex flex-col gap-1 overflow-y-auto overflow-x-hidden">
{navOptions.map((item) => (
@@ -81,7 +81,7 @@ export default function Sidebar(props: {
)}
</div>
<div className="mb-[12px] mt-auto flex flex-col gap-1">
<div className="h-px bg-canvas-900" />
<div className="h-px bg-white/[0.06]" />
{!isAndroid && (
<SidebarItem
item={{