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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
660 changes: 660 additions & 0 deletions FullCountriesData.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions css/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ button {
}

.loader {
position: fixed;
top: 0;
/* position: fixed; */
/* top: 0; */
left: 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the comments

width: 100%;
height: 100%;
Expand Down
2 changes: 1 addition & 1 deletion css/details.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ body {

.country-flag img {
display: block;
max-width: 100%;
/* max-width: 100%; */
object-fit: cover;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here remove comment

}

Expand Down
15 changes: 9 additions & 6 deletions details.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@
<link rel="stylesheet" href="./css/details.css" />
<title>Details Page</title>
</head>
<body>
<body onload="getSelectedCountry()">
<!-- Loader -->
<div class="loader">
<!-- <div class="loader">
<div class="spinner">
<i class="fa-regular fa-circle-notch fa-spin icon"></i>
</div>
</div>
</div> -->
<!-- Scroll Top -->
<button
type="button"
Expand Down Expand Up @@ -69,11 +69,14 @@ <h1>Where in the world?</h1>
</a>
</div>
</div>
<main class="main">
<div class="container">
<section class="country-details"></section>
<main class="main" >
<div class="container" >
<section class="country-details" >

</section>
</div>
</main>

<script src="./js/common.js"></script>
<script src="./js/details.js"></script>
</body>
Expand Down
20 changes: 12 additions & 8 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<link rel="stylesheet" href="./css/main.css" />
<title>Countries Info</title>
</head>
<body>
<body onload="allCountries()">
<!-- Scroll Top -->
<button
type="button"
Expand Down Expand Up @@ -63,18 +63,19 @@ <h1>Where in the world?</h1>
<input
type="text"
class="search-input"
oninput="searchByInputCountries(event)"
placeholder="Search for a country..."
/>
</div>
<div class="dropdown-wrapper">
<div class="dropdown-header flex flex-jc-sb flex-ai-c">
<div class="dropdown-wrapper" >
<div class="dropdown-header flex flex-jc-sb flex-ai-c" onclick="toggleDropdown()">
<span>Filter by Region</span>
<i class="fa-regular fa-chevron-down icon"></i>
</div>
<div class="dropdown-body">
<div class="dropdown-body" onclick="searchByRegion(event)">
<ul>
<li data-region="all">All</li>
<li data-region="africa">Africa</li>
<li data-region="africa" >Africa</li>
<li data-region="americas">America</li>
<li data-region="asia">Asia</li>
<li data-region="europe">Europe</li>
Expand All @@ -87,8 +88,8 @@ <h1>Where in the world?</h1>
<!-- Countries -->
<main class="main">
<div class="container">
<section class="countries-grid">
<a
<section class="countries-grid" onclick="selectCountry(event)">
<!-- <a
href="#"
class="country scale-effect"
data-country-name="Afghanistan"
Expand Down Expand Up @@ -150,9 +151,12 @@ <h2 class="country-title">Belize</h2>
<li><strong>capital: </strong>Belmopan</li>
</ul>
</div>
</a>
</a> -->
</section>
</div>
</main>
<script src="./js/common.js"></script>
<script src="./js/index.js"></script>
<script src="/js/filters.js"></script>
</body>
</html>
85 changes: 85 additions & 0 deletions js/common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@



const getAllCountriesData = async () => {
let isLoading = true;
try {
loading(isLoading);
const result = await fetch(`../FullCountriesData.json`);
if (!result.ok) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded strings should be extracted into constants file

throw "Failed to fetch data";
}
const json = await result.json();
// console.log(json);
return json;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this comment

}
catch (error) {
console.log(error);
} finally {
isLoading = false;
loading(isLoading);
}
}

const loading = () => {
const loader = document.querySelector('.country-details')
? document.querySelector('.country-details')
: document.querySelector('.countries-grid');

if (loader) {
loader.innerHTML = `
<div class="loader">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use innerHTMl, it's a dangerous method

<div class="spinner">
<i class="fa-regular fa-circle-notch fa-spin icon"></i>
</div>
</div>
`;
}
else {
loader.innerHtml = '';
}
}


const selectCountry = async (e) => {
const data = await getAllCountriesData();
const countryName = e.target.closest(".country");
const country = countryName.dataset.countryName;
const findCountry = data.find(({ name }) => name === country)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job I like it.

if (!findCountry) return;

window.location.href = `details.html?country=${country}`;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can extract this code into service that exposes methods instead of writing the same logic again and again



const darkModeToggle = document.querySelector('.theme-toggle');
darkModeToggle.addEventListener('click', () => {
const darkMode = darkModeToggle.classList.contains('dark-mode');
const themeText = document.querySelector('.theme-text');
const themeIcon = document.querySelector('.theme-toggle>i');

themeIcon.classList.add('fa-moon');
themeIcon.classList.remove('fa-sun');
if (darkMode) {
document.body.style.backgroundColor = '#ffff';
themeText.innerHTML = 'Dark Mode';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use classes in here as well to style elements.

themeIcon.classList.add('fa-moon');
themeIcon.classList.remove('fa-sun');
darkModeToggle.classList.remove('dark-mode')
}
else {
themeText.innerText = 'Light Mode';
document.body.style.backgroundColor = '#333';
themeIcon.classList.add('fa-sun');
themeIcon.classList.remove('fa-moon');
darkModeToggle.classList.add('dark-mode');
}
});







54 changes: 54 additions & 0 deletions js/details.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@

const getSelectedCountry = async () => {
const data = await getAllCountriesData();
const displayCountry = document.querySelector('.country-details');

let params = new URLSearchParams(document.location.search);
let countryName = params.get('country');
if (!countryName) return;

const myCountry = data?.find(({ name }) => name === countryName);
console.log(countryName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work on destructuring here


const { name,nativeName,subRegion, flag, population, region, capital,topLevelDomain,currencies,languages ,borders} = myCountry;
displayCountry.innerHTML = `
<div class="country-details ">
<div class="country-flag"style="width: 100%; max-width: 500px;height: 100%;">
<img src="${flag}" alt="${name} Flag" style="width: 100%;object-fit: cover; height: 100%;" />
</div>
<div class="country-info">
<h2 class="country-title">${name}</h2>
<br/>
<div class="col-2">
<ul>
<li><strong>Native Name: </strong>${nativeName}</li>
<li><strong>Population: </strong>${population}</li>
<li><strong>Region: </strong>${region}</li>
<li><strong>Sub Region: </strong>${subRegion}</li>
<li><strong>Capital: </strong>${capital}</li>
</ul>
<ul>
<li><strong>Top Level Domain: </strong>${topLevelDomain.map(item => item)}</li>
<li><strong>Currencies: </strong>${currencies.map(item => item)}</li>
<li><strong>Languages: </strong>${languages.map(item => item)}</li>
</ul>
</div>
<h2><strong>Border Countries: </strong></h2>
<div class="col-3">
${borders.length > 0? borders?.map(item =>
`
<button class="btn">${item}</button>
`
).join(' '): 'No border countries found.'}
</div>
</div>
</div>
`;


}
97 changes: 97 additions & 0 deletions js/filters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

const allCountries = async () => {
const data = await getAllCountriesData();

const countries = document.querySelector('.countries-grid');
countries.innerHTML = '';

return data.forEach(item => {
countries.innerHTML += `
<a
href="#"
class="country scale-effect"
data-country-name='${item.name}'
>
<div class="country-flag">
<img
src='${item.flag}'
alt="'${item.name}' FLag"
/>
</div>
<div class="country-info">
<h2 class="country-title">${item.name}</h2>
<ul class="country-brief">
<li><strong>population: </strong>${item.population}</li>
<li><strong>Region: </strong>${item.region}</li>
<li><strong>capital: </strong>${item.capital}</li>
</ul>
</div>
</a>
`
});
}

const searchByRegion = async (e) => {
const data = await getAllCountriesData();
const selectRegion = e.target.attributes[0].nodeValue;
const clearInputValue = document.querySelector('.search-input');
if (clearInputValue.value !== '') clearInputValue.value = '';


const regionData = data?.filter(({ region }) => {
if (region.toLowerCase() === selectRegion)
return region;
else if (selectRegion == 'all')
return region
});

return displayCountries(regionData)

}

const displayCountries = (data) => {

const countries = document.querySelector('.countries-grid');
countries.innerHTML = '';

data?.forEach(({ name, flag, population, region, capital }) => {
countries.innerHTML += `
<a
href="#"
class="country scale-effect"
data-country-name='${name}'
>
<div class="country-flag">
<img
src='${flag}'
alt="'${name}' FLag"
/>
</div>
<div class="country-info">
<h2 class="country-title">${name}</h2>
<ul class="country-brief">
<li><strong>population: </strong>${population}</li>
<li><strong>Region: </strong>${region}</li>
<li><strong>capital: </strong>${capital}</li>
</ul>
</div>
</a>
`
});
}


const searchByInputCountries = async (e) => {
const data = await getAllCountriesData();
let searchInput = e.target.value.toLowerCase()
let searchLength = searchInput.length;
const filteredData = data?.filter(({ name }) => {
const space = name.toLowerCase().indexOf(searchInput[0]);
if (name.slice(0, searchLength).toLowerCase() == searchInput)
return name;
else if (name[space - 1] === ' ' && name.slice(space, space + searchLength).toLowerCase() == searchInput)
return name;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extract your complex condition into a variable or a function

});

return displayCountries(filteredData);
}
21 changes: 21 additions & 0 deletions js/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
function toggleDropdown() {
const wrapper = document.querySelector('.dropdown-wrapper');
wrapper.classList.toggle('open');

if (wrapper.classList.contains('open')) {
document.addEventListener('click', handleOutsideClick);
} else {
document.removeEventListener('click', handleOutsideClick);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work on removing your event listeners, it's really important practice

}

function handleOutsideClick(event) {
const wrapper = document.querySelector('.dropdown-wrapper');
const body = document.querySelector('.dropdown-body');
const header = document.querySelector('.dropdown-header');

if (!body.contains(event.target) && !header.contains(event.target)) {
wrapper.classList.remove('open');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing in here, extract complex logic into a variable or a function

document.removeEventListener('click', handleOutsideClick);
}
}