Files
bscscore/src/components/NewGame.module.css
Frank Schwenk 076d6ced36 Implement fixed viewport with internal scrolling
Restructure app layout to prevent whole-page scrolling. The viewport
is now locked at 100vh with overflow:hidden, and individual content
areas scroll internally.

Architecture changes:
- Lock html/body at 100% height with overflow:hidden
- Fix Layout component to 100vh, Screen to 100% height
- Enable internal scrolling for content areas with flex:1 + overflow-y:auto

New game wizard improvements:
- Split forms into three sections: form-header (fixed), form-content
  (scrollable), form-footer (fixed with arrow navigation)
- Fixes issue where many player names pushed navigation arrows off-screen
- Applied to Player1Step, Player2Step, Player3Step, GameTypeStep

Game list improvements:
- Filter buttons stay fixed at top
- Games container scrolls internally with overflow-y:auto
- "Neues Spiel" button wrapped with flex-shrink:0

Game detail improvements:
- Game controls stay visible while content scrolls

Additional changes:
- Add Playwright test artifact exclusions to .gitignore
- Add Docker build instructions to README.md
- Remove unnecessary setSelectionRange calls from player input steps

Benefits:
- No accidental page scrolling
- Cleaner mobile UX (no address bar show/hide issues)
- Navigation controls always visible
- Predictable, contained scrolling behavior
2025-11-07 14:23:03 +01:00

416 lines
10 KiB
CSS

/* NewGame-specific styles only. Shared utility classes are now in global CSS. */
.screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
min-height: 100vh;
display: none;
opacity: 0;
transform: translateX(100%);
transition: transform var(--transition-slow), opacity var(--transition-slow);
}
.screen-content {
display: flex;
flex-direction: column;
height: 100%;
padding: var(--space-lg);
overflow-y: auto;
overflow-x: hidden;
-webkit-overflow-scrolling: touch;
min-height: 0;
}
.screen-title {
font-size: var(--font-size-xxl);
font-weight: 700;
color: var(--color-text);
margin-bottom: var(--space-xl);
letter-spacing: 0.5px;
text-align: center;
}
.player-inputs {
display: flex;
flex-direction: column;
gap: var(--space-lg);
width: 100%;
margin-bottom: var(--space-xl);
}
.player-input {
background: var(--color-background);
border-radius: var(--radius-md);
padding: var(--space-lg);
border: 2px solid var(--color-border);
transition: border-color var(--transition-base);
position: relative;
}
.player-input:focus-within {
border-color: var(--color-primary);
box-shadow: 0 0 0 3px var(--color-primary-light);
}
.player-input label {
display: block;
margin-bottom: var(--space-md);
color: var(--color-text);
font-size: var(--font-size-lg);
font-weight: 600;
}
.name-input-container {
display: flex;
gap: var(--space-md);
position: relative;
}
.name-input {
flex: 1;
padding: var(--space-md);
border: 2px solid var(--color-border);
background: var(--color-surface);
color: var(--color-text);
font-size: var(--font-size-base);
min-height: var(--touch-target-comfortable);
border-radius: var(--radius-md);
transition: all var(--transition-base);
}
.name-input:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px var(--color-primary-light);
}
.game-settings {
margin-top: 0;
width: 100%;
margin-bottom: var(--space-xl);
}
.setting-group {
margin-bottom: var(--space-lg);
}
.setting-group label {
display: block;
margin-bottom: var(--space-md);
color: var(--color-text);
font-size: var(--font-size-lg);
font-weight: 600;
}
.setting-group select, .setting-group input {
width: 100%;
padding: var(--space-md);
border: 2px solid var(--color-border);
background: var(--color-surface);
color: var(--color-text);
font-size: var(--font-size-base);
min-height: var(--touch-target-comfortable);
border-radius: var(--radius-md);
transition: border-color var(--transition-base);
}
.setting-group input:focus, .setting-group select:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px var(--color-primary-light);
}
.validation-error {
color: var(--color-danger);
background: var(--color-surface);
border: 1px solid var(--color-danger);
border-radius: var(--radius-md);
padding: var(--space-md);
margin-bottom: var(--space-md);
font-size: var(--font-size-base);
text-align: center;
font-weight: 500;
}
.new-game-form {
width: 100%;
max-width: 600px;
margin: var(--space-xl) auto 0 auto;
background: var(--color-surface);
border-radius: var(--radius-xl);
box-shadow: var(--shadow-lg);
padding: 0;
display: flex;
flex-direction: column;
border: 1px solid var(--color-border);
flex: 1;
min-height: 0;
overflow: hidden;
}
.form-header {
flex-shrink: 0;
padding: var(--space-xl) var(--space-lg) var(--space-md) var(--space-lg);
}
.form-content {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: 0 var(--space-lg);
min-height: 0;
}
.form-footer {
flex-shrink: 0;
padding: var(--space-lg);
}
.progress-indicator {
display: flex;
justify-content: center;
align-items: center;
gap: var(--space-md);
margin-bottom: var(--space-lg);
}
.progress-dot {
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--color-border);
opacity: 0.4;
transition: all var(--transition-base);
position: relative;
}
.progress-dot.active {
background: var(--color-primary);
opacity: 1;
transform: scale(1.2);
box-shadow: 0 0 0 4px var(--color-primary-light);
}
.quick-pick-btn {
min-width: 80px;
min-height: var(--touch-target-comfortable);
font-size: var(--font-size-base);
border-radius: var(--radius-md);
background: var(--color-secondary);
color: var(--color-text);
border: 1px solid var(--color-border);
cursor: pointer;
padding: var(--space-sm) var(--space-md);
transition: all var(--transition-base);
font-weight: 500;
}
.quick-pick-btn:hover, .quick-pick-btn:focus {
background: var(--color-secondary-hover);
border-color: var(--color-primary);
transform: translateY(-1px);
outline: none;
}
.arrow-nav {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: var(--space-xxl);
width: 100%;
gap: var(--space-lg);
}
.arrow-btn {
font-size: 48px;
width: 80px;
height: 80px;
border-radius: 50%;
background: var(--color-secondary);
color: var(--color-text);
border: 2px solid var(--color-border);
box-shadow: var(--shadow-md);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all var(--transition-base);
font-weight: bold;
}
.arrow-btn:hover, .arrow-btn:focus {
background: var(--color-secondary-hover);
border-color: var(--color-primary);
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
outline: none;
}
.arrow-btn:active {
transform: translateY(0);
}
.clear-input-btn {
position: absolute;
right: var(--space-sm);
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
font-size: var(--font-size-xl);
color: var(--color-text-muted);
padding: var(--space-xs);
z-index: 2;
transition: color var(--transition-base);
border-radius: var(--radius-sm);
min-height: var(--touch-target-min);
min-width: var(--touch-target-min);
display: flex;
align-items: center;
justify-content: center;
}
.clear-input-btn:hover, .clear-input-btn:focus {
color: var(--color-text);
background: var(--color-secondary);
outline: none;
}
.game-type-selection {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--space-md);
width: 100%;
margin: var(--space-md) 0;
}
.game-type-btn {
background: var(--color-background);
border: 2px solid var(--color-border);
color: var(--color-text);
font-size: var(--font-size-lg);
font-weight: 600;
padding: var(--space-xl);
border-radius: var(--radius-md);
cursor: pointer;
text-align: center;
transition: all var(--transition-base);
min-height: var(--touch-target-comfortable);
}
.game-type-btn:hover {
background: var(--color-surface);
border-color: var(--color-primary);
transform: translateY(-1px);
}
.game-type-btn.selected {
background: var(--color-primary);
border-color: var(--color-primary);
color: white;
box-shadow: var(--shadow-md);
}
.race-to-selection {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
gap: var(--space-md);
width: 100%;
margin: var(--space-md) 0;
}
.race-to-btn {
background: var(--color-background);
border: 2px solid var(--color-border);
color: var(--color-text);
font-size: var(--font-size-lg);
font-weight: 600;
padding: var(--space-lg) var(--space-sm);
border-radius: var(--radius-md);
cursor: pointer;
text-align: center;
transition: all var(--transition-base);
min-height: 80px;
display: flex;
align-items: center;
justify-content: center;
}
.race-to-btn:hover {
background: var(--color-surface);
border-color: var(--color-primary);
transform: translateY(-1px);
}
.race-to-btn.selected {
background: var(--color-primary);
border-color: var(--color-primary);
color: white;
box-shadow: var(--shadow-md);
}
/* Match selected styling for quick pick buttons used in BreakRuleStep */
.quick-pick-btn.selected {
background: var(--color-primary);
border-color: var(--color-primary);
color: white;
box-shadow: var(--shadow-md);
}
.custom-race-to {
display: flex;
gap: var(--space-md);
margin-top: var(--space-lg);
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%;
}
.player1-input.player-input {
border-color: var(--color-success);
background: linear-gradient(135deg, var(--color-success) 0%, rgba(76, 175, 80, 0.1) 100%);
}
.player2-input.player-input {
border-color: #1565c0;
background: linear-gradient(135deg, #1565c0 0%, rgba(21, 101, 192, 0.1) 100%);
}
.player3-input.player-input {
border-color: var(--color-secondary);
background: linear-gradient(135deg, var(--color-secondary) 0%, rgba(51, 51, 51, 0.1) 100%);
}
.player1-input.player-input input,
.player2-input.player-input input,
.player3-input.player-input input {
background: #fff;
color: #222;
border: 1px solid #ccc;
}
@media (min-width: 768px) and (max-width: 1024px) {
.screen-content {
padding: var(--space-xl);
}
.new-game-form {
max-width: 700px;
padding: var(--space-xxl) var(--space-xl) var(--space-xl) var(--space-xl);
}
.screen-title {
font-size: var(--font-size-xxxl);
}
.arrow-btn {
width: 100px;
height: 100px;
font-size: 56px;
}
.game-type-btn,
.race-to-btn {
padding: var(--space-xl);
font-size: var(--font-size-xl);
min-height: var(--touch-target-comfortable);
}
.quick-pick-btn {
min-height: var(--touch-target-comfortable);
font-size: var(--font-size-lg);
padding: var(--space-md) var(--space-lg);
}
}
@media (max-width: 767px) {
.screen-content {
padding: var(--space-md);
}
.new-game-form {
margin: var(--space-lg) auto 0 auto;
padding: var(--space-lg);
}
.game-type-selection {
grid-template-columns: 1fr;
}
.race-to-selection {
grid-template-columns: repeat(3, 1fr);
}
.arrow-nav {
gap: var(--space-md);
}
.arrow-btn {
width: 70px;
height: 70px;
font-size: 40px;
}
}