feat: tablet-first UX overhaul with wizard improvements

- Tablet-first responsive scoreboard: whole player card is tap target
- Per-step wizard backgrounds and live summary panel
- Larger touch targets, safe-area handling, reduced-motion support
- German UI error strings in App.tsx
- Updated SOUL.md and README.md for current architecture
- Cleanup: removed legacy components, .cursor/, UI_IMPROVEMENTS.md
- Renamed package to bscscore, fixed TOTAL_WIZARD_STEPS
This commit is contained in:
Frank Schwenk
2026-09-21 17:59:31 +02:00
parent 3327f6e19e
commit 678977ab23
92 changed files with 3359 additions and 3063 deletions
@@ -1,4 +1,5 @@
import { test, expect } from '@playwright/test';
import { skipPlayer3 } from '../helpers/wizard';
const LANDSCAPE_VIEWPORTS = [
{ name: 'small-landscape', width: 1024, height: 600 },
@@ -13,36 +14,42 @@ for (const viewport of LANDSCAPE_VIEWPORTS) {
await page.getByRole('button', { name: 'Neues Spiel starten' }).click();
// Step 1: ensure keyboard-sized viewport still keeps controls usable.
await page.getByLabel('Name Spieler 1').fill('Alpha');
await page.getByRole('button', { name: 'Name für Spieler 1 eingeben' }).click();
await page.setViewportSize({
width: viewport.width,
height: Math.max(360, viewport.height - Math.floor(viewport.height * 0.35)),
});
const nextButton = page.getByRole('button', { name: 'Weiter' });
await nextButton.scrollIntoViewIfNeeded();
await expect(nextButton).toBeVisible();
await nextButton.click();
const player1Dialog = page.getByRole('dialog');
const player1Input = page.locator('#player1-input');
await expect(player1Input).toBeFocused();
await player1Input.fill('Alpha');
const confirmButton = player1Dialog.getByRole('button', { name: 'Übernehmen' });
await confirmButton.scrollIntoViewIfNeeded();
await expect(confirmButton).toBeVisible();
await confirmButton.click();
await expect(player1Dialog).toBeHidden();
// Step 2: keep reduced height and verify progression still works.
await page.getByLabel('Name Spieler 2').fill('Beta');
await page.getByRole('button', { name: 'Weiter' }).click();
await page.getByRole('button', { name: 'Überspringen' }).click();
await page.getByRole('button', { name: 'Name für Spieler 2 eingeben' }).click();
const player2Dialog = page.getByRole('dialog');
const player2Input = page.locator('#player2-input');
await expect(player2Input).toBeFocused();
await player2Input.fill('Beta');
await player2Dialog.getByRole('button', { name: 'Übernehmen' }).click();
await expect(player2Dialog).toBeHidden();
await skipPlayer3(page);
// Restore full landscape viewport for remaining wizard steps.
await page.setViewportSize({ width: viewport.width, height: viewport.height });
await page.getByRole('button', { name: '8-Ball' }).click();
await page.getByRole('button', { name: 'Weiter' }).click();
await page.getByRole('button', { name: '5' }).click();
await page.getByRole('button', { name: 'Weiter' }).click();
await page.getByRole('button', { name: 'Break-Regel wählen: Winnerbreak' }).click();
await page.getByRole('button', { name: 'Weiter' }).click();
await page.getByRole('button', { name: 'Zuerst: Alpha' }).click();
await page.getByRole('button', { name: 'Weiter' }).click();
await expect(page.getByRole('button', { name: /Aktueller Punktestand für Alpha/i })).toBeVisible();
await expect(page.getByRole('button', { name: /Aktueller Punktestand für Beta/i })).toBeVisible();
await expect(
page.getByRole('button', { name: 'Punkt für Alpha. Aktueller Stand: 0' }),
).toBeVisible();
await expect(
page.getByRole('button', { name: 'Punkt für Beta. Aktueller Stand: 0' }),
).toBeVisible();
});
}