refactor: Update Race To step UI and logic
- Renames 'Offen' to 'Endlos' and moves it to a separate line. - Extends quick-pick buttons to include 1-9. - Removes 'Custom' button and makes numeric input always visible. - Updates placeholder text for the custom input. - Closes #10
This commit is contained in:
2
.gitea
2
.gitea
@@ -1 +1 @@
|
|||||||
@https://gitea.schwenk.online/froxxxy/bscscore/issues/9
|
@https://gitea.schwenk.online/froxxxy/bscscore/issues/10
|
||||||
@@ -2,7 +2,7 @@ import { h } from 'preact';
|
|||||||
import { useState, useEffect, useCallback } from 'preact/hooks';
|
import { useState, useEffect, useCallback } from 'preact/hooks';
|
||||||
import GameList from './GameList.jsx';
|
import GameList from './GameList.jsx';
|
||||||
import GameDetail from './GameDetail.jsx';
|
import GameDetail from './GameDetail.jsx';
|
||||||
import { Player1Step, Player2Step, Player3Step, GameTypeStep } from './NewGame.jsx';
|
import { Player1Step, Player2Step, Player3Step, GameTypeStep, RaceToStep } from './NewGame.jsx';
|
||||||
import Modal from './Modal.jsx';
|
import Modal from './Modal.jsx';
|
||||||
import ValidationModal from './ValidationModal.jsx';
|
import ValidationModal from './ValidationModal.jsx';
|
||||||
import GameCompletionModal from './GameCompletionModal.jsx';
|
import GameCompletionModal from './GameCompletionModal.jsx';
|
||||||
@@ -156,10 +156,9 @@ const App = () => {
|
|||||||
setNewGameStep('raceTo');
|
setNewGameStep('raceTo');
|
||||||
};
|
};
|
||||||
const handleRaceToNext = (raceTo) => {
|
const handleRaceToNext = (raceTo) => {
|
||||||
setNewGameData(data => ({ ...data, raceTo }));
|
const finalData = { ...newGameData, raceTo };
|
||||||
// Finalize game creation here
|
const newId = handleCreateGame(finalData);
|
||||||
// For now, just go back to game list
|
showGameDetail(newId);
|
||||||
setScreen('game-list');
|
|
||||||
setNewGameStep(null);
|
setNewGameStep(null);
|
||||||
setNewGameData({ player1: '', player2: '', player3: '', gameType: '', raceTo: '' });
|
setNewGameData({ player1: '', player2: '', player3: '', gameType: '', raceTo: '' });
|
||||||
};
|
};
|
||||||
@@ -221,10 +220,11 @@ const App = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{newGameStep === 'raceTo' && (
|
{newGameStep === 'raceTo' && (
|
||||||
<div style={{ padding: 40, textAlign: 'center' }}>
|
<RaceToStep
|
||||||
<h2>Race To Step (TODO)</h2>
|
onNext={handleRaceToNext}
|
||||||
<button onClick={() => handleRaceToNext(5)}>5</button>
|
onCancel={() => setNewGameStep('gameType')}
|
||||||
</div>
|
initialValue={newGameData.raceTo}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -483,4 +483,86 @@ const GameTypeStep = ({ onNext, onCancel, initialValue = '' }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { Player1Step, Player2Step, Player3Step, GameTypeStep };
|
/**
|
||||||
|
* Race To selection step for multi-step game creation wizard.
|
||||||
|
* @param {object} props
|
||||||
|
* @param {Function} props.onNext
|
||||||
|
* @param {Function} props.onCancel
|
||||||
|
* @param {string|number} [props.initialValue]
|
||||||
|
* @returns {import('preact').VNode}
|
||||||
|
*/
|
||||||
|
const RaceToStep = ({ onNext, onCancel, initialValue = '' }) => {
|
||||||
|
const [currentValue, setCurrentValue] = useState(initialValue);
|
||||||
|
const quickPicks = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
|
|
||||||
|
const handleQuickPick = (value) => {
|
||||||
|
onNext(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputChange = (e) => {
|
||||||
|
setCurrentValue(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCustomSubmit = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
onNext(parseInt(currentValue, 10) || 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form className={styles['new-game-form']} onSubmit={handleCustomSubmit} aria-label="Race To auswählen">
|
||||||
|
<div className={styles['screen-title']}>Neues Spiel – Schritt 5/5</div>
|
||||||
|
<div className={styles['progress-indicator']} style={{ marginBottom: 24 }}>
|
||||||
|
<span className={styles['progress-dot']} />
|
||||||
|
<span className={styles['progress-dot']} />
|
||||||
|
<span className={styles['progress-dot']} />
|
||||||
|
<span className={styles['progress-dot']} />
|
||||||
|
<span className={styles['progress-dot'] + ' ' + styles['active']} />
|
||||||
|
</div>
|
||||||
|
<div className={styles['endlos-container']}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`${styles['race-to-btn']} ${styles['endlos-btn']} ${initialValue === 0 ? styles.selected : ''}`}
|
||||||
|
onClick={() => handleQuickPick(0)}
|
||||||
|
>
|
||||||
|
Endlos
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className={styles['race-to-selection']}>
|
||||||
|
{quickPicks.map(value => (
|
||||||
|
<button
|
||||||
|
key={value}
|
||||||
|
type="button"
|
||||||
|
className={`${styles['race-to-btn']} ${parseInt(initialValue, 10) === value ? styles.selected : ''}`}
|
||||||
|
onClick={() => handleQuickPick(value)}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className={styles['custom-race-to']}>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
pattern="[0-9]*"
|
||||||
|
value={currentValue}
|
||||||
|
onInput={handleInputChange}
|
||||||
|
className={styles['name-input']}
|
||||||
|
placeholder="manuelle Eingabe"
|
||||||
|
/>
|
||||||
|
<button type="submit" className={styles['arrow-btn']} aria-label="Bestätigen">✓</button>
|
||||||
|
</div>
|
||||||
|
<div className={styles['arrow-nav']} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 48 }}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={styles['arrow-btn']}
|
||||||
|
aria-label="Zurück"
|
||||||
|
onClick={onCancel}
|
||||||
|
>
|
||||||
|
←
|
||||||
|
</button>
|
||||||
|
<div style={{ width: 80 }} />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Player1Step, Player2Step, Player3Step, GameTypeStep, RaceToStep };
|
||||||
@@ -216,3 +216,62 @@
|
|||||||
background: #4a4a4a;
|
background: #4a4a4a;
|
||||||
border-color: #777;
|
border-color: #777;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.race-to-selection {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(60px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.race-to-btn {
|
||||||
|
background: #2a2a2a;
|
||||||
|
border: 2px solid #333;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 16px 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
transition: background 0.2s, border-color 0.2s;
|
||||||
|
min-height: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.race-to-btn:hover {
|
||||||
|
background: #333;
|
||||||
|
border-color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.race-to-btn.selected {
|
||||||
|
background: #4a4a4a;
|
||||||
|
border-color: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-race-to {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 24px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-race-to input {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-race-to .arrow-btn {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
font-size: 32px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endlos-container {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endlos-btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user