Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,040 changes: 303 additions & 737 deletions README.md

Large diffs are not rendered by default.

72 changes: 49 additions & 23 deletions docs/accessibility.md
Original file line number Diff line number Diff line change
@@ -1,60 +1,86 @@
# Tilgjengelighet

Sjekkliste for universell utforming i appen. Native HTML brukes der det gir riktig semantikk. ARIA legges bare til når native HTML ikke er nok.
Sjekkliste for universell utforming i appen. Vi bruker vanlig HTML der den gir riktig semantikk. ARIA legges bare til når HTML ikke er nok.

Se [testing.md](testing.md) for hvordan dette er testet.

## Tastaturnavigasjon

- Alle interaktive elementer er vanlige `<button>`, `<select>` eller `<input type="checkbox">`.
- Alle interaktive elementer er vanlige `<a>`, `<button>`, `<select>` eller `<input type="checkbox">`.
- Tab flytter fokus mellom kontrollene. Enter og mellomrom aktiverer knapper, og mellomrom veksler avkrysningsboksen.
- Sidemenyen og forrige/neste eier ingen egen tastaturlogikk utover native knapper.
- På smale skjermer har «Landliste» `aria-expanded`. Etter valg av land flyttes fokus tilbake til knappen, slik at den ikke blir værende i en skjult liste.
- **Snarvei:** Første tabulatorstopp er lenken «Hopp til landkortet». Den er skjult til den får fokus, og hopper forbi sortering, filter og alle landene i sidemenyen. Målet (`#landkort`) har `tabindex="-1"`, slik at fokus flyttes dit, og en ramme viser hvor fokus havnet. Rammen vises bare ved tastaturbruk, ikke når man klikker i kortet. Neste Tab går til «Forrige» eller «Neste».
- Sidemenyen og forrige/neste har ingen egen tastaturlogikk utover vanlige knapper.
- På smale skjermer har knappen «Landliste» `aria-expanded`. Etter valg av land flyttes fokus tilbake til knappen, slik at det ikke blir værende i en skjult liste.
- **Safari:** Som standard flytter Tab bare fokus mellom skjemafelt i Safari. For å nå lenker og knapper må brukeren slå på innstillingen for å markere hvert objekt med Tab (Innstillinger → Avansert) eller bruke Option+Tab. Dette gjelder alle nettsider, ikke bare denne appen.

## Tilgjengelige navn

- Sortering og favorittfilter får navn fra synlig `<label>`: «Sorter etter» og «Vis bare favoritter».
- Favorittknappen har `aria-label` på formen «Favoritt: Bangladesh». Den synlige teksten «Favoritt» inngår i navnet.
- Forrige/neste har synlig tekst «Forrige» og «Neste». Det tilgjengelige navnet inkluderer mållandet, for eksempel «Forrige land: Norge» og «Neste land: Sverige». Deaktiverte knapper beholder synlig tekst som navn.
- Forrige/neste har synlig tekst «Forrige» og «Neste». Det tilgjengelige navnet inkluderer mållandet, for eksempel «Forrige land: Brazil» og «Neste land: China». Deaktiverte knapper beholder synlig tekst som navn.
- Land i sidemenyen bruker landnavnet. Favoritter får skjult tekst «(favoritt)».
- Landemerker: `<nav aria-label="Bla mellom land">` og sidemenyen merket via overskriften «Land».

## Synlig fokus

Alle interaktive kontroller har `:focus-visible` med 2 px omriss i aksentfargen. Musklikk viser ikke omrisset, tastaturfokus gjør det.

## Semantisk HTML
## Semantisk HTML og landemerker

- Siden ligger i `<main>`. Sidemenyen er `<aside>`, forrige/neste er `<nav>`, og landkortet er `<article>`.
- Hovedinnholdet ligger i `<main>`. Sidemenyen er `<aside>` merket med overskriften «Land», forrige/neste er `<nav aria-label="Bla mellom land">`, og landkortet er `<article>`.
- Kildehenvisningen ligger i `<footer>` utenfor `<main>`, og blir dermed landemerket `contentinfo`.
- Faktaene i kortet ligger i `<dl>` med `<dt>`/`<dd>`.
- Landlisten er en `<ul>` med én knapp per land. Valgt land har `aria-current="true"`.
- Native `disabled` brukes på forrige/neste ved første og siste land. Unødvendig `role` eller `aria-*` er ikke lagt på knapper, select eller avkrysningsboks.
- Forrige/neste bruker vanlig `disabled` ved første og siste land. Knapper, nedtrekksliste og avkrysningsboks har ingen overflødig `role` eller `aria-*`.

## Overskriftshierarki og dokumentspråk

- Ett `<h1>`: «Utforsk verden».
- `<h2>` brukes til sidemenyen («Land») og landnavnet i kortet. Kortets `article` er koblet til landnavnet med `aria-labelledby`.
- Dokumentspråk (`lang`) og dokumenttittel settes i `index.html` og dekkes av en egen issue.
- `<h2>` brukes til sidemenyen («Land») og landnavnet i kortet. Kortets `<article>` er koblet til landnavnet med `aria-labelledby`.
- `index.html` har `lang="nb"` og tittelen «Utforsk verden».
- Landnavn, regioner og språk kommer fra API-et på engelsk. De er egennavn og er ikke merket med eget `lang`.

## Bildetekst
## Bilder

- Flagget har `alt` på formen «Flagget til …».
- Mangler flagget, eller kan bildet ikke lastes, vises teksten «Flagg ikke tilgjengelig» i stedet for et bilde.
- Stjerner for favoritt er dekorative og skjult med `aria-hidden`.
- Hvert land får et nytt `<img>`-element. Mens et nytt flagg lastes, er flaggfeltet tomt i stedet for å vise flagget til forrige land.
- Stjernene for favoritt er dekorative og skjult med `aria-hidden`.

## Favorittstatus

- Favorittknappen er en vanlig `<button>` med `aria-pressed`. Navnet er det samme i begge tilstander; `aria-pressed` forteller om den er på.
- Favorittknappen er en vanlig `<button>` med `aria-pressed`. Navnet er det samme i begge tilstander, og `aria-pressed` forteller om den er på.
- I sidemenyen vises favoritt både visuelt (★) og for skjermlesere («(favoritt)»).

## Lasting og feil
## Lasting, feil og endringer

- Lasting bruker `role="status"`: «Laster land …».
- Feil bruker `role="alert"` og knappen «Prøv igjen».
- Tomt favorittutvalg bruker `role="status"` og knappen «Vis alle land».
- Posisjonen «Land 3 av 25» ligger i en `aria-live="polite"`-region, slik at skjermlesere leser ny posisjon ved blaing.

## Responsivt reflow og zoom
## Synlig fokus

Alle interaktive kontroller har `:focus-visible` med 2 px omriss i aksentfargen. Et museklikk viser ikke omrisset, men tastaturfokus gjør det. Omrisset har 6,0:1 kontrast mot bakgrunnen i lys modus og 6,8:1 i mørk modus.

## Kontrast

- `viewport` er satt, og layouten bruker flexbox/grid med `max-width: 100%` og `minmax(0, 1fr)`, slik at innholdet ombrekkes i stedet for å gi horisontal scrolling.
Fargene er definert som variabler i `src/index.css`, med egne verdier for lys og mørk modus (`prefers-color-scheme`). Målt kontrast (WCAG 2.2 AA krever 4,5:1 for vanlig tekst):

| Tekst | Lys modus | Mørk modus |
| ------------------------------------------------ | --------- | ---------- |
| Overskrifter og verdier | 20,2:1 | 16,3:1 |
| Etiketter (for eksempel «Hovedstad») | 5,7:1 | 7,0:1 |
| Aksentfarge på bakgrunn (lenker, fokusomriss) | 6,0:1 | 6,8:1 |
| Aksentfarge på aksentflate (knapper, valgt land) | 5,1:1 | 5,3:1 |
| «Flagg ikke tilgjengelig» | 5,2:1 | 6,4:1 |

Aksentfargen i lys modus var `#aa3bff` fra Vite-malen. Den ga bare 3,8:1 på aksentflaten og ble byttet til `#8b2fd9` i issue #17.

## Tekststørrelse, zoom og reflow

- Grunnstørrelsen er satt i prosent (112,5 % på store skjermer og 100 % ellers), og overskrifter og kontroller bruker `rem`. Teksten følger dermed både zoom og nettleserens innstilling for tekststørrelse.
- Overskriften har egen `line-height`, slik at linjene ikke overlapper når den brytes med stor tekst.
- `viewport` er satt, og layouten bruker flexbox/grid med `max-width: 100%` og `minmax(0, 1fr)`, slik at innholdet brytes om i stedet for å gi horisontal scrolling.
- Lange navn og tall brytes med `overflow-wrap`. Flagget beholder proporsjonene.
- Under 641 px ligger menyen over kortet, og landlisten ligger bak knappen «Landliste».
- Tekst og kontroller følger relativ fontstørrelse, slik at zoom og smale skjermer ikke klipper innholdet.
- Til og med 640 px ligger menyen over kortet, og landlisten ligger bak knappen «Landliste».

## Kjente begrensninger

- Appen er ikke testet med skjermleser (VoiceOver, NVDA eller TalkBack). Tilgjengeligheten er kontrollert med axe-core, tastatur og gjennomgang av koden.
- axe-core finner ikke alle problemer, for eksempel om rekkefølgen og formuleringene er forståelige.
49 changes: 42 additions & 7 deletions docs/prosjektstandard.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Prosjektstandarder

Dette repoet følger noen enkle standarder for issues, commits og ferdigstilling (DoD).
Dette repoet følger noen enkle standarder for issues, branches, commits, pull requests og ferdigstilling (DoD).

---

Expand Down Expand Up @@ -36,9 +36,23 @@ Hva som skal gjøres, hvorfor det er nødvendig, og hvilke filer eller deler av

---

## Branches

Hver issue får sin egen branch fra `main`. Branchen lages fra issuen på GitHub («Create a branch»), slik at den kobles til issuen.

```
<issuenummer>-<type>-<kort-beskrivelse>
```

Eksempel: `17-docs-dokumentere-løsning-testing-og-ki-bruk-i-readme`

Branchen slettes etter at pull requesten er merget.

---

## Commit-standard

Vi følger en enkel konvensjon basert på _Conventional Commits_.
Vi følger en enkel konvensjon basert på _Conventional Commits_. Beskrivelsen skrives på norsk i imperativ, for eksempel «legg til», «rett» eller «fjern».

**Format**

Expand Down Expand Up @@ -74,23 +88,43 @@ Bruk et kort område som peker på delen som er endret.

```
feat(app): legg til prosjektoversikt på forsiden
fix(app): rett counter-knappens tekst
fix(app): rett teksten på favorittknappen
style(css): juster layout for mobilvisning
docs(docs): oppdater prosjektstandard med commit-typer
build(deps): oppdater React og Vite-avhengigheter
build(config): legg til strengere TypeScript-innstillinger
refactor(src): flytt hero-innhold til egen komponent
refactor(src): flytt sorteringslogikken til utils
chore(assets): fjern ubrukte Vite-ikoner
```

**Parprogrammering**
Hvis dere jobber to sammen, legg til i commit-meldingen:
**Kobling til issue**
Skriv issuenummeret i meldingen, slik at GitHub viser commiten i issuen:

```
docs(docs): samle testdokumentasjonen i docs/testing.md
Refs #17
```

**Medforfattere og KI**
Medforfattere skrives til slutt i meldingen, etter en tom linje, med én linje per person. De må stå på egne linjer for at GitHub skal gjenkjenne dem:

```
Co-authored-by: Ola Nordmann <ola@example.com>
Co-authored-by: Kari Nordmann <kari@example.com>
```

Har et KI-verktøy skrevet en vesentlig del av endringen, legges verktøyet til på samme måte, og bruken beskrives i README under «Bruk av KI».

---

## Pull requests

- Tittelen følger commit-standarden.
- Beskrivelsen forteller hva som er endret, hvorfor og hvordan det er testet, og avsluttes med `Closes #<issuenummer>`. Da kobles pull requesten til issuen, og issuen lukkes ved merge.
- Et annet gruppemedlem må godkjenne pull requesten før merge (se `.github/CODEOWNERS`).
- Pull requesten merges til `main` først når Definition of Done under er oppfylt.

---

## Definition of Done (DoD)
Expand All @@ -101,6 +135,7 @@ En issue regnes som ferdig når:
- `npm run build` kjører uten feil
- `npm run lint` kjører uten feil
- `npm run format:check` kjører uten feil, eller `npm run format` er kjørt
- `npm run test` kjører uten feil
- Endringen er testet manuelt i appen ved behov
- Dokumentasjon er oppdatert ved behov
- PR er koblet til riktig issue
- PR er koblet til riktig issue og godkjent av et annet gruppemedlem
62 changes: 62 additions & 0 deletions docs/publisering.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Publisering på gruppas VM

Appen er publisert på [http://it2810-36.idi.ntnu.no/project1/](http://it2810-36.idi.ntnu.no/project1/). Maskinen `it2810-36.idi.ntnu.no` kjører Apache og kan bare nås fra NTNUs nett eller via VPN.

## Slik fungerer publiseringen

- `npm run build` lager en statisk app i `dist/`: `index.html`, `favicon.svg` og mappen `assets/` med JavaScript og CSS. Filnavnene i `assets/` inneholder en hash som endres når innholdet endres.
- Apache serverer filene i `/var/www/html/project1/` på adressen `/project1/`.
- `base: '/project1/'` i `vite.config.ts` gjør at `index.html` lenker til `/project1/assets/…`. Uten dette ville nettleseren lete etter filene i roten av serveren, og siden ville bli tom.
- Appen har én side og ingen ruting i nettleseren, så Apache trenger ingen egen konfigurasjon, for eksempel omskriving av adresser.
- Nettleseren henter landdata direkte fra countries.dev. VM-en trenger derfor ingen serverkode, database eller API-nøkkel.

## Legge ut en ny versjon

1. Koble til NTNUs nett eller VPN.
2. Bygg fra oppdatert `main`, lokalt eller på VM-en (krever Node.js 24.6+ og npm 11+ der bygget kjøres):

```bash
git switch main
git pull
npm ci
npm run lint && npm run format:check && npm run test && npm run build
```

3. Kopier _innholdet_ i `dist/` til `/var/www/html/project1/` på VM-en. Eksempel med `rsync` fra egen maskin, der `<brukernavn>` er brukeren dere logger inn på VM-en med:

```bash
rsync -av --delete dist/ <brukernavn>@it2810-36.idi.ntnu.no:/var/www/html/project1/
```

Skråstreken etter `dist/` gjør at innholdet kopieres, ikke selve mappen. `--delete` fjerner gamle filer i `assets/` som ikke lenger brukes.

Mangler brukeren skrivetilgang til `/var/www/html/project1/`, kan filene kopieres til hjemmemappen først og flyttes med `sudo` på VM-en:

```bash
rsync -av --delete dist/ <brukernavn>@it2810-36.idi.ntnu.no:~/project1-dist/
ssh <brukernavn>@it2810-36.idi.ntnu.no
sudo rsync -av --delete ~/project1-dist/ /var/www/html/project1/
```

4. Kontroller den publiserte appen, se under.

## Kontrollere at riktig versjon er publisert

- Åpne appen og sjekk at fanen heter «Utforsk verden», at landkortet vises, og at kildehenvisningen står nederst.
- Sammenlign filnavnet til JavaScript-filen på VM-en med det lokale bygget. Er navnene like, er det samme bygg:

```bash
curl -s http://it2810-36.idi.ntnu.no/project1/ | grep -o 'assets/index-[^"]*\.js'
grep -o 'assets/index-[^"]*\.js' dist/index.html
```

- Last siden på nytt uten nettleserens cache (Cmd+Shift+R eller Ctrl+Shift+R) hvis en eldre versjon vises.

## Feilsøking

| Symptom | Mulig årsak og løsning |
| -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Siden svarer ikke | Du er ikke på NTNUs nett eller VPN, eller Apache kjører ikke på VM-en. |
| Tom side og 404 for `.js`/`.css` i konsollen | Filene ligger i feil mappe, eller `base` i `vite.config.ts` er endret. `index.html` skal ligge rett i `/var/www/html/project1/`. |
| En eldre versjon vises | Nettleseren har lagret den gamle `index.html`. Last siden på nytt uten cache. |
| «Fikk ikke kontakt med API-et» | countries.dev svarer ikke eller er blokkert på nettet du bruker. Appen viser ingen data uten API-et. |
Loading