Need more time

local-first time-management writing unemployment 100daystooffload

It honestly feels like there are not enough hours in the day. I watched a video by Dreams of Code where he talked about Alpine.js. I can’t really remember much about it besides the fact that it has a very descriptive and accurate title. I have proof too! Today I replaced my root github page with an updated start page. This is what I spent my afternoon doing in between looking for jobs. It was a bit like watching Netflix while studying. Which thing are you really doing? Why? Anytime I attempted to do it was because studying wasn’t fun but How I Met Your Mother hadn’t yet ended. Anyways I’ll walk through some of the decisions I made with the first iteration.

Building a Start Page

Here is a snippet from the main script for the page/app:

/**
 * @type {{[category: string]: Array<{name: string, url: string, alt: string, icon?: string}>}}
 */
const data = {
	Custom: [
		{
			name: "omg.lol",
			url: "https://owais.omg.lol",
			alt: "Owais's Page",
			icon: '<i class="i-ri-heart-2-fill"></i>',
		},
		{
			name: "Blog",
			url: "https://desertthunder.dev",
			alt: "Desert Thunder",
			icon: '<i class="i-ri-newspaper-fill"></i>',
		}
	]
}

So here I use JSDoc types because I didn’t feel like dealing with TypeScript today. The point of Alpine is to make interactivity simple, and all I was building was a web page with a few columns of links (I was inspired by this[1]) and a pleasing color scheme[2]. I took this hardcoded array of links and rendered them using the x-for directive. An easy way to loop.

The slightly more challenging aspect of interactivity for me was using the $store magic. Basically I wanted the sidebar visibility to be available globally and spent a long time figuring out why I couldn’t get it to work. It was because you define the initial value of that particular slice with a value, not a function. This, and the dark mode toggle with a little bit of animation are so common in web apps nowadays and its nice that you can just whip it up with a few lines of code.

// The sidebar key added to $store
Alpine.store("sidebar", {
	open: false,
	toggle() {
		this.open = !this.open;
	},
});

// links into a component
Alpine.data("links", () => ({
	byCategory: data,
}));

The sidebar is polished with a few directives added to the markup:

<aside class="fixed top-0 right-0 h-full w-96 md:w-80 bg-gray-800 text-white z-50 flex flex-col p-4 gap-4"
    x-show="$store.sidebar.open"
    x-transition
    x-transition.scale.origin.right
    x-data>
    <section>Sidebar Content</section>
</aside>

The defaults were enough for my purposes. The documentation wisely provides some tailwind specific[3] examples. My favorite thing about tailwind is the LSP. Autocomplete with icon sets is a godsend. Especially with Remix Icon. You can quickly leverage variants of an icon. Here’s how I do hover states with some icons:

<i class="i-ri-spotify-fill hover:i-ri-spotify-line" />

Though more often than not, I want colors to change when an icon is in a button so it’ll look like this:

<button class="group whatever-else-you-put-in-a-button">
    <i class="text-gray-50 i-ri-spotify-fill group-hover:text-gray-500" />
</button>

If not for the LSP, I’d likely have these saved as snippets. I had a lot of fun just playing around with markup today.

Home Cooked Software

This was all inspired by a rabbit hole that Blake sent me on[4]. I didn’t know what a home cooked app was but I like the sentiment. Cooking is a true labor of love and I hope I can provide more joy and show love to people with my work. I’m staring at monospaced fonts all day, may as well bring some warmth to someone’s soul instead of my eye sockets.

Local first software[5], written extensively about by Martin Kleppman (author of Designing Data Intensive Applications), had a talk[6] at their Berlin conference last year about Home Cooked Software and the concept of a barefoot engineers. The central purpose of the talk was to describe the tech savvy programming adjacent person’s new power with tools like v0, ChatGPT, and TLDraw. You probably know a person who doesn’t code but builds the coolest spreadsheets and probably sells notion templates on gumroad. Sometimes they do learn to code but maybe they don’t have to in order to make cool stuff.

This doesn’t really pertain to me. I’m not an amazing engineer. I just do it for the love of the game[7] and can’t use AI autocomplete or AI generated code without getting upset. Robin Sloan’s notes are more in line with how I’d approach this. The key here is really knowing your users. In his notes, one of them is his mother. As I’ve worked on my company’s projects, the best feedback I’ve gotten is from my friends who I know would use my stuff. I’d like for my relationship with users and my community to be a little like that mixed with a cult following (the John Green kind). I feel a lot of joy knowing when someone finds value in my work and it’s a high I chase quite relentlessly.

Thanks for reading.


  1. https://afinestart.me/ by Blake Watson who I discovered googling about some of Alpine’s directives. ↩︎

  2. https://rosepinetheme.com/ Rosé Pine is one of my favorite colorschemes ↩︎

  3. https://alpinejs.dev/directives/transition ↩︎

  4. https://blakewatson.com/journal/alpinejs-for-home-cooked-apps/ ↩︎

  5. https://localfirstweb.dev/ For my money, this is real serverless work. There’s an entire company that recreated Postgres in WASM. How cool is that? ↩︎

  6. https://maggieappleton.com/home-cooked-software Maggie Appleton (who runs the Digital Garden awesome) on Github. ↩︎

  7. Okay not exactly true. I love programming but I would like to contribute to an organization and collaborate with a team again. Email me if you’re hiring or want to collaborate! ↩︎


View this page on GitHub.