What we’re building
We’ve had to find our Mastodon account ID more than a handfull of times, and like any good coder, if you find yourself repeating a tedious task, make a tool!
We want a simple form that fetches the ID, basically
fetch(`https://${server}/api/v2/search?q=@${userName}`)
VSCode + HTML
We use VSCode for all our web development. The features, extensions and speed make it an outstanding text editor.
For example, with emmet built-in you can scaffold an HTML page just by typing ! then tab.
Our entire app HTML is a simple form
<main>
<form action="">
<h1>Find your Mastodon ID</h1>
<label>
Username
<input type="text" placeholder="e.g blackspike" class="username" />
</label>
<label>
Server
<input type="text" placeholder="e.g mastodon.cloud" class="server" />
</label>
<input class="btn" type="submit" value="Get your Mastodon ID" />
<output hidden></output>
</form>
</main>
We don’t often use the <output />
element, but it’s appropriate here.
Live Preview
One of the benefits of using framework like Vue or Astro is that you get Hot Module Reloading (HMR), normally thanks to Vite or WebPack or BrowserSync.
If you’re not using one of those, VS Code has an official Microsoft extension called Live Preview that enables you to see your changes in a browser window within VS Code as you type, for HTML, CSS and JavaScript.
CSS
We’d normally reach for open props for CSS tokens, but this is so simple we won’t even use sass.
The CSS is pretty straightforward, a couple of small notes
Logical Properties
We use logical properties instead of things like width
and height
, preferring inline-size
and block-size
so the page will work better in non-left-to-right languages. Chris Coyier has a great post explaining the details.
Clamp for font-size
font-size: clamp(0.75rem, 0.2rem + 4vw, 1.25rem);
This means the font should at a minimum be .75rem, a maximum of 1.25rem, and ideally, 5% of the device width. Easy responsive text!
Centering with grid
We’ve all seen the memes about how hard it is to center stuff is in CSS. Not in 2023 jackasses!
body {
block-size: 100%;
display: grid;
place-content: center;
}
Done.
Conic gradients
We can use conic gradients across all browsers now, so let us. In fact, let us pinch one from the aforementioned open-props, choose one from open-props.style/#gradients
background-image: conic-gradient(at 125% 50%, rgb(183, 140, 247), rgb(255, 124, 148), rgb(255, 207, 13), rgb(255, 124, 148), rgb(183, 140, 247));
A better box-shadow
You can get better box shadows if you layer them up, they are softer and more natural coloured. Use shadows.brumm.af to generate them for you.
* { box-sizing: border-box; font-family: sans-serif; font-size: 1.25rem; margin: 0; padding: 0; } html { block-size: 100%; background-color: #eee; background-image: conic-gradient(at 125% 50%, rgb(183, 140, 247), rgb(255, 124, 148), rgb(255, 207, 13), rgb(255, 124, 148), rgb(183, 140, 247)); } body { block-size: 100%; display: grid; place-content: center; } h1 { font-size: 1.75rem; letter-spacing: -1px; } form { background-color: #fff; border-radius: clamp(1rem, 5vw, 2rem); box-shadow: 0px 2px 2.2px rgba(0, 0, 0, 0.02), 0px 4.8px 5.3px rgba(0, 0, 0, 0.028), 0px 9px 10px rgba(0, 0, 0, 0.035), 0px 16.1px 17.9px rgba(0, 0, 0, 0.042), 0px 30.1px 33.4px rgba(0, 0, 0, 0.05), 0px 72px 80px rgba(0, 0, 0, 0.07); display: flex; flex-direction: column; gap: 1rem; inline-size: min(90vw, 25rem); padding: clamp(1rem, 5vw, 2rem); } label { display: flex; flex-direction: column; font-size: 0.75rem; font-weight: 700; gap: 0.5rem; text-transform: uppercase; } input, output { background-color: #eee; border-radius: 0.5rem; border: 0; font-size: clamp(0.75rem, 0.2rem + 4vw, 1.25rem); inline-size: 100%; padding: 0.75rem; } output { font-family: 'SF Mono', monospace; text-align: center; } [type='submit'] { background-color: #1e1e1e; color: #fff; } ::placeholder { color: rgb(0 0 0 / 0.2); }
JavaScript
We just need to grab the username and server from two inputs, do a fetch, grab the ID from the returned JSON and either pop it in the output or show an error.
const userName = document.querySelector('.username')
const server = document.querySelector('.server')
const button = document.querySelector('.btn')
const output = document.querySelector('output')
const fetchId = async (e) => {
e.preventDefault()
try {
const getId = await fetch(`https://${server.value}/api/v2/search?q=@${userName.value}`)
const { accounts } = await getId.json()
output.value = accounts[0].id
output.hidden = false
} catch (error) {
console.error(error)
output.value = 'Are your details correct?'
output.hidden = false
}
}
button.addEventListener('click', fetchId)
We use native fetch, arrow functions, async-await, template literals, object destructuring. All the good stuff in ES6.
If you don’t understand these words, we can recommend the excellent ES6 For Everyone course by Wes Bos.
We also don’t use semi-colons to end our lines because we are cool.
Publishing - Easy mode
Publishing - Advanced mode
Meta tags
Add a domain name
If you need web development or an icon for your Mac app - do get in touch!