From 76b306cb29809bf57a091bd7e092ffb3aad333ae Mon Sep 17 00:00:00 2001 From: Erol Haagenrud Date: Thu, 20 Aug 2026 08:45:54 +0200 Subject: [PATCH] =?UTF-8?q?Skjul=20flytende=20"Registrer=20score"=20n?= =?UTF-8?q?=C3=A5r=20spillerlisten=20er=20n=C3=A5dd/passert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ny playerListReached-tilstand skjuler den flytende knappen (og dens spacer) fra #140 så snart spillerlisten når headerens høyde -- forblir skjult resten av veien nedover, dukker opp igjen kun ved scroll tilbake opp forbi listen. Første forsøk med IntersectionObserver+rootMargin var feil (fyrer ikke på interne terskler mens allerede overlappende) -- byttet til en scroll/resize-lytter med direkte getBoundingClientRect-sjekk. Se CHANGELOG.md #141. Ikke rullet ut ennå. Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 37 +++++++++++++ frontend/components/round-detail.tsx | 77 +++++++++++++++++++++++----- 2 files changed, 101 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bebc26a..bc1ca52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13547,3 +13547,40 @@ Neste steg: **Rullet ut 2026-08-20** -- bruker bekreftet, samlet med #139. Ren frontend. `docker compose build teecup_frontend && up -d`, rene logger, 200 OK. + +141. **Flytende "Registrer score" hang igjen synlig etter at spillerlisten + var nådd, 2026-08-20.** Direkte oppfølging av #140 -- bruker viste + skjermbilde: selv etter å ha scrollet forbi spillerkortene (helt ned + til kommentarfeltet), sto den flytende "Registrer score ↓"-knappen + fortsatt og fløt over bunnen av skjermen, uten mening siden + spillerlisten allerede var passert (pilen peker "ned til spillerne", + men spillerne var nå OVER, ikke under). Bruker spurte om dette burde + V0-promptes -- Claude vurderte det til å være ren VIS/SKJUL-LOGIKK + rundt et allerede ferdig designet element (fra #140), ikke en ny + visuell flate, og løste det direkte. + + `round-detail.tsx`: ny `playerListReached`-tilstand, sant når + spillerlistens toppkant har nådd/passert headerens høyde (112px, + samme referanse som `scroll-mt-28`). Knappen (og spaceren under den, + fra #140) vises nå kun når `mapExpanded && !playerListReached`. + + **Feilslått første forsøk, funnet i scratch:** brukte først + `IntersectionObserver` med en krympet `rootMargin` for å fange + 112px-krysningen. Viste seg feil -- med standard `threshold: [0]` + fyrer observatøren KUN ved 0%->0%-kryssinger (elementet helt inn/ut av + roten), ikke ved at `boundingClientRect.top` passerer en vilkårlig + linje MENS elementet allerede overlapper roten. Spillerlisten ble + dermed hengende fast på "ikke nådd" gjennom resten av scrollingen, + identisk med bugen selv om koden så riktig ut. Erstattet med en vanlig + `scroll`/`resize`-lytter (passive) som leser + `getBoundingClientRect().top` direkte -- korrekt, kontinuerlig + oppdatering. + + **Verifisert i scratch** (samme mock-oppsett som #139/#140): utvidet + banekartet, trykket flytende "Registrer score" -- knappen forsvant nå + korrekt idet spillerkort 1 landet synlig, ingen tomt mellomrom stod + igjen. Scrollet helt ned til kommentarfeltet -- knappen forble skjult + (ikke lenger den opprinnelige bugen). Scrollet tilbake opp forbi + spillerlisten -- knappen dukket korrekt opp igjen. `tsc --noEmit` rent. + + **Ikke rullet ut ennå** -- venter på bekreftelse fra bruker. diff --git a/frontend/components/round-detail.tsx b/frontend/components/round-detail.tsx index c586488..0f81f68 100644 --- a/frontend/components/round-detail.tsx +++ b/frontend/components/round-detail.tsx @@ -6719,6 +6719,43 @@ function PlayerHoleCards({ const [mapExpanded, setMapExpanded] = useState(false) const [distanceAvailable, setDistanceAvailable] = useState(false) const playerListRef = useRef(null) + // Flytende "Registrer score" (2026-08-20) skal kun vises mens + // spillerlisten fortsatt er UTENFOR synlig område -- brukerfunn: den + // hang igjen synlig (og dekket delvis over spillerkort 1) selv etter at + // brukeren allerede hadde scrollet forbi/til spillerlisten, der den ikke + // lenger gir mening ("Registrer score ↓" når du allerede ser + // spillerne). "Reached" = listens toppkant har nådd/passert headerens + // faktiske høyde (samme 112px som scroll-mt-28 andre steder i denne + // filen) -- forblir sant BÅDE mens listen vises OG etter at brukeren + // har scrollet helt forbi den (listen ligger da over synlig område, + // `top` er negativ). Kun scroll TILBAKE OPP forbi listen (top blir + // igjen større enn 112) gjør at knappen skal dukke opp igjen. + // + // Første forsøk brukte IntersectionObserver med en krympet rootMargin + // -- viste seg FEIL i scratch-verifisering: med standard threshold=[0] + // fyrer den kun ved 0%->>0%-kryssinger (element helt inn/ut av roten), + // ikke ved at `boundingClientRect.top` passerer en INTERN linje midt i + // et allerede-overlappende element. Listen ble dermed hengende på + // "ikke nådd" gjennom hele resten av scrollingen forbi 112px-grensen. + // Vanlig scroll-lytter med direkte `getBoundingClientRect()`-sjekk gir + // korrekt, kontinuerlig oppdatering. + const [playerListReached, setPlayerListReached] = useState(false) + useEffect(() => { + if (!mapExpanded) return + const HEADER_HEIGHT_PX = 112 + function check() { + const el = playerListRef.current + if (!el) return + setPlayerListReached(el.getBoundingClientRect().top <= HEADER_HEIGHT_PX) + } + check() + window.addEventListener("scroll", check, { passive: true }) + window.addEventListener("resize", check) + return () => { + window.removeEventListener("scroll", check) + window.removeEventListener("resize", check) + } + }, [mapExpanded]) const holeMeta: Record = {} for (const list of Object.values(holesByParticipant)) { for (const h of list) { @@ -7102,23 +7139,34 @@ function PlayerHoleCards({ /> )} - {/* Flytende "Registrer score" (V0-eksport, 2026-08-20) -- kun mens - banekartet er utvidet. `fixed` posisjonerer mot selve viewporten - (ingen ancestor her setter transform/filter, så det er trygt), - gradient-scrim + skygge løfter den visuelt over innholdet under, - `env(safe-area-inset-bottom)` unngår at den klemmes helt inntil - kanten på telefoner med gest-navigasjon. `pointer-events-none` på - selve scrim-sonen når skjult/i overgang, slik at den aldri - blokkerer klikk på innhold bak. */} + {/* Flytende "Registrer score" (V0-eksport, 2026-08-20) -- mens + banekartet er utvidet OG spillerlisten fortsatt er utenfor synlig + område (se `playerListReached` over -- uten denne betingelsen hang + knappen igjen synlig, og dekket delvis over spillerkort 1, selv + etter at brukeren allerede hadde scrollet dit). `fixed` + posisjonerer mot selve viewporten (ingen ancestor her setter + transform/filter, så det er trygt), gradient-scrim + skygge + løfter den visuelt over innholdet under, `env(safe-area-inset- + bottom)` unngår at den klemmes helt inntil kanten på telefoner + med gest-navigasjon. `pointer-events-none` på selve scrim-sonen + når skjult/i overgang, slik at den aldri blokkerer klikk på + innhold bak. */}
-
+
playerListRef.current?.scrollIntoView({ behavior: "smooth", block: "start" })} @@ -7127,8 +7175,11 @@ function PlayerHoleCards({
{/* Gir siste innhold på siden rom til å scrolle klar av den flytende - knappen i stedet for å bli permanent skjult bak den. */} - {mapExpanded &&