Kontoen til Fredrik Mathisen (fødselsdato under 13 år, ingen tilknyttet aktivitet) er slettet fra ekte teecup_db, og e-posten med forklaring ble sendt til fredrik.f.mathisen@gmail.com før slettingen ble bekreftet fullført.
17 KiB
TeeCup — designsystem (referanse)
Dette dokumentet beskriver det VISUELLE grunnlaget for alt frontend- arbeid i TeeCup — fargetoken, typografi, avstand, komponentmønstre og tilgjengelighetsregler. Det er en beskrivelse av hva som ER etablert i koden (
frontend/app/globals.css,frontend/components/ui/*, og mønstrene brukt på tvers avcomponents/*.tsx), ikke et nytt forslag — hensikten er at både V0-prompter og håndkodet arbeid skal kunne forankres i akkurat dette, i stedet for å gjettes på nytt hver gang.Ufravikelig grunnregel (fra CLAUDE.md, gjelder ALT, eksisterende og fremtidig): appen skal være lesbar, forståelig og betjenbar for noen med noe redusert syn UTEN briller. God kontrast, stor nok skrift, store nok trykkflater, ikke ikon-only uten tekstlabel for viktige handlinger, ikke avhengig av finmotorikk/skarpt syn. Enhver visuell beslutning under veies mot dette først.
2026-08-10 (ADR-052): paletten under er "clubhouse" — resultatet av en full overtagelse denne dagen. Frem til da var dette dokumentet "Forest Green" (nøytral grå + lys grønn primær, opprinnelig formalisert 2026-07-29). Clubhouse oppsto som en isolert
/logg-inn-utforskning 2026-08-07 (ADR-047), ble utvidet til dashbord/bunnnav/velkommen, og tok til slutt over shadcn-tokenene iglobals.cssfor HELE appen (unntatt ny-runde-veiviserens egennr-*-palett, ADR-048 — den er bevisst en tredje, frittstående palett og beskrives ikke her). Innholdet under er derfor nå den faktiske koden, ikke et forslag.
Merkevare-opprinnelse
Fargeformen/-tonen er hentet fra Teeoff-logoen (samme merkevarefamilie, egne farger — se ADR-009/ADR-016), IKKE navn eller logo. "Clubhouse" (ADR-047/052) er en nyere, varmere fortolkning av den samme opprinnelsen, tegnet fra selve TeeCup-logoen:
- Grønn ("tee" / "tee-strong"):
#8bbd51/#2f6b1e - Oransjerød ("cup" / "cup-strong"):
#ff5427/#cf3c17
brand-orange (den eldre, separate sekundærtokenen, #ff5722) lever
videre uendret — den er allerede nesten identisk med cup, samme
merkevarefamilie, ingen dissonans. Personlighet: "klubbhus-stemning, ikke
countryklubb-snobberi" — varm, jordnær, vennlig.
Fargetoken (frontend/app/globals.css)
Kildepaletten er ti hex-verdier (--tee, --tee-strong, --cup,
--cup-strong, --clubhouse-bg, --clubhouse-card, --clubhouse-ink,
--clubhouse-muted, --clubhouse-border, --clubhouse-field), definert
i egne :root/.dark/@media-blokker i globals.css. shadcn-tokenene
(--background, --card, --primary osv.) KOPIERER disse verdiene
direkte, slik at Tailwind-klassene under (bg-primary,
text-muted-foreground osv.) er de du skal bruke i vanlig kode — aldri
rå hex/oklch, og ALDRI hardkodede Tailwind-fargeklasser som
slate-500/gray-100. Hardkodede farger bryter den automatiske mørk/
lys-tema-logikken, som ellers virker helt av seg selv så lenge
token-klassene brukes.
| Token | Lys modus | Mørk modus | Rolle |
|---|---|---|---|
background / foreground |
#f3f6ec / #17200f |
#131a0f / #eef3e6 |
sideflate / brødtekst |
card / card-foreground |
#ffffff / #17200f |
#1d2616 / #eef3e6 |
kort, paneler, seksjoner |
primary / primary-foreground |
#2f6b1e / hvit |
#3c8226 / hvit |
hovedhandling, valgt tilstand, "under par"/positiv |
secondary/muted/accent (+ -foreground) |
#f7f9f3 / #17200f |
#26301d / #eef3e6 |
bakgrunnstoner, hover, sekundær tekst |
destructive |
rød-oransje (uendret fra Forest Green) | uendret | slett/fare-handlinger |
border / input |
#dbe1cd |
#34402a |
kant på kort, felt, delelinjer |
ring |
samme som primary |
samme som primary |
fokus-ring (tastatur-tilgjengelighet) |
brand-orange / brand-orange-foreground |
oklch(0.6792 0.2128 36.53) (uendret) |
uendret | sekundærfarge — "over par"/advarsel, IKKE feil (det er destructive) |
chart-1 … chart-6 |
grønn→blå→gul→oransje→rød-skala (uendret) | uendret | statistikk-/fordelingsvisualiseringer (ADR-033), ALDRI brukt for kategoriske UI-tilstander |
Hvorfor destructive/brand-orange/info/gold/chart er uendret (ADR-052): disse er bevisst distinkte semantiske signalfarger, ikke del av nøytral/primær-identiteten paletten styrer — å tvinge dem inn i clubhouse sin fargefamilie ville visket ut skillet mellom "dette er merkevaren" og "dette er et signal (feil/advarsel/rekord/statistikk)".
Farge-semantikk, konsekvent på tvers av hele appen:
primary(grønn) = valgt/aktiv, positivt resultat (under par, ledende, bekreftet), primærhandling.brand-orange= nest viktigst/kontrast-pol i et par (over par, "Poeng" i noen sammenhenger), IKKE en feilfarge.destructive= KUN faktiske slette-/fare-handlinger (Slett runde, fjern spiller), aldri "over par" eller lignende domenetilstand.muted-foreground= all sekundær/bildetekst-tekst, aldri brødtekstens hovedfarge.
Aldri farge alene. Hver gang farge bærer betydning (over/under par, leder, valgt/uvalgt), følges den av FORM (sirkel vs. firkant, fylt vs. bordered), tekst (+N/−N/E, "Deg"/"Eier"), eller et ikon — se "Golfscore-språket" under. Dette er ikke en stilistisk preferanse, det er et direkte utslag av tilgjengelighetsregelen øverst.
Typografi
- Skrifttype: Nunito (
next/font/google, lastet iapp/layout.tsx, eksponert som--font-sans) — rund, vennlig, god lesbarhet på små trykkflater. Ingen sekundær/monospace-font i UI-et (tabular-nums brukes for tallinnretting i stedet for en egen tallfont — se under). - Skala (Tailwind-klasser, brukt konsekvent):
text-sm— bildetekst, sekundær informasjon, knapp-tekst i tette kontekstertext-base— brødtekst, standard knapp-/felt-tekst, listeelementertext-lg/text-xl— kortoverskrifter, seksjonstitlertext-2xl/text-3xl— sideoverskrifter, hull-header, store resultat-tall
- Vekt (revidert 2026-07-29): ved
text-base(16px) og god kontrast (text-foreground) erfont-normalhelt akseptabelt og FORETRUKKET for brødtekst — unngår visuell støy av at alt roper likt. Hierarki skapes primært med STØRRELSE og FARGE (kontrast), ikke bare vekt.text-smeller mindre (bildetekst/metadata) bør derimot ofte gisfont-mediumfor å kompensere for den mindre størrelsen — aldrifont-normalundertext-base. Overskrifter/tall/primærhandlinger beholderfont-bold/font-extraboldsom før. tabular-numspå ALL numerisk visning (skår, HCP, datoer, rangeringer) — hindrer tall fra å "hoppe" i bredde når de endres.- Golfvis fortegn: til-par-tall formateres ALLTID som "E" (jevnt med par), "+N" (over), "−N" — ekte minustegn (U+2212), ALDRI en vanlig bindestrek eller et bart negativt tall. Samme regel for HCP/ differensial-tall der fortegn er meningsbærende.
Avstand, hjørner og lag
- 8-punkts rutenett (2026-07-29): marger, padding og
gapfølger 8-gangen (p-2=8px,p-4=16px,p-6=24px,p-8=32px) for forutsigbar rytme. Halv-steg (gap-1.5,py-2.5osv.) unngås i nytt arbeid — brukes kun der et etablert mønster (f.eks. shadcn sine egne primitiver) allerede definerer det. - Kort får tydeligere løft (2026-07-29):
shadow-md shadow-black/8(opp frashadow-sm shadow-black/5) på kort/paneler i lyst tema — mer synlig separasjon fra bakgrunnen. Seround-card.tsx/tournament-card.tsx/install-prompt.tsx/dashboard.tsxfor det gjeldende mønsteret; eldre skjermer som fortsatt harshadow-sm shadow-black/5bør rettes opp neste gang de røres. - Hjørneradius (fra
--radius: 0.625rem, skalert opp via--radius-sm/md/lg/xl/2xl/3xl/4xl):rounded-xlfor felt/knapper i tette rader,rounded-2xlfor kort/paneler/knapper med normal vekt,rounded-3xlfor store side-nivå-containere (hull-panel, rundekort).rounded-fullreservert for sirkulære tilstander (se golfscore-språket) og pille-formede brytere/merker. - Kort/panel-basismønster:
rounded-2xlellerrounded-3xl,border border-border,bg-card,p-4(tett) tilp-5 sm:p-6(romslig), ofteshadow-sm shadow-black/5for lett løft fra bakgrunnen. - Sammenhengende lister (leaderboard, spillerliste): ÉN container
(
rounded-2xl border border-border overflow-hidden) meddivide-y divide-bordermellom radene — IKKE separate kort med mellomrom, det gir en "kort-følelse" som virker mer oppstykket enn nødvendig når radene i praksis hører sammen (bevisst rettet opp 2026-07-26 på leaderboardet, se CLAUDE.md). - Stiplet kant (
border border-dashed border-border) markerer en "legg til"/tom-tilstand-affordance (f.eks. "+ Medspiller"), ALDRI brukt på innhold som allerede finnes.
Trykkflater og avstand mellom elementer
- 44px er det ufravikelige gulvet for enhver trykkbar flate
(
min-h-11i Tailwind-tall siden 1 enhet = 4px). Primærhandlinger er ofte enda større:h-12–h-16for tallvelgere/hovedknapper. - Runde ikon-only-knapper (lukk, fjern) er minimum
size-11. - Gap mellom relaterte kontroller:
gap-2/gap-2.5/gap-3normalt,gap-4/gap-6mellom distinkte seksjoner.
Interaksjon (2026-07-29)
- Alle interaktive elementer skal ha en definert
:hover- OG:active-tilstand —:active(f.eks.active:scale-[0.98]på kort/ knapper,active:opacity-70på lenker/ikon-knapper) gir umiddelbar, taktil bekreftelse på at trykket faktisk ble registrert. shadcn sinButton-primitiv har alleredeactive:translate-y-pxinnebygd; egne håndbygde trykkflater (kort,<Link>-baserte rader) må legge det til eksplisitt siden de ikke arver primitivens klasser. disabledbrukerdisabled:opacity-50 disabled:pointer-events-none(allerede standard iInput/Button).- Bevegelse:
transition-all duration-200 ease-in-outfor state- endringer på knapper/kort — kjapt og "snappy", ikke en treg nettside- følelse. Ingen animasjon/fade lenger enn 300ms.
Skjemaer og inndata (mobil-først)
- Tekst i
<input>/<select>/<textarea>er ALLTID minsttext-base(16px) — mindre utløser tvungen auto-zoom på iOS Safari. shadcn sinInput-primitiv løser dette allerede (text-base md:text-sm— større på mobil, kan trappes ned på desktop der zoom ikke er et problem). - Riktig
inputModefor numeriske felt ("numeric"/"decimal"for HCP/ slag/score) slik at riktig mobiltastatur vises med det samme — se tallvelgerne i scoring-flyten for eksisterende bruk. - Fokus:
focus-visible:ring-2 focus-visible:ring-ring(aldri nettleser-standard outline).
Safe areas og skjermkanter (2026-07-29)
Elementer festet til topp (sticky header) eller bunn (footer-handlinger)
skal ikke havne bak en fysisk notch/Dynamic Island eller hjem-
indikatoren. Praktisk løsning: pt-[env(safe-area-inset-top)] på selve
sticky-headeren, pb-[max(4rem,env(safe-area-inset-bottom))] på siste
innholdscontainer — env() resolver til 0 på enheter uten notch, så dette
er trygt å legge til overalt, ikke bare på skjermer der det faktisk
trengs.
Layout-containere
- Innloggede/app-sider:
mx-auto w-full max-w-3xlfor innholdsrike sider (runde-detalj),max-w-xlfor enklere/lesevisninger (leaderboard, scorekort, statistikk). - Sticky header:
sticky top-0 z-10(ellerz-20når flere lag stables),border-b border-border,bg-background/90til/95+backdrop-blur— innhold forblir lesbart under skrolling uten å bli en solid, brå kant. - Fullskjerm-overlegg (scoringsveiviser):
fixed inset-0 z-50 flex flex-col bg-background, medheader/main(scroller,flex-1 overflow-y-auto) /footer(handling-rad,shrink-0) — samme tre-delt struktur uansett hvor i appen et slikt overlegg brukes. - Fast-per-rad-høyde når kort skal se enhetlige ut i en liste
(
min-h-[Npx]+truncatepå tekstlinjer i stedet for fri wrapping) — brukt bevisst på spillerkort 2026-07-26 for at rader med ulikt antall merker/lengde på navn likevel blir like høye.
Komponentmønstre (gjenbrukes, ikke gjenoppfinnes)
Disse er alle allerede bygget som lokale funksjoner i de respektive
components/*.tsx-filene (ikke delte imports på tvers av filer — hver
fil har sin egen lokale kopi tilpasset sin kontekst, et bevisst valg
gjentatt flere ganger denne økten fremfor tidlig abstraksjon).
NumberPicker(round-detail.tsx) — 3-kolonners rutenett av store (h-16) tallknapper, valgt tilstand = fyltbg-primary, med en valgfri liten bildetekst under tallet (par-merke, eller — Slag- varianten — kontekstuell golf-term: Albatross/Eagle/Birdie/Par/Bogey/ Dobbel bogey relativt til hullets par). Utvidbar "10+"-knapp for sjeldne høye verdier, holder standardvisningen kort.Stepper(+/−) — pille-formet rad med tosize-11-knapper som flankerer et sentrert tall. Brukt for løpende antall (putter, chip, bunker, straffeslag) der en full talltavle ville vært overkill.ChoiceRow— horisontal rad av segmenterte knapper (flex-1, valgt =bg-primary), for korte, faste alternativlister (avstand første putt, kjønn, statistikknivå).DirectionCross— 3×3-rutenett med retningsikoner (ArrowUp/Left/ Right/Down+Targeti sentrum) for utslags-/innspillretning. Tekst- label på hver knapp (ALDRI kun ikon), matcher tilgjengelighetsregelen.ModeToggle/segmentert bryter —inline-flex gap-1 rounded-full bg-muted p-1, hver fanerounded-full, valgt =bg-primary text- primary-foreground. Brukt for Brutto/Netto/Poeng, Score/Spillere-faner osv.Badge(delt shadcn-komponent,components/ui/badge.tsx) —variant="default"(fylt grønn) for "Deg",variant="outline"(bordered) for "Eier" — de to skal ALLTID være visuelt distinkte varianter av hverandre, ikke samme stil i to farger.
Golfscore-språket (form + farge, aldri farge alene)
Det viktigste, mest gjenbrukte visuelle mønsteret i appen — brukt i
round-scorecard.tsx (ScoreMark), round-leaderboard.tsx
(ToParMark/PointsMark/HoleMark), og flere steder til:
- Sirkel (
rounded-full) = under par / positivt resultat. - Firkant med liten radius (
rounded-[4px]–rounded-[6px]) = over par / negativt resultat. - Ren tekst, ingen ramme = nøyaktig par ("E").
- Fylt bakgrunn (
bg-primary/bg-brand-orange+ kontrastfarget tekst) = ekstra vekt (eagle+/dobbel bogey+, eller lederen i en rangering) — fortsatt SAMME form som den vanlige varianten, kun fyllingen endres. Vanlig variant =border-2+/10-tint bakgrunn + farget tekst. - Poeng (stableford) har ingen retning (høyere er alltid bedre) — får derfor kun ÉN fast form (sirkel), samme fylt/bordered-emphasis- logikk som resten.
- Rangeringstall bruker et eget, nøytralt merke (
bg-muted/bg-primaryved leder) — ikke samme form-språk som selve resultatet, for å unngå at rangering og resultat blandes visuelt sammen.
Ikonografi
lucide-react, konsekvent gjennom hele appen — ingen annen ikonpakke blandet inn.- Ethvert ikon som er rent dekorativt får
aria-hidden="true". - Ikon-only er ALDRI lov for en viktig handling — en tekstlabel følger
alltid med (unntak eksplisitt vurdert og akseptert: bjelleikonet for
varsler, fordi det er universelt gjenkjent OG har en beskrivende
aria-labelmed antall uleste).
Tilbakemelding og tilstander
- Lasting: sentrert spinner,
size-8–size-10 animate-spin rounded-full border-4 border-primary/20 border-t-primary. - Feil:
role="alert",text-destructive, alltid som ren tekst (aldri kun et ikon eller en farget kant). - Tomme lister: en kort forklarende tekst + evt. en stiplet "legg til"-affordance, aldri en stille blank flate.
- Sanntid (WebSocket): ingen egen visuell "oppdatert!"-indikator — data hentes på nytt og erstatter stille, siden radene allerede har stabile nøkler/layout (unngår blunking).
Navneformat (innhold, ikke et rent visuelt punkt — men styrer hva som vises hvor)
Direkte adressering av brukeren (dashbord-hilsen, e-post/varsel rettet TIL mottakeren) bruker KUN fornavn. Alt annet (lister, roster, chat, administrasjonsvisninger) bruker fullt navn/initialer — se CLAUDE.md for den fulle, ufravikelige regelen. Nevnt her fordi det er en like fast STANDING forventning til fremtidig UI som resten av dette dokumentet.
Hva dette dokumentet bevisst IKKE er
- Ikke en erstatning for CLAUDE.md sin tilgjengelighetsregel (den er autoritativ og gjengitt her kun i sammendrag).
- Ikke en frys av dagens design — nye mønstre legges til etter hvert som de bygges (både via V0 og håndkodet), men skal alltid først sjekkes mot det som ALLEREDE er etablert her fremfor å finne opp noe nytt.
- Ikke en komponent-API-referanse — se selve kildefilene
(
components/ui/*.tsx, og de lokale komponentene i hvercomponents/*.tsx) for eksakte prop-signaturer.