Mirror of my GitHub Pages site
0

Configure Feed

Select the types of activity you want to include in your feed.

Format

authored by

Spenser Black and committed by
GitHub
(Jun 30, 2026, 11:01 PM UTC) 823dec07 b6d4b2e9

+132 -78
+2 -2
.github/workflows/ci.yml
··· 2 2 3 3 on: 4 4 push: 5 - branches: [ "main" ] 5 + branches: ["main"] 6 6 pull_request: 7 - branches: [ "main" ] 7 + branches: ["main"] 8 8 9 9 jobs: 10 10 build:
+1 -1
astro.config.mjs
··· 1 1 // @ts-check 2 - import { defineConfig } from 'astro/config'; 2 + import { defineConfig } from "astro/config"; 3 3 4 4 // https://astro.build/config 5 5 export default defineConfig({});
+1
src/components/ExternalLink.astro
··· 1 1 --- 2 2 const { link } = Astro.props; 3 3 --- 4 + 4 5 <a href={link} target="_blank"><slot /></a>
+13 -2
src/components/Header.astro
··· 4 4 ["Projects", "/projects/"], 5 5 ]; 6 6 --- 7 + 7 8 <header> 8 9 <nav> 9 10 { 10 - pages.map(([description, link]) => <a class="button primary" href={link}>{description}</a>) 11 + pages.map(([description, link]) => ( 12 + <a class="button primary" href={link}> 13 + {description} 14 + </a> 15 + )) 11 16 } 12 17 </nav> 13 18 <div class="controls"> 14 19 <div id="theme-dropdown" class="dropdown"> 15 - <button type="button" id="theme-dropdown-button" class="primary theme" aria-expanded="false" aria-controls="theme-dropdown"> 20 + <button 21 + type="button" 22 + id="theme-dropdown-button" 23 + class="primary theme" 24 + aria-expanded="false" 25 + aria-controls="theme-dropdown" 26 + > 16 27 Theme 17 28 </button> 18 29 <ul id="theme-dropdown-content" class="dropdown-content hide">
+10 -5
src/components/LinkList.astro
··· 12 12 13 13 const { items } = Astro.props; 14 14 --- 15 + 15 16 <ul> 16 17 { 17 - items.map(({ link, name, external }) => <li>{ 18 - external 19 - ? <ExternalLink link={link}>{name}</ExternalLink> 20 - : <a href={link}>{name}</a> 21 - }</li>) 18 + items.map(({ link, name, external }) => ( 19 + <li> 20 + {external ? ( 21 + <ExternalLink link={link}>{name}</ExternalLink> 22 + ) : ( 23 + <a href={link}>{name}</a> 24 + )} 25 + </li> 26 + )) 22 27 } 23 28 </ul>
+1
src/components/ProjectHeading.astro
··· 5 5 6 6 const { link } = Astro.props; 7 7 --- 8 + 8 9 <h2><a href={link}><slot /></a></h2>
+3 -1
src/components/ProjectStats.astro
··· 12 12 13 13 const { language, relation } = Astro.props; 14 14 --- 15 + 15 16 <dl> 16 17 <dt>Relation</dt> 17 18 <dd class="relation" title={relationTitle[relation]}>{relation}</dd> ··· 32 33 dd { 33 34 grid-row: 2; 34 35 } 35 - dt, dd { 36 + dt, 37 + dd { 36 38 margin: 0; 37 39 text-align: center; 38 40 }
+1 -1
src/layouts/BaseLayout.astro
··· 8 8 <html lang="en"> 9 9 <head> 10 10 <meta charset="utf-8" /> 11 - <link rel='shortcut icon' type='image/x-icon' href='/favicon.ico' /> 11 + <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" /> 12 12 <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> 13 13 <meta name="viewport" content="width=device-width" /> 14 14 <meta name="generator" content={Astro.generator} />
+21 -11
src/pages/index.astro
··· 4 4 import LinkList from "../components/LinkList.astro"; 5 5 const title = "Homepage"; 6 6 7 - const mapToExternalLinks = (items: Record<string, string>) => Object.entries(items) 8 - .map(([name, link]) => ({ name, link, external: true })); 7 + const mapToExternalLinks = (items: Record<string, string>) => 8 + Object.entries(items).map(([name, link]) => ({ name, link, external: true })); 9 9 10 10 const languages = mapToExternalLinks({ 11 11 Go: "https://go.dev/", ··· 22 22 const animeAndManga = mapToExternalLinks({ 23 23 Baki: "https://youtu.be/vazrSoijLmA", 24 24 Drifters: "https://en.wikipedia.org/wiki/Drifters_(manga)", 25 - "Getter Robo Armageddon": "https://en.wikipedia.org/wiki/Getter_Robo_Armageddon", 25 + "Getter Robo Armageddon": 26 + "https://en.wikipedia.org/wiki/Getter_Robo_Armageddon", 26 27 }); 27 28 const games = mapToExternalLinks({ 28 29 "Resident Evil": "https://en.wikipedia.org/wiki/Resident_Evil", ··· 33 34 34 35 <BaseLayout title={title}> 35 36 <h2>Introduction</h2> 36 - <p>👋 This is my personal site. I'm a developer, both for work and as a hobby, and I enjoy using the following languages:</p> 37 + <p> 38 + 👋 This is my personal site. I'm a developer, both for work and as a hobby, 39 + and I enjoy using the following languages: 40 + </p> 37 41 <LinkList items={languages} /> 38 42 <p> 39 - As you can probably tell from this site's styling, I am not much of 40 - a <ExternalLink link="https://en.wikipedia.org/wiki/Front_end_and_back_end">front-end</ExternalLink> developer, 41 - and tend to keep my websites simple. When I <em>do</em> write frontend stuff, I typically use 42 - either <ExternalLink link="https://svelte.dev/">Svelte</ExternalLink> or <ExternalLink link="https://vuejs.org/">Vue</ExternalLink>. 43 - This site has been written with <strong><ExternalLink link="https://astro.build/">Astro</ExternalLink></strong>, both as a means 44 - of teaching myself Astro and also because it seemed like a good tool to build this site. 43 + As you can probably tell from this site's styling, I am not much of a <ExternalLink 44 + link="https://en.wikipedia.org/wiki/Front_end_and_back_end" 45 + >front-end</ExternalLink 46 + > developer, and tend to keep my websites simple. When I <em>do</em> write frontend 47 + stuff, I typically use either <ExternalLink link="https://svelte.dev/" 48 + >Svelte</ExternalLink 49 + > or <ExternalLink link="https://vuejs.org/">Vue</ExternalLink>. This site 50 + has been written with <strong 51 + ><ExternalLink link="https://astro.build/">Astro</ExternalLink></strong 52 + >, both as a means of teaching myself Astro and also because it seemed like 53 + a good tool to build this site. 45 54 </p> 46 55 47 56 <p> 48 - Besides coding stuff, I like reading, video games, movies, anime and manga, and sometimes working out. I especially like: 57 + Besides coding stuff, I like reading, video games, movies, anime and manga, 58 + and sometimes working out. I especially like: 49 59 </p> 50 60 <ul> 51 61 <li>
+37 -23
src/pages/projects.astro
··· 5 5 import ProjectStats from "../components/ProjectStats.astro"; 6 6 const title = "Projects"; 7 7 --- 8 + 8 9 <BaseLayout title={title}> 9 - <p> 10 - Here are some of the open-source projects that I work on. 11 - </p> 12 - <ProjectHeading link="https://github.com/spenserblack/fancy-tree">fancy-tree</ProjectHeading> 10 + <p>Here are some of the open-source projects that I work on.</p> 11 + <ProjectHeading link="https://github.com/spenserblack/fancy-tree" 12 + >fancy-tree</ProjectHeading 13 + > 13 14 <ProjectStats language="Rust" relation="owner" /> 14 15 <p> 15 - An alternative to <ExternalLink link="https://en.wikipedia.org/wiki/Tree_(command)"><code>tree</code></ExternalLink> with 16 - support for Git status and code language detection. 17 - It uses <ExternalLink link="https://www.lua.org/">Lua</ExternalLink> configuration files to 18 - support fine-grained customization. 16 + An alternative to <ExternalLink 17 + link="https://en.wikipedia.org/wiki/Tree_(command)" 18 + ><code>tree</code></ExternalLink 19 + > with support for Git status and code language detection. It uses <ExternalLink 20 + link="https://www.lua.org/">Lua</ExternalLink 21 + > configuration files to support fine-grained customization. 19 22 </p> 20 23 21 - <ProjectHeading link="https://github.com/spenserblack/from-ascii">from-ascii</ProjectHeading> 24 + <ProjectHeading link="https://github.com/spenserblack/from-ascii" 25 + >from-ascii</ProjectHeading 26 + > 22 27 <ProjectStats language="Go" relation="owner" /> 23 28 <p> 24 - A tool to convert ASCII art into an actual image, treating each character like a pixel. Pixel 25 - opacity is determined the ASCII character used, and ANSI color escape codes are parsed into 26 - colors for each color. 29 + A tool to convert ASCII art into an actual image, treating each character 30 + like a pixel. Pixel opacity is determined the ASCII character used, and ANSI 31 + color escape codes are parsed into colors for each color. 27 32 </p> 28 33 29 - <ProjectHeading link="https://github.com/spenserblack/gengo">gengo</ProjectHeading> 34 + <ProjectHeading link="https://github.com/spenserblack/gengo" 35 + >gengo</ProjectHeading 36 + > 30 37 <ProjectStats language="Rust" relation="owner" /> 31 38 <p> 32 - A multi-purpose tool to help identify the code languages within a project. Works on both work trees and bare git repositories. 39 + A multi-purpose tool to help identify the code languages within a project. 40 + Works on both work trees and bare git repositories. 33 41 </p> 34 42 35 - <ProjectHeading link="https://github.com/o2sh/onefetch">Onefetch</ProjectHeading> 43 + <ProjectHeading link="https://github.com/o2sh/onefetch" 44 + >Onefetch</ProjectHeading 45 + > 36 46 <ProjectStats language="Rust" relation="maintainer" /> 37 47 <p> 38 - A CLI tool that analyzes your repository and prints an ASCII logo for its primary language and 39 - various repository statistics. 40 - Think like <ExternalLink link="https://github.com/dylanaraps/neofetch"><code>neofetch</code></ExternalLink>, 41 - but for a Git repository. 48 + A CLI tool that analyzes your repository and prints an ASCII logo for its 49 + primary language and various repository statistics. Think like <ExternalLink 50 + link="https://github.com/dylanaraps/neofetch" 51 + ><code>neofetch</code></ExternalLink 52 + >, but for a Git repository. 42 53 </p> 43 54 44 - <ProjectHeading link="https://github.com/spenserblack/steamdown">Steamdown</ProjectHeading> 55 + <ProjectHeading link="https://github.com/spenserblack/steamdown" 56 + >Steamdown</ProjectHeading 57 + > 45 58 <ProjectStats language="TypeScript" relation="owner" /> 46 59 <p> 47 - A parser and renderer for a markdown-like syntax. Content can be rendered 48 - as <ExternalLink link="https://steamcommunity.com/comment/Recommendation/formattinghelp">Steam's formatting language</ExternalLink>, 49 - or as HTML for a preview. 60 + A parser and renderer for a markdown-like syntax. Content can be rendered as <ExternalLink 61 + link="https://steamcommunity.com/comment/Recommendation/formattinghelp" 62 + >Steam's formatting language</ExternalLink 63 + >, or as HTML for a preview. 50 64 </p> 51 65 </BaseLayout>
+18 -8
src/scripts/theme-dropdown.ts
··· 1 1 const dropdown = document.getElementById("theme-dropdown") as HTMLDivElement; 2 - const button = document.getElementById("theme-dropdown-button") as HTMLButtonElement; 3 - const content = document.getElementById("theme-dropdown-content") as HTMLDivElement; 2 + const button = document.getElementById( 3 + "theme-dropdown-button", 4 + ) as HTMLButtonElement; 5 + const content = document.getElementById( 6 + "theme-dropdown-content", 7 + ) as HTMLDivElement; 4 8 5 9 const themeKey = "spenserblack.github.io theme"; 6 10 const setTheme = (theme: string) => { ··· 17 21 setTheme(savedTheme); 18 22 } 19 23 20 - const buttonVariants: [string, HTMLButtonElement][] = ["system", "dark", "light"] 21 - .map((variant) => [variant, document.getElementById(`theme-${variant}`) as HTMLButtonElement]); 22 - const themeButtons = buttonVariants.map(([,button]) => button); 24 + const buttonVariants: [string, HTMLButtonElement][] = [ 25 + "system", 26 + "dark", 27 + "light", 28 + ].map((variant) => [ 29 + variant, 30 + document.getElementById(`theme-${variant}`) as HTMLButtonElement, 31 + ]); 32 + const themeButtons = buttonVariants.map(([, button]) => button); 23 33 24 34 const show = () => { 25 35 content.classList.remove("hide"); ··· 41 51 42 52 button.addEventListener("click", toggle); 43 53 button.addEventListener("blur", (e) => { 44 - const isThemeButton = e.target && themeButtons.includes(e.target as HTMLButtonElement); 54 + const isThemeButton = 55 + e.target && themeButtons.includes(e.target as HTMLButtonElement); 45 56 if (!isThemeButton) { 46 57 hide(); 47 58 } 48 59 }); 49 60 50 - buttonVariants 51 - .forEach(([variant, button]) => { 61 + buttonVariants.forEach(([variant, button]) => { 52 62 button.addEventListener("mousedown", () => { 53 63 setTheme(variant); 54 64 saveTheme(variant);
+24 -24
src/styles/global.css
··· 1 1 :root { 2 2 --dark-main-bg: #333; 3 - --dark-main-fg: #EEE; 4 - --dark-primary: #FA4; 5 - --dark-link: #FC4; 6 - --dark-link-visited: #FA4; 7 - --dark-link-hover: #FD5; 3 + --dark-main-fg: #eee; 4 + --dark-primary: #fa4; 5 + --dark-link: #fc4; 6 + --dark-link-visited: #fa4; 7 + --dark-link-hover: #fd5; 8 8 --dark-contrast: #222; 9 9 10 - --light-main-bg: #EEE; 10 + --light-main-bg: #eee; 11 11 --light-main-fg: #333; 12 - --light-primary: #E84; 13 - --light-link: #E64; 14 - --light-link-visited: #E84; 15 - --light-link-hover: #D60; 16 - --light-contrast: #FFF; 12 + --light-primary: #e84; 13 + --light-link: #e64; 14 + --light-link-visited: #e84; 15 + --light-link-hover: #d60; 16 + --light-contrast: #fff; 17 17 18 18 --main-bg: var(--dark-main-bg); 19 19 --main-fg: var(--dark-main-fg); ··· 38 38 @media (prefers-color-scheme: light) { 39 39 :root { 40 40 --main-bg: var(--light-main-bg); 41 - --main-fg: var(--light-main-fg); 42 - --primary: var(--light-primary); 43 - --contrast: var(--light-contrast); 44 - --link: var(--light-link); 45 - --link-visited: var(--light-link-visited); 46 - --link-hover: var(--light-link-hover); 41 + --main-fg: var(--light-main-fg); 42 + --primary: var(--light-primary); 43 + --contrast: var(--light-contrast); 44 + --link: var(--light-link); 45 + --link-visited: var(--light-link-visited); 46 + --link-hover: var(--light-link-hover); 47 47 } 48 48 } 49 49 50 50 :root[data-theme="light"] { 51 - --main-bg: var(--light-main-bg); 52 - --main-fg: var(--light-main-fg); 53 - --primary: var(--light-primary); 54 - --contrast: var(--light-contrast); 55 - --link: var(--light-link); 56 - --link-visited: var(--light-link-visited); 57 - --link-hover: var(--light-link-hover); 51 + --main-bg: var(--light-main-bg); 52 + --main-fg: var(--light-main-fg); 53 + --primary: var(--light-primary); 54 + --contrast: var(--light-contrast); 55 + --link: var(--light-link); 56 + --link-visited: var(--light-link-visited); 57 + --link-hover: var(--light-link-hover); 58 58 } 59 59 60 60 :root[data-theme="dark"] {