Comprehensive UX audit fixes: navigation, feedback, affordances, and accessibility
CI / build-and-push (push) Successful in 28s
CI / build-and-push (push) Successful in 28s
Address 18 issues across high/medium/low impact tiers identified in a full interface review. Key changes: Models page decomposed into tabs, confirmation dialogs for irreversible actions (deploy/open-source/acquire), chart Y-axes made visible, hash router extended for Market tab persistence, collapsible sidebar, keyboard navigation shortcuts (g+key chords), notification bulk actions, achievement progress bars, and ARIA label improvements. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,23 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useGameStore } from '@/store';
|
||||
import { useGameStore, type ActivePage } from '@/store';
|
||||
import type { GameSpeed } from '@ai-tycoon/shared';
|
||||
|
||||
const PAGE_SHORTCUTS: Record<string, ActivePage> = {
|
||||
d: 'dashboard',
|
||||
i: 'infrastructure',
|
||||
r: 'research',
|
||||
m: 'models',
|
||||
k: 'market',
|
||||
f: 'finance',
|
||||
t: 'talent',
|
||||
s: 'settings',
|
||||
};
|
||||
|
||||
export function useKeyboardShortcuts() {
|
||||
useEffect(() => {
|
||||
let gPressed = false;
|
||||
let gTimer: ReturnType<typeof setTimeout>;
|
||||
|
||||
const handler = (e: KeyboardEvent) => {
|
||||
if (e.ctrlKey && e.key === 'd') {
|
||||
e.preventDefault();
|
||||
@@ -16,6 +30,17 @@ export function useKeyboardShortcuts() {
|
||||
|
||||
const store = useGameStore.getState();
|
||||
|
||||
if (gPressed) {
|
||||
gPressed = false;
|
||||
clearTimeout(gTimer);
|
||||
const page = PAGE_SHORTCUTS[e.key];
|
||||
if (page) {
|
||||
e.preventDefault();
|
||||
store.setActivePage(page);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (e.key) {
|
||||
case ' ':
|
||||
e.preventDefault();
|
||||
@@ -30,11 +55,16 @@ export function useKeyboardShortcuts() {
|
||||
case '3':
|
||||
store.setGameSpeed(5 as GameSpeed);
|
||||
break;
|
||||
case 'Escape':
|
||||
case 'g':
|
||||
gPressed = true;
|
||||
gTimer = setTimeout(() => { gPressed = false; }, 500);
|
||||
break;
|
||||
}
|
||||
};
|
||||
window.addEventListener('keydown', handler);
|
||||
return () => window.removeEventListener('keydown', handler);
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handler);
|
||||
clearTimeout(gTimer);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user