From 5534b28df216a598a500e1979decc6e9ba1246c9 Mon Sep 17 00:00:00 2001 From: Helene Lotsberg Date: Wed, 21 Oct 2026 22:50:17 +0200 Subject: [PATCH 1/8] add button to add plant from ExplorePlants page to MyMatches page --- .../src/pages/explorePlants/ExplorePlants.css | 30 ++++++++++++ .../src/pages/explorePlants/ExplorePlants.tsx | 49 ++++++++++++++----- 2 files changed, 66 insertions(+), 13 deletions(-) diff --git a/frontend/src/pages/explorePlants/ExplorePlants.css b/frontend/src/pages/explorePlants/ExplorePlants.css index 6d06402..2a682c1 100644 --- a/frontend/src/pages/explorePlants/ExplorePlants.css +++ b/frontend/src/pages/explorePlants/ExplorePlants.css @@ -118,6 +118,7 @@ width: calc(390px * var(--card-scale)); height: calc(620px * var(--card-scale)); justify-self: center; + position: relative; } .explore-plant-item .plant-card-flipper { @@ -227,6 +228,35 @@ font-weight: 700; } +.add-match-button { + position: absolute; + top: -15px; + right: -15px; + z-index: 2; + width: 36px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + border: none; + border-radius: 50%; + background-color: var(--dark-pink); + color: var(--text-light); + font-size: 18px; + line-height: 1; + cursor: pointer; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); +} + +.add-match-button:not(:disabled):hover { + transform: scale(1.1); +} + +.add-match-button:disabled { + opacity: 0.5; + cursor: default; +} + @media (max-width: 767px) { .explore-page { margin-left: 0; diff --git a/frontend/src/pages/explorePlants/ExplorePlants.tsx b/frontend/src/pages/explorePlants/ExplorePlants.tsx index dbcd700..4226dee 100644 --- a/frontend/src/pages/explorePlants/ExplorePlants.tsx +++ b/frontend/src/pages/explorePlants/ExplorePlants.tsx @@ -9,6 +9,7 @@ import { type ExplorePlantsData, } from "./explorePlantsQuery.ts"; import PlantCard from "../../components/plantCard/PlantCard.tsx"; +import { useMatchedPlants } from "../../hooks/useMatchedPlants.ts"; import "./ExplorePlants.css"; const PAGE_SIZE = 12; @@ -18,6 +19,9 @@ const SORT_OPTIONS = ["name_asc", "name_desc", "watering_asc", "careLevel_asc"]; export default function ExplorePlants() { const { t } = useTranslation(); + // Same hook as PlantMatch, so both pages share the same matches + const { matches, addMatch } = useMatchedPlants(); + const [search, setSearch] = useSessionState("ExplorePlants.search"); const debouncedSearch = useDebounce(search, 800); const [watering, setWatering] = useSessionState("ExplorePlants.watering"); @@ -202,19 +206,38 @@ export default function ExplorePlants() { )} {totalCount > 0 && ( From 465cbd13bb4697476dcd46daf099bd47c406d03d Mon Sep 17 00:00:00 2001 From: Helene Lotsberg Date: Wed, 21 Oct 2026 22:52:48 +0200 Subject: [PATCH 2/8] add translation for aria-label for add-match-button --- frontend/src/i18n/locales/en/translation.json | 4 +++- frontend/src/i18n/locales/no/translation.json | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/i18n/locales/en/translation.json b/frontend/src/i18n/locales/en/translation.json index 53b0d75..cd780f2 100644 --- a/frontend/src/i18n/locales/en/translation.json +++ b/frontend/src/i18n/locales/en/translation.json @@ -67,7 +67,9 @@ "pagination": "Page navigation", "pageOf": "Page {{page}} of {{totalPages}}", "previous": "Previous", - "next": "Next" + "next": "Next", + "addMatch": "Add to my matches", + "alreadyMatched": "Already in my matches" }, "myMatchesPage": { "noMatches": "You have no matches yet. Press the flower on the match page to match with a plant.", diff --git a/frontend/src/i18n/locales/no/translation.json b/frontend/src/i18n/locales/no/translation.json index 371dbb8..b618f25 100644 --- a/frontend/src/i18n/locales/no/translation.json +++ b/frontend/src/i18n/locales/no/translation.json @@ -67,7 +67,9 @@ "pagination": "Sidenavigasjon", "pageOf": "Side {{page}} av {{totalPages}}", "previous": "Forrige", - "next": "Neste" + "next": "Neste", + "addMatch": "Legg til i mine matcher", + "alreadyMatched": "Allerede i mine matcher" }, "myMatchesPage": { "noMatches": "Du har ingen matcher ennå. Trykk på blomsten på match-siden for å matche med en plante.", From d69846b5a73c6060f9d515045f97f721665a081c Mon Sep 17 00:00:00 2001 From: Helene Lotsberg Date: Thu, 22 Oct 2026 14:00:13 +0200 Subject: [PATCH 3/8] adjust same sized plant cards for explorePlants and myMatches --- frontend/src/components/plantCard/PlantCard.css | 6 +++--- frontend/src/pages/myMatches/MyMatchesPage.css | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/plantCard/PlantCard.css b/frontend/src/components/plantCard/PlantCard.css index 87a310e..853bb95 100644 --- a/frontend/src/components/plantCard/PlantCard.css +++ b/frontend/src/components/plantCard/PlantCard.css @@ -87,7 +87,7 @@ height: var(--card-name-height); margin: 0; - padding: 16px 28px; + padding: 5px 40px; display: flex; align-items: center; @@ -95,7 +95,7 @@ color: var(--dark-green); - font-size: 1.65rem; + font-size: 1.5rem; font-weight: 700; line-height: 1.1; text-align: center; @@ -255,7 +255,7 @@ height: auto; min-height: 62px; - padding: 0 10px; + padding: 0 24px; color: var(--light-green); diff --git a/frontend/src/pages/myMatches/MyMatchesPage.css b/frontend/src/pages/myMatches/MyMatchesPage.css index 3cce7ad..db5e25e 100644 --- a/frontend/src/pages/myMatches/MyMatchesPage.css +++ b/frontend/src/pages/myMatches/MyMatchesPage.css @@ -11,11 +11,12 @@ gap: 30px; font-family: Georgia, serif; + --card-scale: 0.8; } .matches-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 340px)); + grid-template-columns: repeat(auto-fill, calc(390px * var(--card-scale))); justify-content: center; gap: 32px; @@ -28,7 +29,8 @@ position: relative; /* PlantCard fills its parent, so the wrapper needs a fixed height. Same height as the card on the match page. */ - height: 620px; + width: calc(390px * var(--card-scale)); + height: calc(620px * var(--card-scale)); border-radius: 32px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1); @@ -43,10 +45,17 @@ box-shadow: 0 12px 28px rgba(0, 0, 0, 0.14); } +.plant-card-match .plant-card-flipper { + width: 390px; + height: 620px; + transform: scale(var(--card-scale)); + transform-origin: top left; +} + .remove-match-button { position: absolute; - top: 10px; - right: 10px; + top: -15px; + right: -15px; z-index: 2; width: 36px; height: 36px; From aa2cb1743e872fa93e8db9703b1ee1b3914effa1 Mon Sep 17 00:00:00 2001 From: Helene Lotsberg Date: Thu, 22 Oct 2026 14:08:44 +0200 Subject: [PATCH 4/8] adjust same placement and size of buttons on plantcard across pages --- frontend/src/pages/explorePlants/ExplorePlants.css | 4 ++-- frontend/src/pages/myMatches/MyMatchesPage.css | 4 ++-- frontend/src/pages/plantMatch/PlantMatchPage.css | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/pages/explorePlants/ExplorePlants.css b/frontend/src/pages/explorePlants/ExplorePlants.css index 2a682c1..101a070 100644 --- a/frontend/src/pages/explorePlants/ExplorePlants.css +++ b/frontend/src/pages/explorePlants/ExplorePlants.css @@ -233,8 +233,8 @@ top: -15px; right: -15px; z-index: 2; - width: 36px; - height: 36px; + width: 50px; + height: 50px; display: flex; align-items: center; justify-content: center; diff --git a/frontend/src/pages/myMatches/MyMatchesPage.css b/frontend/src/pages/myMatches/MyMatchesPage.css index db5e25e..682f974 100644 --- a/frontend/src/pages/myMatches/MyMatchesPage.css +++ b/frontend/src/pages/myMatches/MyMatchesPage.css @@ -57,8 +57,8 @@ top: -15px; right: -15px; z-index: 2; - width: 36px; - height: 36px; + width: 50px; + height: 50px; border: none; border-radius: 50%; background: var(--dark-pink); diff --git a/frontend/src/pages/plantMatch/PlantMatchPage.css b/frontend/src/pages/plantMatch/PlantMatchPage.css index 5621bac..07bb32d 100644 --- a/frontend/src/pages/plantMatch/PlantMatchPage.css +++ b/frontend/src/pages/plantMatch/PlantMatchPage.css @@ -35,8 +35,8 @@ } .match-info-button { - width: 47px; - height: 47px; + width: 50px; + height: 50px; display: flex; align-items: center; justify-content: center; From 57f60ab3e81b8bad180b4cb5d9950ebf247a948b Mon Sep 17 00:00:00 2001 From: Helene Lotsberg Date: Thu, 22 Oct 2026 14:51:15 +0200 Subject: [PATCH 5/8] adjust styling for mobile use --- .../src/pages/explorePlants/ExplorePlants.css | 11 ++++ .../src/pages/myMatches/MyMatchesPage.css | 54 +++++++++++++------ .../src/pages/myMatches/MyMatchesPage.tsx | 4 +- .../src/pages/plantMatch/PlantMatchPage.css | 9 +--- 4 files changed, 54 insertions(+), 24 deletions(-) diff --git a/frontend/src/pages/explorePlants/ExplorePlants.css b/frontend/src/pages/explorePlants/ExplorePlants.css index 101a070..3ad377f 100644 --- a/frontend/src/pages/explorePlants/ExplorePlants.css +++ b/frontend/src/pages/explorePlants/ExplorePlants.css @@ -102,6 +102,12 @@ background-color: var(--light-pink); } +.explore-results p { + font-size: 20px; + text-align: center; + font-family: Georgia, serif; +} + .plant-grid { list-style: none; margin: 0; @@ -285,4 +291,9 @@ height: 100%; transform: none; } + + .add-match-button { + width: 35px; + height: 35px; + } } diff --git a/frontend/src/pages/myMatches/MyMatchesPage.css b/frontend/src/pages/myMatches/MyMatchesPage.css index 682f974..d61f930 100644 --- a/frontend/src/pages/myMatches/MyMatchesPage.css +++ b/frontend/src/pages/myMatches/MyMatchesPage.css @@ -16,17 +16,31 @@ .matches-grid { display: grid; - grid-template-columns: repeat(auto-fill, calc(390px * var(--card-scale))); - justify-content: center; - gap: 32px; + grid-template-columns: repeat( + auto-fill, + minmax(calc(390px * var(--card-scale)), 1fr) + ); + gap: 30px 20px; width: 100%; - max-width: 1200px; - padding-bottom: 40px; + box-sizing: border-box; + padding: 40px; + border-radius: 16px; + background-color: var(--light-pink); +} + +.matches-grid > p { + grid-column: 1 / -1; + margin: 0; + text-align: center; + font-size: 20px; + text-align: center; + font-family: Georgia, serif; } .plant-card-match { position: relative; + justify-self: center; /* PlantCard fills its parent, so the wrapper needs a fixed height. Same height as the card on the match page. */ width: calc(390px * var(--card-scale)); @@ -41,7 +55,6 @@ } .plant-card-match:hover { - transform: translateY(-4px); box-shadow: 0 12px 28px rgba(0, 0, 0, 0.14); } @@ -67,6 +80,10 @@ cursor: pointer; } +.remove-match-button:hover { + transform: scale(1.1); +} + @media (prefers-reduced-motion: reduce) { .plant-card-match { transition: none; @@ -85,21 +102,28 @@ gap: 20px; } - .my-matches-page h2 { - font-size: 28px; - text-align: center; - white-space: nowrap; - font-family: Georgia, serif; - } - .matches-grid { - grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 280px)); + grid-template-columns: 1fr; gap: 20px; + padding: 20px 12px; + border-radius: 12px; } .plant-card-match { - /* Same height as the card on the mobile match page. */ + /* Same size as the cards on the mobile explore page. */ + width: min(280px, 62vw); height: 502px; border-radius: 24px; } + + .plant-card-match .plant-card-flipper { + width: 100%; + height: 100%; + transform: none; + } + + .remove-match-button { + width: 35px; + height: 35px; + } } diff --git a/frontend/src/pages/myMatches/MyMatchesPage.tsx b/frontend/src/pages/myMatches/MyMatchesPage.tsx index 1b38ad8..e826003 100644 --- a/frontend/src/pages/myMatches/MyMatchesPage.tsx +++ b/frontend/src/pages/myMatches/MyMatchesPage.tsx @@ -10,9 +10,9 @@ function MyMatchesPage() { return (
- {matches.length === 0 &&

{t("myMatchesPage.noMatches")}

} -
+ {matches.length === 0 &&

{t("myMatchesPage.noMatches")}

} + {matches.map((plant) => (
Date: Thu, 22 Oct 2026 15:08:16 +0200 Subject: [PATCH 6/8] add popup message when hovering over add-match-button on explorePlants --- frontend/src/i18n/locales/en/translation.json | 4 +-- frontend/src/i18n/locales/no/translation.json | 4 +-- .../src/pages/explorePlants/ExplorePlants.css | 32 ++++++++++++++++++- .../src/pages/explorePlants/ExplorePlants.tsx | 30 +++++++++-------- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/frontend/src/i18n/locales/en/translation.json b/frontend/src/i18n/locales/en/translation.json index cd780f2..3e779f7 100644 --- a/frontend/src/i18n/locales/en/translation.json +++ b/frontend/src/i18n/locales/en/translation.json @@ -68,8 +68,8 @@ "pageOf": "Page {{page}} of {{totalPages}}", "previous": "Previous", "next": "Next", - "addMatch": "Add to my matches", - "alreadyMatched": "Already in my matches" + "addMatch": "Add to My Matches", + "alreadyMatched": "Already in My Matches" }, "myMatchesPage": { "noMatches": "You have no matches yet. Press the flower on the match page to match with a plant.", diff --git a/frontend/src/i18n/locales/no/translation.json b/frontend/src/i18n/locales/no/translation.json index b618f25..77c5176 100644 --- a/frontend/src/i18n/locales/no/translation.json +++ b/frontend/src/i18n/locales/no/translation.json @@ -68,8 +68,8 @@ "pageOf": "Side {{page}} av {{totalPages}}", "previous": "Forrige", "next": "Neste", - "addMatch": "Legg til i mine matcher", - "alreadyMatched": "Allerede i mine matcher" + "addMatch": "Legg til i Mine Matches", + "alreadyMatched": "Allerede i Mine Matches" }, "myMatchesPage": { "noMatches": "Du har ingen matcher ennå. Trykk på blomsten på match-siden for å matche med en plante.", diff --git a/frontend/src/pages/explorePlants/ExplorePlants.css b/frontend/src/pages/explorePlants/ExplorePlants.css index 3ad377f..8484c63 100644 --- a/frontend/src/pages/explorePlants/ExplorePlants.css +++ b/frontend/src/pages/explorePlants/ExplorePlants.css @@ -234,11 +234,40 @@ font-weight: 700; } -.add-match-button { +.add-match { position: absolute; top: -15px; right: -15px; z-index: 2; +} + +.add-match-tooltip { + position: absolute; + top: calc(100% + 8px); + right: 0; + z-index: 20; + padding: 8px 12px; + background: var(--light-background); + color: var(--pink-text); + border-radius: 10px; + box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12); + font-size: 14px; + white-space: nowrap; + opacity: 0; + visibility: hidden; + pointer-events: none; + transition: + opacity 0.15s ease, + visibility 0.15s ease; +} + +.add-match:hover .add-match-tooltip, +.add-match:focus-within .add-match-tooltip { + opacity: 1; + visibility: visible; +} + +.add-match-button { width: 50px; height: 50px; display: flex; @@ -261,6 +290,7 @@ .add-match-button:disabled { opacity: 0.5; cursor: default; + pointer-events: none; } @media (max-width: 767px) { diff --git a/frontend/src/pages/explorePlants/ExplorePlants.tsx b/frontend/src/pages/explorePlants/ExplorePlants.tsx index 4226dee..83bca2b 100644 --- a/frontend/src/pages/explorePlants/ExplorePlants.tsx +++ b/frontend/src/pages/explorePlants/ExplorePlants.tsx @@ -209,6 +209,9 @@ export default function ExplorePlants() { {plants.map((plant) => { // Disable the button if the plant is already in MyMatches const isMatched = matches.some((match) => match.id === plant.id); + const addLabel = isMatched + ? t("ExplorePlants.alreadyMatched") + : t("ExplorePlants.addMatch"); return (
  • @@ -222,19 +225,20 @@ export default function ExplorePlants() { careLevel={plant.careLevel} /> {/* Sibling of the card (not inside it), so no nested buttons */} - + + + +
  • ); })} From 6e883f3d407ffa25b3bf0960c11fb38a8fc5f586 Mon Sep 17 00:00:00 2001 From: Helene Lotsberg Date: Thu, 22 Oct 2026 15:39:13 +0200 Subject: [PATCH 7/8] add search icon and fixed styling for explorePlants --- .../src/pages/explorePlants/ExplorePlants.css | 64 ++++++++++++------- .../src/pages/explorePlants/ExplorePlants.tsx | 2 + 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/frontend/src/pages/explorePlants/ExplorePlants.css b/frontend/src/pages/explorePlants/ExplorePlants.css index 8484c63..9e52808 100644 --- a/frontend/src/pages/explorePlants/ExplorePlants.css +++ b/frontend/src/pages/explorePlants/ExplorePlants.css @@ -28,19 +28,36 @@ width: 100%; } +.explore-search { + position: relative; + display: block; +} + +.explore-search-icon { + position: absolute; + top: 50%; + left: 1rem; + font-size: 1.25rem; + transform: translateY(-50%); + color: var(--dark-pink); + pointer-events: none; +} + .explore-search input { width: 100%; - padding: 0.75rem 1rem; - font-size: 1rem; - border: 1px solid var(--border-soft); + padding: 0.75rem 1rem 0.75rem 2.75rem; + font-size: 1.25rem; + color: var(--text-dark); + background-color: var(--light-pink); + border: 1px solid var(--dark-pink); border-radius: 8px; box-sizing: border-box; } .explore-search input:focus { outline: none; - border-color: var(--dark-green); - box-shadow: 0 0 0 2px var(--dark-green); + border-color: var(--dark-pink); + box-shadow: 0 0 0 2px var(--dark-pink); } .explore-filters { @@ -56,42 +73,43 @@ display: flex; flex-direction: column; gap: 0.25rem; + font-size: 1rem; } .filter select { padding: 0.5rem; - border: 1px solid var(--border-soft); + border: 1px solid var(--dark-pink); border-radius: 8px; min-width: 160px; } .filter select:focus { outline: none; - border-color: var(--dark-green); - box-shadow: 0 0 0 2px var(--dark-green); + border-color: var(--dark-pink); + box-shadow: 0 0 0 2px var(--dark-pink); } .reset-button { align-self: flex-start; width: 74px; height: 38px; - border: 1px solid var(--border-soft); + border: 1px solid var(--dark-pink); border-radius: 8px; - background-color: var(--light-green); + background-color: var(--light-background); color: var(--text-dark); - font-size: 16px; + font-size: 15px; cursor: pointer; } .reset-button:hover { - background-color: var(--dark-green); + background-color: var(--dark-pink); color: var(--text-light); } .reset-button:focus-within { outline: none; - border: var(--dark-green); - box-shadow: 0 0 0 2px var(--dark-green); + border: var(--dark-pink); + box-shadow: 0 0 0 2px var(--dark-pink); } .explore-results { @@ -145,7 +163,7 @@ .pagination button { padding: 0.5rem 1rem; - border: 1px solid var(--border-soft); + border: 1px solid var(--dark-green); border-radius: 8px; background-color: var(--light-green); color: var(--text-dark); @@ -179,23 +197,23 @@ justify-content: center; width: 40px; height: 40px; - border: 1px solid var(--border-soft); + border: 1px solid var(--dark-pink); border-radius: 8px; - background-color: var(--light-green); + background-color: var(--light-background); color: var(--text-dark); - font-size: 1.4rem; + font-size: 1.5rem; cursor: pointer; } .sort-button:hover { - background-color: var(--dark-green); + background-color: var(--dark-pink); color: var(--text-light); } .sort-button:focus-visible, .sort-option:focus-visible { outline: none; - box-shadow: 0 0 0 2px var(--dark-green); + box-shadow: 0 0 0 2px var(--dark-pink); } .sort-options { @@ -208,7 +226,7 @@ padding: 0.25rem; list-style: none; background-color: var(--light-background); - border: 1px solid var(--border-soft); + border: 1px solid var(--dark-pink); border-radius: 8px; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12); } @@ -226,11 +244,11 @@ } .sort-option:hover { - background-color: var(--light-green); + background-color: var(--light-pink); } .sort-option--active { - background-color: var(--light-green); + background-color: var(--light-pink); font-weight: 700; } diff --git a/frontend/src/pages/explorePlants/ExplorePlants.tsx b/frontend/src/pages/explorePlants/ExplorePlants.tsx index 83bca2b..6a03e44 100644 --- a/frontend/src/pages/explorePlants/ExplorePlants.tsx +++ b/frontend/src/pages/explorePlants/ExplorePlants.tsx @@ -1,5 +1,6 @@ import { useEffect, useRef, useState } from "react"; import { BiSortAlt2 } from "react-icons/bi"; +import { FaSearch } from "react-icons/fa"; import { useTranslation } from "react-i18next"; import { useQuery } from "@apollo/client/react"; import { useDebounce } from "../../hooks/useDebounce"; @@ -81,6 +82,7 @@ export default function ExplorePlants() { >