From ee91d035148a5db729652d6e30db733b948e3899 Mon Sep 17 00:00:00 2001 From: Erol Haagenrud Date: Tue, 11 Aug 2026 14:41:22 +0200 Subject: [PATCH] Fiks ScrollFade: sprettende scroll-hint overlappet en ekte pil-knapp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bruker (skjermbilde): "Den sprettende ned-pilen fungerer ikke. Den ligger OPPÅ en annen nedpil." -- gjelder Retning-steget (Utslag/ Innspill) i score-registreringen, hvor "Kort"-knappen har sitt eget ArrowDown-ikon. To reelle feil i ScrollFade (round-detail.tsx): 1. ResizeObserver observerte scroll-BEHOLDEREN, ikke innholdet. Beholderens boks-størrelse er fast (flex-1), så den endrer seg aldri når man bytter steg i veiviseren -- observeren fyrte derfor ALDRI når et steg med reelt overflow-innhold ble vist. Hintet dukket rett og slett ikke opp der det trengtes (f.eks. nettopp Retning-steget). Rettet ved å observere innholds-diven i stedet. 2. Fade-/pil-overlayet er absolutt posisjonert over de siste 64px av scroll-området, uten noen garanti om at ekte innhold ikke havner der. På Retning-steget landet "Kort"-knappens egen pil nøyaktig i den sonen -- to piler oppå hverandre. Rettet med en usynlig 64px-buffer etter innholdet (samme høyde som overlayet), slik at overlayet aldri kan dekke et ekte element. hasMore-utregningen trekker fra bufferhøyden så den ikke gir falske positiver på kort innhold som uansett får plass. Scratch-verifisert (egen DB/rolle/MinIO/API/frontend-container, ekte bruker med fullt kølle-utvalg for å reprodusere nøyaktig samme rutenett som i brukerens skjermbilde): hintet vises korrekt når Retning-steget faktisk overflower, forsvinner korrekt ved reell bunn, "Kort"-knappen fullt synlig og utenfor overlay-sonen ved skrolling, lys+mørk, ingen konsollfeil. tsc --noEmit rent, 45/45 vitest grønt. Co-Authored-By: Claude Sonnet 5 --- frontend/components/round-detail.tsx | 41 ++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/frontend/components/round-detail.tsx b/frontend/components/round-detail.tsx index babb088..fc316cf 100644 --- a/frontend/components/round-detail.tsx +++ b/frontend/components/round-detail.tsx @@ -6577,30 +6577,49 @@ function WizardSection({ title, children }: { title: string; children: React.Rea // finnes mer innhold under fold-linjen -- og skjuler seg av seg selv idet man // har scrollet helt ned. Fanger både resize og innholdsendringer (ulikt // stat_level/par gir ulik høyde) via en ResizeObserver på selve scrollboksen. +// Høyden (px) på fade-/piloverlayet under -- MÅ matche spacer-diven sin +// h-16 og trekkes fra i hasMore-utregningen, se begrunnelse der. +const SCROLL_FADE_HEIGHT_PX = 64 + function ScrollFade({ children, className }: { children: React.ReactNode; className?: string }) { - const ref = useRef(null) + const scrollRef = useRef(null) + const contentRef = useRef(null) const [hasMore, setHasMore] = useState(false) useEffect(() => { - const el = ref.current - if (!el) return + const scrollEl = scrollRef.current + const contentEl = contentRef.current + if (!scrollEl || !contentEl) return const update = () => { - // 4px slingring: unngår at en sub-piksel-rest holder hintet i live - // når man i praksis ER nederst. - setHasMore(el.scrollTop + el.clientHeight < el.scrollHeight - 4) + // Trekker fra spacer-divens egen høyde (samme SCROLL_FADE_HEIGHT_PX) + // i tillegg til 4px slingring -- uten dette ville "hasMore" blitt + // sant utelukkende fordi spaceren selv gjør scrollHeight større, selv + // når ALT ekte innhold allerede er synlig (falskt positivt hint). + setHasMore(scrollEl.scrollTop + scrollEl.clientHeight < scrollEl.scrollHeight - SCROLL_FADE_HEIGHT_PX - 4) } update() - el.addEventListener("scroll", update, { passive: true }) + scrollEl.addEventListener("scroll", update, { passive: true }) + // Observerer INNHOLDS-diven, IKKE scroll-beholderen selv -- + // beholderens egen boks-størrelse er fast (flex-1, bundet av + // veiviserens layout), den endrer seg ALDRI når man bytter steg. Uten + // dette ble "hasMore" aldri regnet på nytt ved stegbytte -- den + // sprettende pilen dukket rett og slett ikke opp på steg som faktisk + // trengte scrolling (f.eks. "Retning"-steget med kølle-rutenett). const ro = new ResizeObserver(update) - ro.observe(el) + ro.observe(contentEl) return () => { - el.removeEventListener("scroll", update) + scrollEl.removeEventListener("scroll", update) ro.disconnect() } }, []) return (
-
- {children} +
+
{children}
+ {/* Usynlig buffer, SAMME høyde som fade-/piloverlayet -- garanterer at + overlayet aldri dekker et ekte, interaktivt element (f.eks. en + retningsknapp med sin egen pil-ikon nederst i steget). Uten denne + kunne den sprettende pilen havne rett oppå en annen pil. */} + {/* Rent dekorativt -- selve scrollingen er fullt mulig uten dette. */}