This is a solution to the REST Countries API with color theme switcher challenge on Frontend Mentor. Frontend Mentor challenges help you improve your coding skills by building realistic projects.
Users should be able to:
- See all countries from the API on the homepage
- Search for a country using an
input
field - Filter countries by region
- Click on a country to see more detailed information on a separate page
- Click through to the border countries on the detail page
- Toggle the color scheme between light and dark mode (optional)
Detail Country Page - (Dark Mode)
- Live Site URL: https://rest-countries-api-tan.vercel.app/
- Mobile-first workflow
- Semantic HTML5 markup
- CSS custom properties
- CSS Grid & Flexbox
- React - JS library
- Next.js - React framework
- Styled Components - For styles
- Axios - HTTP client
- SWR - React Hooks for Data Fetching
- React Icons - Icons
This project is very interesting. I learned new things that can be applied to complete this project well. Here are the details:
Usually I will use input
Tag with text type. But HTML has another type which is search. In this type, some web browsers will display an empty button (x) when we type something in it.
<input
type="search"
id="country"
name="country"
aria-label="Name of Country"
placeholder="Search for country..."
/>
Displaying an Image in a container that has a fixed size is quite a tricky thing. Given also we need to adjust to the width of the screen to be responsive.
However, some images have different sizes, if you use object-fit:cover;
, then there are some parts of the flag image that are not visible.
Therefore, I implemented object-fit:scale-down
. thus displaying the image flag in full without being cropped and the height of the image container will be the same size.
.flag-image {
object-fit: scale-down;
object-position: center;
}
I just found out that some web browsers can detect theme colors on the device system.
This is very helpful for implementing color mode in web applications. In css, we can detect user's theme preference by using media query:
@media (prefers-color-scheme: dark) {
.dark {
background-color: black;
color: white;
}
}
We can also detect if the user's web browser supports it or not.
if (window.matchMedia('(prefers-color-scheme)').media !== 'not all') {
var queryMedia = window.matchMedia('(prefers-color-scheme: dark)');
if (queryMedia.matches) {
setDark();
} else {
setLight();
}
} else {
setLight();
}
Returns numbers separated by commas. It can also help the user to know quickly what the number will be if the value is very large.
const numberWithCommas = (x: number) => {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};
In order to test my skills and adapt to the provided design, I think I need to add some features to this project to make it more relevant.
I'm trying to make it look exactly the same as the available design. The select box is a unique part.
Before the user selects a region, the text shown is a label i.e., filter by region. However, when the user chooses, the label text is not included in the selection. This is very interesting.
So, I applied it to the code. And lets me add a Reset Button if the user wants to cancel the filter.
I've also added a highlight for keywords that match the name of the country being searched for. By using a function from JavaScript, namely .replace()
.
const MarkText = ({ text, keyword }) => {
if (keyword !== '') {
const splitterText = '___{$#(!VMV!)#$}___';
const regExpKeyword = new RegExp(keyword, 'gi');
// Replacement with string
const replace = text.replaceAll(
regExpKeyword,
`${splitterText}$&${splitterText}`
);
const split = replace.split(splitterText);
return (
<>
{split.map((word, index) => {
if (word.toLowerCase() === keyword.toLowerCase())
return <mark key={index}>{word}</mark>;
return word;
})}
</>
);
}
return <>{text}</>;
};
I didn't create a navbar with a fixed position on top. So when a user has reached the bottom of the page and they want to change a keyword or filter by a region, the user needs to go to the top of the page manually.
Therefore, I created a button that when the user presses the button, they will be directly directed to the top of the page. I think this is also often seen on the web and other blogs.
const handleClick = () => {
window.scrollTo({
top: 0,
behavior: 'smooth',
});
};
- https://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript
- https://dev.to/wh1zk1d/swr-dynamic-routes-in-next-js-3cbl
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll
- https://www.kindacode.com/article/how-to-create-a-scroll-to-top-button-in-react/
- https://web.dev/prefers-color-scheme/
- https://sreetamdas.com/blog/the-perfect-dark-mode
- Website - https://cholis04.github.io
- Frontend Mentor - @cholis04
- Dribbble - cholis04
- Instagram - @cholis04
- Codepen - cholis04
Many thanks to anyone who provided feedback.