Rutenett-stil for spillerpool-tabellen, ingen sidescroll på bred skjerm (tillegg til ADR-094)
EditTable (player-import-view.tsx) får samme grid-stil som spillertabellen, med individuell kolonnebredde per felt slik at alle 13 spillerpool-felt får plass uten sidescroll. mode.kind==="roster"- grenen bevart ved manuell fletting siden V0-eksporten var en eldre snapshot uten den varianten. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
47e3874198
commit
7632f53702
3 changed files with 111 additions and 56 deletions
|
|
@ -9627,6 +9627,29 @@ navn) -- ren visuell omskriving, ingen endring i `SetupTab` sin
|
||||||
sammenkobling nødvendig. Verifisert i ny lokal scratch-visning (bred
|
sammenkobling nødvendig. Verifisert i ny lokal scratch-visning (bred
|
||||||
skjerm bekreftet fylt uten sidescroll med 3 runde-kolonner, lys+mørk).
|
skjerm bekreftet fylt uten sidescroll med 3 runde-kolonner, lys+mørk).
|
||||||
|
|
||||||
|
**Tillegg 2026-08-19 -- samme rutenett-mønster utvidet til spillerpool-
|
||||||
|
tabellen (`player-import-view.tsx` sin `EditTable`).** Bruker: "Jeg
|
||||||
|
ønsker at tabellen skal være så bred at jeg slipper å scrolle
|
||||||
|
sidelengs" -- presisert etter en første runde der jeg feilaktig hadde
|
||||||
|
bedt V0 om å BEHOLDE horisontal scroll (misforsto "mye bredere" som
|
||||||
|
"behold bredden", ikke "fyll bredden slik at scroll blir unødvendig").
|
||||||
|
Denne tabellen viser opptil 13 datafelt + slett-knapp samtidig i
|
||||||
|
spillerpool-modus (ingen filtrering på kolonnetilknytning der, ulikt
|
||||||
|
CSV-import-modus) -- retting: samme `table-fixed`+`<colgroup>`-teknikk
|
||||||
|
som over, men med EN fast pikselbredde PER felt (`COL_W`, 70-190px
|
||||||
|
avhengig av innholdstype) i stedet for få brede kolonner, slik at alle
|
||||||
|
13 feltene faktisk får plass på en bred skjerm. V0-eksporten denne
|
||||||
|
runden var en eldre prosjekt-snapshot uten `"roster"`-varianten av
|
||||||
|
`Mode`-typen (kun `team`/`individual`) -- fletting gjort manuelt i
|
||||||
|
stedet for å lime inn rått, for å bevare `mode.kind === "roster"`-
|
||||||
|
grenen (annen hjelpetekst, ingen lag/klasse-kolonner) og selve
|
||||||
|
`Mode`/`FieldKey`-typene uendret. `FIELD_MIN_W`-konstanten (nå erstattet
|
||||||
|
av `COL_W`) fjernet som dødt kode. Verifisert i lokal scratch (5 rader,
|
||||||
|
alle 13 spillerpool-felt) -- bekreftet ALLE kolonner synlige uten
|
||||||
|
sidescroll på 1900px, riktig `mode.kind === "roster"`-hjelpetekst
|
||||||
|
bevart, redigering og sticky navnekolonne fungerer, lys+mørk, smal
|
||||||
|
skjerm faller korrekt tilbake til sidescroll.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Utviklingsplan (rekkefølge)
|
## Utviklingsplan (rekkefølge)
|
||||||
|
|
|
||||||
22
CHANGELOG.md
22
CHANGELOG.md
|
|
@ -13039,3 +13039,25 @@ Neste steg:
|
||||||
**Rullet ut 2026-08-19** -- bruker bekreftet. Ren frontend.
|
**Rullet ut 2026-08-19** -- bruker bekreftet. Ren frontend.
|
||||||
`docker compose build teecup_frontend && up -d`, rene logger,
|
`docker compose build teecup_frontend && up -d`, rene logger,
|
||||||
200 OK.
|
200 OK.
|
||||||
|
|
||||||
|
128. **Samme rutenett-stil utvidet til spillerpool-tabellen -- 2026-08-19
|
||||||
|
(tillegg til ADR-094).** Bruker: "Jeg ønsker at tabellen skal være
|
||||||
|
så bred at jeg slipper å scrolle sidelengs" -- presisering etter at
|
||||||
|
jeg først (feilaktig) hadde bedt V0 om å BEHOLDE sidescroll for
|
||||||
|
denne tabellen. `player-import-view.tsx` sin `EditTable` (opptil
|
||||||
|
13 felt + slett-knapp samtidig i spillerpool-modus) fikk samme
|
||||||
|
`table-fixed`+`<colgroup>`-teknikk som spillertabellen (#127), men
|
||||||
|
med individuelt tilpasset pikselbredde per felt (70-190px) i stedet
|
||||||
|
for få brede kolonner -- alle 13 feltene får nå plass uten
|
||||||
|
sidescroll på en bred skjerm. V0-eksporten manglet `"roster"`-
|
||||||
|
varianten av `Mode`-typen (eldre snapshot) -- flettet inn manuelt
|
||||||
|
for å bevare den grenen og selve typene uendret. Fjernet nå-død
|
||||||
|
`FIELD_MIN_W`-konstant.
|
||||||
|
|
||||||
|
**Verifisert:** `tsc --noEmit` rent, `vitest run` 55/55. Scratch-
|
||||||
|
visning (5 rader, alle 13 spillerpool-felt): alle kolonner synlige
|
||||||
|
uten sidescroll på 1900px, riktig hjelpetekst for spillerpool-modus
|
||||||
|
bevart, redigering + sticky navnekolonne fungerer, lys+mørk, smal
|
||||||
|
skjerm faller korrekt tilbake til sidescroll.
|
||||||
|
|
||||||
|
**Rullet ut:** venter på bekreftelse.
|
||||||
|
|
|
||||||
|
|
@ -108,26 +108,6 @@ const FIELD_ORDER: FieldKey[] = [
|
||||||
"comment",
|
"comment",
|
||||||
]
|
]
|
||||||
|
|
||||||
// Per-field column width for the edit table. Compact by default so a wide
|
|
||||||
// screen shows many columns at once; wider for free-text-heavy fields.
|
|
||||||
const FIELD_MIN_W: Partial<Record<FieldKey, string>> = {
|
|
||||||
display_name: "min-w-44",
|
|
||||||
first_name: "min-w-36",
|
|
||||||
last_name: "min-w-36",
|
|
||||||
nickname: "min-w-32",
|
|
||||||
email: "min-w-52",
|
|
||||||
mobile: "min-w-36",
|
|
||||||
handicap_index: "min-w-20",
|
|
||||||
gender: "min-w-28",
|
|
||||||
birth_date: "min-w-36",
|
|
||||||
club: "min-w-44",
|
|
||||||
club_member_number: "min-w-28",
|
|
||||||
country: "min-w-28",
|
|
||||||
team_name: "min-w-40",
|
|
||||||
class_name: "min-w-40",
|
|
||||||
comment: "min-w-56",
|
|
||||||
}
|
|
||||||
|
|
||||||
const GENDER_OPTIONS: { value: string; label: string }[] = [
|
const GENDER_OPTIONS: { value: string; label: string }[] = [
|
||||||
{ value: "", label: "—" },
|
{ value: "", label: "—" },
|
||||||
{ value: "female", label: "Kvinne" },
|
{ value: "female", label: "Kvinne" },
|
||||||
|
|
@ -429,6 +409,39 @@ function MapStep({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Realistisk, innholds-tilpasset kolonnebredde (px), ikke en rundhåndet
|
||||||
|
// min-bredde -- med table-fixed + w-full fordeler nettleseren overskytende
|
||||||
|
// plass proporsjonalt, så alle ~14 felt (spillerpool-modus) får plass uten
|
||||||
|
// sidescroll på en bred skjerm (bruker eksplisitt: "jeg ønsker at tabellen
|
||||||
|
// skal være så bred at jeg slipper å scrolle sidelengs", 2026-08-19).
|
||||||
|
// overflow-x-auto-wrapperen står igjen som fallback for smal skjerm.
|
||||||
|
const COL_W: Partial<Record<FieldKey, number>> = {
|
||||||
|
display_name: 150,
|
||||||
|
first_name: 110,
|
||||||
|
last_name: 110,
|
||||||
|
nickname: 100,
|
||||||
|
email: 190,
|
||||||
|
mobile: 120,
|
||||||
|
handicap_index: 70,
|
||||||
|
gender: 92,
|
||||||
|
birth_date: 130,
|
||||||
|
club: 140,
|
||||||
|
club_member_number: 104,
|
||||||
|
country: 90,
|
||||||
|
team_name: 128,
|
||||||
|
class_name: 128,
|
||||||
|
comment: 180,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rutenett-cellekontroll (2026-08-19): flat, fyller hele cellen, ingen egen
|
||||||
|
// kant -- rutenett-linjene definerer strukturen, kontrollen lyser kun opp
|
||||||
|
// ved hover/fokus. Samme mønster som tournament-players-table.tsx.
|
||||||
|
const CELL =
|
||||||
|
"h-full w-full border-0 bg-transparent px-2 py-1.5 text-[13px] leading-tight text-foreground outline-none transition-colors hover:bg-accent/40 focus-visible:bg-background focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
|
const TD = "border-b border-r border-border p-0 align-middle"
|
||||||
|
const TH =
|
||||||
|
"border-b border-r border-border bg-muted px-2 py-2 text-left text-[11px] font-bold uppercase tracking-wide text-muted-foreground"
|
||||||
|
|
||||||
function EditTable({
|
function EditTable({
|
||||||
mode,
|
mode,
|
||||||
rows,
|
rows,
|
||||||
|
|
@ -463,19 +476,21 @@ function EditTable({
|
||||||
// narrow screens; on a wide screen every column is visible. `relative`
|
// narrow screens; on a wide screen every column is visible. `relative`
|
||||||
// gives absolutely-positioned descendants (sr-only) a clipped block.
|
// gives absolutely-positioned descendants (sr-only) a clipped block.
|
||||||
<div className="relative min-w-0 overflow-x-auto rounded-2xl border border-border">
|
<div className="relative min-w-0 overflow-x-auto rounded-2xl border border-border">
|
||||||
<table className="w-full border-collapse text-left">
|
<table className="w-full table-fixed border-collapse text-left">
|
||||||
<thead className="sticky top-0 z-10">
|
<colgroup>
|
||||||
<tr className="border-b border-border bg-muted">
|
{editFields.map((field) => (
|
||||||
{editFields.map((field) => (
|
<col key={field} style={{ width: COL_W[field] ?? 120 }} />
|
||||||
<th
|
))}
|
||||||
key={field}
|
<col style={{ width: 72 }} />
|
||||||
scope="col"
|
</colgroup>
|
||||||
className="whitespace-nowrap px-3 py-2.5 text-xs font-extrabold uppercase tracking-wide text-muted-foreground"
|
<thead className="sticky top-0 z-20">
|
||||||
>
|
<tr className="h-9">
|
||||||
|
{editFields.map((field, i) => (
|
||||||
|
<th key={field} scope="col" className={cn(TH, "truncate", i === 0 && "sticky left-0 z-30")}>
|
||||||
{FIELD_LABELS[field]}
|
{FIELD_LABELS[field]}
|
||||||
</th>
|
</th>
|
||||||
))}
|
))}
|
||||||
<th scope="col" className="px-3 py-2.5 text-right">
|
<th scope="col" className={cn(TH, "border-r-0 text-right")}>
|
||||||
<span className="sr-only">Handlinger</span>
|
<span className="sr-only">Handlinger</span>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -490,19 +505,16 @@ function EditTable({
|
||||||
// scrolle til riktig rad uten å måtte utvide selve
|
// scrolle til riktig rad uten å måtte utvide selve
|
||||||
// props-kontrakten eller endre noe synlig her.
|
// props-kontrakten eller endre noe synlig her.
|
||||||
data-row-key={row.key}
|
data-row-key={row.key}
|
||||||
className={cn(
|
className="group h-9 hover:bg-accent/20"
|
||||||
"border-b border-border last:border-b-0",
|
|
||||||
rowIndex % 2 === 1 && "bg-muted/30",
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
{editFields.map((field) => (
|
{editFields.map((field, i) => (
|
||||||
<td key={field} className="px-2 py-1.5 align-middle">
|
<td key={field} className={cn(TD, i === 0 && "sticky left-0 z-10 bg-card group-hover:bg-accent/20")}>
|
||||||
{field === "gender" ? (
|
{field === "gender" ? (
|
||||||
<select
|
<select
|
||||||
aria-label={`${FIELD_LABELS[field]} for rad ${rowIndex + 1}`}
|
aria-label={`${FIELD_LABELS[field]} for rad ${rowIndex + 1}`}
|
||||||
value={row[field] ?? ""}
|
value={row[field] ?? ""}
|
||||||
onChange={(e) => onCellChange(row.key, field, e.target.value)}
|
onChange={(e) => onCellChange(row.key, field, e.target.value)}
|
||||||
className={cn(CONTROL_BASE, FIELD_MIN_W[field], "w-full px-2 text-sm font-semibold")}
|
className={cn(CELL, "cursor-pointer font-medium")}
|
||||||
>
|
>
|
||||||
{GENDER_OPTIONS.map((opt) => (
|
{GENDER_OPTIONS.map((opt) => (
|
||||||
<option key={opt.value} value={opt.value}>
|
<option key={opt.value} value={opt.value}>
|
||||||
|
|
@ -515,7 +527,7 @@ function EditTable({
|
||||||
aria-label={`Lag for rad ${rowIndex + 1}`}
|
aria-label={`Lag for rad ${rowIndex + 1}`}
|
||||||
value={row[field] ?? ""}
|
value={row[field] ?? ""}
|
||||||
onChange={(e) => onCellChange(row.key, field, e.target.value)}
|
onChange={(e) => onCellChange(row.key, field, e.target.value)}
|
||||||
className={cn(CONTROL_BASE, FIELD_MIN_W[field], "w-full px-2 text-sm font-semibold")}
|
className={cn(CELL, "cursor-pointer font-medium")}
|
||||||
>
|
>
|
||||||
<option value="">—</option>
|
<option value="">—</option>
|
||||||
{mode.teams.map((t) => (
|
{mode.teams.map((t) => (
|
||||||
|
|
@ -529,7 +541,7 @@ function EditTable({
|
||||||
aria-label={`Klasse for rad ${rowIndex + 1}`}
|
aria-label={`Klasse for rad ${rowIndex + 1}`}
|
||||||
value={row[field] ?? ""}
|
value={row[field] ?? ""}
|
||||||
onChange={(e) => onCellChange(row.key, field, e.target.value)}
|
onChange={(e) => onCellChange(row.key, field, e.target.value)}
|
||||||
className={cn(CONTROL_BASE, FIELD_MIN_W[field], "w-full px-2 text-sm font-semibold")}
|
className={cn(CELL, "cursor-pointer font-medium")}
|
||||||
>
|
>
|
||||||
<option value="">—</option>
|
<option value="">—</option>
|
||||||
{mode.classes.map((c) => (
|
{mode.classes.map((c) => (
|
||||||
|
|
@ -544,27 +556,25 @@ function EditTable({
|
||||||
value={row[field] ?? ""}
|
value={row[field] ?? ""}
|
||||||
inputMode={field === "email" ? "email" : field === "mobile" ? "tel" : "text"}
|
inputMode={field === "email" ? "email" : field === "mobile" ? "tel" : "text"}
|
||||||
onChange={(e) => onCellChange(row.key, field, e.target.value)}
|
onChange={(e) => onCellChange(row.key, field, e.target.value)}
|
||||||
className={cn(CONTROL_BASE, FIELD_MIN_W[field], "w-full px-2.5 text-sm")}
|
className={cn(CELL, field === "handicap_index" && "text-right tabular-nums")}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
))}
|
))}
|
||||||
<td className="px-2 py-1.5 align-middle">
|
<td className={cn(TD, "border-r-0 px-1 text-center")}>
|
||||||
<div className="flex justify-end">
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
onClick={() => onDeleteRow(row.key)}
|
||||||
onClick={() => onDeleteRow(row.key)}
|
aria-label={`Slett rad ${rowIndex + 1}${row.display_name ? ` for ${row.display_name}` : ""}`}
|
||||||
aria-label={`Slett rad ${rowIndex + 1}${row.display_name ? ` for ${row.display_name}` : ""}`}
|
className={cn(
|
||||||
className={cn(
|
"inline-flex h-7 items-center gap-1 rounded-md px-2 text-xs font-bold text-muted-foreground transition-colors",
|
||||||
"inline-flex h-9 items-center gap-1.5 rounded-lg border border-border px-2.5 text-sm font-bold text-muted-foreground transition-colors",
|
"hover:bg-destructive/10 hover:text-destructive active:scale-[0.98]",
|
||||||
"hover:border-destructive/40 hover:bg-destructive/10 hover:text-destructive active:scale-[0.98]",
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
|
||||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
)}
|
||||||
)}
|
>
|
||||||
>
|
<Trash2 aria-hidden="true" className="size-3.5" />
|
||||||
<Trash2 aria-hidden="true" className="size-4" />
|
Slett
|
||||||
Slett
|
</button>
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue