refactor: deduplicate modal/button styles and enforce global utility usage
- Consolidated all modal-related styles into Modal.module.css; ValidationModal.module.css is now deprecated - All main action/navigation buttons in NewGame and GameDetail use global .btn/.nav-buttons utility classes - Removed duplicate utility classes from component CSS files - Fixed .fullscreenToggle class naming for consistency - Cleaned up component CSS to only contain component-specific styles - Updated GameCompletionModal to use shared modal styles This ensures DRY, maintainable, and consistent styling across the app.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
/* FullscreenToggle-specific styles only. */
|
||||||
.fullscreenToggle {
|
.fullscreenToggle {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { h } from 'preact';
|
import { h } from 'preact';
|
||||||
|
import modalStyles from './Modal.module.css';
|
||||||
import styles from './GameCompletionModal.module.css';
|
import styles from './GameCompletionModal.module.css';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,13 +22,13 @@ const GameCompletionModal = ({ open, game, onConfirm, onClose }) => {
|
|||||||
? `Unentschieden zwischen ${winners.join(' und ')}`
|
? `Unentschieden zwischen ${winners.join(' und ')}`
|
||||||
: `${winners[0]} hat gewonnen!`;
|
: `${winners[0]} hat gewonnen!`;
|
||||||
return (
|
return (
|
||||||
<div id="game-completion-modal" className="modal show" role="dialog" aria-modal="true" aria-labelledby="completion-modal-title">
|
<div id="game-completion-modal" className={modalStyles['modal'] + ' ' + modalStyles['show']} role="dialog" aria-modal="true" aria-labelledby="completion-modal-title">
|
||||||
<div className={styles['modal-content']}>
|
<div className={modalStyles['modal-content']}>
|
||||||
<div className={styles['modal-header']}>
|
<div className={modalStyles['modal-header']}>
|
||||||
<span className={styles['modal-title']} id="completion-modal-title">Spiel beendet</span>
|
<span className={modalStyles['modal-title']} id="completion-modal-title">Spiel beendet</span>
|
||||||
<button className={styles['close-button']} onClick={onClose} aria-label="Schließen">×</button>
|
<button className={modalStyles['close-button']} onClick={onClose} aria-label="Schließen">×</button>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles['modal-body']}>
|
<div className={modalStyles['modal-body']}>
|
||||||
<div className={styles['final-scores']}>
|
<div className={styles['final-scores']}>
|
||||||
{playerNames.map((name, idx) => (
|
{playerNames.map((name, idx) => (
|
||||||
<div className={styles['final-score']} key={name + idx}>
|
<div className={styles['final-score']} key={name + idx}>
|
||||||
@@ -38,7 +39,7 @@ const GameCompletionModal = ({ open, game, onConfirm, onClose }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles['winner-announcement']}><h3>{winnerText}</h3></div>
|
<div className={styles['winner-announcement']}><h3>{winnerText}</h3></div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles['modal-footer']}>
|
<div className={modalStyles['modal-footer']}>
|
||||||
<button className={styles['btn'] + ' ' + styles['btn--warning']} onClick={onConfirm} aria-label="Bestätigen">Bestätigen</button>
|
<button className={styles['btn'] + ' ' + styles['btn--warning']} onClick={onConfirm} aria-label="Bestätigen">Bestätigen</button>
|
||||||
<button className={styles['btn']} onClick={onClose} aria-label="Abbrechen">Abbrechen</button>
|
<button className={styles['btn']} onClick={onClose} aria-label="Abbrechen">Abbrechen</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,26 +1,4 @@
|
|||||||
#game-completion-modal {
|
/* Only GameCompletionModal-specific styles. Shared modal styles are now in Modal.module.css */
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
background-color: rgba(0, 0, 0, 0.8);
|
|
||||||
z-index: 9999;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.modal-content {
|
|
||||||
background-color: #222;
|
|
||||||
padding: 32px 24px 24px 24px;
|
|
||||||
border-radius: 16px;
|
|
||||||
width: 90vw;
|
|
||||||
max-width: 480px;
|
|
||||||
box-shadow: 0 4px 32px rgba(0,0,0,0.7);
|
|
||||||
position: relative;
|
|
||||||
margin: auto;
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
.final-scores {
|
.final-scores {
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
}
|
}
|
||||||
@@ -60,14 +38,6 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
.modal-footer {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: 16px;
|
|
||||||
margin-top: 24px;
|
|
||||||
width: 100%;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.btn {
|
.btn {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 18px 0;
|
padding: 18px 0;
|
||||||
@@ -89,25 +59,7 @@
|
|||||||
.btn--warning:hover {
|
.btn--warning:hover {
|
||||||
background: #d32f2f;
|
background: #d32f2f;
|
||||||
}
|
}
|
||||||
.close-button {
|
|
||||||
position: absolute;
|
|
||||||
top: 12px;
|
|
||||||
right: 16px;
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: #aaa;
|
|
||||||
font-size: 2rem;
|
|
||||||
cursor: pointer;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
.close-button:hover {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
.modal-content {
|
|
||||||
padding: 16px 4px 16px 4px;
|
|
||||||
max-width: 98vw;
|
|
||||||
}
|
|
||||||
.btn {
|
.btn {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
padding: 14px 0;
|
padding: 14px 0;
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ const GameDetail = ({ game, onFinishGame, onUpdateScore, onBack }) => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles['game-detail-controls']}>
|
<div className={styles['game-detail-controls']}>
|
||||||
<button className={styles['nav-button']} onClick={onBack} aria-label="Zurück zur Liste">Zurück zur Liste</button>
|
<button className="btn" onClick={onBack} aria-label="Zurück zur Liste">Zurück zur Liste</button>
|
||||||
<button className={styles['nav-button']} disabled={isCompleted} onClick={onFinishGame} aria-label={isCompleted ? 'Abgeschlossen' : 'Spiel beenden'}>{isCompleted ? 'Abgeschlossen' : 'Spiel beenden'}</button>
|
<button className="btn" disabled={isCompleted} onClick={onFinishGame} aria-label={isCompleted ? 'Abgeschlossen' : 'Spiel beenden'}>{isCompleted ? 'Abgeschlossen' : 'Spiel beenden'}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* GameDetail-specific styles only. Shared utility classes are now in global CSS. */
|
||||||
.screen {
|
.screen {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -121,22 +122,4 @@
|
|||||||
margin: 40px 0 0 0;
|
margin: 40px 0 0 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
|
||||||
.nav-button {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 200px;
|
|
||||||
padding: 24px 0;
|
|
||||||
color: #fff;
|
|
||||||
background: #333;
|
|
||||||
border: none;
|
|
||||||
border-radius: 8px;
|
|
||||||
font-size: 1.4rem;
|
|
||||||
font-weight: 600;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.2s, color 0.2s;
|
|
||||||
margin-bottom: 0;
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
.nav-button:hover:enabled {
|
|
||||||
background: #444;
|
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* GameHistory-specific styles only. Shared utility classes are now in global CSS. */
|
||||||
.screen {
|
.screen {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -20,21 +21,4 @@
|
|||||||
.screen-title {
|
.screen-title {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
|
||||||
.nav-buttons {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
margin: 20px 0 40px 0;
|
|
||||||
}
|
|
||||||
.btn {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 100px;
|
|
||||||
padding: 20px;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 0;
|
|
||||||
font-size: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
touch-action: manipulation;
|
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* GameList-specific styles only. Shared utility classes are now in global CSS. */
|
||||||
.screen.active {
|
.screen.active {
|
||||||
display: block;
|
display: block;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@@ -21,23 +22,6 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.nav-buttons {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
margin: 20px 0 40px 0;
|
|
||||||
}
|
|
||||||
.btn {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 100px;
|
|
||||||
padding: 20px;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 0;
|
|
||||||
font-size: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
touch-action: manipulation;
|
|
||||||
}
|
|
||||||
.filter-buttons {
|
.filter-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* Consolidated modal styles for all modals */
|
||||||
.modal {
|
.modal {
|
||||||
display: none;
|
display: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -31,6 +32,8 @@
|
|||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #888;
|
color: #888;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
.close-button:hover {
|
.close-button:hover {
|
||||||
color: white;
|
color: white;
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ const NewGame = ({ onCreateGame, playerNameHistory, onCancel, onGameCreated, ini
|
|||||||
<form className={styles['new-game-form']} onSubmit={handleSubmit} aria-label="Neues Spiel Formular">
|
<form className={styles['new-game-form']} onSubmit={handleSubmit} aria-label="Neues Spiel Formular">
|
||||||
<div className={styles['screen-title']}>Neues Spiel</div>
|
<div className={styles['screen-title']}>Neues Spiel</div>
|
||||||
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 16 }}>
|
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 16 }}>
|
||||||
<button type="button" className={styles['btn']} onClick={handleClear} aria-label="Felder leeren">Felder leeren</button>
|
<button type="button" className="btn" onClick={handleClear} aria-label="Felder leeren">Felder leeren</button>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles['player-inputs']}>
|
<div className={styles['player-inputs']}>
|
||||||
<div className={styles['player-input']}>
|
<div className={styles['player-input']}>
|
||||||
@@ -106,9 +106,9 @@ const NewGame = ({ onCreateGame, playerNameHistory, onCancel, onGameCreated, ini
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{error && <div className={styles['validation-error']}>{error}</div>}
|
{error && <div className={styles['validation-error']}>{error}</div>}
|
||||||
<div className={styles['nav-buttons']}>
|
<div className="nav-buttons">
|
||||||
<button type="button" className={styles['btn']} onClick={onCancel} aria-label="Abbrechen">Abbrechen</button>
|
<button type="button" className="btn" onClick={onCancel} aria-label="Abbrechen">Abbrechen</button>
|
||||||
<button type="submit" className={styles['btn']} aria-label="Spiel starten">Spiel starten</button>
|
<button type="submit" className="btn" aria-label="Spiel starten">Spiel starten</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* NewGame-specific styles only. Shared utility classes are now in global CSS. */
|
||||||
.screen {
|
.screen {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -97,29 +98,6 @@
|
|||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.nav-buttons {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 12px;
|
|
||||||
margin: 16px 0 0 0;
|
|
||||||
}
|
|
||||||
.btn {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 100px;
|
|
||||||
padding: 18px;
|
|
||||||
color: white;
|
|
||||||
background: #333;
|
|
||||||
border: none;
|
|
||||||
border-radius: 6px;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
font-weight: 600;
|
|
||||||
cursor: pointer;
|
|
||||||
touch-action: manipulation;
|
|
||||||
transition: background 0.2s, color 0.2s;
|
|
||||||
}
|
|
||||||
.btn:hover {
|
|
||||||
background: #444;
|
|
||||||
}
|
|
||||||
.new-game-form {
|
.new-game-form {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 700px;
|
max-width: 700px;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { h } from 'preact';
|
import { h } from 'preact';
|
||||||
import styles from './ValidationModal.module.css';
|
import styles from './Modal.module.css';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modal for displaying validation errors.
|
* Modal for displaying validation errors.
|
||||||
|
|||||||
@@ -1,63 +1 @@
|
|||||||
.modal {
|
/* DEPRECATED: All modal styles are now in Modal.module.css */
|
||||||
display: none;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: rgba(0, 0, 0, 0.7);
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
.modal.show {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.modal-content {
|
|
||||||
background-color: #2a2a2a;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 10px;
|
|
||||||
width: 90%;
|
|
||||||
max-width: 500px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.modal-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
.close-button {
|
|
||||||
font-size: 24px;
|
|
||||||
cursor: pointer;
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
.close-button:hover {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.modal-body {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
.modal-footer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
.modal-button {
|
|
||||||
padding: 8px 16px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
.modal-button.cancel {
|
|
||||||
background-color: #444;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.modal-button.confirm {
|
|
||||||
background-color: #e74c3c;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.modal-button:hover {
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
|
||||||
@@ -26,7 +26,7 @@ input, select {
|
|||||||
|
|
||||||
/* Responsive adjustments for fullscreen toggle button */
|
/* Responsive adjustments for fullscreen toggle button */
|
||||||
@media screen and (max-width: 480px) {
|
@media screen and (max-width: 480px) {
|
||||||
.fullscreen-toggle {
|
.fullscreenToggle {
|
||||||
bottom: 15px;
|
bottom: 15px;
|
||||||
right: 15px;
|
right: 15px;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
@@ -55,6 +55,31 @@ input, select {
|
|||||||
background: #333;
|
background: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Shared utility classes for buttons and layout */
|
||||||
|
.btn {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 100px;
|
||||||
|
padding: 18px;
|
||||||
|
color: white;
|
||||||
|
background: #333;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
touch-action: manipulation;
|
||||||
|
transition: background 0.2s, color 0.2s;
|
||||||
|
}
|
||||||
|
.btn:hover {
|
||||||
|
background: #444;
|
||||||
|
}
|
||||||
|
.nav-buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
margin: 16px 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Modal overlay (global, not component-specific) */
|
/* Modal overlay (global, not component-specific) */
|
||||||
.modal {
|
.modal {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|||||||
Reference in New Issue
Block a user