From 2fcc2eb9842209efae34468fd6b48479de12586b Mon Sep 17 00:00:00 2001 From: Karen Skauge Date: Thu, 10 Sep 2026 17:48:18 +0200 Subject: [PATCH 01/12] refactor: move Character type and set up detail card --- src/components/CharacterDetailCard.css | 0 src/components/CharacterDetailCard.tsx | 0 src/pages/CharactersPage.tsx | 10 +--------- src/types/Character.ts | 13 +++++++++++++ 4 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 src/components/CharacterDetailCard.css create mode 100644 src/components/CharacterDetailCard.tsx create mode 100644 src/types/Character.ts diff --git a/src/components/CharacterDetailCard.css b/src/components/CharacterDetailCard.css new file mode 100644 index 0000000..e69de29 diff --git a/src/components/CharacterDetailCard.tsx b/src/components/CharacterDetailCard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/CharactersPage.tsx b/src/pages/CharactersPage.tsx index b654f7d..363fc0b 100644 --- a/src/pages/CharactersPage.tsx +++ b/src/pages/CharactersPage.tsx @@ -4,15 +4,7 @@ import { useEffect, useState } from "react"; import CharacterCardSmall from "../components/CharacterCardSmall"; import SearchIcon from "../assets/search.svg" -type Character = { - id: number; - name: string; - species: string; - status: string; - gender: string; - origin: string; - image: string; -}; +import type { Character } from "../types/Character"; const filters = [ {title: 'Gender', options: ['Female', 'Male', 'Unknown'] }, diff --git a/src/types/Character.ts b/src/types/Character.ts new file mode 100644 index 0000000..39eb0ea --- /dev/null +++ b/src/types/Character.ts @@ -0,0 +1,13 @@ +export type Character = { + id: number; + name: string; + species: string; + status: string; + gender: string; + origin: { + name: string; + url: string; + } + image: string; + episode: string[]; +} \ No newline at end of file From 255d7d6225bf8f0fc9b2371a910306396d6a39ba Mon Sep 17 00:00:00 2001 From: Karen Skauge Date: Thu, 10 Sep 2026 17:58:05 +0200 Subject: [PATCH 02/12] feat: create character detail card component --- src/components/CharacterDetailCard.tsx | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/components/CharacterDetailCard.tsx b/src/components/CharacterDetailCard.tsx index e69de29..0bccfbb 100644 --- a/src/components/CharacterDetailCard.tsx +++ b/src/components/CharacterDetailCard.tsx @@ -0,0 +1,31 @@ +import "./CharacterDetailCard.css"; +import type { Character } from "../types/Character"; + +type CharacterDetailCardProps = { + character: Character; + onClose: () => void; +} + +export default function CharacterDetailCard({ character, onClose }: CharacterDetailCardProps) { + return ( +
+ + +
+

{character.name}

+

Gender: {character.gender}

+

Species: {character.species}

+

Origin: {character.origin.name}

+

Status: {character.status}

+
+ + {character.name} +
+ ) +} \ No newline at end of file From 2fbfd70ff9349614ff3ae8ec0c6ee96cafa15052 Mon Sep 17 00:00:00 2001 From: Karen Skauge Date: Thu, 10 Sep 2026 18:14:57 +0200 Subject: [PATCH 03/12] feat: connect character detail card --- src/components/CharacterCardSmall.tsx | 5 +++-- src/pages/CharactersPage.tsx | 9 +++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/CharacterCardSmall.tsx b/src/components/CharacterCardSmall.tsx index 756030a..39c7a36 100644 --- a/src/components/CharacterCardSmall.tsx +++ b/src/components/CharacterCardSmall.tsx @@ -5,9 +5,10 @@ import StarShape from '../assets/star.svg' type CharacterCardSmallProps = { name: string; image: string; + onDetails: () => void; }; -export default function CharacterCardSmall({name, image}: CharacterCardSmallProps){ +export default function CharacterCardSmall({name, image, onDetails}: CharacterCardSmallProps){ return(
@@ -15,7 +16,7 @@ export default function CharacterCardSmall({name, image}: CharacterCardSmallProp character image

{name}

- + diff --git a/src/pages/CharactersPage.tsx b/src/pages/CharactersPage.tsx index 363fc0b..16476ba 100644 --- a/src/pages/CharactersPage.tsx +++ b/src/pages/CharactersPage.tsx @@ -2,6 +2,7 @@ import './CharactersPage.css' import { useEffect, useState } from "react"; import CharacterCardSmall from "../components/CharacterCardSmall"; +import CharacterDetailCard from "../components/CharacterDetailCard"; import SearchIcon from "../assets/search.svg" import type { Character } from "../types/Character"; @@ -15,6 +16,7 @@ const filters = [ export default function CharactersPage(){ const [characters, setCharacters] = useState([]); + const [selectedCharacter, setSelectedCharacter] = useState(null); useEffect(() => { async function fetchCharacters(){ @@ -50,6 +52,7 @@ export default function CharactersPage(){ key={character.id} name={character.name} image={character.image} + onDetails={() => setSelectedCharacter(character)} /> ))} @@ -68,6 +71,12 @@ export default function CharactersPage(){ ))}
+ {selectedCharacter && ( + setSelectedCharacter(null)} + /> + )} ) } \ No newline at end of file From 387c74978e7c5df21d82b03f2c2f1aff6538804f Mon Sep 17 00:00:00 2001 From: Karen Skauge Date: Fri, 11 Sep 2026 12:29:23 +0200 Subject: [PATCH 04/12] feat: style character detail card --- src/assets/detail-card-shape.svg | 23 ++++++++ src/components/CharacterDetailCard.css | 74 ++++++++++++++++++++++++++ src/components/CharacterDetailCard.tsx | 39 ++++++++------ 3 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 src/assets/detail-card-shape.svg diff --git a/src/assets/detail-card-shape.svg b/src/assets/detail-card-shape.svg new file mode 100644 index 0000000..30d3da3 --- /dev/null +++ b/src/assets/detail-card-shape.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/CharacterDetailCard.css b/src/components/CharacterDetailCard.css index e69de29..2bed62c 100644 --- a/src/components/CharacterDetailCard.css +++ b/src/components/CharacterDetailCard.css @@ -0,0 +1,74 @@ +.detail-overlay { + position: fixed; + inset: 0; + z-index: 10; + + display: flex; + align-items: center; + justify-content: center; + + background-color: rgb(0 0 0 / 75%); +} + +.detail-card { + position: relative; + display: flex; + gap: 2rem; + + width: 60rem; + max-width: 90%; + padding: 3rem; + + color: white; + background-color: #5A7D0D; + border-radius: 1.5rem; +} + +.detail-info { + flex: 1; +} + +.detail-info h2 { + margin-top: 0; + color: white; + font-size: 3rem; + font-weight: bold; + text-transform: uppercase; +} + +.detail-image-frame { + position: relative; + display: flex; + align-items: center; + justify-content: center; + + width: 45%; +} + +.detail-card-shape { + position: absolute; + width: 100%; + height: 100%; +} + +.detail-character-image { + position: relative; + z-index: 1; + + width: 90%; + height: 90%; + object-fit: cover; + border-radius: 1rem; +} + +.close-button { + position: absolute; + top: 1rem; + right: 1rem; + + border: none; + background: transparent; + color: white; + font-size: 1.5rem; + cursor: pointer; +} \ No newline at end of file diff --git a/src/components/CharacterDetailCard.tsx b/src/components/CharacterDetailCard.tsx index 0bccfbb..5b418d8 100644 --- a/src/components/CharacterDetailCard.tsx +++ b/src/components/CharacterDetailCard.tsx @@ -1,5 +1,6 @@ import "./CharacterDetailCard.css"; import type { Character } from "../types/Character"; +import DetailCardShape from '../assets/detail-card-shape.svg' type CharacterDetailCardProps = { character: Character; @@ -8,24 +9,28 @@ type CharacterDetailCardProps = { export default function CharacterDetailCard({ character, onClose }: CharacterDetailCardProps) { return ( -
- +
+
+ -
-

{character.name}

-

Gender: {character.gender}

-

Species: {character.species}

-

Origin: {character.origin.name}

-

Status: {character.status}

-
+
+

{character.name}

+

Gender: {character.gender}

+

Species: {character.species}

+

Origin: {character.origin.name}

+

Status: {character.status}

+
- {character.name} -
+
+ + + {character.name} +
+
+ ) } \ No newline at end of file From 3ca79bb9c2b2034c1d173eb3c9b31d8c259a3ee7 Mon Sep 17 00:00:00 2001 From: Karen Skauge Date: Fri, 11 Sep 2026 12:39:21 +0200 Subject: [PATCH 05/12] feat: fetch and display character episodes --- src/components/CharacterDetailCard.css | 28 +++++++++++++-- src/components/CharacterDetailCard.tsx | 48 ++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/src/components/CharacterDetailCard.css b/src/components/CharacterDetailCard.css index 2bed62c..92a8e01 100644 --- a/src/components/CharacterDetailCard.css +++ b/src/components/CharacterDetailCard.css @@ -46,9 +46,9 @@ } .detail-card-shape { - position: absolute; - width: 100%; - height: 100%; + position: absolute; + width: 100%; + height: 100%; } .detail-character-image { @@ -71,4 +71,26 @@ color: white; font-size: 1.5rem; cursor: pointer; +} + +.detail-episodes { + margin-top: 2rem; +} + +.detail-episodes h3 { + margin-bottom: 0.5rem; + font-size: 2rem; + text-transform: uppercase; +} + +.detail-episodes ul { + max-height: 10rem; + margin: 0; + padding-left: 1.0rem; + overflow-y: auto; + list-style: none; +} + +.detail-episodes li { + margin-bottom: 0.4rem; } \ No newline at end of file diff --git a/src/components/CharacterDetailCard.tsx b/src/components/CharacterDetailCard.tsx index 5b418d8..3f9ad3a 100644 --- a/src/components/CharacterDetailCard.tsx +++ b/src/components/CharacterDetailCard.tsx @@ -1,4 +1,6 @@ import "./CharacterDetailCard.css"; +import { useEffect, useState } from "react"; + import type { Character } from "../types/Character"; import DetailCardShape from '../assets/detail-card-shape.svg' @@ -7,7 +9,41 @@ type CharacterDetailCardProps = { onClose: () => void; } +type Episode = { + id: number; + name: string; + episode: string; +} + export default function CharacterDetailCard({ character, onClose }: CharacterDetailCardProps) { + + const [episodes, setEpisodes] = useState([]); + + useEffect(() => { + async function fetchEpisodes() { + try { + const episodeData = await Promise.all( + character.episode.map(async (episodeUrl) => { + const response = await fetch(episodeUrl); + + if (!response.ok) { + throw new Error(`Could not fetch episode: ${response.status}`) + } + + return response.json(); + }) + ); + + setEpisodes(episodeData); + } + catch (error) { + console.error(error); + } + } + + fetchEpisodes(); + }, [character]) + return (
@@ -19,6 +55,18 @@ export default function CharacterDetailCard({ character, onClose }: CharacterDet

Species: {character.species}

Origin: {character.origin.name}

Status: {character.status}

+ +
+

Episodes

+ +
    + {episodes.map((episode) => ( +
  • + {episode.episode} - {episode.name} +
  • + ))} +
+
From c8ddca6dccf2d9cb4efccbac5246bd3f7b9546bc Mon Sep 17 00:00:00 2001 From: Karen Skauge Date: Fri, 11 Sep 2026 12:47:11 +0200 Subject: [PATCH 06/12] feat: refine character detail card layout --- src/components/CharacterDetailCard.css | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/CharacterDetailCard.css b/src/components/CharacterDetailCard.css index 92a8e01..20e3cb2 100644 --- a/src/components/CharacterDetailCard.css +++ b/src/components/CharacterDetailCard.css @@ -24,8 +24,12 @@ border-radius: 1.5rem; } -.detail-info { - flex: 1; +.detail-info p { + font-weight: 400; +} + +.detail-info strong { + font-weight: 800; } .detail-info h2 { @@ -43,6 +47,8 @@ justify-content: center; width: 45%; + margin-left: auto; + transform: translateX(0.5rem); } .detail-card-shape { From cca01244c28a7c979bb8164f12c2fccb0a82f9c7 Mon Sep 17 00:00:00 2001 From: Karen Skauge Date: Fri, 11 Sep 2026 13:09:10 +0200 Subject: [PATCH 07/12] feat: add character navigation --- src/assets/X.svg | 3 +++ src/assets/arrow-left.svg | 3 +++ src/assets/arrow-right.svg | 3 +++ src/components/CharacterDetailCard.css | 34 ++++++++++++++++++++++++-- src/components/CharacterDetailCard.tsx | 29 ++++++++++++++++++++-- src/pages/CharactersPage.tsx | 28 +++++++++++++++++++++ 6 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 src/assets/X.svg create mode 100644 src/assets/arrow-left.svg create mode 100644 src/assets/arrow-right.svg diff --git a/src/assets/X.svg b/src/assets/X.svg new file mode 100644 index 0000000..b246dcf --- /dev/null +++ b/src/assets/X.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/arrow-left.svg b/src/assets/arrow-left.svg new file mode 100644 index 0000000..0b5ced9 --- /dev/null +++ b/src/assets/arrow-left.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/arrow-right.svg b/src/assets/arrow-right.svg new file mode 100644 index 0000000..0b847d0 --- /dev/null +++ b/src/assets/arrow-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/CharacterDetailCard.css b/src/components/CharacterDetailCard.css index 20e3cb2..cc3f8d4 100644 --- a/src/components/CharacterDetailCard.css +++ b/src/components/CharacterDetailCard.css @@ -72,13 +72,18 @@ top: 1rem; right: 1rem; + padding: 0; border: none; background: transparent; - color: white; - font-size: 1.5rem; cursor: pointer; } +.close-button img { + display: block; + width: 1.5rem; + height: 1.5rem; +} + .detail-episodes { margin-top: 2rem; } @@ -99,4 +104,29 @@ .detail-episodes li { margin-bottom: 0.4rem; +} + +.previous-button, +.next-button { + position: absolute; + top: 50%; + z-index: 11; + + border: none; + background: transparent; + cursor: pointer; + transform: translateY(-50%); +} + +.previous-button { + left: 2rem; +} + +.next-button { + right: 2rem; +} + +.navigation-arrow { + width: 3rem; + height: 3rem; } \ No newline at end of file diff --git a/src/components/CharacterDetailCard.tsx b/src/components/CharacterDetailCard.tsx index 3f9ad3a..69e4303 100644 --- a/src/components/CharacterDetailCard.tsx +++ b/src/components/CharacterDetailCard.tsx @@ -3,10 +3,15 @@ import { useEffect, useState } from "react"; import type { Character } from "../types/Character"; import DetailCardShape from '../assets/detail-card-shape.svg' +import ArrowLeft from '../assets/arrow-left.svg' +import ArrowRight from '../assets/arrow-right.svg' +import X from '../assets/X.svg' type CharacterDetailCardProps = { character: Character; onClose: () => void; + onPrevious: () => void; + onNext: () => void; } type Episode = { @@ -15,7 +20,7 @@ type Episode = { episode: string; } -export default function CharacterDetailCard({ character, onClose }: CharacterDetailCardProps) { +export default function CharacterDetailCard({ character, onClose, onPrevious, onNext }: CharacterDetailCardProps) { const [episodes, setEpisodes] = useState([]); @@ -46,8 +51,19 @@ export default function CharacterDetailCard({ character, onClose }: CharacterDet return (
+ +
- +

{character.name}

@@ -79,6 +95,15 @@ export default function CharacterDetailCard({ character, onClose }: CharacterDet />
+ +
) } \ No newline at end of file diff --git a/src/pages/CharactersPage.tsx b/src/pages/CharactersPage.tsx index 16476ba..1204ce6 100644 --- a/src/pages/CharactersPage.tsx +++ b/src/pages/CharactersPage.tsx @@ -37,6 +37,32 @@ export default function CharactersPage(){ fetchCharacters() }, []) + function showPreviousCharacter(){ + if (!selectedCharacter) return; + + const currentIndex = characters.findIndex( + (character) => character.id === selectedCharacter.id + ); + + const previousIndex = + currentIndex === 0 ? characters.length - 1 : currentIndex - 1; + + setSelectedCharacter(characters[previousIndex]); + } + + function showNextCharacter(){ + if (!selectedCharacter) return; + + const currentIndex = characters.findIndex( + (character) => character.id === selectedCharacter.id + ); + + const nextIndex = + currentIndex === characters.length - 1 ? 0 : currentIndex + 1; + + setSelectedCharacter(characters[nextIndex]); + } + return(
@@ -75,6 +101,8 @@ export default function CharactersPage(){ setSelectedCharacter(null)} + onPrevious={showPreviousCharacter} + onNext={showNextCharacter} /> )}
From b0e18d705a19e09ccda6ae5f6ccdc0ef0913a0bb Mon Sep 17 00:00:00 2001 From: Karen Skauge Date: Fri, 11 Sep 2026 13:28:06 +0200 Subject: [PATCH 08/12] feat: make character detail card responsive --- src/components/CharacterDetailCard.css | 80 ++++++++++++++++++++++++++ src/components/CharacterDetailCard.tsx | 12 ++-- 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/src/components/CharacterDetailCard.css b/src/components/CharacterDetailCard.css index cc3f8d4..8755768 100644 --- a/src/components/CharacterDetailCard.css +++ b/src/components/CharacterDetailCard.css @@ -32,6 +32,17 @@ font-weight: 800; } +.character-facts { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.75rem 2rem; +} + +.character-facts p { + margin: 0; + padding: 0; +} + .detail-info h2 { margin-top: 0; color: white; @@ -129,4 +140,73 @@ .navigation-arrow { width: 3rem; height: 3rem; +} + +@media (max-width: 600px) { + .detail-overlay { + padding: 1rem; + box-sizing: border-box; + } + + .detail-card { + flex-direction: column; + + width: 100%; + max-width: 100%; + max-height: 90vh; + padding: 3rem 1.5rem 1.5rem; + box-sizing: border-box; + + overflow-y: auto; + } + + .detail-card-shape { + transform: scaleY(1.03); + transform-origin: center; + } + + .detail-info h2 { + font-size: 2rem; + overflow-wrap: anywhere; + } + + .detail-info p { + font-size: 1rem; + overflow-wrap: anywhere; + } + + .detail-character-image { + width: 100%; + height: 100%; + } + + .detail-image-frame { + width: 100%; + margin: 0; + padding: 2.0rem; + box-sizing: border-box; + transform: none; + aspect-ratio: 1 / 1; + } + + .detail-episodes h3 { + font-size: 1.5rem; + } + + .detail-episodes li { + font-size: 1rem; + } + + .previous-button { + left: 0.25rem; + } + + .next-button { + right: 0.25rem; + } + + .navigation-arrow { + width: 1.5rem; + height: 1.5rem; + } } \ No newline at end of file diff --git a/src/components/CharacterDetailCard.tsx b/src/components/CharacterDetailCard.tsx index 69e4303..6fe3aac 100644 --- a/src/components/CharacterDetailCard.tsx +++ b/src/components/CharacterDetailCard.tsx @@ -61,16 +61,18 @@ export default function CharacterDetailCard({ character, onClose, onPrevious, on
-

{character.name}

-

Gender: {character.gender}

-

Species: {character.species}

-

Origin: {character.origin.name}

-

Status: {character.status}

+
+

Gender: {character.gender}

+

Origin: {character.origin.name}

+

Species: {character.species}

+

Status: {character.status}

+

Episodes

From 4c32e5d0fc9afbb81fc2fdbc0c22476a32589ac2 Mon Sep 17 00:00:00 2001 From: Karen Skauge Date: Fri, 11 Sep 2026 13:48:01 +0200 Subject: [PATCH 09/12] feat: refine character detail card responsiveness --- src/components/CharacterDetailCard.css | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/components/CharacterDetailCard.css b/src/components/CharacterDetailCard.css index 8755768..c5284d9 100644 --- a/src/components/CharacterDetailCard.css +++ b/src/components/CharacterDetailCard.css @@ -60,6 +60,9 @@ width: 45%; margin-left: auto; transform: translateX(0.5rem); + + aspect-ratio: 1 / 0.93; + align-self: center; } .detail-card-shape { @@ -181,8 +184,8 @@ } .detail-image-frame { - width: 100%; - margin: 0; + width: 85%; + margin: 0 auto; padding: 2.0rem; box-sizing: border-box; transform: none; @@ -197,16 +200,20 @@ font-size: 1rem; } + .previous-button, .next-button { + padding: 0; + } + .previous-button { - left: 0.25rem; + left: 1.2rem; } .next-button { - right: 0.25rem; + right: 1.2rem; } .navigation-arrow { - width: 1.5rem; - height: 1.5rem; + width: 2.25rem; + height: 2.25rem; } } \ No newline at end of file From f862096b5348ff5497b118d88c8979311f6a8fa4 Mon Sep 17 00:00:00 2001 From: Karen Skauge Date: Fri, 11 Sep 2026 13:53:25 +0200 Subject: [PATCH 10/12] chore: add AI notice and polish styling --- src/components/CharacterDetailCard.css | 4 ++-- src/components/CharacterDetailCard.tsx | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/CharacterDetailCard.css b/src/components/CharacterDetailCard.css index c5284d9..7698d0b 100644 --- a/src/components/CharacterDetailCard.css +++ b/src/components/CharacterDetailCard.css @@ -111,7 +111,7 @@ .detail-episodes ul { max-height: 10rem; margin: 0; - padding-left: 1.0rem; + padding-left: 1rem; overflow-y: auto; list-style: none; } @@ -186,7 +186,7 @@ .detail-image-frame { width: 85%; margin: 0 auto; - padding: 2.0rem; + padding: 2rem; box-sizing: border-box; transform: none; aspect-ratio: 1 / 1; diff --git a/src/components/CharacterDetailCard.tsx b/src/components/CharacterDetailCard.tsx index 6fe3aac..3d1cfc3 100644 --- a/src/components/CharacterDetailCard.tsx +++ b/src/components/CharacterDetailCard.tsx @@ -24,7 +24,7 @@ export default function CharacterDetailCard({ character, onClose, onPrevious, on const [episodes, setEpisodes] = useState([]); - useEffect(() => { + useEffect(() => { /* AI was used to create this piece of code */ async function fetchEpisodes() { try { const episodeData = await Promise.all( @@ -38,14 +38,12 @@ export default function CharacterDetailCard({ character, onClose, onPrevious, on return response.json(); }) ); - setEpisodes(episodeData); } catch (error) { console.error(error); } } - fetchEpisodes(); }, [character]) From ae86a707ec1481a60667bfac59945ce15a879633 Mon Sep 17 00:00:00 2001 From: Karen Skauge Date: Fri, 11 Sep 2026 13:57:40 +0200 Subject: [PATCH 11/12] chore: update AI-assisted code marking --- src/components/CharacterDetailCard.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/CharacterDetailCard.tsx b/src/components/CharacterDetailCard.tsx index 3d1cfc3..0628211 100644 --- a/src/components/CharacterDetailCard.tsx +++ b/src/components/CharacterDetailCard.tsx @@ -24,17 +24,16 @@ export default function CharacterDetailCard({ character, onClose, onPrevious, on const [episodes, setEpisodes] = useState([]); - useEffect(() => { /* AI was used to create this piece of code */ + // AI was used to create this piece of code (the useEffect function). + useEffect(() => { async function fetchEpisodes() { try { const episodeData = await Promise.all( character.episode.map(async (episodeUrl) => { const response = await fetch(episodeUrl); - if (!response.ok) { throw new Error(`Could not fetch episode: ${response.status}`) } - return response.json(); }) ); From 6a2b42d43f3735ce6a5a045086a62557aa42961f Mon Sep 17 00:00:00 2001 From: Karen Skauge Date: Fri, 11 Sep 2026 19:44:44 +0200 Subject: [PATCH 12/12] feat: add favorite button to character detail card --- src/components/CharacterDetailCard.css | 25 +++++++++++++++++- src/components/CharacterDetailCard.tsx | 35 ++++++++++---------------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/components/CharacterDetailCard.css b/src/components/CharacterDetailCard.css index 7698d0b..2d0fd84 100644 --- a/src/components/CharacterDetailCard.css +++ b/src/components/CharacterDetailCard.css @@ -145,6 +145,28 @@ height: 3rem; } +.detail-heading { + display: flex; + align-items: center; + gap: 1rem; + margin-bottom: 1.5rem; +} + +.detail-favorite-button { + flex-shrink: 0; + padding: 0; + border: none; + background: transparent; + cursor: pointer; +} + +.detail-star { + display: block; + width: 2.5rem; + height: 2.5rem; + filter: brightness(0) invert(1); +} + @media (max-width: 600px) { .detail-overlay { padding: 1rem; @@ -200,7 +222,8 @@ font-size: 1rem; } - .previous-button, .next-button { + .previous-button, + .next-button { padding: 0; } diff --git a/src/components/CharacterDetailCard.tsx b/src/components/CharacterDetailCard.tsx index 0628211..6fe547c 100644 --- a/src/components/CharacterDetailCard.tsx +++ b/src/components/CharacterDetailCard.tsx @@ -1,11 +1,12 @@ import "./CharacterDetailCard.css"; -import { useEffect, useState } from "react"; +import { useEffect, useState } from "react" import type { Character } from "../types/Character"; import DetailCardShape from '../assets/detail-card-shape.svg' import ArrowLeft from '../assets/arrow-left.svg' import ArrowRight from '../assets/arrow-right.svg' import X from '../assets/X.svg' +import Star from '../assets/star.svg' type CharacterDetailCardProps = { character: Character; @@ -24,7 +25,7 @@ export default function CharacterDetailCard({ character, onClose, onPrevious, on const [episodes, setEpisodes] = useState([]); - // AI was used to create this piece of code (the useEffect function). + // AI was used to create this useEffect function. useEffect(() => { async function fetchEpisodes() { try { @@ -48,12 +49,7 @@ export default function CharacterDetailCard({ character, onClose, onPrevious, on return (
- @@ -63,7 +59,13 @@ export default function CharacterDetailCard({ character, onClose, onPrevious, on
-

{character.name}

+
+

{character.name}

+ +
+

Gender: {character.gender}

Origin: {character.origin.name}

@@ -73,7 +75,6 @@ export default function CharacterDetailCard({ character, onClose, onPrevious, on

Episodes

-
    {episodes.map((episode) => (
  • @@ -86,21 +87,11 @@ export default function CharacterDetailCard({ character, onClose, onPrevious, on
    - - {character.name} + {character.name}
-