fix formatting

This commit is contained in:
2025-11-24 10:22:06 -05:00
parent e181c735b8
commit 321aa058ed
41 changed files with 776 additions and 767 deletions
+13 -13
View File
@@ -1,27 +1,27 @@
---
import { Image } from "astro:assets";
import { Image } from 'astro:assets';
import portrait from "../assets/portrait.jpg";
import portrait from '../assets/portrait.jpg';
interface Props {
size: number;
size: number;
}
const { size } = Astro.props;
---
<Image
src={portrait}
alt="Illustrated portrait of a person with glasses and a beard, wearing a red and black plaid shirt. The background is a solid green color."
class="portrait"
width={`${size}`}
height={`${size}`}
src={portrait}
alt="Illustrated portrait of a person with glasses and a beard, wearing a red and black plaid shirt. The background is a solid green color."
class="portrait"
width={`${size}`}
height={`${size}`}
/>
<style lang="scss">
.portrait {
display: block;
margin: auto;
border-radius: 200px;
}
.portrait {
display: block;
margin: auto;
border-radius: 200px;
}
</style>
+25 -25
View File
@@ -1,43 +1,43 @@
---
import { add, format } from "date-fns";
import { add, format } from 'date-fns';
import CalendarIcon from "@assets/svg/calendar.svg";
import CalendarIcon from '@assets/svg/calendar.svg';
interface Props {
title: string;
date: Date;
slug?: string;
title: string;
date: Date;
slug?: string;
}
const { title, date, slug } = Astro.props;
---
<div class="blog-header">
{slug ? <a href={`/blog/${slug}`}>{title}</a> : <h1>{title}</h1>}
<div>
<CalendarIcon class="calendar-icon" width={24} height={24} />
<strong>{format(add(new Date(date), { hours: 6 }), "MMM do, y")}</strong>
</div>
{slug ? <a href={`/blog/${slug}`}>{title}</a> : <h1>{title}</h1>}
<div>
<CalendarIcon class="calendar-icon" width={24} height={24} />
<strong>{format(add(new Date(date), { hours: 6 }), 'MMM do, y')}</strong>
</div>
</div>
<style lang="scss">
a {
font-size: 1.3rem;
}
a {
font-size: 1.3rem;
}
strong {
font-weight: bolder;
}
strong {
font-weight: bolder;
}
.blog-header {
margin: 1rem 0;
.blog-header {
margin: 1rem 0;
& h2 {
margin: 0;
}
}
& h2 {
margin: 0;
}
}
.calendar-icon {
transform: translateY(0.3rem);
}
.calendar-icon {
transform: translateY(0.3rem);
}
</style>
+16 -16
View File
@@ -3,23 +3,23 @@
---
<div class="sidebar">
<section>
<h2>Tags</h2>
<ul>
<li>Hello</li>
<li>Hello</li>
<li>Hello</li>
<li>Hello</li>
</ul>
</section>
<section>
<h2>Tags</h2>
<ul>
<li>Hello</li>
<li>Hello</li>
<li>Hello</li>
<li>Hello</li>
</ul>
</section>
</div>
<style lang="scss">
.sidebar {
padding: 16px;
border: var(--border);
min-width: 140px;
margin-left: 14px;
height: fit-content;
}
.sidebar {
padding: 16px;
border: var(--border);
min-width: 140px;
margin-left: 14px;
height: fit-content;
}
</style>
+12 -12
View File
@@ -1,26 +1,26 @@
---
import type { CollectionEntry } from "astro:content";
import BlogHeader from "./BlogHeader.astro";
import Tags from "./Tags.astro";
import type { CollectionEntry } from 'astro:content';
import BlogHeader from './BlogHeader.astro';
import Tags from './Tags.astro';
interface Props {
post: CollectionEntry<"blog">;
post: CollectionEntry<'blog'>;
}
const { post } = Astro.props;
---
<article>
<BlogHeader title={post.data.title} date={post.data.pubDate} slug={post.id} />
<Tags tags={post.data.tags} />
<BlogHeader title={post.data.title} date={post.data.pubDate} slug={post.id} />
<Tags tags={post.data.tags} />
</article>
<style lang="scss">
article {
padding-bottom: 20px;
article {
padding-bottom: 20px;
&:not(:first-child) {
border-top: var(--border);
}
}
&:not(:first-child) {
border-top: var(--border);
}
}
</style>
+11 -11
View File
@@ -1,20 +1,20 @@
---
interface Props {
tags: string[];
tags: string[];
}
const { tags } = Astro.props;
---
<span>
{
tags.sort().map((tag: string, index: number) => (
<>
<a class="tag" href={`/blog/tag/${tag}`}>
{tag}
</a>
{index < tags.length - 1 ? " | " : ""}
</>
))
}
{
tags.sort().map((tag: string, index: number) => (
<>
<a class="tag" href={`/blog/tag/${tag}`}>
{tag}
</a>
{index < tags.length - 1 ? ' | ' : ''}
</>
))
}
</span>
+50 -50
View File
@@ -1,68 +1,68 @@
---
import MastodonIcon from "../assets/svg/mastodon.svg";
import RssIcon from "../assets/svg/rss.svg";
import ThemeToggle from "./ThemeToggle.astro";
import MastodonIcon from '../assets/svg/mastodon.svg';
import RssIcon from '../assets/svg/rss.svg';
import ThemeToggle from './ThemeToggle.astro';
const year = new Date().getFullYear();
---
<footer>
<ThemeToggle />
<div class="socials">
<a
href="https://mastodon.social/@ghalldev"
target="_blank"
rel="noopener noreferrer"
><MastodonIcon class="mastodon-icon" width={20} height={20} /> Follow me on
Mastodon</a
>
<ThemeToggle />
<div class="socials">
<a
href="https://mastodon.social/@ghalldev"
target="_blank"
rel="noopener noreferrer"
><MastodonIcon class="mastodon-icon" width={20} height={20} /> Follow me on
Mastodon</a
>
<a href="/rss.xml"
><RssIcon class="rss-icon" width={20} height={20} /> Subscribe with RSS</a
>
</div>
<p>
Copyright 2022 - {year}, Graham Hall
<a href="/rss.xml"
><RssIcon class="rss-icon" width={20} height={20} /> Subscribe with RSS</a
>
</div>
<p>
Copyright 2022 - {year}, Graham Hall
<br />
Built with <a href="https://astro.build">Astro</a>
</p>
<br />
Built with <a href="https://astro.build">Astro</a>
</p>
</footer>
<style lang="scss">
footer {
margin: 2rem 0;
text-align: center;
border-top: var(--border);
padding-top: 24px;
}
footer {
margin: 2rem 0;
text-align: center;
border-top: var(--border);
padding-top: 24px;
}
.rss-icon {
transform: translateY(0.18rem);
}
.rss-icon {
transform: translateY(0.18rem);
}
.socials {
display: flex;
gap: 24px;
justify-content: center;
.socials {
display: flex;
gap: 24px;
justify-content: center;
& a {
color: var(--text);
& a {
color: var(--text);
& .rss-icon {
color: var(--orange);
}
& .rss-icon {
color: var(--orange);
}
& .mastodon-icon {
color: var(--blue);
transform: translateY(4px);
}
}
}
& .mastodon-icon {
color: var(--blue);
transform: translateY(4px);
}
}
}
@media (max-width: 516px) {
.socials {
flex-direction: column;
}
}
@media (max-width: 516px) {
.socials {
flex-direction: column;
}
}
</style>
+80 -80
View File
@@ -1,97 +1,97 @@
---
import BarsIcon from "../../assets/svg/bars.svg";
import CloseIcon from "../../assets/svg/xmark.svg";
import { navLinks } from "../../data/nav-links";
import BarsIcon from '../../assets/svg/bars.svg';
import CloseIcon from '../../assets/svg/xmark.svg';
import { navLinks } from '../../data/nav-links';
---
<!-- drawerOpened is defined in /src/layouts/Layout.astro -->
<div class="drawer-container" @keydown.escape="drawerOpen = false">
<button class="icon-button" @click="drawerOpen = !drawerOpen">
<BarsIcon width={24} height={24} />
</button>
<div
class="overlay"
@click="drawerOpen = !drawerOpen"
x-show="drawerOpen"
x-transition:enter-start="hidden-overlay"
x-transition:enter-end="visible-overlay"
x-transition:leave-start="visible-overlay"
x-transition:leave-end="hidden-overlay"
>
</div>
<div
class="drawer"
x-show="drawerOpen"
x-transition:enter-start="hidden-drawer"
x-transition:enter-end="visible-drawer"
x-transition:leave-start="visible-drawer"
x-transition:leave-end="hidden-drawer"
>
<div>
<button class="icon-button" @click="drawerOpen = !drawerOpen">
<CloseIcon width={24} height={24} /></button
>
</div>
<nav>
{navLinks.map((link) => <a href={`/${link.path}`}>{link.label}</a>)}
</nav>
</div>
<button class="icon-button" @click="drawerOpen = !drawerOpen">
<BarsIcon width={24} height={24} />
</button>
<div
class="overlay"
@click="drawerOpen = !drawerOpen"
x-show="drawerOpen"
x-transition:enter-start="hidden-overlay"
x-transition:enter-end="visible-overlay"
x-transition:leave-start="visible-overlay"
x-transition:leave-end="hidden-overlay"
>
</div>
<div
class="drawer"
x-show="drawerOpen"
x-transition:enter-start="hidden-drawer"
x-transition:enter-end="visible-drawer"
x-transition:leave-start="visible-drawer"
x-transition:leave-end="hidden-drawer"
>
<div>
<button class="icon-button" @click="drawerOpen = !drawerOpen">
<CloseIcon width={24} height={24} /></button
>
</div>
<nav>
{navLinks.map((link) => <a href={`/${link.path}`}>{link.label}</a>)}
</nav>
</div>
</div>
<style lang="scss">
@use "../../styles/variables.scss" as *;
@use '../../styles/variables.scss' as *;
.drawer-container {
display: none;
}
.drawer-container {
display: none;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.6);
z-index: 2;
transition: $transition;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.6);
z-index: 2;
transition: $transition;
}
.hidden-overlay {
opacity: 0;
}
.hidden-overlay {
opacity: 0;
}
.drawer {
right: 0;
top: 0;
background-color: var(--background);
position: absolute;
width: 75vw;
height: 100vh;
z-index: 3;
transition: $transition;
.drawer {
right: 0;
top: 0;
background-color: var(--background);
position: absolute;
width: 75vw;
height: 100vh;
z-index: 3;
transition: $transition;
& div {
padding: 8px 6px 4px;
border-bottom: var(--border);
}
}
& div {
padding: 8px 6px 4px;
border-bottom: var(--border);
}
}
nav {
text-align: left;
padding: 12px;
display: flex;
flex-direction: column;
gap: 12px;
font-size: 1.2rem;
}
nav {
text-align: left;
padding: 12px;
display: flex;
flex-direction: column;
gap: 12px;
font-size: 1.2rem;
}
.hidden-drawer {
transform: translateX(75vw);
}
.hidden-drawer {
transform: translateX(75vw);
}
@media screen and (max-width: $max-mobile-width) {
.drawer-container {
display: block;
}
}
@media screen and (max-width: $max-mobile-width) {
.drawer-container {
display: block;
}
}
</style>
+40 -40
View File
@@ -1,53 +1,53 @@
---
import Drawer from "./Drawer.astro";
import Nav from "./Nav.astro";
import Drawer from './Drawer.astro';
import Nav from './Nav.astro';
---
<header>
<div class="container">
<a href="/">ghall.space</a>
<div>
<Nav />
<div class="container">
<a href="/">ghall.space</a>
<div>
<Nav />
<Drawer />
</div>
</div>
<Drawer />
</div>
</div>
</header>
<style lang="scss">
@use "../../styles/variables.scss" as *;
@use '../../styles/variables.scss' as *;
header {
margin-bottom: 20px;
height: 70px;
background-color: var(--background);
width: 100%;
top: 0;
position: fixed;
z-index: 1;
border-bottom: var(--border);
header {
margin-bottom: 20px;
height: 70px;
background-color: var(--background);
width: 100%;
top: 0;
position: fixed;
z-index: 1;
border-bottom: var(--border);
& .container {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
max-width: $max-page-width;
margin: auto;
padding: 0 16px;
height: 100%;
& .container {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
max-width: $max-page-width;
margin: auto;
padding: 0 16px;
height: 100%;
& div {
display: flex;
gap: 20px;
align-items: center;
}
}
}
& div {
display: flex;
gap: 20px;
align-items: center;
}
}
}
a {
font-size: 1.6rem;
color: var(--text);
font-weight: bold;
}
a {
font-size: 1.6rem;
color: var(--text);
font-weight: bold;
}
</style>
+29 -29
View File
@@ -1,40 +1,40 @@
---
import { navLinks } from "../../data/nav-links";
import { navLinks } from '../../data/nav-links';
---
<nav>
<ul>
{
navLinks.map((link) => (
<li>
<a href={`/${link.path}`}>{link.label}</a>
</li>
))
}
</ul>
<ul>
{
navLinks.map((link) => (
<li>
<a href={`/${link.path}`}>{link.label}</a>
</li>
))
}
</ul>
</nav>
<style lang="scss">
@use "../../styles/variables.scss" as *;
@use '../../styles/variables.scss' as *;
ul {
display: flex;
flex-direction: row;
list-style: none;
gap: 10px;
font-size: 1.15rem;
font-weight: 600;
align-items: center;
ul {
display: flex;
flex-direction: row;
list-style: none;
gap: 10px;
font-size: 1.15rem;
font-weight: 600;
align-items: center;
& a {
color: var(--text);
padding: 5px 10px;
}
}
& a {
color: var(--text);
padding: 5px 10px;
}
}
@media screen and (max-width: $max-mobile-width) {
nav {
display: none;
}
}
@media screen and (max-width: $max-mobile-width) {
nav {
display: none;
}
}
</style>
+25 -25
View File
@@ -1,5 +1,5 @@
<div
x-data="{
x-data="{
latestPost: null,
fetchPost() {
fetch('https://mastodon.social/@ghalldev.rss')
@@ -21,34 +21,34 @@
});
},
}"
x-init="fetchPost()"
x-init="fetchPost()"
>
<template x-if="latestPost">
<div class="mastodon-post">
<h2>Latest Mastodon Post</h2>
<div x-html="latestPost.body"></div>
<a x-bind:href="latestPost.link" target="_blank" rel="noopener noreferrer"
>View Post</a
>
</div>
</template>
<template x-if="!latestPost">
<p>Loading...</p>
</template>
<template x-if="latestPost">
<div class="mastodon-post">
<h2>Latest Mastodon Post</h2>
<div x-html="latestPost.body"></div>
<a x-bind:href="latestPost.link" target="_blank" rel="noopener noreferrer"
>View Post</a
>
</div>
</template>
<template x-if="!latestPost">
<p>Loading...</p>
</template>
</div>
<style lang="scss">
@use "../styles/variables.scss" as *;
@use '../styles/variables.scss' as *;
.mastodon-post {
margin: 2rem auto;
padding: 1rem;
max-width: 600px;
border-radius: $radius;
border: var(--border);
}
.mastodon-post {
margin: 2rem auto;
padding: 1rem;
max-width: 600px;
border-radius: $radius;
border: var(--border);
}
.mastodon-post > h2 {
margin-top: 0;
}
.mastodon-post > h2 {
margin-top: 0;
}
</style>
+3 -3
View File
@@ -1,8 +1,8 @@
import { defineCollection, z } from "astro:content";
import { glob } from "astro/loaders";
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const blogCollection = defineCollection({
loader: glob({ pattern: "**/*.md", base: "./src/content/blog" }),
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
pubDate: z.string().transform((str: string) => new Date(str)),
+1 -1
View File
@@ -12,7 +12,7 @@ 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:
![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)
![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.
@@ -3,6 +3,7 @@ title: 'AI & Creativity'
pubDate: '11/11/24'
tags: ['Tech', 'Creativity']
---
Recently, Ive been pondering generative AI and its effects. Not on jobs, the economy, or even the damage its done to our ability to trust information we see online (whether its something generated by a malicious actor looking to mislead, or a simple “hallucination” causing an innocent mistake). No, Ive been pondering its effects on human creativity, and our capacity to learn and grow as creative creatures. This is something Ive had in the back of my mind for a quite a while, and I think Ive finally reached a point where I can put my feelings into words.
My experience with generative AI started way back at the end of 2022 with [an AI-assisted dating profile](https://ghall.blog/posts/2022/creating-a-dating-profile-with-ai/). Just over a month later, I posted a [follow up](https://ghall.blog/posts/2023/an-update-on-my-ai-dating-profile/), in which I said the following:
@@ -25,4 +25,5 @@ While any code getting shipped to the browser will still need to be compiled to
I started off being annoyed with using types in my code because, to be quite frank, they are annoying. They'll make your code throw errors whenever you try to multiply a string, or something silly like that. But that's part of the beauty I've come to appreciate. They're there to help you write better code, and to point you in the right direction when something inevitably goes wrong.
[^1]: [Here](https://stackoverflow.com/questions/1517582/what-is-the-difference-between-statically-typed-and-dynamically-typed-languages) is a StackOverflow thread on the difference between dynamic and static typing put far better than I ever could explain it
[^2]: As an example, I rewrote [my CLI clone of Wordle](https://github.com/ghall89/wordle-cli) in TypeScript
@@ -3,6 +3,7 @@ title: 'Announcing AutoDock'
pubDate: '1/17/25'
tags: ['MacOS', 'Apps', 'Programming']
---
I'm a MacBook Air user who often uses a larger external display, and I have a, perhaps, idiosyncratic desire to have the dock always visible on the larger display at my desk, but prefer it hidden when using the smaller, built-in one.
While it's not all that inconvenient to manually swap the dock with a quick <kbd>opt</kbd> + <kbd>cmd</kbd> + <kbd>D</kbd>, I thought it would be cool to automate the process based on display size. I looked around for an app that would do this, and couldn't find one that worked reliably.
@@ -3,6 +3,7 @@ title: 'Skip the Algorithm: Be Your Own Online Curator'
pubDate: '3/1/25'
tags: ['Tech', 'Mindfulness', 'Apps']
---
Ever since I started using Mastodon, I've become a lot more interested in reducing the presence of algorithmic content in my digital life. I've never been particularly thrilled with algorithmic feeds of content. I was among the people who was quite furious when Instagram ditched the chronological timeline, and then started inserting content from accounts I didn't even follow.
Somewhere along the line, I think I just started accepting what I assumed was inevitable. I think I was probably naive, and didn't consider the ills both social and psychological that resulted algorithmically curated content. It was just an annoying thing that I just had to accept.
@@ -8,10 +8,10 @@ Recently, I found myself wishing for a device with all the modern conveniences o
Over the last several weeks, I've been slowly paring down what's on my phone. It started with basically anything with an endless, scrollable feed with the exception of Tapestry, Ivory,Ice Cubes, and Bluesky, though I'll come back to those. I also turned off all notifications except for the bare essentials, like text alerts, and have made judicious use of the iPhone's "Scheduled Summary" feature for things that I still want to get notified about, but don't warrant an alert, like podcast notifications.
I've also removed any free-to-play games, with the exception of Pokémon TCG Pocket (it's been my guilty pleasure since it released 😅), and unsubscribed from Apple Arcade. My phone is not my primary gaming device, nor do I ever want it to be, so limiting my phone to games that I can just pick up and play for a few minutes here and there just makes sense.
I've also removed any free-to-play games, with the exception of Pokémon TCG Pocket (it's been my guilty pleasure since it released 😅), and unsubscribed from Apple Arcade. My phone is not my primary gaming device, nor do I ever want it to be, so limiting my phone to games that I can just pick up and play for a few minutes here and there just makes sense.
More recently, I began the next phase of my plan for a better smartphone; removing the remaining "infinite feed" apps I mentioned earlier. Bluesky was easy, I spend very little time on there, there are just a few people in the web dev and gaming worlds I like to follow. Ivory and Ice Cubes (my Mastodon clients of choice) will probably be the most missed, but I have it open at pretty much all times when I'm at my computer, so I'm sure I will adapt.
Tapestry, I think, I will leave on because I have a little bit of a soft spot for it from being a Kickstarter backer, and because my feed is just web comics and cute animals.
Tapestry, I think, I will leave on because I have a little bit of a soft spot for it from being a Kickstarter backer, and because my feed is just web comics and cute animals.
There are definitely more things I can do to achieve the "perfect" smartphone. It's going to take a combination of experimentation and re-training my brain, but I think it can be done.
@@ -4,7 +4,7 @@ pubDate: '5/11/25'
tags: ['Gaming']
---
My latest board gaming obsession is quite an unlikely one for me. Im not particularly fond of the viking aesthetic in general, and, while I dont dislike engine-builder games, theyre not generally the type of game Id go out of my way to play.
My latest board gaming obsession is quite an unlikely one for me. Im not particularly fond of the viking aesthetic in general, and, while I dont dislike engine-builder games, theyre not generally the type of game Id go out of my way to play.
But a little game called [Knarr](https://boardgamegeek.com/boardgame/379629) struck a chord with me. Someone in my gaming group introduced me, and I enjoyed it so much I ended up picking up my own copy. Something that has only happened once before with [Akropolis](https://boardgamegeek.com/boardgame/357563), another favorite of mine.
+20 -20
View File
@@ -10,26 +10,26 @@ The Switch is also the console Ive played the most games on, so I thought it
Also, I listed them in alphabetical order partly because I couldnt decide on a ranking, but mostly because it makes my brain happy. 🧠
* A Short Hike
* Animal Crossing: New Horizons
* Fire Emblem Engage
* Hades
* Kirby and the Forgotten Land
* The Legend of Zelda: Tears of the Kingdom
* Metroid Dread
* Persona 5 Royal
* Pokemon Legends: Arceus
* Sea of Stars
* Shantae and the Seven Sirens
* Splatoon 3
* Super Mario Odyssey
* Super Mario Wonder
* Super Smash Bros Ultimate
* Tetris 99
* Unicorn Overlord
* The Witcher 3: Wild Hunt
* Xenoblade Chronicles 3
* Yooka-Laylee and the Impossible Lair
- A Short Hike
- Animal Crossing: New Horizons
- Fire Emblem Engage
- Hades
- Kirby and the Forgotten Land
- The Legend of Zelda: Tears of the Kingdom
- Metroid Dread
- Persona 5 Royal
- Pokemon Legends: Arceus
- Sea of Stars
- Shantae and the Seven Sirens
- Splatoon 3
- Super Mario Odyssey
- Super Mario Wonder
- Super Smash Bros Ultimate
- Tetris 99
- Unicorn Overlord
- The Witcher 3: Wild Hunt
- Xenoblade Chronicles 3
- Yooka-Laylee and the Impossible Lair
I opted to stay away from remasters/remakes, but as a bonus here are the ones that stood out to me…
@@ -14,7 +14,7 @@ Unlike Arc, and indeed unlike most browsers these days, Zen doesnt use Chromi
On the web dev side, Ive found the developer tools to be…fine. Ive used the Firefox dev tools in the past, so Im comfortable with them, and it didnt take me long to adjust. While I much prefer the Chromium dev tools (which is about the only thing I _like_ about Chromium), I dont find the Gecko dev tools that much worse. Which is more than I can say about Safaris dev tools. 😬
Another major positive is battery life. Id become somewhat used to the less-than-ideal battery life I was getting with Arc, and slightly less so than Vivaldi. But after switching to Zen, I started to notice my battery was lasting quite a bit longer. As I write this (with Zen open in the background), my M2 MacBook Air is at about 88% battery, with 11 hours remaining. I know in practice it wont *actually* last 11 hours, but thats higher than any estimation that I can recall ever getting using a Chromium-based browser. In practice, it means that, generally, depending on which Node environments I have to run locally that day, I can make it through an entire 8 hour workday, with a bit to spare.
Another major positive is battery life. Id become somewhat used to the less-than-ideal battery life I was getting with Arc, and slightly less so than Vivaldi. But after switching to Zen, I started to notice my battery was lasting quite a bit longer. As I write this (with Zen open in the background), my M2 MacBook Air is at about 88% battery, with 11 hours remaining. I know in practice it wont _actually_ last 11 hours, but thats higher than any estimation that I can recall ever getting using a Chromium-based browser. In practice, it means that, generally, depending on which Node environments I have to run locally that day, I can make it through an entire 8 hour workday, with a bit to spare.
The biggest downsides are the inability to access DRMd content online, specifically on streaming services (Ive been swapping to Safari to get my Andor and Doctor Who fix), and the fact that the iCloud Keychain extension doesn't work (though I've heard through the internet grapevine a fix is coming). Also, the fun and I will admit, relatively obnoxious animations on this site do not work, but that should be remedied whenever Firefox fully implements the View Transition API.
@@ -3,6 +3,7 @@ title: 'The New ghall.space'
pubDate: '9/1/25'
tags: ['Meta', 'Programming', 'Web Dev']
---
It's been a while since I originally built this website, which started life as a little project to learn the, at the time, brand new web framework Astro. My skills in web development have improved greatly in that time, as has the functionality of the Astro framework. Therefore, I thought it would be a fun project to make some improvements to the site, both visually and in how the codebase is structured.
One of the biggest front-facing changes I've made, aside from new typography and some layout adjustments, is a mobile-responsive navigation bar. Mobile is always something I've been conscious of when building this site, but I opted for a simplified approach by ensuring the site was usable on mobile without introducing many responsive elements. But as the site morphed from a simple blog to a more generalized space on the internet (hence the ".space" TLD), I've discovered the limits of that design philosophy.
+2 -2
View File
@@ -8,9 +8,9 @@ The big news in the tech and gaming worlds this past week is Valve announcing [t
Up until now, I never had any interest in Valve's hardare products. Despite being a big handheld gamer, the Steam Deck did not appeal to me in the slightest. While it's certainly an impressive piece of kit, they sacrificed too much of what attracts me to handheld games in favor of raw power. The size, battery life, and relative complexity of the software ecosystem[^1], make the Steam Deck a non-starter for me.[^2]
The Steam Machine, by virtue of being a decidedly non-portable device, solves 2 out of the 3 issues I have with the Steam Deck. And honestly, depending on how well the hardware performs, and how much they can improve Proton (their compatibility layer for running Windows games on Linux), software compatibility might not even be that big of an issue.
The Steam Machine, by virtue of being a decidedly non-portable device, solves 2 out of the 3 issues I have with the Steam Deck. And honestly, depending on how well the hardware performs, and how much they can improve Proton (their compatibility layer for running Windows games on Linux), software compatibility might not even be that big of an issue.
Whatever happens, it's not going to replace my PlayStation 5. But gaming has been going through a weird period, the hobby has been trending more expensive, even if you don't factor in tariffs affecting the price of hardware. By the time the PlayStation 6 rolls around, something like the Steam Machine, which could potentially have access to the last 15-20 years of gaming in addition to all the latest titles, might be a far better value proposition.
Whatever happens, it's not going to replace my PlayStation 5. But gaming has been going through a weird period, the hobby has been trending more expensive, even if you don't factor in tariffs affecting the price of hardware. By the time the PlayStation 6 rolls around, something like the Steam Machine, which could potentially have access to the last 15-20 years of gaming in addition to all the latest titles, might be a far better value proposition.
[^1]: I'm primarily talking about software compatibility. For the Switch, any game on the eShop will 100% be compatibile, but not every game on Steam will work on the Steam Deck.
@@ -1,7 +1,7 @@
---
title: 'Tinkering With Linux'
pubDate: '10/27/25'
tags: ['Tech', 'Linux' ]
tags: ['Tech', 'Linux']
---
For the last 8 or 9 months, I've been experimenting on and off with Linux. Specifically Fedora (via Asahi Linux) for those who are curious. I installed it on an M1 MacBook Air, which I keep around as an emergency backup, and I've been mostly pleased with how well it's been running.
@@ -41,5 +41,7 @@ I do, however, have some questions for the Linux community if any of you haven't
Feel free to reach out to me on [Mastodon](https://mastodon.social/@ghalldev).
[^1]: However, to continue my series of gimicky posts, like when I [wrote about the Mac using Mac OS 7](/blog/2024/ramblings-on-the-macintosh), and [wrote about taking intentional analog time with pen and paper](/blog/2025/intentional-analog-time), I'm writing this blog post in Linux.
[^2]: This annoyingly does not work for all apps, but I'm probably missing something obvious.
[^3]: Of note, the Plasma shell itself seems to be the most memory intensive process, using about 500MB of RAM, which seems more than reasonable.
+4 -4
View File
@@ -4,8 +4,8 @@ export interface NavLink {
}
export const navLinks: NavLink[] = [
{ label: "Blog", path: "blog/page/1" },
{ label: "Now", path: "now" },
{ label: "Projects", path: "projects" },
{ label: "Search", path: "search" },
{ label: 'Blog', path: 'blog/page/1' },
{ label: 'Now', path: 'now' },
{ label: 'Projects', path: 'projects' },
{ label: 'Search', path: 'search' },
];
+12 -12
View File
@@ -1,6 +1,6 @@
import autodockImg from "@assets/projects/autodock.png";
import bggClientImg from "@assets/projects/bgg-client.png";
import keystashImg from "@assets/projects/keystash.png";
import autodockImg from '@assets/projects/autodock.png';
import bggClientImg from '@assets/projects/bgg-client.png';
import keystashImg from '@assets/projects/keystash.png';
export interface Project {
title: string;
@@ -11,24 +11,24 @@ export interface Project {
export const projects: Project[] = [
{
title: "AutoDock",
title: 'AutoDock',
description:
"A MacOS menubar utility for automatically hiding and showing the Dock based on the screen size of the connected displays.",
'A MacOS menubar utility for automatically hiding and showing the Dock based on the screen size of the connected displays.',
image: autodockImg,
link: "https://github.com/ghall89/AutoDock",
link: 'https://github.com/ghall89/AutoDock',
},
{
title: "KeyStash",
title: 'KeyStash',
description:
"A MacOS application for managing software license keys for software purchased outside the Mac App Store.",
'A MacOS application for managing software license keys for software purchased outside the Mac App Store.',
image: keystashImg,
link: "https://github.com/ghall89/KeyStash",
link: 'https://github.com/ghall89/KeyStash',
},
{
title: "bgg-client",
title: 'bgg-client',
description:
"A TypeScript client for working with the BoardGameGeek.com API.",
'A TypeScript client for working with the BoardGameGeek.com API.',
image: bggClientImg,
link: "https://www.npmjs.com/package/bgg-client",
link: 'https://www.npmjs.com/package/bgg-client',
},
];
+2 -2
View File
@@ -1,5 +1,5 @@
import persist from "@alpinejs/persist";
import type { Alpine } from "alpinejs";
import persist from '@alpinejs/persist';
import type { Alpine } from 'alpinejs';
export default (Alpine: Alpine) => {
Alpine.plugin(persist);
+1 -1
View File
@@ -1,5 +1,5 @@
/// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" />
interface Window {
Alpine: import("alpinejs").Alpine;
Alpine: import('alpinejs').Alpine;
}
+39 -39
View File
@@ -1,58 +1,58 @@
---
import { ClientRouter } from "astro:transitions";
import { ClientRouter } from 'astro:transitions';
import "../styles/global.scss";
import '../styles/global.scss';
import Footer from "@components/Footer.astro";
import Header from "@components/Header/Header.astro";
import Footer from '@components/Footer.astro';
import Header from '@components/Header/Header.astro';
export interface Props {
title: string;
frontmatter?: {
title: string;
};
title: string;
frontmatter?: {
title: string;
};
}
const title = Astro.props.title || Astro.props.frontmatter?.title || "Unknown";
const title = Astro.props.title || Astro.props.frontmatter?.title || 'Unknown';
---
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="robots" content="noindex" /><meta
name="description"
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"
x-data="{
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="robots" content="noindex" /><meta
name="description"
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"
x-data="{
drawerOpen: false,
darkMode: $persist(false),
serifs: $persist(true)
}"
:class="{ 'lock-scroll': drawerOpen, 'theme-dark': darkMode, 'serif-text': serifs}"
>
<Header />
<main transition:animate="initial">
<slot />
</main>
<Footer />
</body>
:class="{ 'lock-scroll': drawerOpen, 'theme-dark': darkMode, 'serif-text': serifs}"
>
<Header />
<main transition:animate="initial">
<slot />
</main>
<Footer />
</body>
</html>
<style lang="scss">
/* Prevent scrolling when drawer (located in Header) is open */
.lock-scroll {
overflow: hidden;
}
/* Prevent scrolling when drawer (located in Header) is open */
.lock-scroll {
overflow: hidden;
}
</style>
+19 -19
View File
@@ -1,30 +1,30 @@
---
import { Image } from "astro:assets";
import Layout from "@layouts/Layout.astro";
import { Image } from 'astro:assets';
import Layout from '@layouts/Layout.astro';
import DataGif from "../assets/it-does-not-exist.gif";
import DataGif from '../assets/it-does-not-exist.gif';
---
<Layout title="Not Found">
<h2>404 - Page Not Found</h2>
<Image
class="gif"
src={DataGif}
alt="Data from Star Trek with the caption 'It does not exist'"
/>
<h2>404 - Page Not Found</h2>
<Image
class="gif"
src={DataGif}
alt="Data from Star Trek with the caption 'It does not exist'"
/>
</Layout>
<style lang="scss">
@use "../styles/variables.scss" as *;
@use '../styles/variables.scss' as *;
h2 {
text-align: center;
}
h2 {
text-align: center;
}
.gif {
display: block;
margin: auto;
border-radius: $radius;
box-shadow: var(--shadow);
}
.gif {
display: block;
margin: auto;
border-radius: $radius;
box-shadow: var(--shadow);
}
</style>
+26 -26
View File
@@ -1,15 +1,15 @@
---
import { getCollection, render } from "astro:content";
import BlogHeader from "@components/Blog/BlogHeader.astro";
import Tags from "@components/Blog/Tags.astro";
import Layout from "@layouts/Layout.astro";
import { getCollection, render } from 'astro:content';
import BlogHeader from '@components/Blog/BlogHeader.astro';
import Tags from '@components/Blog/Tags.astro';
import Layout from '@layouts/Layout.astro';
export async function getStaticPaths() {
const posts = await getCollection("blog");
return posts.map((post) => ({
params: { slug: post.id },
props: { post },
}));
const posts = await getCollection('blog');
return posts.map((post) => ({
params: { slug: post.id },
props: { post },
}));
}
const { post } = Astro.props;
@@ -20,24 +20,24 @@ const { Content } = await render(post);
---
<Layout title={data.title}>
<article>
<BlogHeader title={data.title} date={data.pubDate} />
<Tags tags={data.tags} />
<Content />
<a href="https://notbyai.fyi/" target="_blank">
<i class="not-by-ai"></i>
</a>
</article>
<article>
<BlogHeader title={data.title} date={data.pubDate} />
<Tags tags={data.tags} />
<Content />
<a href="https://notbyai.fyi/" target="_blank">
<i class="not-by-ai"></i>
</a>
</article>
</Layout>
<style lang="scss">
.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;
}
.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;
}
</style>
+42 -42
View File
@@ -1,64 +1,64 @@
---
import { type CollectionEntry, getCollection } from "astro:content";
import PostPreview from "@components/Blog/PostPreview.astro";
import { type CollectionEntry, getCollection } from 'astro:content';
import PostPreview from '@components/Blog/PostPreview.astro';
import Layout from "@layouts/Layout.astro";
import type { Page } from "astro";
import Layout from '@layouts/Layout.astro';
import type { Page } from 'astro';
export async function getStaticPaths({ paginate }) {
const allPosts = await getCollection("blog");
const allPosts = await getCollection('blog');
allPosts.sort(
(a, b) =>
Date.parse(String(b.data.pubDate)) - Date.parse(String(a.data.pubDate)),
);
allPosts.sort(
(a, b) =>
Date.parse(String(b.data.pubDate)) - Date.parse(String(a.data.pubDate))
);
return paginate(allPosts, { pageSize: 10 });
return paginate(allPosts, { pageSize: 10 });
}
interface Props {
page: Page<CollectionEntry<"blog">>;
page: Page<CollectionEntry<'blog'>>;
}
const { page } = Astro.props;
---
<Layout title="Blog Archive">
{page.data.map((post) => <PostPreview post={post} />)}
{page.data.map((post) => <PostPreview post={post} />)}
<div class="pagination">
{
page.currentPage !== 1 ? (
<a href={`/blog/page/${page.currentPage - 1}`}>Previous</a>
) : (
<span class="disabled">Previous</span>
)
}
{
page.currentPage !== page.lastPage ? (
<a href={`/blog/page/${page.currentPage + 1}`}>Next</a>
) : (
<span class="disabled">Next</span>
)
}
</div>
<div class="pagination">
{
page.currentPage !== 1 ? (
<a href={`/blog/page/${page.currentPage - 1}`}>Previous</a>
) : (
<span class="disabled">Previous</span>
)
}
{
page.currentPage !== page.lastPage ? (
<a href={`/blog/page/${page.currentPage + 1}`}>Next</a>
) : (
<span class="disabled">Next</span>
)
}
</div>
</Layout>
<style lang="scss">
ul {
list-style: none;
}
ul {
list-style: none;
}
.pagination {
display: flex;
justify-content: center;
margin: auto;
margin-top: 2rem;
gap: 1rem;
}
.pagination {
display: flex;
justify-content: center;
margin: auto;
margin-top: 2rem;
gap: 1rem;
}
.disabled {
color: var(--text);
opacity: 0.5;
}
.disabled {
color: var(--text);
opacity: 0.5;
}
</style>
+46 -46
View File
@@ -1,72 +1,72 @@
---
import { getCollection } from "astro:content";
import Layout from "@layouts/Layout.astro";
import { add, format } from "date-fns";
import { getCollection } from 'astro:content';
import Layout from '@layouts/Layout.astro';
import { add, format } from 'date-fns';
export async function getStaticPaths() {
const posts = await getCollection("blog");
const posts = await getCollection('blog');
const tags = ["all"];
const tags = ['all'];
posts.forEach((post) => {
post.data.tags.forEach((tag) => {
if (!tags.includes(tag)) {
tags.push(tag);
}
});
});
posts.forEach((post) => {
post.data.tags.forEach((tag) => {
if (!tags.includes(tag)) {
tags.push(tag);
}
});
});
return tags.map((tag) => ({
params: { tag },
props: { tag },
}));
return tags.map((tag) => ({
params: { tag },
props: { tag },
}));
}
const { tag }: { tag?: string } = Astro.params;
const posts = await getCollection("blog", ({ data }) => {
if (!tag) {
return false;
}
const posts = await getCollection('blog', ({ data }) => {
if (!tag) {
return false;
}
if (tag === "all") {
return true;
}
if (tag === 'all') {
return true;
}
return data.tags.includes(tag);
return data.tags.includes(tag);
});
if (posts.length === 0) {
return Astro.redirect("/404");
return Astro.redirect('/404');
}
posts.sort(
(a, b) =>
Date.parse(String(b.data.pubDate)) - Date.parse(String(a.data.pubDate)),
(a, b) =>
Date.parse(String(b.data.pubDate)) - Date.parse(String(a.data.pubDate))
);
---
<Layout title={`Blog - ${tag}`}>
<h1>All posts tagged: {tag}</h1>
<ul>
{
posts.map((post) => (
<li>
<a href={`/posts/${post.id}`}>{post.data.title}</a> -
<span>
{format(
add(new Date(post.data.pubDate), { hours: 6 }),
"MMM do, y",
)}
</span>
</li>
))
}
</ul>
<h1>All posts tagged: {tag}</h1>
<ul>
{
posts.map((post) => (
<li>
<a href={`/posts/${post.id}`}>{post.data.title}</a> -
<span>
{format(
add(new Date(post.data.pubDate), { hours: 6 }),
'MMM do, y'
)}
</span>
</li>
))
}
</ul>
</Layout>
<style lang="scss">
ul {
list-style: none;
}
ul {
list-style: none;
}
</style>
+60 -60
View File
@@ -1,75 +1,75 @@
---
export const prerender = true;
import { getCollection } from "astro:content";
import Avatar from "@components/Avatar.astro";
import LatestPost from "@components/LatestPost.astro";
import Layout from "@layouts/Layout.astro";
import BlueskyIcon from "../assets/svg/bluesky.svg";
import MastodonIcon from "../assets/svg/mastodon.svg";
import { getCollection } from 'astro:content';
import Avatar from '@components/Avatar.astro';
import LatestPost from '@components/LatestPost.astro';
import Layout from '@layouts/Layout.astro';
import BlueskyIcon from '../assets/svg/bluesky.svg';
import MastodonIcon from '../assets/svg/mastodon.svg';
const iconSize = 16;
const posts = await getCollection("blog");
const posts = await getCollection('blog');
const latestPost = posts.sort(
(a, b) =>
new Date(b.data.pubDate).valueOf() - new Date(a.data.pubDate).valueOf(),
(a, b) =>
new Date(b.data.pubDate).valueOf() - new Date(a.data.pubDate).valueOf()
)[0];
---
<Layout title="Welcome">
<Avatar size={200} />
<p>
My name is <strong>Graham</strong> (he/him), a full-stack web developer, and
tech enthusiast.
</p>
<p>
When I'm not writing code, I'm usually enjoying one of my other hobbies;
video games, board games, music, photography, art, the list goes on...
</p>
<p>
I also like writing about stuff, so I put together this site to share
whatever's on my mind about the world of tech, gaming, life, web
development, and whatever else strikes my fancy.
</p>
<p>
Read my latest blog post, <a href={`blog/${latestPost.id}`}
>{latestPost.data.title}</a
>, posted on {new Date(latestPost.data.pubDate).toLocaleDateString()}.
</p>
<p>
If your interested in checking out my web dev projects, check out <a
href="https://ghall.dev/"
target="_blank"
rel="noopener noreferrer">my portfolio</a
>.
</p>
<p>
If you want to get in touch, I'm on <a
rel="me"
href="https://mastodon.social/@ghalldev"
target="_blank"
rel="noopener noreferrer"
><MastodonIcon width={iconSize} height={iconSize} />Mastodon</a
> and <a
href="https://bsky.app/profile/ghalldev.bsky.social"
target="_blank"
rel="noopener noreferrer"
><BlueskyIcon width={iconSize} height={iconSize} />Bluesky</a
>.
</p>
<p>
My portrait was drawn by <a
href="https://www.nataliavazquezgarcia.com"
target="_blank"
rel="noopener noreferrer">Natalia Vazquez</a
>.
</p>
<LatestPost />
<Avatar size={200} />
<p>
My name is <strong>Graham</strong> (he/him), a full-stack web developer, and
tech enthusiast.
</p>
<p>
When I'm not writing code, I'm usually enjoying one of my other hobbies;
video games, board games, music, photography, art, the list goes on...
</p>
<p>
I also like writing about stuff, so I put together this site to share
whatever's on my mind about the world of tech, gaming, life, web
development, and whatever else strikes my fancy.
</p>
<p>
Read my latest blog post, <a href={`blog/${latestPost.id}`}
>{latestPost.data.title}</a
>, posted on {new Date(latestPost.data.pubDate).toLocaleDateString()}.
</p>
<p>
If your interested in checking out my web dev projects, check out <a
href="https://ghall.dev/"
target="_blank"
rel="noopener noreferrer">my portfolio</a
>.
</p>
<p>
If you want to get in touch, I'm on <a
rel="me"
href="https://mastodon.social/@ghalldev"
target="_blank"
rel="noopener noreferrer"
><MastodonIcon width={iconSize} height={iconSize} />Mastodon</a
> and <a
href="https://bsky.app/profile/ghalldev.bsky.social"
target="_blank"
rel="noopener noreferrer"
><BlueskyIcon width={iconSize} height={iconSize} />Bluesky</a
>.
</p>
<p>
My portrait was drawn by <a
href="https://www.nataliavazquezgarcia.com"
target="_blank"
rel="noopener noreferrer">Natalia Vazquez</a
>.
</p>
<LatestPost />
</Layout>
<style lang="scss">
a > svg {
transform: translateY(0.1rem);
}
a > svg {
transform: translateY(0.1rem);
}
</style>
+37 -37
View File
@@ -1,47 +1,47 @@
---
import Card from "@components/Card.astro";
import { projects } from "@data/projects";
import Layout from "@layouts/Layout.astro";
import Card from '@components/Card.astro';
import { projects } from '@data/projects';
import Layout from '@layouts/Layout.astro';
const title = "Projects";
const title = 'Projects';
---
<Layout title={title}>
<h1>{title}</h1>
<div class="projects-grid">
{
projects.map((project) => (
<Card
title={project.title}
image={project.image}
links={[
{
label: "More...",
href: project.link,
newWindow: true,
},
]}
>
<div class="project-content">
<p>{project.description}</p>
</div>
</Card>
))
}
</div>
<h1>{title}</h1>
<div class="projects-grid">
{
projects.map((project) => (
<Card
title={project.title}
image={project.image}
links={[
{
label: 'More...',
href: project.link,
newWindow: true,
},
]}
>
<div class="project-content">
<p>{project.description}</p>
</div>
</Card>
))
}
</div>
</Layout>
<style lang="scss">
.projects-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1rem;
}
.projects-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1rem;
}
.project-content {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 8rem;
}
.project-content {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 8rem;
}
</style>
+6 -6
View File
@@ -1,15 +1,15 @@
import { getCollection } from "astro:content";
import rss from "@astrojs/rss";
import MarkdownIt from "markdown-it";
import { getCollection } from 'astro:content';
import rss from '@astrojs/rss';
import MarkdownIt from 'markdown-it';
const parser = new MarkdownIt({ html: true });
export async function GET(context) {
const blog = await getCollection("blog");
const blog = await getCollection('blog');
return rss({
title: "ghall.space",
title: 'ghall.space',
description:
"My personal blog about life, gaming, tech, and whatever else I feel like writing about.",
'My personal blog about life, gaming, tech, and whatever else I feel like writing about.',
site: context.site,
trailingSlash: false,
items: blog
+47 -47
View File
@@ -1,64 +1,64 @@
---
import Layout from "@layouts/Layout.astro";
import SearchField from "astro-pagefind/components/Search";
import Layout from '@layouts/Layout.astro';
import SearchField from 'astro-pagefind/components/Search';
---
<Layout title="Search">
<div class="search-container">
<h2>Looking for something?</h2>
<SearchField
id="search"
className="pagefind-ui"
uiOptions={{ showImages: false }}
/>
</div>
<div class="search-container">
<h2>Looking for something?</h2>
<SearchField
id="search"
className="pagefind-ui"
uiOptions={{ showImages: false }}
/>
</div>
</Layout>
<style is:global>
.search-container {
min-height: 60vh;
}
.search-container {
min-height: 60vh;
}
.pagefind-ui {
font-family: var(--font) !important;
color: var(--text) !important;
}
.pagefind-ui {
font-family: var(--font) !important;
color: var(--text) !important;
}
.pagefind-ui__form::before {
background-color: var(--text) !important;
}
.pagefind-ui__form::before {
background-color: var(--text) !important;
}
.pagefind-ui__search-input,
.pagefind-ui__button {
color: var(--text) !important;
border: var(--border) !important;
background-color: var(--background) !important;
}
.pagefind-ui__search-input,
.pagefind-ui__button {
color: var(--text) !important;
border: var(--border) !important;
background-color: var(--background) !important;
}
.pagefind-ui__button:hover {
opacity: 0.75;
}
.pagefind-ui__button:hover {
opacity: 0.75;
}
.pagefind-ui__search-clear {
color: var(--red) !important;
background-color: var(--background) !important;
}
.pagefind-ui__search-clear {
color: var(--red) !important;
background-color: var(--background) !important;
}
.pagefind-ui__result-excerpt > mark {
background-color: var(--highlight);
}
.pagefind-ui__result-excerpt > mark {
background-color: var(--highlight);
}
.pagefind-ui__result-link {
color: var(--blue) !important;
text-decoration: none !important;
}
.pagefind-ui__result-link {
color: var(--blue) !important;
text-decoration: none !important;
}
.pagefind-ui__result-link:hover {
opacity: 0.75;
}
.pagefind-ui__result-link:hover {
opacity: 0.75;
}
.pagefind-ui__result {
border: none !important;
border-bottom: var(--border) !important;
}
.pagefind-ui__result {
border: none !important;
border-bottom: var(--border) !important;
}
</style>
+6 -6
View File
@@ -1,14 +1,14 @@
@font-face {
font-family: "Noto Sans";
src: url("./fonts/NotoSans-VariableFont_wdth,wght.ttf") format("truetype");
font-family: 'Noto Sans';
src: url('./fonts/NotoSans-VariableFont_wdth,wght.ttf') format('truetype');
}
@font-face {
font-family: "Noto Serif";
src: url("./fonts/NotoSerif-VariableFont_wdth,wght.ttf") format("truetype");
font-family: 'Noto Serif';
src: url('./fonts/NotoSerif-VariableFont_wdth,wght.ttf') format('truetype');
}
@font-face {
font-family: "JetBrainsMono";
src: url("./fonts/JetBrainsMono-VariableFont_wght.ttf") format("truetype");
font-family: 'JetBrainsMono';
src: url('./fonts/JetBrainsMono-VariableFont_wght.ttf') format('truetype');
}
+75 -75
View File
@@ -1,139 +1,139 @@
@use "./variables.scss" as *;
@use "fonts.scss";
@use './variables.scss' as *;
@use 'fonts.scss';
:root {
--blue: #1e66f5;
--sky: #04a5e5;
--red: #d20f39;
--orange: #fe640b;
--text: #40360e;
--highlight: #ffeebd;
--background: #fffdf5;
--border: #{$border-style} #8f7a20;
--font: "Noto Sans", sans-serif;
--blue: #1e66f5;
--sky: #04a5e5;
--red: #d20f39;
--orange: #fe640b;
--text: #40360e;
--highlight: #ffeebd;
--background: #fffdf5;
--border: #{$border-style} #8f7a20;
--font: 'Noto Sans', sans-serif;
}
.theme-dark {
--blue: #5da7fb;
--sky: #00b0f5;
--red: #f38ba8;
--orange: #fab387;
--text: #c4caed;
--background: #2a2c32;
--border: #{$border-style} #505160;
--blue: #5da7fb;
--sky: #00b0f5;
--red: #f38ba8;
--orange: #fab387;
--text: #c4caed;
--background: #2a2c32;
--border: #{$border-style} #505160;
}
.serif-text {
--font: "Noto Serif", serif;
--font: 'Noto Serif', serif;
}
body {
color: var(--text);
background-color: var(--background);
font-family: var(--font);
font-size: 1.1rem;
margin: 0;
padding: 0;
color: var(--text);
background-color: var(--background);
font-family: var(--font);
font-size: 1.1rem;
margin: 0;
padding: 0;
}
main {
max-width: 800px;
margin: auto;
padding: 0 1rem;
margin-top: 100px;
max-width: 800px;
margin: auto;
padding: 0 1rem;
margin-top: 100px;
}
a {
color: var(--blue);
text-decoration: none;
color: var(--blue);
text-decoration: none;
&:hover {
opacity: 0.75;
}
&:hover {
opacity: 0.75;
}
}
main p {
line-height: 1.5;
line-height: 1.5;
}
/* Article image style */
article img {
border-radius: $radius;
display: block;
margin: auto;
max-width: $max-page-width;
height: auto;
border-radius: $radius;
display: block;
margin: auto;
max-width: $max-page-width;
height: auto;
}
/* Typography */
.footnotes {
font-size: 1rem;
font-size: 1rem;
}
.footnotes p {
display: inline;
display: inline;
}
blockquote {
border-left: 4px solid;
border-color: var(--text);
margin-left: 1rem;
padding-left: 2rem;
font-style: italic;
border-left: 4px solid;
border-color: var(--text);
margin-left: 1rem;
padding-left: 2rem;
font-style: italic;
}
code {
color: var(--orange);
padding: 1px 4px;
margin: 0 2px;
user-select: all;
color: var(--orange);
padding: 1px 4px;
margin: 0 2px;
user-select: all;
}
kbd {
border: var(--border);
border-radius: $radius;
padding: 1px 4px;
white-space: nowrap;
border: var(--border);
border-radius: $radius;
padding: 1px 4px;
white-space: nowrap;
}
code,
kbd {
font-size: 0.85rem;
font-size: 0.85rem;
}
/* Icon button */
.icon-button {
background: none;
padding: 2px 2px -2px;
border: none;
line-height: 1;
aspect-ratio: square;
height: 24px;
width: 24px;
background: none;
padding: 2px 2px -2px;
border: none;
line-height: 1;
aspect-ratio: square;
height: 24px;
width: 24px;
&:active {
opacity: 0.3;
}
&:active {
opacity: 0.3;
}
& svg {
color: var(--text);
}
& svg {
color: var(--text);
}
}
/* shiki */
.astro-code,
.astro-code span {
background-color: var(--background) !important;
/* Optional, if you also want font styles */
font-style: var(--shiki-light-font-style);
font-weight: var(--shiki-light-font-weight);
text-decoration: var(--shiki-light-text-decoration);
background-color: var(--background) !important;
/* Optional, if you also want font styles */
font-style: var(--shiki-light-font-style);
font-weight: var(--shiki-light-font-weight);
text-decoration: var(--shiki-light-text-decoration);
}
.theme-dark .astro-code,
.theme-dark .astro-code span {
color: var(--shiki-dark) !important;
color: var(--shiki-dark) !important;
}