/* ============================================================================ AaronMHampton.com UI Kit — shared components, data, atoms Exports to window for cross-file use (Babel scopes are per-script). ========================================================================== */ /* ---- Icon (Lucide, imperatively mounted so React never fights it) --------- */ function Icon({ name, size = 18, stroke = 1.75, className = "" }) { const ref = React.useRef(null); React.useEffect(() => { const el = ref.current; if (!el || !window.lucide) return; el.innerHTML = ""; const pascal = name.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(""); const node = window.lucide.icons && window.lucide.icons[pascal] || window.lucide[pascal]; if (node && window.lucide.createElement) { const svg = window.lucide.createElement(node); svg.setAttribute("width", size); svg.setAttribute("height", size); svg.setAttribute("stroke-width", stroke); el.appendChild(svg); } }); return ( ); } /* ---- Atoms ---------------------------------------------------------------- */ function Crosshair() {return ;} function Eyebrow({ idx, children }) { return ( {idx && {idx} —} {children} ); } function Button({ variant = "primary", children, onClick, as = "button", href }) { const cls = "btn btn-" + variant; if (as === "a") return {children}; return ; } function Tag({ children, on, onClick }) { return ; } function Placeholder({ label = "Image", style }) { return (
{label}
); } /* ---- Brand / Logo --------------------------------------------------------- */ function BrandMark() { return ( AMH); } function Brand({ onClick }) { return ( Aaron M. Hampton ); } /* ---- Theme toggle (controlled by App) ------------------------------------- */ function ThemeToggle({ theme, onToggle }) { return ( ); } /* ---- Search trigger — the front door to ⌘K global search ------------------ */ function SearchTrigger({ onClick, compact }) { const mod = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform || "") ? "\u2318" : "Ctrl"; if (compact) { return ( ); } return ( ); } /* ---- Nav data ------------------------------------------------------------- */ const NAV = [ { id: "writing", label: "Writing" }, { id: "projects", label: "Projects" }, { id: "photos", label: "Photos" }, { id: "about", label: "About" }]; /* ---- Top bar -------------------------------------------------------------- */ function TopBar({ route, go, theme, onToggleTheme, onSearch }) { const [open, setOpen] = React.useState(false); const navTo = (id) => {go(id);setOpen(false);}; return (
navTo("home")} />
{NAV.map((n) => navTo(n.id)}>{n.label} )} navTo("subscribe")}>Subscribe →
); } /* ---- Footer --------------------------------------------------------------- */ function Footer({ go }) { return ( ); } /* ---- Content data --------------------------------------------------------- */ const POSTS = [ { id: "p1", num: "014", cat: "Essay", title: "Attention is the only scarce resource I have left", desc: "A short argument for treating focus as capital — and three habits I changed once I believed it.", date: "2026-05-12", read: "7 min", tags: ["philosophy", "technology"] }, { id: "p2", num: "013", cat: "Note", title: "What the printing press actually changed", desc: "Less about literacy than we think, more about the economics of being wrong in public.", date: "2026-04-28", read: "5 min", tags: ["history"] }, { id: "p3", num: "012", cat: "Essay", title: "A bias toward the legible", desc: "Why systems drift toward what's measurable, and what gets quietly deleted on the way.", date: "2026-04-09", read: "9 min", tags: ["politics", "science"] }, { id: "p4", num: "011", cat: "Note", title: "Tools are arguments about how to live", desc: "Every interface encodes a theory of the person using it. Most of them are wrong about you.", date: "2026-03-22", read: "4 min", tags: ["technology", "philosophy"] }, { id: "p5", num: "010", cat: "Essay", title: "On keeping a slow archive", desc: "I write to remember what I actually thought, not what I wish I had. Here's the system.", date: "2026-03-01", read: "6 min", tags: ["science"] }]; const PROJECTS = [ { id: "j1", title: "Marginalia", tagline: "A reader that pulls your notes into the margin where they belong.", lang: "TypeScript", stars: "1.2k", year: "2026" }, { id: "j2", title: "Plotpaper", tagline: "Minimal charting library for thinking in public. Hairlines, no chartjunk.", lang: "Rust · WASM", stars: "640", year: "2025" }, { id: "j3", title: "Slowfeed", tagline: "An RSS reader that refuses to show you anything more than once a day.", lang: "Go", stars: "2.1k", year: "2025" }, { id: "j4", title: "Index", tagline: "The engine behind this site. Markdown in, quiet HTML out.", lang: "TypeScript", stars: "310", year: "2024" }]; const PHOTOS = [ { id: "ph1", cap: "Coastal range", meta: "35mm", ar: "3/4" }, { id: "ph2", cap: "Reading desk", meta: "50mm", ar: "1/1" }, { id: "ph3", cap: "Fog, early", meta: "35mm", ar: "4/5" }, { id: "ph4", cap: "Library stacks", meta: "28mm", ar: "1/1" }, { id: "ph5", cap: "Long exposure", meta: "35mm", ar: "3/4" }, { id: "ph6", cap: "Train window", meta: "50mm", ar: "4/5" }, { id: "ph7", cap: "Workbench", meta: "35mm", ar: "1/1" }, { id: "ph8", cap: "Dusk field", meta: "28mm", ar: "3/4" }, { id: "ph9", cap: "Notebook study", meta: "50mm", ar: "4/5" }]; Object.assign(window, { Icon, Crosshair, Eyebrow, Button, Tag, Placeholder, BrandMark, Brand, ThemeToggle, SearchTrigger, TopBar, Footer, NAV, POSTS, PROJECTS, PHOTOS });