diff --git a/@types/defaults.d.ts b/@types/defaults.d.ts index 1efca40..7ad137d 100644 --- a/@types/defaults.d.ts +++ b/@types/defaults.d.ts @@ -29,5 +29,5 @@ interface IParams { } interface CSSStyleProps extends React.CSSProperties { - "--min-column-size": string; + "--min-col-size": string; } diff --git a/README.md b/README.md index f4da3c4..fbd5af2 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,81 @@ +# Countries of the World + +This application uses the REST Countries API to get info about countries on planet earth. + +## Table of contents + +- [Countries of the World](#countries-of-the-world) + - [Table of contents](#table-of-contents) + - [Overview](#overview) + - [The challenge](#the-challenge) + - [Screenshot](#screenshot) + - [Links](#links) + - [Project Development](#project-development) + - [Running the App](#running-the-app) + - [Deploying the App](#deploying-the-app) + - [My process](#my-process) + - [Built with](#built-with) + - [What I learned](#what-i-learned) + - [Continued development](#continued-development) + - [Useful resources](#useful-resources) + - [Author](#author) + - [Acknowledgments](#acknowledgments) + +## Overview + This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). -## Getting Started +### The challenge + +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)_ + +### Screenshot + +![](./screenshot.jpg) + +### Links + +Press . on the keyboard to view this project's code in the _`github.dev`_ code editor just like in _`Visual Studio Code`_ -First, run the development server: +- Code: [Github Repository](https://github.com/princemuel/rest-countries) +- Live Site: [REST Countries of the World](https://rest-countries-mocha.vercel.app/) + +## Project Development + +### Running the App + +- Clone the repo by running the command: + +```bash +git clone https://github.com/princemuel/rest-countries.git +``` + +- Enter into the project folder: + +```bash +cd rest-countries +``` + +- Install the project's dependencies: + +```bash +# NOTE: This project uses pnpm as package manager but that's optional. You may delete the lockfile and install the deps using your choice of package manager + +npm install +# or +yarn install +# or +pnpm install +``` + +- Then, run the development server: ```bash npm run dev @@ -12,23 +85,60 @@ yarn dev pnpm dev ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +Open [http://localhost:3000](http://localhost:3000) to view it in the browser. You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. +### Deploying the App + +Your app is ready to be deployed! The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out the [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. + +## My process + +### Built with + +- Semantic HTML5 markup +- CSS custom properties +- Flexbox +- CSS Grid +- Mobile-first workflow +- [React](https://react.dev/) - JS library +- [Next.js](https://nextjs.org/docs) - React framework +- [Tailwind CSS](https://tailwindcss.com/docs) - For composing component styles using utility classes + +### What I learned + +```html +

Some HTML code I'm proud of

+``` + +```css +.proud-of-this-css { + color: papayawhip; +} +``` + +```js +const proudOfThisFunc = () => { + console.log('🎉'); +}; +``` -## Learn More +### Continued development -To learn more about Next.js, take a look at the following resources: +Use this section to outline areas that you want to continue focusing on in future projects. These could be concepts you're still not completely comfortable with or techniques you found useful that you want to refine and perfect. -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +### Useful resources -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! +- [Example resource 1](https://www.example.com) - This helped me for XYZ reason. I really liked this pattern and will use it going forward. +- [Example resource 2](https://www.example.com) - This is an amazing article which helped me finally understand XYZ. I'd recommend it to anyone still learning this concept. -## Deploy on Vercel +## Author -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +- Website (In Development) - [Prince Muel](https://princemuel.vercel.app/) +- LinkedIn - [@princemuel](https://linkedin.com/in/princemuel/) +- Twitter - [@iamprincemuel](https://twitter.com/iamprincemuel) -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. +## Acknowledgments diff --git a/app/countries/[slug]/page.tsx b/app/countries/[slug]/page.tsx index dccc861..6f9f609 100644 --- a/app/countries/[slug]/page.tsx +++ b/app/countries/[slug]/page.tsx @@ -1,3 +1,5 @@ +import { defineMeta } from '@/config'; +import { hasValues } from '@/helpers'; import { getAllCountries, getCountryBySlug, @@ -5,6 +7,7 @@ import { preloadCountry, } from '@/lib'; import type { Metadata } from 'next'; +import { notFound } from 'next/navigation'; import CountryDetailsTemplate from './country'; interface Props { @@ -16,7 +19,9 @@ async function PageRoute({ params: { slug } }: Props) { const imageResponse = await getCountryBySlug(slug); - preloadBase64(imageResponse[0].flags.svg); + if (!imageResponse || !hasValues(imageResponse)) throw notFound(); + + preloadBase64(imageResponse[0]?.flags?.svg); return ; } @@ -35,16 +40,17 @@ export async function generateMetadata({ const response = await getCountryBySlug(slug); const country = response[0]; + if (!country) throw notFound(); - if (!country) - return { - title: 'Country Not Found', - description: 'The requested resource does not exist', - }; + // if (!country) + // return { + // title: 'Country Not Found', + // description: 'The requested resource does not exist', + // }; const title = `${country?.name?.common} `; - return { + return defineMeta({ title: title, description: country?.flags?.alt, icons: [ @@ -70,5 +76,5 @@ export async function generateMetadata({ description: country?.flags?.alt, images: [country?.flags?.png, country?.flags?.svg], }, - }; + }); } diff --git a/app/fonts/index.ts b/app/fonts/index.ts index 16580ef..4bab2be 100644 --- a/app/fonts/index.ts +++ b/app/fonts/index.ts @@ -1,10 +1,21 @@ import { cn } from '@/helpers'; +import { Nunito_Sans } from 'next/font/google'; import localFont from 'next/font/local'; -const FontSans = localFont({ +const isProduction = process.env.NODE_ENV === 'production'; + +const FontSans_DEV = localFont({ display: 'swap', variable: '--font-sans', src: './nunito-sans.ttf', }); -export const fonts = cn(FontSans.variable); +const FontSans_PROD = Nunito_Sans({ + display: 'swap', + variable: '--font-sans', + subsets: ['latin'], +}); + +export const fonts = cn( + isProduction ? [FontSans_PROD.variable] : [FontSans_DEV.variable] +); diff --git a/app/layout.tsx b/app/layout.tsx index 14ada95..ed703aa 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,12 +1,12 @@ import { BaseLayout } from '@/components'; -import { seo } from '@/config'; +import { defineMeta } from '@/config'; import { Providers } from '@/context'; import { cn } from '@/helpers'; import { Analytics } from '@vercel/analytics/react'; import { fonts } from './fonts'; import './globals.css'; -export const metadata = seo; +export const metadata = defineMeta(); export default function RootLayout({ children, diff --git a/components/atoms/theme.tsx b/components/atoms/theme.tsx index 89ad1db..7658ec6 100644 --- a/components/atoms/theme.tsx +++ b/components/atoms/theme.tsx @@ -7,14 +7,9 @@ import * as React from 'react'; export function ThemeSwitch() { const { resolvedTheme, setTheme } = useTheme(); const [_, startTransition] = React.useTransition(); - const hasMounted = React.useRef(false); + const [hasMounted, setHasMounted] = React.useState(false); - React.useEffect(() => { - hasMounted.current = true; - return () => { - hasMounted.current = false; - }; - }, []); + React.useEffect(() => setHasMounted(true), []); const isDarkTheme = resolvedTheme === 'dark'; @@ -26,7 +21,7 @@ export function ThemeSwitch() { const text = isDarkTheme ? 'dark mode' : 'light mode'; - if (!hasMounted.current) return null; + if (!hasMounted) return null; return (