Compare commits

...

2 Commits

Author SHA1 Message Date
a2bdf9626c Merge feature/ux-mobile-2: Genotyp-Tabellen horizontal scrollbar (overflow-x-Wrapper + nowrap) + app-main overflow-x:hidden gegen Page-Overflow [god-QA validated]
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 54s
CI / Frontend Tests (Node/Vite) (push) Successful in 9m32s
CI / Docker Build & Push (push) Failing after 10s
2026-06-06 15:43:43 +02:00
d116b8d8f1 UX-MOBILE-2: Genotyp-Tabellen-Overflow behoben (scrollbar statt page-overflow)
- BreedingResultView: <table class="genotype-table"> in <div class="genotype-table-scroll"> gewrapped.
- index.css: .genotype-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch }.
  .genotype-table td { white-space: nowrap } → Tabelle scrollt statt Zellen umzubrechen.
  width: 100% entfernt (Tabelle auto-sized to content).
- index.css: .app-main { overflow-x: hidden } → verhindert, dass breite Inhalte
  den Page-Body horizontal überlaufen lassen (document.scrollWidth == clientWidth).
- e2e/genotype-table.spec.ts (4 Tests): Wrapper sichtbar, Wrapper selbst scrollbar
  (scrollWidth > clientWidth), keine Page-Overflow auf 390px. Beide Viewports.
- Vitest 78 / e2e 106 grün.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-06 15:41:59 +02:00
3 changed files with 89 additions and 22 deletions

View File

@@ -0,0 +1,54 @@
/**
* UX-MOBILE-2: Genotyp-Tabellen-Overflow — die Tabelle scrollt horizontal,
* die Seite selbst bleibt NICHT breiter als der Viewport (kein horizontaler
* Page-Overflow auf 390px).
*/
import { de, expect, skipUnlessMock, test } from './fixtures'
const tl = de.pages.litters
test('Phone: Genotyp-Detail-Tabelle scrollt im eigenen Wrapper, kein Page-Overflow', async ({
page,
}, testInfo) => {
skipUnlessMock()
if (testInfo.project.name !== 'phone') return
// Wurf w-kruemel hat beide Eltern mit Genotypen → BreedingResultView rendert.
await page.goto('/wuerfe/w-kruemel')
await expect(page.getByRole('heading', { name: 'Wurf K' })).toBeVisible()
await expect(page.getByText(tl.detail.expectedColors).first()).toBeVisible()
// Genotyp-Detail-Tabelle ausklappen.
await page.getByRole('button', { name: de.pages.genetik.showGenotypes }).click()
// Scroll-Wrapper und Tabelle müssen vorhanden und sichtbar sein.
const wrapper = page.locator('.genotype-table-scroll').first()
await expect(wrapper).toBeVisible()
await expect(wrapper.locator('.genotype-table')).toBeVisible()
// Wrapper ist selbst scrollbar (Tabelle breiter als der sichtbare Bereich).
const wrapperScrollable = await wrapper.evaluate(
(el) => el.scrollWidth > el.clientWidth,
)
expect(wrapperScrollable).toBe(true)
// Die Seite selbst darf NICHT breiter als der Viewport sein.
const pageOverflow = await page.evaluate(
() => document.documentElement.scrollWidth > document.documentElement.clientWidth,
)
expect(pageOverflow).toBe(false)
})
test('Desktop: Genotyp-Detail-Tabelle zeigt Wrapper auch auf breitem Viewport', async ({
page,
}, testInfo) => {
skipUnlessMock()
if (testInfo.project.name !== 'desktop') return
await page.goto('/wuerfe/w-kruemel')
await expect(page.getByText(tl.detail.expectedColors).first()).toBeVisible()
await page.getByRole('button', { name: de.pages.genetik.showGenotypes }).click()
await expect(page.locator('.genotype-table-scroll').first()).toBeVisible()
await expect(page.locator('.genotype-table').first()).toBeVisible()
})

View File

@@ -65,28 +65,30 @@ export default function BreedingResultView({ result, title }: BreedingResultView
</button>
{showGenotypes && (
<table className="genotype-table">
<thead>
<tr>
<th>{t.genotypeLabel}</th>
<th>{t.genotypePreview}</th>
<th>{t.probability}</th>
</tr>
</thead>
<tbody>
{result.offspring.map((o) => (
<tr key={o.genotype}>
<td>
<code>{o.genotype}</code>
</td>
<td>{o.farbschlag}</td>
<td>
{o.probability.percent} <small>({o.probability.text})</small>
</td>
<div className="genotype-table-scroll">
<table className="genotype-table">
<thead>
<tr>
<th>{t.genotypeLabel}</th>
<th>{t.genotypePreview}</th>
<th>{t.probability}</th>
</tr>
))}
</tbody>
</table>
</thead>
<tbody>
{result.offspring.map((o) => (
<tr key={o.genotype}>
<td>
<code>{o.genotype}</code>
</td>
<td>{o.farbschlag}</td>
<td>
{o.probability.percent} <small>({o.probability.text})</small>
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</>
)}

View File

@@ -77,6 +77,10 @@ a {
padding: 1rem;
max-width: 60rem;
width: 100%;
/* UX-MOBILE-2: prevent any wide content (e.g. genotype table) from making
the page body scroll horizontally. The .genotype-table-scroll wrapper
provides the per-table horizontal scroll. */
overflow-x: hidden;
}
/* Tab-Leiste unten */
@@ -559,8 +563,14 @@ textarea {
white-space: nowrap;
}
/* UX-MOBILE-2: scroll wrapper so genotype table scrolls horizontally on mobile
instead of overflowing the page. */
.genotype-table-scroll {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.genotype-table {
width: 100%;
border-collapse: collapse;
margin-top: 0.75rem;
font-size: 0.9rem;
@@ -571,6 +581,7 @@ textarea {
text-align: left;
padding: 0.4rem 0.5rem;
border-bottom: 1px solid var(--color-border);
white-space: nowrap;
}
.genotype-table code {