🏗 Restructure project, change font to Maple Mono

This commit is contained in:
2025-08-29 12:37:17 -04:00
parent 0733e44d8b
commit b8445f4a1b
63 changed files with 1522 additions and 842 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

After

Width:  |  Height:  |  Size: 2.7 MiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before

Width:  |  Height:  |  Size: 386 B

After

Width:  |  Height:  |  Size: 386 B

Before

Width:  |  Height:  |  Size: 619 B

After

Width:  |  Height:  |  Size: 619 B

Before

Width:  |  Height:  |  Size: 630 B

After

Width:  |  Height:  |  Size: 630 B

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before

Width:  |  Height:  |  Size: 439 B

After

Width:  |  Height:  |  Size: 439 B

+1 -1
View File
@@ -1,7 +1,7 @@
---
import { Image } from 'astro:assets';
import portrait from '../img/portrait.jpg';
import portrait from '../assets/portrait.jpg';
interface Props {
size: number;
+2 -2
View File
@@ -1,7 +1,7 @@
---
import { format, add } from 'date-fns';
import CalendarIcon from '../img/svg/calendar.svg';
import CalendarIcon from '../assets/svg/calendar.svg';
interface Props {
title: string;
@@ -17,7 +17,7 @@ const { title, date, slug } = Astro.props;
{slug ? <a href={`/blog/${slug}`}>{title}</a> : title}
</h2>
<div>
<CalendarIcon class="calendar-icon" size={24} />
<CalendarIcon class="calendar-icon" width={24} height={24} />
{format(add(new Date(date), { hours: 6 }), 'MMM do, y')}
</div>
</div>
+7 -2
View File
@@ -1,5 +1,5 @@
---
import RssIcon from '../img/svg/rss.svg';
import RssIcon from '../assets/svg/rss.svg';
const year = new Date().getFullYear();
---
@@ -13,12 +13,17 @@ const year = new Date().getFullYear();
<p>
<a href="/rss.xml"
><RssIcon class="rss-icon" size={20} /> Subscribe with RSS</a
><RssIcon class="rss-icon" width={20} height={20} /> Subscribe with RSS</a
>
</p>
</footer>
<style>
footer {
margin: 4rem 0;
text-align: center;
}
.rss-icon {
transform: translateY(0.18rem);
}
+34 -12
View File
@@ -20,15 +20,10 @@ const pathComponents = pathname.split('/').slice(1);
---
<header>
<div>
{
pathComponents[0] !== '' ? (
<a href="/" transition:name="my-avatar">
<Avatar size={60} />
</a>
) : null
}
</div>
<a href="/">
<Avatar size={60} />
</a>
<nav>
{
navLinks.map((link) => (
@@ -36,9 +31,7 @@ const pathComponents = pathname.split('/').slice(1);
<a href={`/${link.path}`}>
<span>{link.label}</span>
</a>
{pathComponents[0] === link.path ? (
<div class="underline" transition:name="menu-selection-indicator" />
) : null}
{pathComponents[0] === link.path ? <div class="underline" /> : null}
</li>
))
}
@@ -46,6 +39,35 @@ const pathComponents = pathname.split('/').slice(1);
</header>
<style>
header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
height: 120px;
}
header > h1 > a {
color: var(--text);
}
header > nav {
display: flex;
flex-direction: row;
list-style: none;
gap: 20px;
font-size: 1.15rem;
}
header > nav > li > a:hover {
text-decoration: none;
}
header > nav > li > .selected {
font-weight: bold;
}
.underline {
height: 2px;
width: 100%;
+1 -1
View File
@@ -19,7 +19,7 @@ const { post } = Astro.props;
const { data, slug } = post;
---
<article transition:name={slug}>
<article>
<BlogHeader title={post.data.title} date={data.pubDate} slug={slug} />
<Tags tags={data.tags} />
</article>
+6 -3
View File
@@ -9,9 +9,12 @@ const { tags } = Astro.props;
<span>
{
tags.sort().map((tag: string, index: number) => (
<a class="tag" href={`/blog/archive/${tag}`}>
{`${tag}${index < tags.length - 1 ? ', ' : ''}`}
</a>
<>
<a class="tag" href={`/blog/archive/${tag}`}>
{tag}
</a>
{index < tags.length - 1 ? ' | ' : ''}
</>
))
}
</span>
@@ -12,7 +12,7 @@ I decided to use [OpenAI](https://openai.com/) for the written portion, and [Eve
I decided against using AI generated images because, even though Im letting an AI create a dating profile for me, I want it to be somewhat genuine. Also Im not looking to catfish anybody with this image I generated just to see how good AI could make me look:
<img src="/media/my-ai-portrait.jpg" width="260" alt="an AI-generated portrait of me" />
![An AI-generated portrait of me](src/assets/blog/my-ai-portrait.jpg)
Originally this was going to be one post Id write over the course of a week, but as I was writing I decided I should split it into 2 parts: Part 1, this part, about setting up the dating profile, and part 2, coming at the end of the experiment, about the experience and how it went.
@@ -10,13 +10,13 @@ But I did find a rather salty post I wrote about a Mac theme I created back when
If you were around the Mac customization scenespecifically on the now-defunct MacThemes.netaround 2007, you probably remember a little project called iLeopard. Admittedly, the chance that youre in that extremely specific niché is incredibly small. The best data I could find is this [Ars Technica article](https://arstechnica.com/gadgets/2007/03/7296/) from March 2007 saying the Mac hit about 6% marketshare. And only a tiny subset of those users even had the thought that customizing the look of Mac OS X was something they wanted to do.
<img src="/media/ileopard/mac-os-10-1.png" width="90%" alt="a screenshot of Mac OS X 10.1 with various apps open" />
![a screenshot of Mac OS X 10.1 with various apps open](src/assets/blog/ileopard/mac-os-10-1.png)
*Mac OS X 10.1 and the Aqua Interface, from* [_GUIdebook_](https://guidebookgallery.org/screenshots/macosx101)
I was one of the few that had that had that idea pop into my head. I was super into finding and downloading cool themes, including one I distinctly remember that looked like Windows Vista for some reason. It was 2007, the Aqua Interface (the playful, plastic-looking interface style Apple used for about a decade) was already feeling a little passé to me. I wanted something new, and weirdly enough that new thing came from Apple, in the form of iTunes 7.
<img src="/media/ileopard/itunes-7.gif" width="80%" alt="a screenshot iTunes 7 with the iTunes Music Store open" />
![a screenshot iTunes 7 with the iTunes Music Store open](src/assets/blog/ileopard/itunes-7.gif)
_iTunes 7 screenshot, from [AppleInsider](https://appleinsider.com/articles/06/09/12/apple_introduces_itunes_7_previews_itv_device)_
@@ -40,7 +40,7 @@ Being that I was a bored teenager in high school with way too much time on my ha
After dozens of restarts, and a couple corrupted OS installs, I had figured out a good chunk of the building blocks making up Leopards UI. Even still, after weeks of this, there was still so much to be done. Bear in mind, there was no documentation on any of this stuff. I was about to create, as far as I know, the first theme for Mac OS X Leopard.
<img src="/media/ileopard/ileopard-2-0-1.png" width="75%" alt="a screenshot of the Mac OS X Appearance preference pane showing off the modifications made by iLeopard" />
![a screenshot of the Mac OS X Appearance preference pane showing off the modifications made by iLeopard](src/assets/blog/ileopard/ileopard-2-0-1.png)
_iLeopard 2.0.1 screenshot, from [AmazingHenry on MacRumors](https://forums.macrumors.com/threads/ileopard-theme.2045553/), released by fellow MacThemes.net user gcamp' after I essentially handed off the project_
+3 -3
View File
@@ -12,17 +12,17 @@ I've never been a Gundam fan, the genre just never really appealed to me. But I
So, there was a little anime I watched back in high school called [Full Metal Panic](https://en.wikipedia.org/wiki/Full_Metal_Panic!) which, like Gundam, features people piloting giant mecha. As luck would have it, Bandai, the makers of Gunpla kits, have/had the license to make kits for the series. Not-so-luckily, the kit I wanted based on the main character's mech is impossible to find at a reasonable price at the moment, so I settled for my second pick:
<img src="/media/gunpla/box.jpg" width="90%" alt="a box sitting on a table with an image of a mech and text that reads 'M9 Gernsback ver IV (Agressor Squadron)'" />
![a box sitting on a table with an image of a mech and text that reads 'M9 Gernsback ver IV \(Agressor Squadron)'](src/assets/blog/gunpla/box.jpg)
So, with the kit in hand, I opened the box and was greeted by a handful of plastic pouches containing what seemed like a thousand parts connected on plastic sprues in a variety of blues and grays. I took out the contents and perused through the included instructions, which read very much like it was designed by Ikea, if Ikea sold miniature giant robots. The writing was all in Japanese, but the illustrations were enough to guide one through the process no matter what language they can read.
<img src="/media/gunpla/all-the-parts.jpg" width="90%" alt="neatly piled plastic sprues sorted by color, an instruction booklet, and a model of R2-D2 lurking in the corner" />
![neatly piled plastic sprues sorted by color, an instruction booklet, and a model of R2-D2 lurking in the corner](src/assets/blog/gunpla/all-the-parts.jpg)
Separating the individual pieces from each sprue was pretty painless. They came off very cleanly and I barely had to use my handy hobby knife to clean up bits of excess plastic, and when I did it cut through like butter. Not a drop of glue was needed, everything snapped together perfectly. I struggled a bit with the smaller parts (of which there were plenty), and there were a couple seemingly microscopic stickers I had to apply, so my iFixIt tweezers came in handy quite a few times.
After a couple hours, I had a pretty sweet looking miniature mecha.
<img src="/media/gunpla/final.jpg" width="90%" alt="the finished model, standing tall, and holding a scary looking gun" />
![the finished model, standing tall, and holding a scary looking gun](src/assets/blog/gunpla/final.jpg)
Putting it together, I was just so amazed by the level of engineering that went into this kit. Putting it all together, I could tell someone put a lot of care and attention into designing this thing, rivaling some of the Lego kits I've built, from the near-seamless fit of all the pieces, to the various types of joints enabling a quite frankly insane level of pose-ability for something this size.
@@ -32,11 +32,11 @@ Once both MUI Base and Tailwind are installed, we next need to run `yarn tailwin
First thing's first, open up the project folder in your code editor of choice and at the root of the project you should see the 'tailwind.config.js' we created in step 2. Open that, and under `module.exports` you should see an empty array named 'content'. Add the following to the array: `'./src/**/*.{js,jsx,ts,tsx}'` Your config file should look like this:
<img src="/media/mui-plus-tailwind/tailwind-config.png" width="80%" alt="module.exports = { content: ['./src/**/*.{js,jsx,ts,tsx}'], theme: { extend: {}, }, plugins: [],};">
<img src="src/assets/blog/mui-plus-tailwind/tailwind-config.png" width="80%" alt="module.exports = { content: ['./src/**/*.{js,jsx,ts,tsx}'], theme: { extend: {}, }, plugins: [],};">
Next, we need to import Tailwind into our 'globals.css' file, which is located in 'src/styles/'. We can delete everything in the file as we won't be needing any of it. Then, add the following:
<img src="/media/mui-plus-tailwind/global-css.png" width="80%" alt="@tailwind base; @tailwind components; @tailwind utilities;">
<img src="src/assets/blog/mui-plus-tailwind/global-css.png" width="80%" alt="@tailwind base; @tailwind components; @tailwind utilities;">
And that's it! We're ready to start creating something!
@@ -46,7 +46,7 @@ Ideally, we'd want to create smaller, reusable component files, but that's beyon
First, we should delete everything we don't need so that our 'index.js' file looks like this:
<img src="/media/mui-plus-tailwind/index-js.png" width="80%" alt="export default function Home() { return() }">
<img src="src/assets/blog/mui-plus-tailwind/index-js.png" width="80%" alt="export default function Home() { return() }">
We're going to create a simple button, nothing too fancy. So first we need to import the MUI Unstyled Button component by adding `import { ButtonUnstyled as Button } from '@mui/base'` on the first line of our file.
@@ -54,21 +54,21 @@ _Note: The official MUI docs say to import as `import ButtonUnstyled from '@mui/
Now we can create our button. Inside the return statement, add the following:
<img src="/media/mui-plus-tailwind/unstyled-button-code.png" width="80%" alt="<Button>Click Me!</Button>" />
<img src="src/assets/blog/mui-plus-tailwind/unstyled-button-code.png" width="80%" alt="<Button>Click Me!</Button>" />
Next, go back to your terminal and run `yarn dev` to start up the dev server, and click the 'localhost' link that appears (most likely 'localhost:3000'). We'll be greeted by what looks like just a bit of text (it's a button, I promise), which isn't what we want, but that's because we haven't added any styles yet!
<img src="/media/mui-plus-tailwind/unstyled-button.png" width="40%" alt="A plain old 'button' that reads 'Click Me!'" />
<img src="src/assets/blog/mui-plus-tailwind/unstyled-button.png" width="40%" alt="A plain old 'button' that reads 'Click Me!'" />
All we need to do is add the `className` prop with some nice Tailwind utility classes:
<img src="/media/mui-plus-tailwind/styled-button-code.png" width="80%" alt="<Button className='rounded-lg border-2 border-sky-500 bg-sky-600 py-2 px-10 font-medium text-slate-300 shadow hover:bg-sky-700 active:translate-y-0.5'>
<img src="src/assets/blog/mui-plus-tailwind/styled-button-code.png" width="80%" alt="<Button className='rounded-lg border-2 border-sky-500 bg-sky-600 py-2 px-10 font-medium text-slate-300 shadow hover:bg-sky-700 active:translate-y-0.5'>
Click Me!
</Button>" />
Now, when we go back to the browser, we should see the following:
<img src="/media/mui-plus-tailwind/styled-button.png" width="40%" alt="A styled blue button that reads 'Click Me!'" />
<img src="src/assets/blog/mui-plus-tailwind/styled-button.png" width="40%" alt="A styled blue button that reads 'Click Me!'" />
Nice! That looks a lot more like a button.
+13 -63
View File
@@ -1,20 +1,21 @@
@font-face {
font-family: Manrope;
src: url(./fonts/Manrope-Regular.ttf) format('truetype');
font-family: Maple Mono;
src: url(./assets/fonts/MapleMono-Regular.ttf) format('truetype');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: Manrope;
src: url(./fonts/Manrope-Bold.ttf) format('truetype');
font-family: Maple Mono;
src: url(./assets/fonts/MapleMono-Bold.ttf) format('truetype');
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: JetBrainsMono;
src: url(./fonts/JetBrainsMono-VariableFont_wght.ttf) format('truetype');
src: url(./assets/fonts/JetBrainsMono-VariableFont_wght.ttf)
format('truetype');
font-style: normal;
font-display: block;
}
@@ -25,7 +26,7 @@
--red: #d20f39;
--orange: #fe640b;
--text: #4c4f69;
--background: white;
--background: #fff8fa;
--radius: 5px;
--shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
--border: 1px solid #8c8fa1;
@@ -46,7 +47,7 @@
html {
color: var(--text);
background-color: var(--background);
font-family: 'Manrope', sans-serif;
font-family: 'Maple Mono', monospace;
font-size: 1.05rem;
}
@@ -65,38 +66,9 @@ a:hover {
opacity: 0.75;
}
header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
height: 120px;
}
header > h1 > a {
color: var(--text);
}
header > nav {
display: flex;
flex-direction: row;
list-style: none;
gap: 20px;
font-size: 1.15rem;
}
header > nav > li > a:hover {
text-decoration: none;
}
header > nav > li > .selected {
font-weight: bold;
}
footer {
margin: 4rem 0;
text-align: center;
main p {
text-align: justify;
line-height: 1.4;
}
article img {
@@ -104,6 +76,8 @@ article img {
box-shadow: var(--shadow);
display: block;
margin: auto;
max-width: 100%;
height: auto;
}
.no-shadow {
@@ -124,12 +98,6 @@ article img {
margin: 0;
}
.more-posts {
text-align: center;
padding: 1rem;
font-size: 1.2rem;
}
blockquote {
border-left: 4px solid;
border-color: var(--text);
@@ -159,24 +127,6 @@ kbd {
white-space: nowrap;
}
/* Not By AI badge */
.not-by-ai {
display: block;
width: 134px;
height: 45px;
background-image: url(svg/Written-By-Human-Not-By-AI-Badge-white.svg);
background-repeat: no-repeat;
background-position: center;
margin: 1rem 0;
}
@media (prefers-color-scheme: dark) {
.not-by-ai {
background-image: url(svg/Written-By-Human-Not-By-AI-Badge-black.svg);
}
}
@media (max-width: 590px) {
header {
flex-direction: column;
+3 -5
View File
@@ -1,6 +1,5 @@
---
import '@styles/global.css';
import { ClientRouter } from 'astro:transitions';
import '../global.css';
import Header from '@components/Header.astro';
import Footer from '@components/Footer.astro';
@@ -23,16 +22,15 @@ const title = Astro.props.title || Astro.props.frontmatter?.title || 'Unknown';
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="robots" content="noindex" /><meta
name="description"
content="My personal blog about life, gaming, tech, and whatever else I feel like writing about."
content="My little space on the World Wide Web."
/><link
rel="alternate"
type="application/rss+xml"
title="ghall.space - RSS"
href={`${Astro.site}rss.xml`}
/><title>{`ghall.space - ${title}`}</title>
<ClientRouter />
</head>
<body class="layout-simple" transition:animate="fade">
<body class="layout-simple">
<Header />
<main>
<slot />
+1 -1
View File
@@ -2,7 +2,7 @@
import Layout from '@layouts/Layout.astro';
import { Image } from 'astro:assets';
import DataGif from '../img/it-does-not-exist.gif';
import DataGif from '../assets/it-does-not-exist.gif';
---
<Layout title="Not Found">
+20 -2
View File
@@ -15,13 +15,13 @@ export async function getStaticPaths() {
const { post } = Astro.props;
const { data, slug } = post;
const { data } = post;
const { Content } = await post.render();
---
<Layout title={data.title}>
<article transition:name={slug}>
<article>
<BlogHeader title={data.title} date={data.pubDate} />
<Content />
<a href="https://notbyai.fyi/">
@@ -30,3 +30,21 @@ const { Content } = await post.render();
<Tags tags={data.tags} />
</article>
</Layout>
<style>
.not-by-ai {
display: block;
width: 134px;
height: 45px;
background-image: url(../../assets/svg/Written-By-Human-Not-By-AI-Badge-white.svg);
background-repeat: no-repeat;
background-position: center;
margin: 1rem 0;
}
@media (prefers-color-scheme: dark) {
.not-by-ai {
background-image: url(../../assets/svg/Written-By-Human-Not-By-AI-Badge-black.svg);
}
}
</style>
+1 -1
View File
@@ -50,7 +50,7 @@ posts.sort(
<ul>
{
posts.map(({ slug, data }) => (
<li transition:name={slug}>
<li>
<a href={`/posts/${slug}`}>{data.title}</a> -
<span>
{format(add(new Date(data.pubDate), { hours: 6 }), 'MMM do, y')}
+8
View File
@@ -26,3 +26,11 @@ const posts = await getCollection('blog');
)
}
</Layout>
<style>
.more-posts {
text-align: center;
padding: 1rem;
font-size: 1.2rem;
}
</style>
+6 -7
View File
@@ -6,8 +6,8 @@ import { getCollection } from 'astro:content';
import Layout from '@layouts/Layout.astro';
import Avatar from '@components/Avatar.astro';
import MastodonIcon from '../img/svg/mastodon.svg';
import BlueskyIcon from '../img/svg/bluesky.svg';
import MastodonIcon from '../assets/svg/mastodon.svg';
import BlueskyIcon from '../assets/svg/bluesky.svg';
const iconSize = 16;
const posts = await getCollection('blog');
@@ -19,9 +19,6 @@ const latestPost = posts.sort(
---
<Layout title="Welcome">
<div transition:name="my-avatar">
<Avatar size={200} />
</div>
<p>
My name is <strong>Graham</strong> (he/him), a full-stack web developer, and
tech enthusiast.
@@ -50,10 +47,12 @@ const latestPost = posts.sort(
If you want to get in touch, I'm on <a
rel="me"
href="https://mastodon.social/@ghalldev"
target="_blank"><MastodonIcon size={iconSize} />Mastodon</a
target="_blank"
><MastodonIcon width={iconSize} height={iconSize} />Mastodon</a
> and <a
href="https://bsky.app/profile/ghalldev.bsky.social"
target="_blank"><BlueskyIcon size={iconSize} />Bluesky</a
target="_blank"
><BlueskyIcon width={iconSize} height={iconSize} />Bluesky</a
>.
</p>
<p>
+3 -5
View File
@@ -5,19 +5,17 @@ title: Now
Hey there, this is my [/now page](https://nownownow.com/about)!
_Last updated: July 28, 2025_
_Last updated: August 29, 2025_
## 🎧 Listening
- [Tunnel Vision - Beach Bunny](https://album.link/i/1794412465)
- [Flood - They Might Be Giants](https://album.link/us/i/298111036)
- [Video Game Legends - Celestial Aeon Project, Deck Hard & Stellar Conflux](https://album.link/i/1814286119)
- [Ego Death at a Bachelorette Party - Hayley Williams](https://album.link/i/1833006180)
## 🎮 Playing
- [Batman Arkham Asylum](https://www.igdb.com/games/batman-arkham-asylum)
- [Assassin's Creed Shadows](https://www.igdb.com/games/assassins-creed-shadows)
- [Baldur's Gate 3](https://www.igdb.com/games/baldurs-gate-3)
- [Rune Factory: Guardians of Azuma](https://www.igdb.com/games/rune-factory-guardians-of-azuma--1)
## 📺 Watching
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.