Compare commits

2 Commits

Author SHA1 Message Date
Frank Schwenk
d016868ff2 feat(ux): autofocus name inputs on new game steps\n\nFocus Player 1/2/3 inputs on mount and place caret at end for faster entry.\n\nNo behavior changes beyond focus; adheres to accessibility with native focus.\n\nRefs #26 2025-10-30 10:15:30 +01:00
Frank Schwenk
89300bc021 fix(ui): align delete icon inline in game list
Apply game-item grid layout to game list rows and switch to two-column layout (1fr auto) so the delete action has a fixed-width slot on the right.

Keeps existing delete button and accessibility attributes; prevents layout stretch.
No behavioral changes beyond layout; click targets unchanged.

Refs #26
2025-10-30 10:04:11 +01:00
3 changed files with 37 additions and 2 deletions

View File

@@ -76,7 +76,7 @@
/* Game item with better symmetry and spacing */ /* Game item with better symmetry and spacing */
.game-item { .game-item {
display: grid; display: grid;
grid-template-columns: auto 1fr auto; grid-template-columns: 1fr auto;
align-items: center; align-items: center;
gap: var(--space-md); gap: var(--space-md);
padding: var(--space-lg); padding: var(--space-lg);

View File

@@ -82,7 +82,9 @@ export default function GameList({
<Card <Card
key={game.id} key={game.id}
variant="elevated" variant="elevated"
className={game.status === 'completed' ? styles['completed'] : styles['active']} className={
styles['game-item'] + ' ' + (game.status === 'completed' ? styles['completed'] : styles['active'])
}
> >
<div <div
className={styles['game-info']} className={styles['game-info']}

View File

@@ -56,6 +56,17 @@ const Player1Step = ({ playerNameHistory, onNext, onCancel, initialValue = '' }:
const [isModalOpen, setIsModalOpen] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false);
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
const el = inputRef.current;
if (el) {
el.focus();
const end = el.value.length;
try {
el.setSelectionRange(end, end);
} catch {}
}
}, []);
useEffect(() => { useEffect(() => {
if (!player1) { if (!player1) {
setFilteredNames(playerNameHistory); setFilteredNames(playerNameHistory);
@@ -296,6 +307,17 @@ const Player2Step = ({ playerNameHistory, onNext, onCancel, initialValue = '' }:
const [filteredNames, setFilteredNames] = useState(playerNameHistory); const [filteredNames, setFilteredNames] = useState(playerNameHistory);
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
const el = inputRef.current;
if (el) {
el.focus();
const end = el.value.length;
try {
el.setSelectionRange(end, end);
} catch {}
}
}, []);
useEffect(() => { useEffect(() => {
if (!player2) { if (!player2) {
setFilteredNames(playerNameHistory); setFilteredNames(playerNameHistory);
@@ -430,6 +452,17 @@ const Player3Step = ({ playerNameHistory, onNext, onCancel, initialValue = '' }:
const [filteredNames, setFilteredNames] = useState(playerNameHistory); const [filteredNames, setFilteredNames] = useState(playerNameHistory);
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
const el = inputRef.current;
if (el) {
el.focus();
const end = el.value.length;
try {
el.setSelectionRange(end, end);
} catch {}
}
}, []);
useEffect(() => { useEffect(() => {
if (!player3) { if (!player3) {
setFilteredNames(playerNameHistory); setFilteredNames(playerNameHistory);