diff --git a/.Jules/palette.md b/.Jules/palette.md new file mode 100644 index 0000000..6b89342 --- /dev/null +++ b/.Jules/palette.md @@ -0,0 +1,7 @@ +## 2025-05-14 - [A11y: Semantic Buttons and Focus States] +**Learning:** Using semantic ` ))} {remainingCount > 0 && ( @@ -73,19 +74,20 @@ const GameCard: React.FC = ({ game, onClick, viewMode, onFilter, return (
{allMetadata.map((item) => ( - { e.stopPropagation(); e.preventDefault(); console.log('[GameCard] Metadata tag clicked:', item.type, item.name); onFilter?.(item.type, item.name); }} - className="px-1.5 py-0.5 text-xs rounded bg-gray-700/50 theme-text-muted hover:bg-indigo-600/30 transition-colors cursor-pointer select-none" - role="button" + className="px-1.5 py-0.5 text-xs rounded bg-gray-700/50 theme-text-muted hover:bg-indigo-600/30 transition-colors cursor-pointer select-none focus-visible:ring-2 focus-visible:ring-indigo-500" + aria-label={`${t(item.type as any)}: ${item.name}`} > {item.name} - + ))}
); @@ -132,18 +134,19 @@ const GameCard: React.FC = ({ game, onClick, viewMode, onFilter, const label = COMPLETION_STATUS_LABELS[completion_status as keyof typeof COMPLETION_STATUS_LABELS] || completion_status; return ( - { e.stopPropagation(); e.preventDefault(); console.log('[GameCard] Status badge clicked:', completion_status); onFilter?.('status', completion_status); }} - className={`absolute top-2 left-2 px-2 py-1 rounded-full text-xs text-white ${statusColors[completion_status] || 'bg-gray-600'} hover:opacity-80 transition-opacity cursor-pointer select-none`} - role="button" + className={`absolute top-2 left-2 px-2 py-1 rounded-full text-xs text-white z-10 ${statusColors[completion_status] || 'bg-gray-600'} hover:opacity-80 transition-opacity cursor-pointer select-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-white`} + aria-label={`${t('completionStatus')}: ${label}`} > {label} - + ); }; diff --git a/src/components/Library/GameDetailHeader.tsx b/src/components/Library/GameDetailHeader.tsx index aa3d128..4e1bccc 100644 --- a/src/components/Library/GameDetailHeader.tsx +++ b/src/components/Library/GameDetailHeader.tsx @@ -276,8 +276,10 @@ export function GameDetailHeader({ game, onGameUpdated, onPlatformChange, onFilt {game.genres.map((genre) => ( @@ -292,8 +294,10 @@ export function GameDetailHeader({ game, onGameUpdated, onPlatformChange, onFilt {game.game_modes.map((mode) => ( @@ -308,8 +312,10 @@ export function GameDetailHeader({ game, onGameUpdated, onPlatformChange, onFilt {game.player_perspectives.map((persp) => ( @@ -324,8 +330,10 @@ export function GameDetailHeader({ game, onGameUpdated, onPlatformChange, onFilt {game.themes.map((theme) => ( diff --git a/src/components/Library/GameScreenshotsCarousel.tsx b/src/components/Library/GameScreenshotsCarousel.tsx index 6a4e37c..bfae3b8 100644 --- a/src/components/Library/GameScreenshotsCarousel.tsx +++ b/src/components/Library/GameScreenshotsCarousel.tsx @@ -20,7 +20,6 @@ export function GameScreenshotsCarousel({ gameId }: GameScreenshotsCarouselProps const [igdbScreenshots, setIgdbScreenshots] = useState([]); const [currentIndex, setCurrentIndex] = useState(0); const [loading, setLoading] = useState(true); - const [hasIgdbId, setHasIgdbId] = useState(false); useEffect(() => { const loadScreenshots = async () => { @@ -29,7 +28,6 @@ export function GameScreenshotsCarousel({ gameId }: GameScreenshotsCarouselProps // Load game data to check IGDB ID try { const game = await invoke<{ igdb_id: number | null }>("get_game_by_id", { id: gameId }); - setHasIgdbId(!!game?.igdb_id); // Load IGDB screenshots if available if (game?.igdb_id) {