feat: a whole bunch of fixes ahead of launch

This commit is contained in:
Devin Haska 2024-03-03 00:27:54 -08:00
parent 01647bf930
commit 8e54b46b6b
48 changed files with 184 additions and 140 deletions

View file

@ -83,6 +83,15 @@ const filterFavourites = (collection) => {
return collection.filter((item) => item.data.favourite);
};
const isOld = (dateArg) => {
const date = dayjs(dateArg);
const now = dayjs();
const diffInYears = now.diff(date, "years");
return diffInYears >= 2;
};
module.exports = {
allTagCounts,
allTags,
@ -91,6 +100,7 @@ module.exports = {
filterCatalogueTags,
filterFavourites,
formatDate,
isOld,
keys,
limit,
organizeByDate,

View file

@ -12,6 +12,7 @@ const {
filterCatalogueTags,
filterFavourites,
formatDate,
isOld,
keys,
limit,
organizeByDate,
@ -39,6 +40,7 @@ module.exports = (eleventyConfig) => {
eleventyConfig.addFilter("filterCatalogueTags", filterCatalogueTags);
eleventyConfig.addFilter("filterFavourites", filterFavourites);
eleventyConfig.addFilter("formatDate", formatDate);
eleventyConfig.addFilter("isOld", isOld);
eleventyConfig.addFilter("keys", keys);
eleventyConfig.addFilter("limit", limit);
eleventyConfig.addFilter("organizeByDate", organizeByDate);

View file

@ -5,32 +5,30 @@ imageCaption: ""
---
{% set filteredTags = tags | filterCatalogueTags %}
{% from "macros/date.njk" import format %}
{% from "macros/utils.njk" import stars %}
<article class="[ catalogue ] [ flow ]">
{% block image %}
{% if image %}
{% image image, imageAlt, imageCaption %}
{% endif %}
{% endblock %}
<section class="[ catalogue-meta ] [ flow ]">
{% block title %}<h1>{{ title }}</h1>{% endblock %}
{% if subtitle %}<h2 class="[ text-fadeText flow-space-0.25 ]">{{ subtitle }}</h2>{% endif %}
{{ tertiary | safe }}
{% if rating %}
<div class="[ flex justify-center ]">
{% from "macros/utils.njk" import stars %}
{{ stars(rating) }}
</div>
<header class="[ flow flow-space-1 ]">
{{ format(page.date) }}
<h1>{{ title }}</h1>
{% if subtitle %}<h2>{{ subtitle }}</h2>{% endif %}
{% if rating %}<div class="[ text-skew ]">{{ stars(rating) }}</div>{% endif %}
{% if tertiary %}
<div class="[ text-skew flow-space-1 line-height-m ]">
{{ tertiary | safe }}
</div>
{% endif %}
{% if filteredTags | length > 0 %}
<ul class="[ categories ] [ cluster justify-center p-0 ]" role="list">
<ul class="[ categories ] [ cluster p-0 flow-space-2 ]" role="list">
{% for tag in filteredTags %}<li class="[ flex gap-0.25 ]">{{ tag }}</li>{% endfor %}
</ul>
{% endif %}
</section>
<hr class="[ my-1.5 ]" />
{% from "macros/date.njk" import format %}
{{ format(page.date) }}
{% block content %}{{ content | safe }}{% endblock %}
</header>
{% if image %}
{% image image, imageAlt, imageCaption, "[ my-3 ]" %}
{% endif %}
{{ content | safe }}
{% if url %}
<a href="{{ url }}" class="[ flex mt-1 items-center gap-0.5 ]" target="_blank" rel="external noreferrer noopener">
{% include "svgs/link.svg" %}{{ linkTitle }}

View file

@ -2,9 +2,9 @@
layout: "layouts/base"
---
{% from "macros/date.njk" import format %}
<article class="[ flow ]">
<header class="[ flow flow-space-1 mb-2 ]">
{% from "macros/date.njk" import format %}
{{ format(page.date) }}
<h1>{{ title }}</h1>
<ul class="[ categories ] [ cluster list-none p-0 ]">

View file

@ -5,6 +5,8 @@ title: About
tags: ["page"]
---
# About me
Hello! Ahoj! Welcome to my site!
My name is **Devin Haska** and this is my little slice of the internet I call home.

View file

@ -5,7 +5,7 @@ author: Cal Newport
isbn: 9780525536512
rating: 4
image: https://cdn.wonderfulfrog.com/digital-minimalism.jpg
tags: ["white guy productivity"]
tags: ["white guy productivity", "technology"]
---
I enjoyed the latter chapters focusing on finding "high quality leisure time". I try to find activities that are creative in the sense that after some time I will have created something.

View file

@ -4,7 +4,7 @@ author: Brené Brown
isbn: 9781473562523
rating: 5
image: https://cdn.wonderfulfrog.com/dare-to-lead.jpeg
tags: ["leadership", "self help"]
tags: ["leadership", "self help", "business"]
---
Really great read. Highlights the importance of empathy and how to develop that skill -- essential not only for leaders but for everyone.

View file

@ -5,7 +5,7 @@ author: Edmond Lau
isbn: 9780996128100
rating: 4
image: https://cdn.wonderfulfrog.com/the-effective-engineer.jpeg
tags: ["leadership", "software development"]
tags: ["leadership", "software development", "technology"]
---
Lots of applicable advice here for anyone working in software engineering. I was excited to apply this to my own workplace, but didn't realize it's harder to apply in agency work than in other fields (and when you are not a lead). Still, we managed to recognize areas where we need improvement.

View file

@ -5,6 +5,7 @@ author: James Clear
isbn: 9780735211292
rating: 5
image: https://cdn.wonderfulfrog.com/atomic-habits.jpeg
tags: ["psychology", "self help"]
---
Great insight into how habits work and how they start. Ideas into how to break undesirable habits and begin good ones. The latter chapter about making it easy resonated with me. It never occurred to me why trying to start a habit with a difficult task leads to quitting fast. Start simple, aim low, build high.

View file

@ -5,6 +5,7 @@ author: Matthew Walker
isbn: 9781501144318
rating: 5
image: https://cdn.wonderfulfrog.com/why-we-sleep.jpeg
tags: ["sleep"]
---
Fell asleep many times reading this, which I believe was part of the author's intent. Incredibly informative in regards to all things sleep. Helpful appendix to summarize the book's contents, and a useful crib sheet to give to others not willing to read the entire book. I feel empowered with new knowledge about sleep and additional reasons to ensure that I sleep more.

View file

@ -4,6 +4,7 @@ author: Neil deGrasse Tyson
isbn: 9780393609394
rating: 2
image: https://cdn.wonderfulfrog.com/astro-in-hurry.jpeg
tags: ["science"]
---
I found it hard to follow at times. It felt like it couldn't decide if it wanted to be a beginners or an advanced book. I have more than a passing fancy when it comes to astrophysics, but sometimes the pure information-dump was just too much. There was a lot of process, and some of it I just plain didn't get. I would still push Stephen Hawking's A Brief History of Time as a primer into the world of astrophysics (and everything in-between). Still, I feel like it serves as a catalyst for more learning.

View file

@ -4,6 +4,7 @@ author: Angie Thomas
isbn: 9780062498533
rating: 5
image: https://cdn.wonderfulfrog.com/the-hate-u-give.jpg
tags: ["fiction", "racism"]
---
A gripping tale. Especially chilling given the current events happening at the time surrounding George Floyd when I read the book. I could not put this book down and read it at virtually any opportunity. It challenged every previously held belief I had about race and the struggles that black people face every day.

View file

@ -5,6 +5,7 @@ author: Desmond Cole
isbn: 9780385686341
rating: 5
image: https://cdn.wonderfulfrog.com/the-skin-were-in.jpeg
tags: ["politics", "canada", "racism"]
---
A pretty damning read on how far Canada has to go on dealing with systemic racism. Like many Canadians, I knew things were bad, but this spelt out how truly bad it is. If the situation in the US was not reason enough to convince me that we need to defund the police, then this is it. While the book was not setting out to necessarily claim this message, that was my own conclusion. The police seemed to be a recurring undercurrent to the issues POC face today.

View file

@ -5,6 +5,7 @@ author: Gay Hendricks
isbn: 9780061735363
rating: 3
image: https://cdn.wonderfulfrog.com/the-big-leap.jpg
tags: ["self help"]
---
These days I would style myself as a recovering addict when it comes to self-help books. There never is (and never was) a single trick to turn my life around. Im increasingly wary of the entire industry, as Im now certain that not everyone is looking to help people out. I think these kinds of books can be helpful as a springboard, but a lot seem to parrot the same advice, only phrased differently using the authors writing style. This book largely seems to follow that trend. Im frankly tired of hearing about how the author overcame adversity when the adversity is so disconnected with what your average person faces. The amount of famous people (read: white billionaires) hes helped is numerous and wants to remind us quite often. I dont care. The author loves to use chirpy terms like “Zone of Genius” non-ironically, and its very grating. These hokey-sounding terms cause me to view their ideas with increased skepticism.

View file

@ -4,6 +4,7 @@ author: Joshua Whitehead
isbn: 9781551527253
rating: 4
image: https://cdn.wonderfulfrog.com/jonny-appleseed.jpeg
tags: ["fictional", "emotional"]
---
Absolutely raw and gripping. Very often uncomfortable.

View file

@ -5,6 +5,7 @@ author: Scott McCloud
isbn: 9780060976255
rating: 5
image: https://cdn.wonderfulfrog.com/understanding-comics.jpg
tags: ["comics", "art", "history"]
---
I debated if this should end up in a different catalogue, but it deserves to be in both, if anything.

View file

@ -5,6 +5,7 @@ author: Victoria Ortiz
isbn: 978054497364
rating: 4
image: https://cdn.wonderfulfrog.com/dissenter-on-the-bench.jpeg
tags: ["biography"]
---
I believe this book is meant for young adults (slash teenagers), but as an ancient man myself at the ripe age of 33 I found it very engaging. It's structured in such a way to give context into each of RBG's many important involvements in the law. It will lead with a relevant case that RBG presided (or represented) and then go back in time to explain her history and reason for her eventual involvement. It's educational and fun to read.

View file

@ -4,6 +4,7 @@ author: Jim Butcher
image: https://cdn.wonderfulfrog.com/jim-butcher-peace-talks.jpeg
isbn: 9780393609394
rating: 2
tags: ["fiction", "fantasy"]
---
I feverishly consumed the entire Dresden series in a few years ago. I thought it was so cool to see a blend of fantasy and real life that didn't seem to exist (as far as I knew). The writing sometimes felt chauvinistic (Dresden himself even admits as much) but I would roll my eyes and plod on.

View file

@ -5,6 +5,7 @@ image: https://cdn.wonderfulfrog.com/9780807041307_p0_v1_s1200x630.jpg
url: https://www.yourfatfriend.com/book
isbn: 9780807041307
rating: 5
tags: ["anti-fat"]
---
This book in combination with the [Maintenance Phase](http://www.maintenancephase.com) podcast has flipped my mindset when it comes to my relationship with my body. I previously believed that weight was something we all had complete control over and could change with diet and exercise. Anyone who was overweight was not trying hard enough.

View file

@ -5,7 +5,7 @@ author: Johann Hari
isbn: 9781526620224
rating: 4
image: https://cdn.wonderfulfrog.com/stolen-focus.jpg
tags: ["focus", "adhd"]
tags: ["focus", "adhd", "psychology"]
---
I found this book mostly interesting and easy to digest. Hari has a writing style that keeps you turning the page.

View file

@ -3,6 +3,7 @@ module.exports = {
tags: "comic",
permalink: "catalogue/comics/{{ page.fileSlug }}/index.html",
eleventyComputed: {
subtitle: (data) => `${data.author} (${data.year})`,
tertiary: (data) =>
`<p class="[ flow-space-0.5 ]"><span class="[ text-fadeText ]">by</span> ${data.author}</p>`,
},
};

View file

@ -1,8 +1,8 @@
---
title: "Super Mario World 2: Yoshi's Island"
subtitle: Super Nintendo
platform: Super Nintendo
image: https://cdn.wonderfulfrog.com/Yoshi's_Island_(Super_Mario_World_2)_box_art.jpg
tags: ["snes", "platformer"]
tags: ["platformer"]
year: 1995
---

View file

@ -1,8 +1,8 @@
---
title: "Majora's Mask 3D"
subtitle: Nintendo 3DS
platform: Nintendo 3DS
image: https://cdn.wonderfulfrog.com/Majora's_Mask_3D_cover.png
tags: ["3ds"]
tags: ["adventure", "single player"]
year: 2015
---

View file

@ -1,8 +1,8 @@
---
title: "Mario & Luigi: Dream Team"
subtitle: Nintendo 3DS
platform: Nintendo 3DS
image: https://cdn.wonderfulfrog.com/MarioLuigiDreamTeam.jpg
tags: ["3ds"]
tags: ["rpg", "turn based", "single player"]
year: 2013
---

View file

@ -1,8 +1,8 @@
---
title: "Donkey Kong Country: Tropical Freeze"
subtitle: Nintendo Wii U
platform: Nintendo Wii U
image: https://cdn.wonderfulfrog.com/DKC5_box_art.jpg
tags: ["wii u"]
tags: ["platformer", "challenging", "single player", "multiplayer"]
year: 2014
---

View file

@ -1,8 +1,8 @@
---
title: "Professor Layton vs. Phoenix Wright: Ace Attorney"
subtitle: Nintendo 3DS
platform: Nintendo 3DS
image: https://cdn.wonderfulfrog.com/Laytonvsaceattorneycover.jpg
tags: ["3ds"]
tags: ["puzzle", "narrative", "visual novel", "single player"]
year: 2014
---

View file

@ -1,8 +1,8 @@
---
title: "The Wonderful 101"
subtitle: Nintendo Wii U
platform: Nintendo Wii U
image: https://cdn.wonderfulfrog.com/Wonderful_101_box_artwork.jpg
tags: ["wii u", "action"]
tags: ["action", "beat em up", "single player"]
year: 2013
---

View file

@ -1,8 +1,8 @@
---
title: Fallout 4
subtitle: PC
platform: PC
image: https://cdn.wonderfulfrog.com/Fallout_4_cover_art.jpg
tags: ["pc", "role-playing", "action"]
tags: ["rpg", "action", "single player"]
year: 2015
---

View file

@ -1,8 +1,8 @@
---
title: "Persona 3 Portable"
subtitle: PlayStation Portable
platform: PlayStation Portable
image: https://cdn.wonderfulfrog.com/p3p.jpg
tags: ["psp", "persona"]
tags: ["rpg", "turn based", "persona", "single player"]
youtube: true
year: 2009
---

View file

@ -1,8 +1,8 @@
---
title: Shovel Knight
subtitle: Nintendo Wii U
platform: Nintendo Wii U
image: https://cdn.wonderfulfrog.com/Shovel_knight_cover.jpg
tags: ["wii u"]
tags: ["platformer", "retro", "single player"]
year: 2014
---

View file

@ -1,8 +1,8 @@
---
title: Tomb Raider
subtitle: PC
platform: PC
image: https://cdn.wonderfulfrog.com/TombRaider2013.jpg
tags: ["pc"]
tags: ["action", "adventure", "puzzle", "reboot", "single player"]
year: 2013
---

View file

@ -1,8 +1,8 @@
---
title: "Assassin's Creed IV: Black Flag"
subtitle: PlayStation 3
platform: PlayStation 3
image: https://cdn.wonderfulfrog.com/Assassin's_Creed_IV_-_Black_Flag_cover.jpg
tags: ["ps3"]
tags: ["action", "adventure", "single player"]
year: 2013
---

View file

@ -1,8 +1,8 @@
---
title: DOOM
subtitle: PC
platform: PC
image: https://cdn.wonderfulfrog.com/Doom_Cover.jpg
tags: ["pc"]
tags: ["action", "fps", "retro shooter", "single player"]
year: 2016
---

View file

@ -1,8 +1,8 @@
---
title: Hyper Light Drifter
subtitle: PC
platform: PC
image: https://cdn.wonderfulfrog.com/HyperLightDrifterBoxArt.png
tags: ["pc"]
tags: ["action", "hack and slash", "retro", "indie", "open world", "single player"]
year: 2016
---

View file

@ -1,8 +1,8 @@
---
title: Vanquish
subtitle: PlayStation 3
platform: PlayStation 3
image: https://cdn.wonderfulfrog.com/PG_Vanquish_box_artwork.png
tags: ["ps3"]
tags: ["action", "platinum", "shooter", "single player"]
year: 2010
---

View file

@ -1,7 +1,7 @@
---
title: Persona 5
subtitle: PlayStation 4
platform: PlayStation 4
image: https://cdn.wonderfulfrog.com/Persona_5_cover_art.jpg
tags: ["ps4"]
tags: ["rpg", "turn based", "single player", "persona"]
year: 2016
---

View file

@ -1,7 +1,7 @@
---
title: Axiom Verge
subtitle: Nintendo Switch
platform: Nintendo Switch
image: https://cdn.wonderfulfrog.com/Axiom_Verge_Title.png
tags: ["switch"]
tags: ["action", "metroidvania", "indie", "single player"]
year: 2015
---

View file

@ -2,7 +2,7 @@
title: Her Story
platform: PC
image: https://cdn.wonderfulfrog.com/Her_Story_store_art.jpg
tags: ["pc", "narrative", "simulator"]
tags: ["pc", "narrative", "simulator", "indie", "single player"]
year: 2015
---

View file

@ -1,8 +1,8 @@
---
title: "Middle-earth: Shadow of Mordor"
subtitle: PC
platform: PC
image: https://cdn.wonderfulfrog.com/Shadow_of_Mordor_cover_art.jpg
tags: ["pc"]
tags: ["action", "nemesis system", "hack and slash", "single player", "open world"]
year: 2014
---

View file

@ -1,8 +1,8 @@
---
title: Citizen Sleeper
subtitle: PC
platform: PC
image: https://cdn.wonderfulfrog.com/Citizen_Sleeper_cover_art.jpg
tags: ["pc"]
tags: ["narrative", "visual novel", "indie", "rpg", "single player"]
year: 2022
rating: 4
---

View file

@ -3,6 +3,6 @@ module.exports = {
tags: "game",
permalink: "catalogue/games/{{ page.fileSlug }}/index.html",
eleventyComputed: {
subtitle: (data) => data.year,
subtitle: (data) => `${data.platform}`,
},
};

View file

@ -4,19 +4,13 @@
gap: var(--spacing-1);
}
.catalogue-list-item a {
display: block;
.catalogue h2 {
--flow-space: var(--spacing-0\.5);
transform: var(--text-skew);
color: var(--color-fadeText);
}
.catalogue source,
.catalogue img {
max-width: 300px;
}
.catalogue h1 {
transform: none;
}
.catalogue-meta {
text-align: center;
}

View file

@ -4,3 +4,7 @@
drop-shadow(0 -1px 0 var(--color-white))
drop-shadow(0 1px 0 var(--color-white));
}
.menu > li:has(a:focus-visible) {
filter: none;
}

View file

@ -5,6 +5,7 @@
}
.site-logo .logo img {
user-select: none;
filter: drop-shadow(0 1px 0 var(--color-white))
drop-shadow(1px 0 0 var(--color-white))
drop-shadow(-1px 0 0 var(--color-white))

View file

@ -34,7 +34,7 @@ h1 {
font-weight: var(--font-weight-display-extrabold);
letter-spacing: -0.05rem;
line-height: 3rem;
transform: skew(0deg, -1deg);
transform: var(--text-skew);
}
h2 {
@ -102,7 +102,7 @@ blockquote > * + * {
:focus-visible {
outline: 3px solid;
outline-color: var(--color-primary);
outline-color: var(--color-text);
outline-offset: 0.3ch;
}
@ -125,10 +125,6 @@ hr {
:not(pre) > code {
background-color: var(--color-surface);
color: var(--color-primary);
border-color: var(--color-border);
border-style: solid;
border-width: 1px;
border-radius: 0.5em;
padding-block: 0.15em;
padding-inline: 0.25em;

View file

@ -6,5 +6,7 @@
--color-white: white;
--color-black: black;
--text-skew: skew(0deg, -1deg);
--triangles: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 80"><path stroke-width="0" d="M0,0 40,40 80,0z" /></svg>');
}

View file

@ -33,3 +33,7 @@
.line-height-xl {
line-height: 2rem;
}
.text-skew {
transform: var(--text-skew);
}

View file

@ -15,7 +15,7 @@ Ive had a Figma file ready for months now that outlined my basic design - all
{% image "https://cdn.wonderfulfrog.com/figma-v3.png", "A screenshot from Figma showing my blog prototype. There are various elements visible like buttons and widgets. A colour scheme using teal.", "Figma screenshot" %}
{% image "https://cdn.wonderfulfrog.com/figma-v3-lightmode.png", "Another screenshot from Figma showing my blog prototype. This is showing the 'light theme' with a serif title font, monospaced body font, and teal accent colours.", "Astute observers will notice the current version doesn't look a whole lot like the site now!" %}
{% image "https://cdn.wonderfulfrog.com/figma-v3-lightmode.png", "Another screenshot from Figma showing my blog prototype. This is showing the 'light theme' with a serif title font, monospaced body font, and teal accent colours.", "Astute observers will notice the site you're looking at doesn't look a whole lot like the design!" %}
Something that always frustrated me was having my content along the code. I sought out a solution for this for months. I tried a whole bunch of headless CMS options like [Sanity](https://www.sanity.io/), [Hygraph](https://hygraph.com/), [Ghost](https://ghost.org/), and even hosting my own [WordPress](https://wordpress.com) (that was an exciting prospect until I discovered their mobile app does not support plugins).
@ -23,7 +23,7 @@ I was always paranoid that bad actors would clone my git repo and steal my conte
One day I thought to myself “who cares?” and it was like a switch flipped. Bad actors can still copy and paste everything, so having the content off the repo makes little difference. LLMs are exploding and would make it trivial to scrape my site (if they wanted to).
At last, that let me narrow down my options. Ill just keep the text content in the repo. But I still wanted a way to store images and other large media outside of the repo (more on that later. )
At last, that let me narrow down my options. Ill just keep the text content in the repo. But I still wanted a way to store images and other large media outside of the repo (more on that later).
If the text content can be in the repo, then I can use anything! So lets stick with [Next.js](https://nextjs.org/)! … actually, lets not.
@ -33,9 +33,9 @@ Anyone working in the web dev sphere knows things move fast. Too fast these days
I tried to migrate to the new [app router structure](https://nextjs.org/docs/app) and found myself getting stuck learning about breaking changes in Next.js and breaking changes in React[^1]. I spent way too much time trying to get things working with my tools that I didnt stop and think that my tools should be working for me.
I was originally thinking of [Astro](https://astro.build/), but its still using React. Im happy to use React for work but I dont want to have to deal with its newest idiosyncrasies in my own stuff.
As an alternative, I was thinking of using [Astro](https://astro.build/), but its still React under the hood. Im happy to use React for work but I dont want to have to deal with its newest idiosyncrasies in my own stuff.
Simply put modern React confuses the hell out of me. Im not all in for [“server vs client components”](https://nextjs.org/learn/react-foundations/server-and-client-components). Im certainly not the only one[^4]. I don't want this post to digress into my thoughts on modern React so I'm going to sidestep that for now. Im spending time wrapping my head around modern React - because I have to for my job - but for my personal site I'd rather things should be _easy._ I'm tired of having to deal with breaking changes all the time. I longed for the days of PHP where stuff just worked forever. It was time to embrace an old foe: boring technology.
Simply put modern React confuses the hell out of me. Im not all in for [“server vs client components”](https://nextjs.org/learn/react-foundations/server-and-client-components). Im certainly not the only one[^4]. I don't want this post to digress into my thoughts on modern React so I'm going to sidestep that for now. I am forced to learn its newest architecture for work, but for my personal site I'd rather things be <mark>easy</mark>. I'm tired of having to deal with breaking changes all the time. I longed for the days of PHP where stuff just worked forever. It was time to embrace an old foe: boring technology.
Boring technology - to me, anyway - is something thats been around for a while, probably a few years. Its stable. Its been around long enough that someone has asked the basic questions on how to do XYZ on StackOverflow. And something important to me is that its also *averse to breaking changes*. It tries its best to avoid them, and if they must then there is a clear migration path and plenty of warning.
@ -90,13 +90,24 @@ A methodology that resonated with me was [CUBE CSS](https://cube.fyi/). CUBE sta
I organized everything following this methodolgy, and added a `global.css` file that ties everything together with `@import`and `@import-glob` statements. I used PostCSS to process the CSS into a single file.
In order to include my CSS generation as part of 11ty's build process, I used a JavaScript [Template Data File](https://www.11ty.dev/docs/data-template-dir/) that processes the CSS using PostCSS, and the data file renames the file using the `permalink` property in the frontmatter. It leads to a single `style.css` that has everything I need - nice and clean, and no extra `npm` task required.
For my design tokens, I use a handful of JavaScript files to assemble my JSON design tokens into CSS strings. That leaves me with two chunks of CSS - my design tokens, and site CSS that uses those design tokens.
As part of my CSS build process, I inject my design tokens into the generated CSS from `global.css`. It's not the most elegant way I'm sure, but it works fine. Speaking of design tokens...
I used a JavaScript [Template Data File](https://www.11ty.dev/docs/data-template-dir/) (`css/styles.11tydata.js`) that assembles all of my CSS into one giant string, run it through PostCSS (which includes some extra plugins), and then data file renames the file using the `permalink` property in the frontmatter. It leads to a single `style.css` that has everything I need - nice and clean, and no extra `npm` task required.
# Reinventing the wheel
What PostCSS plugins am I using? The following:
I like Tailwind - especially for work - but I think it comes in heavy-handed. It does a lot, and I don't need the majority of it. I've seen some developers strip away everything but the design system that Tailwind provides out of the box, and I thought about doing that... but what if I did it myself instead?
- [`postcss-import`](https://github.com/postcss/postcss-import) - Any `@import` statements are replaced with the file being imported.
- [`postcss-import-ext-glob`](https://github.com/dimitrinicolas/postcss-import-ext-glob) - Like using `@import` but with glob file paths. More of a developer convenience.
- [`autoprefixer`](https://github.com/postcss/autoprefixer) - Not as essential these days, but there are still some vendor-prefixed CSS rules.
- [`cssnano`](https://github.com/cssnano/cssnano) - Minifies my CSS, and fast.
Combining two CSS strings is perhaps not the most efficient way of doing things, but it makes sense to me and seems fast enough.
Let's take a walk through how my design tokens work!
## Reinventing the wheel
I like Tailwind - especially for work - but I think it comes in heavy-handed. It does a lot, and I don't need the majority of it. I've seen some developers strip away everything but the design system that Tailwind provides out of the box, and I thought about doing that... but what if I built my own solution instead?
Tailwind is yet another dependency. If I only need a small subset of its feature-set, why should I have to spend developer-hours stripping away everything I don't need and instead solve the problem myself with less code?
@ -155,55 +166,47 @@ const helperClasses = [
];
```
I run this array through a `helperClassesToCss` function I wrote, which takes the helper class prefix, appends the colour name (e.g. `primary`) to the prefix, and sets the array of CSS properties to the desired value. If you're curious, here is the full source code with comments:
I run this array through a `helperClassesToCss` function I wrote, which takes the helper class prefix, appends the colour name (e.g. `primary`) to the prefix, and sets the array of CSS properties to the desired value.
### A walkthrough
I wanted to run through an example process from JSON to CSS and how it works - hopefully I can refer to this in the future if I ever forget how the process works.
To start, `cssPropertiesToCss` takes an array of CSS rules and sets them to the same `value`. For example:
```js
/**
* Given an array of CSS properties, output css properties
* with each property equal to `value`
*/
const cssPropertiesToCss = (cssProperties, value) => {
return cssProperties.reduce((css, cssProp) => {
return css + `${cssProp}:${value};`;
}, ``);
};
/**
* Given a helperClass (string) and array of cssProperties,
* will generate a css class named helperClass that has
* all cssProperties mapped to value.
*/
const helperClassToCss = (helperClass, cssProperties, value) => {
const cssProps = cssPropertiesToCss(cssProperties, value);
return `.${helperClass}{${cssProps}}`;
};
/**
* Given an array of helperClasses that map to cssProperties,
* output a string of CSS that maps the helperClass (with variant modifier)
* to the array of css properties with each css property equal to
* value
*
* e.g.
* helperClasses = [["text", ["color"]]],
* variant = "primary",
* value = "#000"
*
* Will output the following:
* .text-primary {
* color: #000;
* }
*/
const helperClassesToCss = (helperClasses, variant, value) => {
return helperClasses.reduce((css, [helperClass, cssProperties]) => {
return (
css + helperClassToCss(`${helperClass}-${variant}`, cssProperties, value)
);
}, ``);
};
const cssProperties = ["margin-left", "margin-right"];
const value = "16px";
const css = cssPropertiesToCss(cssProperties, value);
// css = "margin-left:16px;margin-right:16px;";
```
`cssPropertiesToCss` uses the `.reduce()` function to transform the array of properties into a string by concatenating each item in the array together.
`helperClassToCss` takes the generated CSS string and wraps it with a CSS selector `helperClass`.
```js
const cssProperties = ["margin-left", "margin-right"];
const value = "16px";
const helperClass = "mx-1";
const helperClassCss = helperClassToCss(helperClass, cssProperties, value);
// helperClassCss = ".mx-1{margin-left:16px;margin-right:16px;}"
```
Finally, `helperClassesToCss` ties everything together to make adding new classes and variants easy.
```js
const helperClasses = [["mx", ["margin-left", "margin-right"]], ["my", ["margin-top", "margin-bottom"]]];
const variant = "1";
const value = "16px";
const helperClassesToCss = (helperClasses, variant, value);
// helperClassesToCss = ".mx-1{margin-left:16px;margin-right:16px}.my-1{margin-top:16px;margin-bottom:16px}"
```
It might not be the best, but it makes sense to me!
All of my code related to generating CSS from design tokens uses nothing but plain JavaScript and built-in modules (I think the only one being `path`). I'll never have to worry about my build process breaking. All of my design tokens are JSON. If I ever need to tweak them, the only thing I need to change is a couple of JSON files!
It took me a fair while to write, and certainly some trial and error, but I'm quite pleased with the final outcome. I can shunt this output into any CSS or future project if I want. If I want more helper classes, it's very easy to add more. There are quite a few spacing helpers:
@ -251,11 +254,13 @@ Yep, that's it. It uses a fancy wildcard selector (`* + *`) to achieve the effec
What ends up happening is if you have a bunch of headers and paragraph tags on the page, this one single class styles it up perfectly so that it looks readable and beautiful. No extra work required, because the spacing value is `1em` it will use whatever the current child's `font-size` is. How freakin' cool is that?! I love it.
# Speaking of Cascade... The Data Cascade
Utilities like this are a big part of the principles behind [Build Excellent Websites](https://buildexcellentwebsit.es/). "Be the browser's mentor, not its micromanager." Highly recommend watching [Andy Bell's keynote](https://www.youtube.com/watch?v=5uhIiI9Ld5M) on the subject.
[The Data Cascade](https://www.11ty.dev/docs/data-cascade/) is what I would consider to be 11ty's killer feature (like a [killer app](https://en.wikipedia.org/wiki/Killer_application)). In short, it allows for injecting data (or assembling data) practically anywhere, and rely on context in order to drive where that data goes.
## Speaking of Cascade... The Data Cascade
The simplest data source would be front matter - the data that lives at the top of Markdown files. The neat part is that front matter can be added to non-Markdown files too, which allows for some potential fun stuff.
[The Data Cascade](https://www.11ty.dev/docs/data-cascade/) is what I would consider to be 11ty's killer feature (like a [killer app](https://en.wikipedia.org/wiki/Killer_application)). In short, it allows for injecting (or assembling) data practically anywhere, and rely on context in order to drive where that data goes.
The simplest data source would be frontmatter - the data that lives at the top of Markdown files. The neat part is that frontmatter can be added to non-Markdown files too, which allows for some potential fun stuff.
For example, my catalogue content is inside `/catalogue`. Inside that folder are more subfolders, and a [template data file](https://www.11ty.dev/docs/data-template-dir/) for the folder called `catalogue.json`. It looks like this:
@ -288,10 +293,12 @@ Lets go through this one:
- Every file inside uses the `layouts/catalogue-item` layout
- Applies the `book` tag (and therefore generates a new collection, automatically)
- Creates a permalink using the `fileSlug` variable per page
- Changes the `linkTitle` front matter
- Uses `eleventyComputed` (which is a special field) to inject data from the Markdown file
- Changes the `linkTitle` frontmatter
- Uses `eleventyComputed` (which is a special field) to inject frontmatter into the template's frontmatter
That's a lot! I'd like to turn your attention to the `permalink` variable. By using just this alone, 11ty will automatically generate HTML pages for each of my Markdown files inside this directory and pass in the front matter I set here. With just one line of code! What?! That's awesome!!
Highly suggest reading the docs on [Computed Data](https://www.11ty.dev/docs/data-computed/).
That's a lot! I'd like to turn your attention to the `permalink` variable. By using just this alone, 11ty will automatically generate HTML pages for each of my Markdown files inside this directory and pass in the frontmatter I set here. With just one line of code! What?! That's awesome!!
At this point all I have to do is make sure I have a layout file defined and built the way I like... and 11ty takes care of the rest. Love this!
@ -341,7 +348,7 @@ For now I'm content to trigger a build every so often in order for the data to b
## Alert the media
This was a thorny issue for me. I couldn't decide on how I wanted to manage media storage for a while. All I knew for certain was that I was tired of keeping it in my repo - it needed to be elsewhere.
Media storage was still a thorny issue. I couldn't decide on how I wanted to manage it for a while. All I knew for certain was that I was tired of keeping it in my repo - it needed to be elsewhere.
As I dug into 11ty, I discovered a truly magical plugin called [`eleventy-img`](https://www.11ty.dev/docs/plugins/image/). It takes an image (either locally or remote), optimizes it, and stores it in the _output_ directory. The image can therefore be put anywhere you like, and with a small bit of shortcode it works like magic. For example:
@ -353,7 +360,7 @@ It's a little bit of extra syntax compared to a Markdown image (and the newest v
That left the final question - where do I keep my media? I eventually settled on [Bunny.net](https://bunny.net/) - simple, no-nonsense storage with clear pricing. Has a REST API for uploading images, and even works with SFTP.
I decided to do the painstaking process of manually updating all of my content by myself rather than automating it. I figured the time investment of an automated solution would be roughly equal to the time it would take to do manually. Regardless, all my media is now behind a robust CDN (and with a custom domain too). When my site is built, 11ty will fetch all those images and generate local copies that are resized and output using `srcset`. It's all so seamless and easy, and `eleventy-image` even caches the results so subsequent re-builds are super fast!
I decided to do the painstaking process of manually updating all of my content by myself rather than automating it. I figured the time investment of an automated solution would be roughly equal to the time it would take to do manually. Regardless, all my media is now behind a robust CDN (and with a custom domain too). When my site is built, 11ty will fetch all those images and generate local copies that are resized and output using `srcset`. It's all so seamless and easy, and `eleventy-img` even caches the results so subsequent re-builds are super fast!
## Other organizational details
@ -394,6 +401,12 @@ I'm also using the [`@11ty/eleventy-plugin-rss`](https://www.11ty.dev/docs/plugi
[Shortcodes](https://www.11ty.dev/docs/shortcodes/) are cool. They're like custom Markdown but supercharged. I have my aforementioned `image` shortcode, and another for embedding YouTube videos using [`lite-youtube`](https://github.com/justinribeiro/lite-youtube).
Here is an example of the YouTube shortcode:
```
{% raw %}{% youtube "Video ID", "Video Title" %}{% endraw %}
```
### Transforms
[Transforms](https://www.11ty.dev/docs/config/#transforms) are great for modifying the template output. I only have one which minifies the HTML output using [`html-minifier-terser`](https://github.com/terser/html-minifier-terser).
@ -423,6 +436,10 @@ I use the [`netlify-plugin-cache`](https://github.com/jakejarvis/netlify-plugin-
Whenever a change is detected on the `main` branch, a new version is deployed automatically.
## Accessibility
I tried hard to ensure that my site is fully accessible. I'm still learning how to properly test this - automated tools can only go so far - so if I missed something obvious [please tell me]({{ meta.social.mastodon }})!
## Conclusion
That was a lot, but I covered everything! I hope.
@ -437,6 +454,8 @@ This has been a long (but fun) project, and I'm glad it's done. Now time to prod
If you'd like to view the source for my website, it's [available here](https://github.com/wonderfulfrog/wonderfulfrog.com)!
If you have any questions, please [reach out to me on Mastodon]({{ meta.social.mastodon }})!
Here are some resources I used (likely heavily) while building the site.
### Inspiration