From d92b7ea3574984bf1d1fa29525de7b0df1cb6fa3 Mon Sep 17 00:00:00 2001 From: OfekSagiv Date: Wed, 25 Dec 2024 00:03:45 +0200 Subject: [PATCH 1/8] Implemented all components for the main page, including country cards --- eslint.config.js | 5 +++++ index.html | 9 ++++++--- src/App.jsx | 11 +++++++--- src/assets/CountriesData.json | 29 ++++++++++++++++++++++++++ src/assets/css/main.css | 3 +++ src/components/Country.jsx | 24 ++++++++++++++++------ src/components/Header.jsx | 17 ++++++++++++++++ src/components/Logo.jsx | 13 ++++++++++++ src/components/RegionFilter.jsx | 24 ++++++++++++++++++++++ src/components/SearchBox.jsx | 16 +++++++++++++++ src/components/ThemeToggle.jsx | 12 +++++++++++ src/index.css | 17 +++++++++------- src/pages/Home.jsx | 36 +++++++++++++++++++++++++++------ 13 files changed, 191 insertions(+), 25 deletions(-) create mode 100644 src/components/Header.jsx create mode 100644 src/components/Logo.jsx create mode 100644 src/components/RegionFilter.jsx create mode 100644 src/components/SearchBox.jsx create mode 100644 src/components/ThemeToggle.jsx diff --git a/eslint.config.js b/eslint.config.js index 238d2e4..9602812 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -33,6 +33,11 @@ export default [ 'warn', { allowConstantExport: true }, ], + "no-undef": "off", + "no-unused-vars": [ + "warn", + { "varsIgnorePattern": "^_" } // מתעלם ממשתנים שמתחילים ב-_. + ], }, }, ] diff --git a/index.html b/index.html index 0c589ec..815e93c 100644 --- a/index.html +++ b/index.html @@ -2,12 +2,15 @@ - - Vite + React + + Countries React
- + diff --git a/src/App.jsx b/src/App.jsx index 2a88e41..d6bf86b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -3,12 +3,17 @@ import "../src/assets/css/details.css"; import "../src/assets/css/main.css"; import "../src/assets/scss/common.scss"; import Home from "./pages/Home"; +import Header from "./components/Header.jsx"; function App() { return ( - <> - - + +
+ + +
+ + ); } diff --git a/src/assets/CountriesData.json b/src/assets/CountriesData.json index 3db67ea..456916c 100644 --- a/src/assets/CountriesData.json +++ b/src/assets/CountriesData.json @@ -1,5 +1,6 @@ [ { + "id": 1, "name": "Åland Islands", "flag": "https://flagcdn.com/w320/ax.png", "population": 21225, @@ -7,6 +8,7 @@ "capital": "Mariehamn" }, { + "id": 2, "name": "Afghanistan", "flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Flag_of_the_Taliban.svg/320px-Flag_of_the_Taliban.svg.png", "population": 27657145, @@ -14,6 +16,7 @@ "capital": "Kabul" }, { + "id": 3, "name": "Albania", "flag": "https://flagcdn.com/w320/al.png", "population": 2886026, @@ -21,6 +24,7 @@ "capital": "Tirana" }, { + "id": 4, "name": "Algeria", "flag": "https://flagcdn.com/w320/dz.png", "population": 40400000, @@ -28,6 +32,7 @@ "capital": "Algiers" }, { + "id": 5, "name": "American Samoa", "flag": "https://flagcdn.com/w320/as.png", "population": 57100, @@ -35,6 +40,7 @@ "capital": "Pago Pago" }, { + "id": 6, "name": "Andorra", "flag": "https://flagcdn.com/w320/ad.png", "population": 78014, @@ -42,6 +48,7 @@ "capital": "Andorra la Vella" }, { + "id": 7, "name": "Angola", "flag": "https://flagcdn.com/w320/ao.png", "population": 25868000, @@ -49,6 +56,7 @@ "capital": "Luanda" }, { + "id": 8, "name": "Anguilla", "flag": "https://flagcdn.com/w320/ai.png", "population": 13452, @@ -56,6 +64,7 @@ "capital": "The Valley" }, { + "id": 9, "name": "Antarctica", "flag": "https://flagcdn.com/w320/aq.png", "population": 1000, @@ -63,6 +72,7 @@ "capital": "" }, { + "id": 10, "name": "Israel", "flag": "https://flagcdn.com/w320/il.png", "population": 8527400, @@ -70,6 +80,7 @@ "capital": "Jerusalem" }, { + "id": 11, "name": "Italy", "flag": "https://flagcdn.com/w320/it.png", "population": 60665551, @@ -77,6 +88,7 @@ "capital": "Rome" }, { + "id": 12, "name": "Jamaica", "flag": "https://flagcdn.com/w320/jm.png", "population": 2723246, @@ -84,6 +96,7 @@ "capital": "Kingston" }, { + "id": 13, "name": "Japan", "flag": "https://flagcdn.com/w320/jp.png", "population": 126960000, @@ -91,6 +104,7 @@ "capital": "Tokyo" }, { + "id": 14, "name": "Jersey", "flag": "https://flagcdn.com/w320/je.png", "population": 100800, @@ -98,6 +112,7 @@ "capital": "Saint Helier" }, { + "id": 15, "name": "Jordan", "flag": "https://flagcdn.com/w320/jo.png", "population": 9531712, @@ -105,6 +120,7 @@ "capital": "Amman" }, { + "id": 16, "name": "Kazakhstan", "flag": "https://flagcdn.com/w320/kz.png", "population": 17753200, @@ -112,6 +128,7 @@ "capital": "Astana" }, { + "id": 17, "name": "Kenya", "flag": "https://flagcdn.com/w320/ke.png", "population": 47251000, @@ -119,6 +136,7 @@ "capital": "Nairobi" }, { + "id": 18, "name": "Kiribati", "flag": "https://flagcdn.com/w320/ki.png", "population": 113400, @@ -126,6 +144,7 @@ "capital": "South Tarawa" }, { + "id": 19, "name": "Kuwait", "flag": "https://flagcdn.com/w320/kw.png", "population": 4183658, @@ -133,6 +152,7 @@ "capital": "Kuwait City" }, { + "id": 20, "name": "Kyrgyzstan", "flag": "https://flagcdn.com/w320/kg.png", "population": 6047800, @@ -140,6 +160,7 @@ "capital": "Bishkek" }, { + "id": 21, "name": "Laos", "flag": "https://flagcdn.com/w320/la.png", "population": 6492400, @@ -147,6 +168,7 @@ "capital": "Vientiane" }, { + "id": 22, "name": "Latvia", "flag": "https://flagcdn.com/w320/lv.png", "population": 1961600, @@ -154,6 +176,7 @@ "capital": "Riga" }, { + "id": 23, "name": "Lebanon", "flag": "https://flagcdn.com/w320/lb.png", "population": 5988000, @@ -161,6 +184,7 @@ "capital": "Beirut" }, { + "id": 24, "name": "Lesotho", "flag": "https://flagcdn.com/w320/ls.png", "population": 1894194, @@ -168,6 +192,7 @@ "capital": "Maseru" }, { + "id": 25, "name": "Liberia", "flag": "https://flagcdn.com/w320/lr.png", "population": 4615000, @@ -175,6 +200,7 @@ "capital": "Monrovia" }, { + "id": 26, "name": "Libya", "flag": "https://flagcdn.com/w320/ly.png", "population": 6385000, @@ -182,6 +208,7 @@ "capital": "Tripoli" }, { + "id": 27, "name": "Liechtenstein", "flag": "https://flagcdn.com/w320/li.png", "population": 37623, @@ -189,6 +216,7 @@ "capital": "Vaduz" }, { + "id": 28, "name": "Lithuania", "flag": "https://flagcdn.com/w320/lt.png", "population": 2872294, @@ -196,6 +224,7 @@ "capital": "Vilnius" }, { + "id": 29, "name": "Luxembourg", "flag": "https://flagcdn.com/w320/lu.png", "population": 576200, diff --git a/src/assets/css/main.css b/src/assets/css/main.css index f51ac8b..d609cf0 100644 --- a/src/assets/css/main.css +++ b/src/assets/css/main.css @@ -147,6 +147,9 @@ .countries-grid { display: grid; gap: 50px; + padding: 0 5% 5%; + + } .countries-grid.no-grid { diff --git a/src/components/Country.jsx b/src/components/Country.jsx index 177580c..b88f71e 100644 --- a/src/components/Country.jsx +++ b/src/components/Country.jsx @@ -1,10 +1,22 @@ -import React from 'react' +import 'react' -const Country = () => { - return ( - // TODO: Country component -
Country
- ) +// eslint-disable-next-line react/prop-types +const Country = ({country}) => { + return ( + +
+ {country.name}/ +
+
+

{country.name}

+
    +
  • Population: {country.population}
  • +
  • Region: {country.region}
  • +
  • Capital: {country.capital}
  • +
+
+
+ ) } export default Country \ No newline at end of file diff --git a/src/components/Header.jsx b/src/components/Header.jsx new file mode 100644 index 0000000..4b224c3 --- /dev/null +++ b/src/components/Header.jsx @@ -0,0 +1,17 @@ +import 'react' +import Logo from "./Logo.jsx"; +import ThemeToggle from "./ThemeToggle.jsx"; + +const Header = () => { + return ( + +
+
+ + +
+
+ ) +} + +export default Header diff --git a/src/components/Logo.jsx b/src/components/Logo.jsx new file mode 100644 index 0000000..717c234 --- /dev/null +++ b/src/components/Logo.jsx @@ -0,0 +1,13 @@ +import 'react' + +const Logo = () => { + return ( + + +

Where in the world?

+
+ +) +} + +export default Logo \ No newline at end of file diff --git a/src/components/RegionFilter.jsx b/src/components/RegionFilter.jsx new file mode 100644 index 0000000..bb1fb66 --- /dev/null +++ b/src/components/RegionFilter.jsx @@ -0,0 +1,24 @@ +import 'react'; + +const RegionFilter = () => { + return ( +
+
+ Filter by Region + +
+
+
    +
  • All
  • +
  • Africa
  • +
  • America
  • +
  • Asia
  • +
  • Europe
  • +
  • Oceania
  • +
+
+
+ ); +}; + +export default RegionFilter; \ No newline at end of file diff --git a/src/components/SearchBox.jsx b/src/components/SearchBox.jsx new file mode 100644 index 0000000..88860b4 --- /dev/null +++ b/src/components/SearchBox.jsx @@ -0,0 +1,16 @@ +import 'react'; + +const SearchBox = () => { + return ( +
+ + +
+ ); +}; + +export default SearchBox; \ No newline at end of file diff --git a/src/components/ThemeToggle.jsx b/src/components/ThemeToggle.jsx new file mode 100644 index 0000000..5bb35d1 --- /dev/null +++ b/src/components/ThemeToggle.jsx @@ -0,0 +1,12 @@ +import React from 'react'; + +const ThemeToggle = () => { + return ( + + ); +}; + +export default ThemeToggle; \ No newline at end of file diff --git a/src/index.css b/src/index.css index 6119ad9..d887e0e 100644 --- a/src/index.css +++ b/src/index.css @@ -1,16 +1,15 @@ -:root { - font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; +#root{ line-height: 1.5; font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - font-synthesis: none; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + width: 100%; +} + +:root{ + } a { @@ -28,6 +27,7 @@ body { place-items: center; min-width: 320px; min-height: 100vh; + } h1 { @@ -58,6 +58,7 @@ button:focus-visible { :root { color: #213547; background-color: #ffffff; + width: 100%; } a:hover { color: #747bff; @@ -66,3 +67,5 @@ button:focus-visible { background-color: #f9f9f9; } } + + diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index 507e0c5..9f7977c 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -1,12 +1,36 @@ -import React from "react"; +import React, {useState, useEffect} from "react"; +import Country from "../components/Country"; +import Header from "../components/Header.jsx"; +import RegionFilter from "../components/RegionFilter.jsx"; +import SearchBox from "../components/SearchBox.jsx"; const Home = () => { + const [countries, setCountries] = useState([]); + + useEffect(() => { + // לדוגמה, טוען נתונים מ-API או מקובץ + fetch("src/assets/CountriesData.json") + .then((response) => response.json()) + .then((data) => setCountries(data)) + .catch((error) => console.error("Error fetching countries:", error)); + }, []); + return ( - // TODO: Home page - // Render Country component (components/Country.jsx) for each country - // Take data from (assets/CountriesData.json) -
Home
+ <> +
+
+
+ + +
+
+
+ {countries.map((country) => ( + + ))} +
+ ); }; -export default Home; +export default Home; \ No newline at end of file From ecc352890456ed34087cb3a6cdb34bda620dd26d Mon Sep 17 00:00:00 2001 From: OfekSagiv Date: Wed, 25 Dec 2024 16:12:36 +0200 Subject: [PATCH 2/8] Add feature to display single country details without navigating to a details page --- index.html | 2 +- public/vite.svg | 1 - src/App.jsx | 8 +-- src/Home.jsx | 51 +++++++++++++ src/assets/css/common.css | 26 +++---- src/assets/css/details.css | 1 + src/assets/css/index.css | 91 ++++++++++++++++++++++++ src/assets/{ => json}/CountriesData.json | 0 src/assets/react.svg | 1 - src/components/Country.jsx | 4 +- src/index.css | 71 ------------------ src/main.jsx | 2 +- src/pages/Home.jsx | 36 ---------- 13 files changed, 162 insertions(+), 132 deletions(-) delete mode 100644 public/vite.svg create mode 100644 src/Home.jsx create mode 100644 src/assets/css/index.css rename src/assets/{ => json}/CountriesData.json (100%) delete mode 100644 src/assets/react.svg delete mode 100644 src/index.css delete mode 100644 src/pages/Home.jsx diff --git a/index.html b/index.html index 815e93c..1c94ad2 100644 --- a/index.html +++ b/index.html @@ -9,7 +9,7 @@ /> Countries React - +
diff --git a/public/vite.svg b/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index d6bf86b..acddb0b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -2,18 +2,14 @@ import "../src/assets/css/common.css"; import "../src/assets/css/details.css"; import "../src/assets/css/main.css"; import "../src/assets/scss/common.scss"; -import Home from "./pages/Home"; -import Header from "./components/Header.jsx"; +import Home from "./Home.jsx"; + function App() { return ( -
-
- - ); } diff --git a/src/Home.jsx b/src/Home.jsx new file mode 100644 index 0000000..ddb6ca5 --- /dev/null +++ b/src/Home.jsx @@ -0,0 +1,51 @@ +import {useState} from "react"; +import Country from "./components/Country.jsx"; +import Header from "./components/Header.jsx"; +import RegionFilter from "./components/RegionFilter.jsx"; +import SearchBox from "./components/SearchBox.jsx"; +import countriesData from './assets/json/CountriesData.json'; + +const Home = () => { + const [countries, setCountries] = useState(countriesData); + + + const showOneCountryDetails = (countryName) => { + setCountries(countriesData.filter((country) => country.name === countryName)); + }; + + const showAllCountries = () => { + setCountries(countriesData); + }; + + + return ( + <> +
+
+
+ {countries.length === 1 && ( + + )} + + +
+
+
+ {countries.map((country) => ( + { + showOneCountryDetails(country.name); + }}> + + + ))} +
+ + ); +}; + +export default Home; \ No newline at end of file diff --git a/src/assets/css/common.css b/src/assets/css/common.css index 7d63db5..f3528af 100644 --- a/src/assets/css/common.css +++ b/src/assets/css/common.css @@ -7,19 +7,19 @@ outline: none; } -html { - font-size: 100%; - scroll-behavior: smooth; -} - -body { - font-family: 'Nunito Sans', sans-serif; - font-weight: 600; - font-size: 14px; - background-color: #fafafa; - color: #111517; - transition: 0.2s linear; -} +/*html {*/ +/* font-size: 100%;*/ +/* scroll-behavior: smooth;*/ +/*}*/ + +/*body {*/ +/* font-family: 'arial', sans-serif;*/ +/* font-weight: 600;*/ +/* font-size: 14px;*/ +/* background-color: #fafafa;*/ +/* color: #111517;*/ +/* transition: 0.2s linear;*/ +/*}*/ a { text-decoration: none; diff --git a/src/assets/css/details.css b/src/assets/css/details.css index 6108d5b..d3f1a50 100644 --- a/src/assets/css/details.css +++ b/src/assets/css/details.css @@ -1,5 +1,6 @@ body { font-size: 16px; + } .btn:hover { diff --git a/src/assets/css/index.css b/src/assets/css/index.css new file mode 100644 index 0000000..0f9be42 --- /dev/null +++ b/src/assets/css/index.css @@ -0,0 +1,91 @@ +#root { + line-height: 1.5; + font-weight: 400; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + width: 100%; + height: 100%; +} + + +/* הגדרות ל-html ול-body */ +html, body { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + overflow-x: hidden; + scroll-behavior: smooth; + font-size: 100%; +} + + +:root { + +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} + +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; + + +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} + +button:hover { + border-color: #646cff; +} + +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + width: 100%; + } + + a:hover { + color: #747bff; + } + + button { + background-color: #f9f9f9; + } +} + + diff --git a/src/assets/CountriesData.json b/src/assets/json/CountriesData.json similarity index 100% rename from src/assets/CountriesData.json rename to src/assets/json/CountriesData.json diff --git a/src/assets/react.svg b/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/components/Country.jsx b/src/components/Country.jsx index b88f71e..5699463 100644 --- a/src/components/Country.jsx +++ b/src/components/Country.jsx @@ -3,7 +3,7 @@ import 'react' // eslint-disable-next-line react/prop-types const Country = ({country}) => { return ( - + <>
{country.name}/
@@ -15,7 +15,7 @@ const Country = ({country}) => {
  • Capital: {country.capital}
  • -
    + ) } diff --git a/src/index.css b/src/index.css deleted file mode 100644 index d887e0e..0000000 --- a/src/index.css +++ /dev/null @@ -1,71 +0,0 @@ -#root{ - line-height: 1.5; - font-weight: 400; - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - width: 100%; -} - -:root{ - -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; - -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - width: 100%; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} - - diff --git a/src/main.jsx b/src/main.jsx index b9a1a6d..aee044a 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -1,6 +1,6 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' -import './index.css' +import './assets/css/index.css' import App from './App.jsx' createRoot(document.getElementById('root')).render( diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx deleted file mode 100644 index 9f7977c..0000000 --- a/src/pages/Home.jsx +++ /dev/null @@ -1,36 +0,0 @@ -import React, {useState, useEffect} from "react"; -import Country from "../components/Country"; -import Header from "../components/Header.jsx"; -import RegionFilter from "../components/RegionFilter.jsx"; -import SearchBox from "../components/SearchBox.jsx"; - -const Home = () => { - const [countries, setCountries] = useState([]); - - useEffect(() => { - // לדוגמה, טוען נתונים מ-API או מקובץ - fetch("src/assets/CountriesData.json") - .then((response) => response.json()) - .then((data) => setCountries(data)) - .catch((error) => console.error("Error fetching countries:", error)); - }, []); - - return ( - <> -
    -
    -
    - - -
    -
    -
    - {countries.map((country) => ( - - ))} -
    - - ); -}; - -export default Home; \ No newline at end of file From a2ebb6279f18af3e51165c39ab0e890110b30052 Mon Sep 17 00:00:00 2001 From: OfekSagiv Date: Wed, 25 Dec 2024 16:38:52 +0200 Subject: [PATCH 3/8] Add feature to search countries dynamically using an input box --- src/Home.jsx | 13 +++++++++++-- src/components/SearchBox.jsx | 3 ++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Home.jsx b/src/Home.jsx index ddb6ca5..eb4a4ad 100644 --- a/src/Home.jsx +++ b/src/Home.jsx @@ -8,7 +8,6 @@ import countriesData from './assets/json/CountriesData.json'; const Home = () => { const [countries, setCountries] = useState(countriesData); - const showOneCountryDetails = (countryName) => { setCountries(countriesData.filter((country) => country.name === countryName)); }; @@ -17,6 +16,16 @@ const Home = () => { setCountries(countriesData); }; + const search = (e) => { + const query = e.target.value.toLowerCase(); + if (query === "") { + setCountries(countriesData); // מחזיר את הרשימה המלאה אם החיפוש ריק + } else { + setCountries(countriesData.filter((country) => + country.name.toLowerCase().startsWith(query) + )); + } + }; return ( <> @@ -28,7 +37,7 @@ const Home = () => { Show All Countries )} - + diff --git a/src/components/SearchBox.jsx b/src/components/SearchBox.jsx index 88860b4..5295269 100644 --- a/src/components/SearchBox.jsx +++ b/src/components/SearchBox.jsx @@ -1,6 +1,6 @@ import 'react'; -const SearchBox = () => { +const SearchBox = ({action}) => { return (
    @@ -8,6 +8,7 @@ const SearchBox = () => { type="text" className="search-input" placeholder="Search for a country..." + onInput={action} />
    ); From 9e8eb0c2e96c8e7808be6966bbb15afa224bf0ba Mon Sep 17 00:00:00 2001 From: OfekSagiv Date: Wed, 25 Dec 2024 17:48:24 +0200 Subject: [PATCH 4/8] Add theme toggle feature with localStorage persistence and button styling for returning to countries grid --- src/App.jsx | 23 ++++++++++++++++- src/Home.jsx | 8 +++--- src/assets/css/common.css | 46 ++++++++++++++++++++++++++++++++++ src/assets/css/index.css | 1 + src/components/Header.jsx | 4 +-- src/components/ThemeToggle.jsx | 15 ++++++----- 6 files changed, 84 insertions(+), 13 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index acddb0b..0bc94fc 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -3,12 +3,33 @@ import "../src/assets/css/details.css"; import "../src/assets/css/main.css"; import "../src/assets/scss/common.scss"; import Home from "./Home.jsx"; +import {useState} from "react"; function App() { + const [theme, setTheme] = useState(() => { + const savedTheme = localStorage.getItem("theme"); + + if (savedTheme) { + document.body.classList.toggle("dark-theme", savedTheme === "dark"); + return savedTheme; + } + + return "light"; + }); + + const toggleTheme = () => { + const isDark = theme === "dark"; + const newTheme = isDark ? "light" : "dark"; + setTheme(newTheme); + + document.body.classList.toggle("dark-theme", newTheme === "dark"); + localStorage.setItem("theme", newTheme); + }; + return (
    - +
    ); } diff --git a/src/Home.jsx b/src/Home.jsx index eb4a4ad..716ea79 100644 --- a/src/Home.jsx +++ b/src/Home.jsx @@ -5,7 +5,7 @@ import RegionFilter from "./components/RegionFilter.jsx"; import SearchBox from "./components/SearchBox.jsx"; import countriesData from './assets/json/CountriesData.json'; -const Home = () => { +const Home = ({ theme, toggleTheme }) => { const [countries, setCountries] = useState(countriesData); const showOneCountryDetails = (countryName) => { @@ -29,11 +29,11 @@ const Home = () => { return ( <> -
    +
    -
    +
    {countries.length === 1 && ( - )} diff --git a/src/assets/css/common.css b/src/assets/css/common.css index f3528af..653b38b 100644 --- a/src/assets/css/common.css +++ b/src/assets/css/common.css @@ -307,3 +307,49 @@ body.dark-theme .country-info li { body.dark-theme .country-info strong { color: white; } + + +.button-all-countries { + padding: 10px 20px; + font-size: 16px; + color: #333; + background-color: #fff; + border: 1px solid #ccc; + border-radius: 5px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + cursor: pointer; + transition: all 0.3s ease; +} + +.button-all-countries:hover { + border-color: #999; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); + transform: translateY(-2px); +} + +.button-all-countries:active { + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + transform: translateY(0); + background-color: #f7f7f7; +} + +/* התאמת הכפתור עבור Dark Mode */ +body.dark-theme .button-all-countries { + color: white; + background-color: #2b3945; + border: 1px solid #3c4a56; /* מסגרת כהה יותר */ + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); +} + +body.dark-theme .button-all-countries:hover { + border-color: #58687a; /* מסגרת כהה במעבר */ + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5); /* צל מודגש */ + transform: translateY(-2px); +} + +body.dark-theme .button-all-countries:active { + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); + transform: translateY(0); + background-color: #354555; /* רקע כהה יותר בעת לחיצה */ +} + diff --git a/src/assets/css/index.css b/src/assets/css/index.css index 0f9be42..3d27505 100644 --- a/src/assets/css/index.css +++ b/src/assets/css/index.css @@ -63,6 +63,7 @@ button { transition: border-color 0.25s; } + button:hover { border-color: #646cff; } diff --git a/src/components/Header.jsx b/src/components/Header.jsx index 4b224c3..da80d50 100644 --- a/src/components/Header.jsx +++ b/src/components/Header.jsx @@ -2,13 +2,13 @@ import 'react' import Logo from "./Logo.jsx"; import ThemeToggle from "./ThemeToggle.jsx"; -const Header = () => { +const Header = ({ theme, toggleTheme }) => { return (
    - +
    ) diff --git a/src/components/ThemeToggle.jsx b/src/components/ThemeToggle.jsx index 5bb35d1..66ea960 100644 --- a/src/components/ThemeToggle.jsx +++ b/src/components/ThemeToggle.jsx @@ -1,12 +1,15 @@ -import React from 'react'; +import 'react'; -const ThemeToggle = () => { +const ThemeToggle = ({theme, toggleTheme}) => { return ( - ); }; - export default ThemeToggle; \ No newline at end of file From 3fa582efdf4eb85c3d71088f77f134fca65d2d47 Mon Sep 17 00:00:00 2001 From: OfekSagiv Date: Wed, 25 Dec 2024 18:21:10 +0200 Subject: [PATCH 5/8] Implement dropdown functionality with dynamic class addition for opening and closing the menu --- src/components/RegionFilter.jsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/RegionFilter.jsx b/src/components/RegionFilter.jsx index bb1fb66..c52b975 100644 --- a/src/components/RegionFilter.jsx +++ b/src/components/RegionFilter.jsx @@ -1,9 +1,16 @@ -import 'react'; +import 'react'; +import {useState} from "react"; const RegionFilter = () => { + const [isOpen, setIsOpen] = useState(false); + + const toggleDropdown = () => { + setIsOpen(!isOpen); + } + return ( -
    -
    +
    +
    Filter by Region
    From e69f1e7c1dcc6396ddf2570d695a4687f4efc295 Mon Sep 17 00:00:00 2001 From: OfekSagiv Date: Thu, 26 Dec 2024 11:49:59 +0200 Subject: [PATCH 6/8] Add region filtering feature for countries list with data from JSON --- src/Home.jsx | 21 +++++++++++++++------ src/components/Country.jsx | 2 +- src/components/RegionFilter.jsx | 16 ++++++++-------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/Home.jsx b/src/Home.jsx index 716ea79..bb16e26 100644 --- a/src/Home.jsx +++ b/src/Home.jsx @@ -5,7 +5,7 @@ import RegionFilter from "./components/RegionFilter.jsx"; import SearchBox from "./components/SearchBox.jsx"; import countriesData from './assets/json/CountriesData.json'; -const Home = ({ theme, toggleTheme }) => { +const Home = ({theme, toggleTheme}) => { const [countries, setCountries] = useState(countriesData); const showOneCountryDetails = (countryName) => { @@ -16,10 +16,10 @@ const Home = ({ theme, toggleTheme }) => { setCountries(countriesData); }; - const search = (e) => { + const searchByInput = (e) => { const query = e.target.value.toLowerCase(); if (query === "") { - setCountries(countriesData); // מחזיר את הרשימה המלאה אם החיפוש ריק + setCountries(countriesData); } else { setCountries(countriesData.filter((country) => country.name.toLowerCase().startsWith(query) @@ -27,18 +27,27 @@ const Home = ({ theme, toggleTheme }) => { } }; + const searchByRegion = (e) => { + const region = e.target.getAttribute("data-region"); + if (region === 'All') { + showAllCountries(); + } else { + setCountries(countriesData.filter((country) => country.region === region)); + } + } + return ( <>
    -
    +
    {countries.length === 1 && ( )} - - + +
    diff --git a/src/components/Country.jsx b/src/components/Country.jsx index 5699463..532a4c6 100644 --- a/src/components/Country.jsx +++ b/src/components/Country.jsx @@ -1,6 +1,6 @@ import 'react' -// eslint-disable-next-line react/prop-types + const Country = ({country}) => { return ( <> diff --git a/src/components/RegionFilter.jsx b/src/components/RegionFilter.jsx index c52b975..a52b0a2 100644 --- a/src/components/RegionFilter.jsx +++ b/src/components/RegionFilter.jsx @@ -1,7 +1,7 @@ import 'react'; import {useState} from "react"; -const RegionFilter = () => { +const RegionFilter = ({action}) => { const [isOpen, setIsOpen] = useState(false); const toggleDropdown = () => { @@ -15,13 +15,13 @@ const RegionFilter = () => {
    -
      -
    • All
    • -
    • Africa
    • -
    • America
    • -
    • Asia
    • -
    • Europe
    • -
    • Oceania
    • +
        +
      • All
      • +
      • Africa
      • +
      • America
      • +
      • Asia
      • +
      • Europe
      • +
      • Oceania
    From 0b0a5bf9d8286213a65b68923103c7a2f5ca6a3b Mon Sep 17 00:00:00 2001 From: OfekSagiv Date: Thu, 26 Dec 2024 12:05:47 +0200 Subject: [PATCH 7/8] Add documentation for components and functions. done --- src/App.jsx | 13 ++++++++++++- src/Home.jsx | 24 ++++++++++++++++++++++++ src/components/Country.jsx | 9 ++++++++- src/components/Header.jsx | 13 +++++++++++-- src/components/Logo.jsx | 12 +++++++++--- src/components/RegionFilter.jsx | 16 ++++++++++++++++ src/components/SearchBox.jsx | 12 +++++++++++- src/components/ThemeToggle.jsx | 10 +++++++++- 8 files changed, 100 insertions(+), 9 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 0bc94fc..a7638f2 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -5,7 +5,14 @@ import "../src/assets/scss/common.scss"; import Home from "./Home.jsx"; import {useState} from "react"; - +/** + * App Component + * Manages the application, including theme state and persistence. + * + * State: + * - theme: Tracks the current theme ("light" or "dark"), initialized from localStorage. + * + */ function App() { const [theme, setTheme] = useState(() => { const savedTheme = localStorage.getItem("theme"); @@ -18,6 +25,10 @@ function App() { return "light"; }); + /** + * toggleTheme + * Switches between light and dark themes, updates class and localStorage. + */ const toggleTheme = () => { const isDark = theme === "dark"; const newTheme = isDark ? "light" : "dark"; diff --git a/src/Home.jsx b/src/Home.jsx index bb16e26..5bf8141 100644 --- a/src/Home.jsx +++ b/src/Home.jsx @@ -5,17 +5,38 @@ import RegionFilter from "./components/RegionFilter.jsx"; import SearchBox from "./components/SearchBox.jsx"; import countriesData from './assets/json/CountriesData.json'; +/** + * Home Component + * Manages the main layout, filtering, and display of countries. + * + * Props: + * - theme: Current theme ("light" or "dark"). + * - toggleTheme: Function to toggle the theme. + * + * Functionality: + * - Displays a list of countries with search and region filtering. + * - Allows toggling between light and dark themes. + */ const Home = ({theme, toggleTheme}) => { const [countries, setCountries] = useState(countriesData); + /** + * Filters the countries list to display details of a single country by name. + */ const showOneCountryDetails = (countryName) => { setCountries(countriesData.filter((country) => country.name === countryName)); }; + /** + * Resets the countries list to show all available countries. + */ const showAllCountries = () => { setCountries(countriesData); }; + /** + * Filters the countries list based on a search query from the input field. + */ const searchByInput = (e) => { const query = e.target.value.toLowerCase(); if (query === "") { @@ -27,6 +48,9 @@ const Home = ({theme, toggleTheme}) => { } }; + /** + * Filters the countries list based on the selected region. + */ const searchByRegion = (e) => { const region = e.target.getAttribute("data-region"); if (region === 'All') { diff --git a/src/components/Country.jsx b/src/components/Country.jsx index 532a4c6..8c6e863 100644 --- a/src/components/Country.jsx +++ b/src/components/Country.jsx @@ -1,7 +1,14 @@ import 'react' - +/** + * Country Component + * Displays a country's flag, name, population, region, and capital. + * + * Props: + * - country: { flag, name, population, region, capital } + */ const Country = ({country}) => { + return ( <>
    diff --git a/src/components/Header.jsx b/src/components/Header.jsx index da80d50..8ee2ea3 100644 --- a/src/components/Header.jsx +++ b/src/components/Header.jsx @@ -2,9 +2,18 @@ import 'react' import Logo from "./Logo.jsx"; import ThemeToggle from "./ThemeToggle.jsx"; -const Header = ({ theme, toggleTheme }) => { - return ( +/** + * Header Component + * Displays the header with a logo and a theme toggle button. + * + * Props: + * - theme: Current theme ("light" or "dark"). + * - toggleTheme: Function to toggle between themes. + */ +const Header = ({theme, toggleTheme}) => { + + return (
    diff --git a/src/components/Logo.jsx b/src/components/Logo.jsx index 717c234..785b39c 100644 --- a/src/components/Logo.jsx +++ b/src/components/Logo.jsx @@ -1,13 +1,19 @@ import 'react' +/** + * Logo Component + * Displays the site logo as a clickable link. + * + * Functionality: + * - Redirects to "index.html" on click. + */ const Logo = () => { - return ( + return (

    Where in the world?

    - -) + ) } export default Logo \ No newline at end of file diff --git a/src/components/RegionFilter.jsx b/src/components/RegionFilter.jsx index a52b0a2..020e7a5 100644 --- a/src/components/RegionFilter.jsx +++ b/src/components/RegionFilter.jsx @@ -1,9 +1,25 @@ import 'react'; import {useState} from "react"; +/** + * RegionFilter Component + * Displays a dropdown menu for filtering by region. + * + * Props: + * - action: Function to handle the selection of a region. + * + * Functionality: + * - Toggles the dropdown menu open and closed. + * - Calls the provided `action` function when a region is clicked. + */ const RegionFilter = ({action}) => { + //this State tracks whether the dropdown menu is open (true) or closed (false). const [isOpen, setIsOpen] = useState(false); + /** + * toggleDropdown Function + * Toggles the state of `isOpen` to open or close the dropdown menu. + */ const toggleDropdown = () => { setIsOpen(!isOpen); } diff --git a/src/components/SearchBox.jsx b/src/components/SearchBox.jsx index 5295269..dc818d3 100644 --- a/src/components/SearchBox.jsx +++ b/src/components/SearchBox.jsx @@ -1,6 +1,16 @@ import 'react'; - +/** + * SearchBox Component + * A search input field with an accompanying icon for filtering countries. + * + * Props: + * - action: Function triggered on input change to handle search functionality. + * + * Functionality: + * - Calls the `action` function whenever the user types in the input field. + */ const SearchBox = ({action}) => { + return (
    diff --git a/src/components/ThemeToggle.jsx b/src/components/ThemeToggle.jsx index 66ea960..0ab93e2 100644 --- a/src/components/ThemeToggle.jsx +++ b/src/components/ThemeToggle.jsx @@ -1,6 +1,14 @@ import 'react'; - +/** + * ThemeToggle Component + * Button to switch between light and dark themes. + * + * Props: + * - theme: Current theme ("light" or "dark"). + * - toggleTheme: Function to toggle the theme. + */ const ThemeToggle = ({theme, toggleTheme}) => { + return ( diff --git a/src/assets/css/common.css b/src/assets/css/common.css index 653b38b..7b465b2 100644 --- a/src/assets/css/common.css +++ b/src/assets/css/common.css @@ -1,3 +1,24 @@ +:root { + --color-black: #111517; + --color-dark-gray: #202c37; + --color-darker-gray: #2b3945; + --color-hover-gray: #283743; + --color-dark-blue: #354555; + --color-white: #ffffff; + --color-light-gray: #fafafa; + --color-medium-gray: #858585; + --color-border-gray: #ccc; + --color-border-hover-gray: #999; + --color-text-dark: #333; + --color-button-hover: #f7f7f7; + + --shadow-light: rgba(0, 0, 0, 0.08); + --shadow-medium: rgba(0, 0, 0, 0.1); + --shadow-hover: rgba(0, 0, 0, 0.2); + --shadow-dark: rgba(0, 0, 0, 0.3); + --shadow-extra-dark: rgba(0, 0, 0, 0.5); +} + *, *:after, *::before { @@ -7,20 +28,6 @@ outline: none; } -/*html {*/ -/* font-size: 100%;*/ -/* scroll-behavior: smooth;*/ -/*}*/ - -/*body {*/ -/* font-family: 'arial', sans-serif;*/ -/* font-weight: 600;*/ -/* font-size: 14px;*/ -/* background-color: #fafafa;*/ -/* color: #111517;*/ -/* transition: 0.2s linear;*/ -/*}*/ - a { text-decoration: none; } @@ -34,7 +41,7 @@ h1, h2, h3, h4 { - color: #111517; + color: var(--color-black); } .container { @@ -89,10 +96,10 @@ button { .btn { display: inline-block; - background-color: white; - color: #111517; + background-color: var(--color-white); + color: var(--color-black); text-transform: capitalize; - box-shadow: 0 2px 15px rgba(0, 0, 0, 0.08); + box-shadow: 0 2px 15px var(--shadow-light); padding: 7px 21px; border-radius: 4px; transition: 0.2s linear; @@ -118,7 +125,7 @@ button { left: 0; width: 100%; height: 100%; - background-color: #fafafa; + background-color: var(--color-light-gray); display: flex; justify-content: center; align-items: center; @@ -133,7 +140,7 @@ button { .loader .spinner .icon { font-size: 80px; - color: #111517; + color: var(--color-black); } .scroll-top { @@ -142,7 +149,7 @@ button { right: 0; width: 45px; height: 45px; - background-color: #202c37; + background-color: var(--color-dark-gray); border-radius: 50%; z-index: 8; opacity: 0; @@ -151,7 +158,7 @@ button { } .scroll-top:hover { - background-color: #283743; + background-color: var(--color-hover-gray); } .scroll-top.show { @@ -161,13 +168,13 @@ button { } .scroll-top .icon { - color: white; + color: var(--color-white); font-size: 17px; } .notifi-wrapper { padding: 25px; - color: #111517; + color: var(--color-black); text-align: center; } @@ -177,9 +184,9 @@ button { .header { position: relative; - background: white; + background: var(--color-white); padding: 1.25rem 0; - box-shadow: 0 2px 15px rgba(0, 0, 0, 0.08); + box-shadow: 0 2px 15px var(--shadow-light); transition: 0.2s linear; } @@ -208,7 +215,7 @@ button { .header .theme-toggle { gap: 0.625rem; font-size: 14px; - color: #111517; + color: var(--color-black); transition: 0.2s linear; } @@ -228,128 +235,125 @@ button { } body.dark-theme { - background-color: #202c37; - color: white; + background-color: var(--color-dark-gray); + color: var(--color-white); } body.dark-theme h1, body.dark-theme h2, body.dark-theme h3, body.dark-theme h4 { - color: white; + color: var(--color-white); } body.dark-theme .header { - background: #2b3945; + background: var(--color-darker-gray); } body.dark-theme .header .theme-toggle { - color: white; + color: var(--color-white); } body.dark-theme .filters .search-icon { - color: white; + color: var(--color-white); } body.dark-theme .filters .search-input { - color: white; - background-color: #2b3945; + color: var(--color-white); + background-color: var(--color-darker-gray); } body.dark-theme .filters .search-input::placeholder { - color: white; + color: var(--color-white); } body.dark-theme .filters .dropdown-header, body.dark-theme .filters .dropdown-body { - background: #2b3945; + background: var(--color-darker-gray); } body.dark-theme .filters .dropdown-body li:hover { - background-color: #354555; + background-color: var(--color-dark-blue); } body.dark-theme .countries-grid .country { - color: white; - background: #2b3945; + color: var(--color-white); + background: var(--color-darker-gray); } body.dark-theme .countries-grid .country span { - color: white; + color: var(--color-white); } body.dark-theme .loader { - background-color: #202c37; + background-color: var(--color-dark-gray); } body.dark-theme .loader .spinner .icon { - color: white; + color: var(--color-white); } body.dark-theme .scroll-top { - background-color: #2b3945; + background-color: var(--color-darker-gray); } body.dark-theme .notifi-wrapper { - color: white; + color: var(--color-white); } body.dark-theme .btn { - background-color: #2b3945; - color: white; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); + background-color: var(--color-darker-gray); + color: var(--color-white); + box-shadow: 0 0 10px var(--shadow-hover); } body.dark-theme .country-info li { - color: #858585; + color: var(--color-medium-gray); } body.dark-theme .country-info strong { - color: white; + color: var(--color-white); } - .button-all-countries { padding: 10px 20px; font-size: 16px; - color: #333; - background-color: #fff; - border: 1px solid #ccc; + color: var(--color-text-dark); + background-color: var(--color-white); + border: 1px solid var(--color-border-gray); border-radius: 5px; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + box-shadow: 0 2px 5px var(--shadow-medium); cursor: pointer; transition: all 0.3s ease; } .button-all-countries:hover { - border-color: #999; - box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); + border-color: var(--color-border-hover-gray); + box-shadow: 0 4px 10px var(--shadow-hover); transform: translateY(-2px); } .button-all-countries:active { - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + box-shadow: 0 2px 5px var(--shadow-medium); transform: translateY(0); - background-color: #f7f7f7; + background-color: var(--color-button-hover); } -/* התאמת הכפתור עבור Dark Mode */ body.dark-theme .button-all-countries { - color: white; - background-color: #2b3945; - border: 1px solid #3c4a56; /* מסגרת כהה יותר */ - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); + color: var(--color-white); + background-color: var(--color-darker-gray); + border: 1px solid var(--color-dark-blue); + box-shadow: 0 2px 10px var(--shadow-dark); } body.dark-theme .button-all-countries:hover { - border-color: #58687a; /* מסגרת כהה במעבר */ - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.5); /* צל מודגש */ + border-color: var(--color-dark-blue); + box-shadow: 0 4px 15px var(--shadow-extra-dark); transform: translateY(-2px); } body.dark-theme .button-all-countries:active { - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); + box-shadow: 0 2px 5px var(--shadow-dark); transform: translateY(0); - background-color: #354555; /* רקע כהה יותר בעת לחיצה */ -} - + background-color: var(--color-dark-blue); +} \ No newline at end of file diff --git a/src/assets/css/details.css b/src/assets/css/details.css index d3f1a50..2ef32c2 100644 --- a/src/assets/css/details.css +++ b/src/assets/css/details.css @@ -1,10 +1,17 @@ +:root { + --color-primary: #111517; + --color-warning: #d21034; + --color-secondary: #2b3945; + --shadow-light: rgba(0, 0, 0, 0.08); + --shadow-medium: rgba(0, 0, 0, 0.11); +} + body { font-size: 16px; - } .btn:hover { - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.11); + box-shadow: 0 4px 20px var(--shadow-medium); } .btn.btn-back { @@ -47,7 +54,7 @@ body { width: 450px; max-width: 450px; max-height: 350px; - box-shadow: 0 2px 15px rgba(0, 0, 0, 0.08); + box-shadow: 0 2px 15px var(--shadow-light); overflow: hidden; margin-right: 70px; border-radius: 6px; @@ -71,22 +78,22 @@ body { } .country-info h1 { - color: #111517; + color: var(--color-primary); margin-bottom: 30px; } .country-info strong { text-transform: capitalize; - color: #111517; + color: var(--color-primary); } .country-info strong.warning { - color: #d21034 !important; + color: var(--color-warning) !important; } .country-info li { text-transform: capitalize; - color: #2b3945; + color: var(--color-secondary); } .country-info li button { @@ -133,4 +140,4 @@ body { align-items: inherit; gap: 8px; flex-wrap: wrap; -} +} \ No newline at end of file diff --git a/src/assets/css/index.css b/src/assets/css/index.css index 3d27505..7fc2722 100644 --- a/src/assets/css/index.css +++ b/src/assets/css/index.css @@ -9,8 +9,6 @@ height: 100%; } - -/* הגדרות ל-html ול-body */ html, body { margin: 0; padding: 0; @@ -21,19 +19,25 @@ html, body { font-size: 100%; } - :root { - + --color-primary: #646cff; + --color-primary-hover: #535bf2; + --color-light-hover: #747bff; + --color-dark-bg: #1a1a1a; + --color-light-bg: #f9f9f9; + --color-text-light: #213547; + --color-white: #ffffff; + --focus-outline-color: -webkit-focus-ring-color; } a { font-weight: 500; - color: #646cff; + color: var(--color-primary); text-decoration: inherit; } a:hover { - color: #535bf2; + color: var(--color-primary-hover); } body { @@ -42,8 +46,6 @@ body { place-items: center; min-width: 320px; min-height: 100vh; - - } h1 { @@ -58,35 +60,32 @@ button { font-size: 1em; font-weight: 500; font-family: inherit; - background-color: #1a1a1a; + background-color: var(--color-dark-bg); cursor: pointer; transition: border-color 0.25s; } - button:hover { - border-color: #646cff; + border-color: var(--color-primary); } button:focus, button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; + outline: 4px auto var(--focus-outline-color); } @media (prefers-color-scheme: light) { :root { - color: #213547; - background-color: #ffffff; + color: var(--color-text-light); + background-color: var(--color-white); width: 100%; } a:hover { - color: #747bff; + color: var(--color-light-hover); } button { - background-color: #f9f9f9; + background-color: var(--color-light-bg); } -} - - +} \ No newline at end of file diff --git a/src/assets/css/main.css b/src/assets/css/main.css index d609cf0..a178cb4 100644 --- a/src/assets/css/main.css +++ b/src/assets/css/main.css @@ -1,3 +1,5 @@ + + .filters { margin: 40px 0 50px 0; } diff --git a/src/components/Country.jsx b/src/components/Country.jsx index 8c6e863..cda2674 100644 --- a/src/components/Country.jsx +++ b/src/components/Country.jsx @@ -7,23 +7,22 @@ import 'react' * Props: * - country: { flag, name, population, region, capital } */ -const Country = ({country}) => { - +const Country = ({ country: { flag, name, population, region, capital } }) => { return ( <>
    - {country.name}/ + {name}
    -

    {country.name}

    +

    {name}

      -
    • Population: {country.population}
    • -
    • Region: {country.region}
    • -
    • Capital: {country.capital}
    • +
    • Population: {population}
    • +
    • Region: {region}
    • +
    • Capital: {capital}
    - ) -} + ); +}; -export default Country \ No newline at end of file +export default Country; \ No newline at end of file diff --git a/src/components/RegionFilter.jsx b/src/components/RegionFilter.jsx index 020e7a5..018baee 100644 --- a/src/components/RegionFilter.jsx +++ b/src/components/RegionFilter.jsx @@ -13,31 +13,27 @@ import {useState} from "react"; * - Calls the provided `action` function when a region is clicked. */ const RegionFilter = ({action}) => { - //this State tracks whether the dropdown menu is open (true) or closed (false). const [isOpen, setIsOpen] = useState(false); - /** - * toggleDropdown Function - * Toggles the state of `isOpen` to open or close the dropdown menu. - */ + const toggleDropdown = () => { setIsOpen(!isOpen); } + const regions = ["All", "Africa", "Americas", "Asia", "Europe", "Oceania"]; + + return ( -
    +
    Filter by Region
      -
    • All
    • -
    • Africa
    • -
    • America
    • -
    • Asia
    • -
    • Europe
    • -
    • Oceania
    • + {regions.map((region) => ( +
    • {region}
    • + ))}
    diff --git a/src/components/ThemeToggle.jsx b/src/components/ThemeToggle.jsx index 0ab93e2..4b3a3d4 100644 --- a/src/components/ThemeToggle.jsx +++ b/src/components/ThemeToggle.jsx @@ -8,15 +8,15 @@ import 'react'; * - toggleTheme: Function to toggle the theme. */ const ThemeToggle = ({theme, toggleTheme}) => { - + const isDarkTheme = theme === "dark"; return ( ); }; diff --git a/src/main.jsx b/src/main.jsx index aee044a..c0721fa 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -3,6 +3,7 @@ import { createRoot } from 'react-dom/client' import './assets/css/index.css' import App from './App.jsx' + createRoot(document.getElementById('root')).render(