--- /** * CategoryArt — terminal-style SVG illustration per category. * Matches the banner-gen visual language (dark #0d1220 canvas, terminal * window with traffic-light dots, JetBrains Mono, status colors) but with a * per-category accent color, so each category is scannable at a glance. * Inline SVG inherits the blog's self-hosted JetBrains Mono for text lines. */ import { categoryMeta } from '../lib/categories'; interface Props { slug: string; } const { slug } = Astro.props; const meta = categoryMeta(slug); // line types: prompt (accent), cmd #e6edf3, ok #3fb950, hl #f5a524, dim #6b7c99 type Line = { t: 'prompt' | 'cmd' | 'ok' | 'hl' | 'dim'; c: string }; const ART: Record = { ai: { title: 'n8n — ai workflows', lines: [ { t: 'dim', c: 'telegram ⇄ llm ⇄ memory' }, { t: 'prompt', c: '>' }, { t: 'cmd', c: ' user: "help me book a slot"' }, { t: 'ok', c: 'bot: done · calendar updated' }, { t: 'hl', c: 'mem0 long-term memory · on' }, ], glyph: 'text', gc: 'λ', }, 'case-studies': { title: 'mr@hoelee — portfolio', lines: [ { t: 'dim', c: 'drwxr-xr-x hoelee projects' }, { t: 'prompt', c: '$' }, { t: 'cmd', c: ' cd digikedai-bot && ship' }, { t: 'ok', c: 'deployed · measured · written up' }, { t: 'hl', c: '→ end-to-end build logs' }, ], glyph: 'check', gc: '', }, devops: { title: 'root@homelab', lines: [ { t: 'dim', c: '~140 containers · 6 hosts' }, { t: 'prompt', c: '$' }, { t: 'cmd', c: ' docker compose up -d' }, { t: 'ok', c: 'traefik · pihole · n8n — Up' }, { t: 'ok', c: 'backups 3-2-1 · verified' }, ], glyph: 'text', gc: '$', }, engineering: { title: 'src — spring & wordpress', lines: [ { t: 'dim', c: 'Java · PHP · TypeScript' }, { t: 'prompt', c: '$' }, { t: 'cmd', c: ' mvn clean package' }, { t: 'ok', c: 'BUILD SUCCESS · 42s' }, { t: 'hl', c: '{ "status": "200 OK" }' }, ], glyph: 'text', gc: '', }, notes: { title: 'scratchpad — gotchas', lines: [ { t: 'dim', c: '3-minute reads' }, { t: 'hl', c: 'fix · traefik forward-auth' }, { t: 'hl', c: 'fix · cv 301 → 404 chain' }, { t: 'dim', c: '→ lessons, fast' }, ], glyph: 'text', gc: '!', }, tutorials: { title: 'learn — follow along', lines: [ { t: 'dim', c: 'copy · run · understand' }, { t: 'prompt', c: '$' }, { t: 'cmd', c: ' npm create astro@latest' }, { t: 'ok', c: 'step 01 · scaffolded' }, { t: 'ok', c: 'step 02 · deployed' }, ], glyph: 'text', gc: '>_', }, web3: { title: 'foundry — testnet 31337', lines: [ { t: 'dim', c: 'solidity · honest scope' }, { t: 'prompt', c: '$' }, { t: 'cmd', c: ' forge test' }, { t: 'ok', c: '[PASS] testMintERC721' }, { t: 'ok', c: '[PASS] testTransferERC20' }, ], glyph: 'text', gc: '0x', }, }; const fallback: (typeof ART)[string] = { title: slug, lines: [ { t: 'dim', c: 'mr hoelee · blog' }, { t: 'prompt', c: '$' }, { t: 'cmd', c: ' ls posts' }, ], glyph: 'text', gc: '#', }; const art = ART[slug] ?? fallback; const accent = meta?.accent ?? '#295cff'; const LINE_COLORS: Record = { prompt: accent, cmd: '#e6edf3', ok: '#3fb950', hl: '#f5a524', dim: '#6b7c99', }; --- {art.title} {art.lines.map((ln, i) => ( {ln.c} ))} {art.glyph === 'text' ? ( {art.gc} ) : ( )}