perf+style: grid subscription hygiene, a11y, shadcn-style consistency
Perf / a11y (high-impact review items) - Timeline arrow-key handler binds once per (viewMode, currentSection) and reads fresh state via navStateRef instead of an 8-element dep array of new-each-render values. - usePhotosQuery collapses 14 individual Zustand selectors into one useShallow selector returning the params object. - PhotoThumbnail no longer subscribes to the search query directly; Timeline subscribes once and passes it down as a prop. - PhotoThumbnail gains role="button", tabIndex, aria-label, aria-pressed, Enter/Space key handlers and a focus-visible ring. Timeline marked role="grid"; RightSidebar marked role="region". Style consistency - Swap clsx for cn (tailwind-merge aware) across 17 files so conflicting utility classes collapse correctly. - New Badge primitive (ui/badge.tsx) with default/neutral/overlay/ outline variants; adopted in ColorsView, RatedView, TagsView for the repeated count overlay pill. - Fix palette drift: text-amber-400 -> text-star, text-green-* -> text-pick, text-red-* -> text-reject (5 files). - Button gains an xs size (h-6 px-1.5 text-[11px]) for the repeated compact-button pattern. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,7 @@ import {
|
||||
Users,
|
||||
Download as DownloadIcon,
|
||||
} from 'lucide-react'
|
||||
import clsx from 'clsx'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { useHeapsQuery, HEAPS_QUERY_KEY } from '../../hooks/useHeapsQuery'
|
||||
import { useSharedHeapsQuery } from '../../hooks/useSharingQueries'
|
||||
@@ -262,7 +262,7 @@ export function HeapsPanel() {
|
||||
return (
|
||||
<div
|
||||
key={heap.id}
|
||||
className={clsx(
|
||||
className={cn(
|
||||
'group relative flex h-[24px] cursor-pointer items-center gap-1 rounded px-2 text-[12px] leading-none',
|
||||
isFiltered ? 'bg-primary/20 text-primary' : 'text-text hover:bg-surface-2',
|
||||
// Active-heap row gets a soft primary wash so the
|
||||
@@ -309,7 +309,7 @@ export function HeapsPanel() {
|
||||
}}
|
||||
>
|
||||
<ShoppingBasket
|
||||
className={clsx(
|
||||
className={cn(
|
||||
'h-3.5 w-3.5 flex-shrink-0',
|
||||
isActive || isFiltered ? 'text-primary' : 'text-text-muted'
|
||||
)}
|
||||
@@ -335,7 +335,7 @@ export function HeapsPanel() {
|
||||
) : (
|
||||
<>
|
||||
<span
|
||||
className={clsx('truncate', isActive && 'font-semibold')}
|
||||
className={cn('truncate', isActive && 'font-semibold')}
|
||||
title={heap.name}
|
||||
>
|
||||
{heap.name}
|
||||
@@ -387,7 +387,7 @@ export function HeapsPanel() {
|
||||
onOpenChange={(o) => setOpenMenuId(o ? heap.id : null)}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
className={cn(
|
||||
'relative flex-shrink-0',
|
||||
isMenuOpen ? 'block' : 'hidden group-hover:block'
|
||||
)}
|
||||
@@ -474,7 +474,7 @@ export function HeapsPanel() {
|
||||
return (
|
||||
<div
|
||||
key={sh.id}
|
||||
className={clsx(
|
||||
className={cn(
|
||||
'group flex h-[24px] cursor-pointer items-center gap-1 rounded px-2 text-[12px] leading-none',
|
||||
isFiltered ? 'bg-primary/20 text-primary' : 'text-text hover:bg-surface-2',
|
||||
)}
|
||||
@@ -484,7 +484,7 @@ export function HeapsPanel() {
|
||||
}
|
||||
>
|
||||
<Users
|
||||
className={clsx(
|
||||
className={cn(
|
||||
'h-3.5 w-3.5 flex-shrink-0',
|
||||
isFiltered ? 'text-primary' : 'text-text-muted'
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user