Flytt "Mer" inn i navnereden, "Mål et slag" inn i "Mer" -- kun scorekortførers eget kort

V0-eksport integrert: PlayerCardMore utvidet med scoreButton/measureShot-
props, navnereden er nå en ikke-knapp wrapper med score-knappen og en
kompakt "Mer"-pille som søsken (unngår button-i-button). "Mål et slag" er
ikke lenger en egen rad -- ligger nå i "Mer"-panelet, og er (som
historikk) begrenset til player.isSelf; var tidligere synlig for alle
spilleres kort. Se CHANGELOG.md #138. Ikke rullet ut ennå.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Erol Haagenrud 2026-08-20 07:48:27 +02:00
parent f10121beaf
commit a52ff91ff1
2 changed files with 126 additions and 50 deletions

View file

@ -13432,3 +13432,46 @@ Neste steg:
`tsc --noEmit` rent.
**Ikke rullet ut ennå** -- venter på bekreftelse fra bruker.
138. **"Mer" flyttet inn i navnereden, "Mål et slag" flyttet inn i "Mer"
-- KUN scorekortførers eget kort, 2026-08-20.** Direkte oppfølging av
#135/#136 samme dag. Bruker viste skjermbilde med to nye punkter:
(1) "Mer" skulle vekk fra sin egen full-bredde-rad og inn i selve
navnereden, ved siden av score-knappen. (2) "Mål et slag" skulle vekk
fra sin egen rad og inn i "Mer"-panelet. Bruker presiserte i tillegg,
uavhengig av skjermbildet: BÅDE hull-historikk OG "Mål et slag" skal
være forbeholdt scorekortføreren selv (`player.isSelf`) -- "Mål et
slag" var tidligere synlig for ALLE spilleres kort (kun klubbutvalget
var allerede begrenset til eget bag via `ownBagClubs`), nå er hele
knappen borte for medspillere.
Claude skrev en V0-prompt (samme mønster som før), bruker kjørte den
og lastet opp eksporten (`player-card-more.tsx`, `PlayerCardBody`).
Løste DOM-utfordringen riktig: navnereden var tidligere ÉN stor
`<button>` (hele raden var trykkflaten som åpner score-registrering)
-- HTML tillater ikke en knapp inni en knapp, så eksporten strukturerte
om til en YTRE, ikke-knapp rad-wrapper med to SØSKEN: score-knappen og
en kompakt "Mer"-pille (44x44px, tekst+chevron).
`round-detail.tsx`:
- `PlayerCardMore` (fra runde 1, se #135) utvidet med en ny
`scoreButton`-prop (den eksisterende, rike navnerad-knappen --
playerSide-prikk/badges/HCP/dimmed/won/ScorecardCell/StrokeDots,
alt UENDRET innhold, kun flyttet til å være denne propen) og en ny
`measureShot`-prop. Selve "Mer"-vekslen flyttet fra en egen
full-bredde rad til en kompakt pille ved siden av `scoreButton` i en
ny, ikke-knapp navnerad-wrapper.
- `PlayerHoleCards`: `ShotMeasurementEntry` er ikke lenger en egen rad
-- sendes nå inn som `measureShot`, gated `player.isSelf && !readOnly`
(før: kun `!readOnly`, altså synlig for alle). `ownBagClubs`-
betingelsen forenklet til alltid `ownBagClubs` siden hele knappen nå
uansett kun rendres for isSelf.
**Verifisert i scratch:** mocket `RoundDetail`-forhåndsvisning, tre
spillere. Bekreftet: navnerad + kompakt "Mer"-pille ligger side ved
side (ingen nøstet knapp, `tsc --noEmit` bekrefter gyldig JSX/DOM),
eget kort sitt panel viser Mål et slag -> historikk -> Avslutt/Send i
riktig rekkefølge, medspillers panel viser KUN Avslutt/Send (verken
Mål et slag eller historikk). Sjekket lys og mørk modus.
**Ikke rullet ut ennå** -- venter på bekreftelse fra bruker.

View file

@ -5949,33 +5949,63 @@ function ParticipantCompletionActions({
)
}
// Tone-ned-mønster for spillerkortets sekundære rader (historikk +
// Avslutt/Send scorekort) på Score-fanen -- V0-eksport (zip, 2026-08-20,
// brukerkorrigering: disse lå tidligere alltid synlig, uansett hvor sjelden
// brukt). Eier KUN vis/skjul -- selve historikk-panelet og handlingsraden
// forblir de ekte, uendrede komponentene (HoleHistoryPanel/
// ParticipantCompletionActions), sendt inn som barn. Brukes KUN i
// PlayerHoleCards (Score-fanen) -- PlayerList ("Spillere og runde") beholder
// ParticipantCompletionActions synlig uten denne vekslen, siden den siden
// allerede er en ren administrasjonsvisning.
function PlayerCardMore({ history, actions }: { history?: React.ReactNode; actions: React.ReactNode }) {
// Tone-ned-mønster for spillerkortets sekundære innhold (Mål et slag,
// historikk, Avslutt/Send scorekort) på Score-fanen -- V0-eksport (zip,
// 2026-08-20). Runde 1: egen "Mer"-rad UNDER navnereden. Runde 2
// (brukerønske samme dag): "Mer" flyttet INN i selve navnereden (kompakt
// pille ved siden av score-knappen), og "Mål et slag" flyttet INN i
// panelet sammen med historikk/Avslutt/Send -- ingen av de tre var brukt
// ofte nok til å fortjene egne, alltid synlige rader.
//
// VIKTIG DOM-BEGRENSNING: navnereden var tidligere ÉN stor <button>. HTML
// tillater ikke en knapp inni en knapp, så "Mer" kan IKKE ligge nøstet
// inni score-knappen. Løsning: denne komponenten eier en ytre
// IKKE-knapp-rad-wrapper med to søsken -- `scoreButton` (sendt inn av
// kalleren, uendret rik knapp-innhold) og "Mer"-pillen selv.
//
// Eier kun vis/skjul + selve rad-strukturen -- historikk-panelet,
// "Mål et slag" og handlingsraden forblir de ekte, uendrede komponentene
// (HoleHistoryPanel/ShotMeasurementEntry/ParticipantCompletionActions),
// sendt inn som barn. Brukes KUN i PlayerHoleCards (Score-fanen) --
// PlayerList ("Spillere og runde") beholder ParticipantCompletionActions
// synlig uten denne vekslen, siden den siden allerede er en ren
// administrasjonsvisning.
function PlayerCardMore({
scoreButton,
measureShot,
history,
actions,
}: {
/** Den eksisterende, rike score-åpne-knappen -- SØSKEN av "Mer", ikke forelder. */
scoreButton: React.ReactNode
/** "Mål et slag" -- kun scorekortførers eget kort (GPS-basert, gir ingen mening for medspillere). */
measureShot?: React.ReactNode
history?: React.ReactNode
actions: React.ReactNode
}) {
const [open, setOpen] = useState(false)
const regionId = useId()
return (
<div className="flex flex-col border-t border-border">
<button
type="button"
onClick={() => setOpen((v) => !v)}
aria-expanded={open}
aria-controls={regionId}
className="flex min-h-11 items-center justify-center gap-1.5 self-center rounded-xl px-4 py-2 text-sm font-bold text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
>
{open ? "Skjul" : "Mer"}
<ChevronDown
aria-hidden="true"
className={cn("size-4 shrink-0 transition-transform duration-200", open && "rotate-180")}
/>
</button>
<div className="flex flex-col">
<div className="flex items-stretch gap-2 p-3">
{scoreButton}
<button
type="button"
onClick={() => setOpen((v) => !v)}
aria-expanded={open}
aria-controls={regionId}
className={cn(
"flex min-h-11 min-w-11 shrink-0 flex-col items-center justify-center gap-0.5 rounded-2xl border border-border px-3 text-xs font-bold text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
open && "bg-accent text-foreground",
)}
>
<span>{open ? "Skjul" : "Mer"}</span>
<ChevronDown
aria-hidden="true"
className={cn("size-4 shrink-0 transition-transform duration-200", open && "rotate-180")}
/>
</button>
</div>
{/* Myk høyde-animasjon via grid-rows 0fr -> 1fr -- samme prinsipp som
"Vis banekart og hindringer" lenger oppe skjermen. Innholdet
fjernes fra a11y-treet og tab-rekkefølgen mens det er skjult. */}
@ -5987,7 +6017,8 @@ function PlayerCardMore({ history, actions }: { history?: React.ReactNode; actio
)}
>
<div className="overflow-hidden">
<div className={cn("flex flex-col gap-2 pb-2", !open && "invisible")} aria-hidden={!open}>
<div className={cn("flex flex-col gap-2 pb-3", !open && "invisible")} aria-hidden={!open}>
{measureShot && <div className="flex justify-end px-4">{measureShot}</div>}
{history && <div className="px-4">{history}</div>}
{actions}
</div>
@ -6852,6 +6883,19 @@ function PlayerHoleCards({
: undefined
}
>
{/* Navnerad + "Mer": navnereden var tidligere ÉN stor
<button> som dekket hele kortbredden. Brukerønske
2026-08-20: flytt "Mer" INN i denne raden (kompakt
pille) og "Mål et slag" INN i "Mer"-panelet -- se
PlayerCardMore-komponenten for DOM-begrunnelsen (knapp
kan ikke ligge nøstet inni knapp, "Mer" er SØSKEN av
score-knappen). Historikk og "Mål et slag" er BEGGE KUN
scorekortførers eget kort -- historikk fordi panelets
tekst eksplisitt sier "Din historikk", "Mål et slag"
fordi avstandsmåling er GPS-basert fra DENNE telefonen
og gir ingen mening for en medspillers slag. */}
<PlayerCardMore
scoreButton={
<button
type="button"
disabled={readOnly}
@ -6863,7 +6907,7 @@ function PlayerHoleCards({
? `${player.name} har avsluttet runden, hull ${currentHole} ikke spilt`
: `Registrer ${player.name} sin score på hull ${currentHole}${apiHole?.strokes_received ? `, mottar ${apiHole.strokes_received} slag` : ""}`
}
className="flex w-full items-center gap-3 p-4 text-left transition-colors hover:bg-accent/30 disabled:opacity-60"
className="flex min-w-0 flex-1 items-center gap-3 rounded-2xl bg-muted/40 p-3 text-left transition-colors hover:bg-muted disabled:opacity-60"
>
<div className="flex min-w-0 flex-1 flex-col gap-1">
<div className="flex flex-wrap items-center gap-x-2 gap-y-1">
@ -6943,30 +6987,19 @@ function PlayerHoleCards({
)}
</div>
</button>
{!readOnly && (
<div className="flex justify-end border-t border-border px-4 py-2">
<ShotMeasurementEntry
roundId={roundId}
holeNumber={currentHole}
owner={{ kind: "participant", id: player.id }}
ownBagClubs={player.isSelf ? ownBagClubs : []}
readOnly={readOnly}
variant="badge"
/>
</div>
)}
{/* Personlig hull-historikk (ADR-072, flyttet hit ut av
slagvinduet ADR-079, 2026-08-16) -- skjermen FØR
registrering/"Avslutt for {navn}", ikke inni selve
slagvinduet. Skjuler seg selv når banen er custom eller
spilleren ikke har historikk ennå. KUN scorekortførers
(isSelf) eget kort (2026-08-20, brukerkorrigering --
panelets tekst sier "Din historikk", som var feil for
andre spilleres kort). Tonet ned bak "Mer" sammen med
Avslutt/Send scorekort (2026-08-20, V0-eksport
`player-card-more.tsx`) -- begge var sjeldent brukte
handlinger som likevel alltid tok plass hvert kort. */}
<PlayerCardMore
}
measureShot={
player.isSelf && !readOnly ? (
<ShotMeasurementEntry
roundId={roundId}
holeNumber={currentHole}
owner={{ kind: "participant", id: player.id }}
ownBagClubs={ownBagClubs}
readOnly={readOnly}
variant="badge"
/>
) : undefined
}
history={
player.isSelf ? (
<HoleHistoryPanel