GitHub User Search App
Abstract:
A FrontendMentor.io build that looks up GitHub users via the API, and includes light and dark modes. Mine runs on vanilla JS and Vite.
Built with:
Mobile-first workflow, semantic HTML, Flexbox, CSS Grid, JavaScript, Vite, Octokit API, localStorage, CSS Shadow Palette Generator
JavaScript
Octokit
It turned out that the GitHub API has its own library called Octokit. I ended up using octokit/rest.js, because I found a note somewhere suggesting this version would work best with Vite. However, Vite still didn’t like it. I eventually solved the issue by replacing node-fetch
with isomorphic-fetch
as suggested in this StackOverflow answer (and some others). After that, retrieving public info from GitHub went just fine:
import { Octokit } from "@octokit/rest";
const octokit = new Octokit({
// this is where you would add auth, but it's not necessary to retrieve this public info
// 'userAgent' is still required
userAgent: 'github-user-search-app Frontendmentor.io exercise',
})
async function fetchResponse(query) {
try {
// Octokit includes default headers, don't need to add unless they need to be changed
const response = await octokit.rest.users.getByUsername({
username: `${query}`,
});
displayResponse(response.data);
} catch (error) {
noResults.style.display = 'block';
console.log(`Error! Status: ${error.status}. Rate limit remaining: ${error.response.headers["x-ratelimit-remaining"]}. Message: ${error.response.data.message}.`)
}
}
Date formatting
FrontendMentor.io happens to be based in the UK, so the user’s “Joined” date is displayed in the app comps like so: 08 Jul 2020
. I wasn’t sure how I was going to get the data returned by GitHub into that format, but I was sure there would be a way to do it with built-in methods instead of a bunch of string manipulations and regexes. After spending some time looking it up, that way turned out to be the Intl.DateTimeFormat() constructor. It has to be made into a standard Date
object first, then you give it the parameters you want:
export function displayResponse(response) {
const date = new Date(response.created_at);
outputBox.innerHTML = `
// etc...
<p class="joined">Joined ${new Intl.DateTimeFormat("en-GB", {
year: "numeric",
month: "short",
day: "2-digit",
}).format(date)}</p>
// etc
`
}
Darkmode
Like my other app builds with both light and dark modes, this checks localStorage
in case a user has been to the site before and saved a preference, then checks prefers-color-scheme
if not.
const localPref = JSON.parse(localStorage.getItem('darkMode')); // boolean or null
const defaultDark = window.matchMedia('(prefers-color-scheme: dark)').matches; // boolean
let darkMode = localPref ?? defaultDark; // boolean; if this evaluates to true, darkMode should be turned on
// etc...
// app saves a preference to localstorage only if you click the toggle
function handleMode() {
if (!darkMode) {
document.body.classList.add('dark-mode');
localStorage.setItem('darkMode', true);
} else if (darkMode) {
document.body.classList.remove('dark-mode');
localStorage.setItem('darkMode', false);
}
darkMode = !darkMode;
}
// this sets darkmode without saving it if it's found in the system preferences only
function setDarkPref(darkMode) {
if (darkMode) {
document.body.classList.add('dark-mode');
}
}
Resources
Josh Comeau’s amazing CSS Shadow Palette Generator.