feat(site): migrate from Next.js to Astro
Build and Deploy / deploy (push) Successful in 1m42s

Replace Next.js 16 + React 19 with Astro 5. Same visual design,
same deploy pipeline, zero client-side framework.

- All components rewritten as .astro files
- Dark mode via inline scripts (no React context)
- Timeline animation via IntersectionObserver script
- Nav active state computed at build time
- Self-hosted Source Code Pro woff2 fonts
- Drop Font Awesome (icons were never loaded)
- Drop unused headshot PNG (1MB, unreferenced)
- Fix pfSense hardware refs (Netgate 1100, not N100)
- Output: 212KB static HTML vs 2.6MB before
- JS shipped: ~700 bytes inline vs ~130KB React runtime
This commit is contained in:
2026-05-18 20:07:24 -04:00
parent d34f9f136c
commit 0c5d9e03b1
47 changed files with 4898 additions and 6345 deletions
+108
View File
@@ -0,0 +1,108 @@
@import "tailwindcss";
@variant dark (&:where(.dark, .dark *));
@theme {
/* macOS Classic Dark (default) */
--color-bg: #131313;
--color-surface: #1e1d1e;
--color-surface-raised: #272727;
--color-border: #3a3a3a;
--color-border-bright: #404040;
--color-text: #caccca;
--color-text-label: #9e9e9e;
--color-text-dim: #8f8f8f;
--color-accent-green: #62ba46;
--color-accent-red: #c74028;
/* Timeline type colors — dark */
--color-timeline-career: #62ba46;
--color-timeline-education: #c28b12;
--color-timeline-cert: #c75828;
--color-timeline-project: #c72855;
--color-timeline-homelab: #e1d797;
/* Typography */
--font-mono: "Source Code Pro", ui-monospace, monospace;
--font-sans: ui-sans-serif, system-ui, sans-serif;
/* Breakpoints */
--breakpoint-xs: 576px;
/* Character-grid spacing — horizontal (ch) */
--spacing-1ch: 1ch;
--spacing-2ch: 2ch;
--spacing-3ch: 3ch;
--spacing-4ch: 4ch;
/* Character-grid spacing — vertical (lh, requires line-height:1.5 on html) */
--spacing-qtr-lh: 0.25lh;
--spacing-half-lh: 0.5lh;
--spacing-1lh: 1lh;
--spacing-2lh: 2lh;
--spacing-3lh: 3lh;
--spacing-4lh: 4lh;
/* Animations */
--animate-fade-in: fadeIn 120ms linear forwards;
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
}
/* Base */
html {
scroll-behavior: smooth;
font-size: 15px;
line-height: 1.5;
background-color: var(--color-bg);
color: var(--color-text);
font-family: var(--font-mono);
}
@keyframes blink { 50% { opacity: 0; } }
.animate-cursor { animation: blink 1s step-start infinite; }
@layer base {
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
}
/* macOS Classic Light overrides */
:root:not(.dark) {
--color-bg: #ffffff;
--color-surface: #f9f9f9;
--color-surface-raised: #f7f7f7;
--color-border: #e0e0e0;
--color-border-bright: #d2d2d2;
--color-text: #000000;
--color-text-label: #505050;
--color-text-dim: #929292;
--color-accent-green: #036a07;
--color-accent-red: #d21f07;
--color-timeline-career: #036a07;
--color-timeline-education: #0433ff;
--color-timeline-cert: #957931;
--color-timeline-project: #6f42c1;
--color-timeline-homelab: #0000a2;
}
/* Default transitions — linear, fast */
a,
button {
transition: color 120ms linear, border-color 120ms linear,
background-color 120ms linear, opacity 120ms linear;
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}