This is a solution to the REST Countries API with color theme switcher challenge on Frontend Mentor.
Users should be able to:
input
fieldI use this methods to make sure the name filter (from the search input) is not updated on every keypress of the user.
function definition:
export const debounce = (callback: (props: any) => void, delay: number = 750) => {
let timeout: ReturnType<typeof setTimeout>;
return (...props: any) => {
clearTimeout(timeout);
timeout = setTimeout(() => {
callback(props);
}, delay);
};
};
Then in the component:
let value: string = $filters.name; // This is the value of the input
const onChange = debounce(() => updateFilter("name", value.trim()), 250); // Runs only if user stops typing for 250ms
$: value && onChange(); // the $: makes sure onChange is called everytime "value" changes
Get the color scheme from the user settings in the browser:
const getPreferedColorScheme = (): ThemeMode => {
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
};
export const getInitialTheme = (defaultValue: ThemeMode): ThemeStore => {
if (!browser) return { mode: defaultValue, prefersColorScheme: true };
const json = window.localStorage.getItem("theme");
if (json === null) return { mode: getPreferedColorScheme(), prefersColorScheme: true };
const storedTheme = JSON.parse(json) as ThemeStore;
const mode = storedTheme.prefersColorScheme ? getPreferedColorScheme() : storedTheme.mode;
return { ...storedTheme, mode };
};
Use these to loop on a JavaScript object like it is an Array
Object.values(data.currencies).forEach((currency) => {
props.currencies = props.currencies.concat((currency as any).name, " ");
});
A readable reactive variable that can be used to track is the app is navigating between two endpoints.
I used it to show a loading overlay when fetching a country in the app:
import { navigating } from "$app/stores";
$: showOverlay = $navigating !== null; // If true --> Show the loading indicator
Use src/lib/* to prevent using absolute paths for imports
When using Typescript you need to declare the path in your tsconfig:
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
// If you want to change is from src/lib you'll need to update your svelte.config file.
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"]
}
}
}
Then your imports look like this:
import SearchInput from "$lib/components/SearchInput.svelte";
import RegionSelect from "$lib/components/RegionSelect.svelte";
import CountryCard from "$lib/components/CountryCard.svelte";
import type { CountrySimple } from "$lib/types";
import { filterCountries } from "$lib/helpers";
import { filters } from "$lib/stores";
I want to implement a service worker to cache the already fetched endpoint for each individual country.
E.g. https://my-url/countries/[name]
This way pages would load faster and the Open Source API owners would appreciate the fewer requests.