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
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
dist
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 80
}
10 changes: 7 additions & 3 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ visuell make-over av søkesiden, en ny favoritt-funksjon lagret i
**Hvor:** `src/index.css`, `src/App.css`, `index.html`

**Hva:**

- Byttet fargepalett fra generisk lilla til et Pokéball-inspirert tema:
rødt (`--accent`) og gult (`--gold`) som aksentfarger, definert som
CSS-variabler i `:root` (både lys og mørk modus er oppdatert).
Expand All @@ -29,7 +30,7 @@ farger og form som minner om selve merkevaren.

**Hvor:** `src/App.tsx`

**Hva:** Fjernet `<section className="list">`-blokken som viste *alle*
**Hva:** Fjernet `<section className="list">`-blokken som viste _alle_
Pokémon i en ustylet `<ul>` (rød tekst, sirkel-bullets), samt
`allPokemon`-state og `useEffect`-kallet som hentet hele listen
(`listAllPokemon()`) ved oppstart.
Expand All @@ -44,6 +45,7 @@ gjennom alle»-visning).
## 3. Favoritter (ny funksjon, lagret i `localStorage`)

**Hvor:**

- `src/useFavorites.ts` (ny fil) – egen hook som eier all lagringslogikk.
- `src/FavoritesSidebar.tsx` (ny fil) – komponenten som viser favorittene.
- `src/App.tsx` – bruker hooken, viser en ★-knapp på hvert søkeresultat,
Expand All @@ -52,6 +54,7 @@ gjennom alle»-visning).
mobiltilpasning.

**Hva:**

- Brukeren kan trykke på en ★-knapp på et hvilket som helst søkeresultat
for å legge det til eller fjerne det fra favorittene sine.
- Favorittene lagres i `localStorage` under nøkkelen `pokedex-favorites`
Expand All @@ -65,7 +68,7 @@ gjennom alle»-visning).
(`@media max-width: 900px`) gjør den om til en fast bunn-bar med
horisontal scroll, slik at favorittene fortsatt er lett tilgjengelige
uten å ta opp all skjermplassen på en liten skjerm. Det er altså
*ingen* egen mobil-komponent – responsiviteten løses kun med CSS.
_ingen_ egen mobil-komponent – responsiviteten løses kun med CSS.
- Hver favoritt kan fjernes direkte fra sidebaren med en ×-knapp.

**Hvorfor `localStorage`:** Favoritter er noe brukeren typisk vil ha
Expand All @@ -86,12 +89,13 @@ Vi har **ikke** implementert dette – bare et forslag til neste steg:
`sessionStorage` (f.eks. under nøkkelen `pokedex-last-search`).

**Hvorfor dette passer godt til `sessionStorage` og ikke `localStorage`:**

- `sessionStorage` overlever en side-oppdatering (F5), men blir tømt når
fanen lukkes. Det er akkurat riktig levetid for et søk: nyttig å
beholde om brukeren ved et uhell laster siden på nytt midt i en
søkeøkt, men det gir ikke mening at et gammelt søk skal ligge og vente
neste gang brukeren åpner siden i en ny fane uker senere (i motsetning
til favoritter, som *skal* vare).
til favoritter, som _skal_ vare).
- Det er en pedagogisk fin kontrast til favoritt-funksjonen: samme
mønster (les/skriv til Web Storage), men bevisst forskjellig levetid
fordi dataene har forskjellig «naturlig» levetid.
Expand Down
25 changes: 15 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,38 @@
# Pokedex

## Koble til VM (hosting)
Hvordan koble til VM:

``` ssh <brukernavn>@it2810-18.idi.ntnu.no ```

Hvordan koble til VM:

`ssh <brukernavn>@it2810-18.idi.ntnu.no`

## Nettside:
<a href="http://it2810-18.idi.ntnu.no/project1/index.html" target="_blank">http://it2810-18.idi.ntnu.no/project1/index.html</a>

Filene ligger i vm under ```/var/www/html/project1```

<a href="http://it2810-18.idi.ntnu.no/project1/index.html" target="_blank">http://it2810-18.idi.ntnu.no/project1/index.html</a>

Filene ligger i vm under `/var/www/html/project1`

## Har du gjort endringer du vil ha på nettsiden live?

```npm run build``` inni prosjekt mappen, deretter flytt filene som er inni ```dist``` mappen til ```/var/www/html/project1```

Da vil de vises på nettsiden.
`npm run build` inni prosjekt mappen, deretter flytt filene som er inni `dist` mappen til `/var/www/html/project1`

Da vil de vises på nettsiden.

## Script for å deploye endringer til nettside hosting (OBS OBS, dette er ikke til git, men bare fra VM directory til nettside hosting directory) prosjekt -> /var/www/html/

```
#!/bin/bash
cd ~/T18-Project-1
git pull
npm install
npm run build
sudo rsync -av --delete dist/ /var/www/html/project1/
echo "Deploy ferdig!"
echo "Deploy ferdig!"
```


## Prettier use
```
npm install
npm run format
```
84 changes: 42 additions & 42 deletions VEIEN-VIDERE.md

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import { defineConfig, globalIgnores } from 'eslint/config'
import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import tseslint from 'typescript-eslint';
import { defineConfig, globalIgnores } from 'eslint/config';

export default defineConfig([
globalIgnores(['dist']),
Expand All @@ -19,4 +19,4 @@ export default defineConfig([
globals: globals.browser,
},
},
])
]);
32 changes: 32 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
"preview": "vite preview",
"format": "prettier --write .",
"format:check": "prettier --check ."
},
"dependencies": {
"pokenode-ts": "^2.3.1",
Expand All @@ -25,9 +27,11 @@
"@vitejs/plugin-react": "^6.1.0",
"babel-plugin-react-compiler": "^1.0.0",
"eslint": "^10.9.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.4",
"globals": "^17.11.0",
"prettier": "^3.9.7",
"typescript": "~6.0.2",
"typescript-eslint": "^8.67.0",
"vite": "^8.2.2"
Expand Down
79 changes: 38 additions & 41 deletions src/Api.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,42 @@


export type Pokemon = {
id: number
name: string
imageUrl: string
apiUrl: string
}
id: number;
name: string;
imageUrl: string;
apiUrl: string;
};

// Slik ser svaret fra liste-endepunktet ut (bare feltene vi bruker).
type PokemonListResponse = {
results: Array<{ name: string; url: string }>
}
results: Array<{ name: string; url: string }>;
};

// limit=100000 gir oss hele lista i ett kall. PokéAPI har ikke noe
// eget søke-endepunkt, så vi henter alle navnene én gang og filtrerer selv.
const LIST_ENDPOINT = 'https://pokeapi.co/api/v2/pokemon?limit=10000'
const LIST_ENDPOINT = 'https://pokeapi.co/api/v2/pokemon?limit=10000';

// Vi mellomlagrer lista i minnet så vi ikke henter den på nytt for hvert søk.
let cachedList: Array<{ name: string; url: string }> | null = null
let cachedList: Array<{ name: string; url: string }> | null = null;

async function fetchPokemonList() {
if (cachedList) {
return cachedList
}
if (cachedList) {
return cachedList;
}

const response = await fetch(LIST_ENDPOINT)
const response = await fetch(LIST_ENDPOINT);

if (!response.ok) {
throw new Error(`PokéAPI svarte med ${response.status}`)
}
if (!response.ok) {
throw new Error(`PokéAPI svarte med ${response.status}`);
}

const data = (await response.json()) as PokemonListResponse
cachedList = data.results
console.log(cachedList)
return cachedList
const data = (await response.json()) as PokemonListResponse;
cachedList = data.results;
console.log(cachedList);
return cachedList;
}

// i Api.tsx
export async function listAllPokemon(): Promise<Pokemon[]> {
const list = await fetchPokemonList()
const list = await fetchPokemonList();
return list
.map((entry) => ({ entry, id: idFromUrl(entry.url) }))
.filter(({ id }) => id > 0)
Expand All @@ -47,34 +45,33 @@ export async function listAllPokemon(): Promise<Pokemon[]> {
name: entry.name,
imageUrl: `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/${id}.png`,
apiUrl: `https://pokeapi.co/api/v2/pokemon/${id}`,
}))
}));
}


export function pokemonApiUrl(id: number) {
return `https://pokeapi.co/api/v2/pokemon/${id}`
return `https://pokeapi.co/api/v2/pokemon/${id}`;
}

// Hvert listeelement har en url som ".../pokemon/25/". Vi plukker ut tallet
// (id-en) fordi vi trenger den for å bygge bilde-URL-en.
function idFromUrl(url: string): number {
const match = url.match(/\/pokemon\/(\d+)\//)
return match ? Number(match[1]) : 0
const match = url.match(/\/pokemon\/(\d+)\//);
return match ? Number(match[1]) : 0;
}

export async function searchPokemon(query: string): Promise<Pokemon[]> {
const list = await fetchPokemonList()
const normalized = query.trim().toLowerCase()
const list = await fetchPokemonList();
const normalized = query.trim().toLowerCase();

return list
.filter((entry) => entry.name.includes(normalized))
.map((entry) => ({ entry, id: idFromUrl(entry.url) }))
.filter(({ id }) => id > 0)
.slice(0, 24)
.map(({ entry, id }) => ({
id,
name: entry.name,
imageUrl: `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/${id}.png`,
apiUrl: `https://pokeapi.co/api/v2/pokemon/${id}`,
}))
return list
.filter((entry) => entry.name.includes(normalized))
.map((entry) => ({ entry, id: idFromUrl(entry.url) }))
.filter(({ id }) => id > 0)
.slice(0, 24)
.map(({ entry, id }) => ({
id,
name: entry.name,
imageUrl: `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/${id}.png`,
apiUrl: `https://pokeapi.co/api/v2/pokemon/${id}`,
}));
}
17 changes: 13 additions & 4 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
font: inherit;
color: var(--text-h);
background: var(--bg);
transition: border-color 0.15s ease, box-shadow 0.15s ease;
transition:
border-color 0.15s ease,
box-shadow 0.15s ease;
}

.search-form input:focus-visible {
Expand All @@ -62,7 +64,9 @@
font: inherit;
font-weight: 700;
cursor: pointer;
transition: transform 0.1s ease, background 0.15s ease;
transition:
transform 0.1s ease,
background 0.15s ease;
}

.search-form button:hover:not(:disabled) {
Expand Down Expand Up @@ -95,7 +99,10 @@
border: 2px solid var(--border);
border-radius: var(--radius);
background: var(--bg-soft);
transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
transition:
border-color 0.15s ease,
transform 0.15s ease,
box-shadow 0.15s ease;
}

.song:hover {
Expand Down Expand Up @@ -143,7 +150,9 @@
line-height: 1;
color: var(--border);
cursor: pointer;
transition: transform 0.15s ease, color 0.15s ease;
transition:
transform 0.15s ease,
color 0.15s ease;
}

.favorite-toggle:hover {
Expand Down
Loading