diff --git a/CHANGELOG.md b/CHANGELOG.md index 02115eb..2df5f50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14664,3 +14664,38 @@ Neste steg: kompakt, hjørne-forankret "Score"-FAB som erstatning, jf. stående instruks om at nye UI-overflater skal gjennom V0 fremfor håndkodes direkte. Ingen utrulling av punktfiksen fant sted. + +165. **Kompakt "Score"-FAB integrert, erstatter fullbredde-bunnbanneret + helt (V0-eksport, oppfølging av punkt 164), 2026-08-23.** V0-prompt + (`Temp-uploads/v0-prompt-compact-score-fab.md`) levert til bruker, + eksport mottatt (`components/compact-score-fab.tsx`) og integrert + tro mot eksporten -- ny fil `frontend/components/compact-score-fab.tsx`, + uendret fra V0 bortsett fra kommentarer. + + **`round-detail.tsx`:** `RegisterScoreButton` (den vanlige, i-flyt- + plasserte knappen) er UENDRET og fortsatt eneste sted "Registrer + score ↓"-teksten/pil-ikonet brukes. Den gamle flytende + fullbredde-banner-JSX-en (`fixed inset-x-0 bottom-0` + gradient-scrim + + `h-20`-spacer) er fjernet i sin helhet, erstattet med + ``. Hele `playerListReached`- + mekanismen (state + effekt + den sårbare `mapExpanded`-vakten som + forårsaket punkt 164) er fjernet -- ikke lenger nødvendig, siden en + liten hjørne-FAB ikke trenger å skjule seg igjen for å unngå å dekke + over innhold. `inFlowButtonRef`/`inFlowButtonVisible`/ + `scrollToPlayerList`/`playerListRef`/`SCROLL_GAP_PX`/ + `getHeaderHeight()` er alle UENDRET og gjenbrukt som før (sistnevnte + to også brukt av `scrollToHolePanel()`, urørt av denne runden). + + **Verifisert i full-stack scratch** (samme oppskrift som punkt 164 -- + 3 spillere + 6 kommentarer for å gi nok scroll-lengde): FAB-en + bekreftet skjult mens i-flyt-knappen er synlig, dukker opp + (fade+skaler, IKKE slide-opp) idet i-flyt-knappen ruller ut av syne, + forblir korrekt synlig helt ned til og forbi Kommentarer UTEN å dekke + over innholdet (bekreftet med skjermbilder, både lys og mørk modus), + og skjules igjen ved scroll tilbake til toppen. Trykkflate målt til + 48px høyde (over 44px-gulvet), innholds-bredde (~110px, ikke full + bredde). `tsc --noEmit` rent, ingen konsollfeil. Alle scratch- + ressurser ryddet opp. + + **Ikke rullet ut ennå** -- venter på brukerens bekreftelse. diff --git a/frontend/components/compact-score-fab.tsx b/frontend/components/compact-score-fab.tsx new file mode 100644 index 0000000..8777759 --- /dev/null +++ b/frontend/components/compact-score-fab.tsx @@ -0,0 +1,49 @@ +"use client" + +import { PencilLine } from "lucide-react" +import { cn } from "@/lib/utils" + +export type CompactScoreFabProps = { + /** Controls the fade + scale in/out. Driven from outside (the page's + * existing `inFlowButtonVisible` state) -- this component owns no + * hide/show-on-scroll logic of its own. */ + visible: boolean + /** Scrolls the user back to the player list (same action as the in-flow + * button). No navigation, no new page. */ + onClick: () => void +} + +/** + * Compact, corner-anchored "Score" quick button (FAB). + * + * Replaces the old full-width bottom banner (round-detail.tsx, removed + * 2026-08-23 -- see CHANGELOG). Because it's small and pinned to the + * bottom-right corner, it never needs to hide to avoid covering content -- + * so there is no scrim, no reserved bottom spacer, and no slide-up + * animation. It simply fades + scales in place. + */ +export function CompactScoreFab({ visible, onClick }: CompactScoreFabProps) { + return ( + + ) +} + +export default CompactScoreFab diff --git a/frontend/components/round-detail.tsx b/frontend/components/round-detail.tsx index dfdebe6..f33af94 100644 --- a/frontend/components/round-detail.tsx +++ b/frontend/components/round-detail.tsx @@ -58,6 +58,7 @@ import { import { ShotMeasurementEntry } from "@/components/shot/shot-measurement-entry" import { HoleTargetDistance } from "@/components/hole-target-distance" import { HoleHistoryDetail } from "@/components/hole-history-detail" +import { CompactScoreFab } from "@/components/compact-score-fab" import { enqueueWrite, flushQueue, queueCount } from "@/lib/offline-queue" // --- Types ----------------------------------------------------------------- @@ -6315,25 +6316,21 @@ function sumForPlayer(list: ApiHole[] | undefined, numbers: number[]): { strokes // linjer avhengig av runden), så en fast pixel-gjetning viste seg feil for // en runde med lengre innhold enn den opprinnelige gjetningen (112px) var // kalibrert mot (scratch-verifisering 2026-08-20: ekte høyde 141,5px for -// en runde med bane+utslag+dato+klokkeslett samtidig). Brukt av BÅDE -// scroll-hoppet til spillerlisten og `playerListReached`-sjekken under. +// en runde med bane+utslag+dato+klokkeslett samtidig). Brukt av +// scroll-hoppene til spillerlisten/hull-panelet under. function getHeaderHeight(): number { return document.querySelector("header")?.getBoundingClientRect().height ?? 112 } -// Pusterom under headeren når spillerlisten scrolles til -- brukt for -// BÅDE selve scroll-målposisjonen og "reached"-terskelen (se begge -// under). Delt konstant med vilje: scroll-hoppet lander bevisst -// `SCROLL_GAP_PX` under headeren (ikke flush), så "reached"-sjekken må -// bruke SAMME avstand, ellers forblir den flytende knappen synlig etter -// at hoppet har landet (funnet i scratch-verifisering 2026-08-20 -- de to -// brukte ulike terskler). +// Pusterom under headeren når det scrolles til spillerlisten/hull-panelet +// -- se `scrollToPlayerList()`/`scrollToHolePanel()` under. const SCROLL_GAP_PX = 16 -// "Registrer score" -- samme knapp, to plasseringer (se PlayerHoleCards): -// i normal side-flyt når banekartet er kollapset, flytende festet nederst -// på skjermen når det er utvidet (V0-eksport, 2026-08-20, brukerønske -- -// det utvidede diagrammet kunne dytte knappen langt utenfor synlig område). +// "Registrer score" -- den vanlige, i normal side-flyt-plasserte knappen +// (se PlayerHoleCards). Den kompakte, hjørne-forankrede "Score"-FAB-en som +// dukker opp når DENNE ruller ut av syne er en egen komponent, +// `CompactScoreFab` (redesignet 2026-08-23, se CHANGELOG) -- ikke lenger +// samme knapp flyttet til en flytende posisjon. function RegisterScoreButton({ onClick }: { onClick: () => void }) { return (