import type { ThumbnailIcon } from "./blogThumbnails"; import { blogThumbnails } from "./blogThumbnails"; interface BlogThumbnailSVGProps { slug: string; variant?: "square" | "banner"; className?: string; } // Grid pattern used in the background const GridPattern: React.FC<{ size: number }> = ({ size }) => ( ); // ─── Icon Renderers ─────────────────────────────────────────────── function renderGauge(cx: number, cy: number, accent: string) { const r = 52; // Arc from ~210° to ~330° (lower half open) const startAngle = (210 * Math.PI) / 180; const endAngle = (330 * Math.PI) / 180; const x1 = cx + r * Math.cos(startAngle); const y1 = cy + r * Math.sin(startAngle); const x2 = cx + r * Math.cos(endAngle); const y2 = cy + r * Math.sin(endAngle); // Needle at ~280° (pointing upper-right = fast/danger zone) const needleAngle = (280 * Math.PI) / 180; const nx = cx + (r - 14) * Math.cos(needleAngle); const ny = cy + (r - 14) * Math.sin(needleAngle); return ( {/* Tick marks */} {[210, 240, 270, 300, 330].map((deg) => { const rad = (deg * Math.PI) / 180; const tx1 = cx + (r + 6) * Math.cos(rad); const ty1 = cy + (r + 6) * Math.sin(rad); const tx2 = cx + (r + 12) * Math.cos(rad); const ty2 = cy + (r + 12) * Math.sin(rad); return ( ); })} ); } function renderBottleneck(cx: number, cy: number, accent: string) { return ( {/* Wide top */} {/* Narrow middle (bottleneck) */} {/* Flow lines */} {[-20, 0, 20].map((offset) => ( ))} {/* Wide bottom */} {/* Arrow down through throttle */} ); } function renderPlugin(cx: number, cy: number, accent: string) { const s = 28; return ( {/* Connected piece 1 */} {/* Connected piece 2 */} {/* Connected piece 3 */} {/* Disconnected piece (offset) */} {/* Connector dots */} {/* Warning */} ! ); } function renderShield(cx: number, cy: number, accent: string) { return ( {/* Checkmark */} ); } function renderCookie(cx: number, cy: number, accent: string) { return ( {/* Cookie circle */} {/* Chips */} {/* Strikethrough */} ); } function renderCloud(cx: number, cy: number, accent: string) { return ( {/* Lock icon inside cloud */} ); } function renderLock(cx: number, cy: number, accent: string) { return ( {/* Lock body */} {/* Lock shackle */} {/* Keyhole */} {/* Chain links */} {[-42, 42].map((offset) => ( 0 ? 14 : -14)} cy={cy + 12} rx="10" ry="6" fill="none" stroke="#cbd5e1" strokeWidth="1.5" /> ))} ); } function renderChart(cx: number, cy: number, accent: string) { const barWidth = 14; const heights = [30, 50, 38, 55, 42]; const baseY = cy + 35; return ( {/* Bars */} {heights.map((h, i) => ( ))} {/* Base line */} {/* Eye with strikethrough */} ); } function renderLeaf(cx: number, cy: number, accent: string) { return ( {/* Leaf shape */} {/* Stem/vein */} {/* Circuit nodes on leaf veins */} {[-20, 0, 20].map((offset, i) => ( ))} ); } function renderPrice(cx: number, cy: number, accent: string) { return ( {/* Tag shape */} {/* Hole */} {/* Equals sign */} ); } function renderPrototype(cx: number, cy: number, accent: string) { return ( {/* Browser frame */} {/* Title bar */} {/* Dots */} {/* Wireframe lines */} {/* Accent wireframe block */} ); } function renderGear(cx: number, cy: number, accent: string) { const teeth = 8; const innerR = 24; const outerR = 36; const toothWidth = 0.2; let d = ""; for (let i = 0; i < teeth; i++) { const angle = (i * 2 * Math.PI) / teeth; const a1 = angle - toothWidth; const a2 = angle + toothWidth; const _midAngle = (a1 + a2) / 2; if (i === 0) { d += `M ${cx + outerR * Math.cos(a1)} ${cy + outerR * Math.sin(a1)} `; } d += `L ${cx + outerR * Math.cos(a2)} ${cy + outerR * Math.sin(a2)} `; const nextAngle = ((i + 1) * 2 * Math.PI) / teeth; const na1 = nextAngle - toothWidth; d += `L ${cx + innerR * Math.cos(a2)} ${cy + innerR * Math.sin(a2)} `; d += `L ${cx + innerR * Math.cos(na1)} ${cy + innerR * Math.sin(na1)} `; d += `L ${cx + outerR * Math.cos(na1)} ${cy + outerR * Math.sin(na1)} `; } d += "Z"; return ( {/* Infinity loop */} ); } function renderHourglass(cx: number, cy: number, accent: string) { return ( {/* Top triangle */} {/* Bottom triangle */} {/* "Sand" fill in bottom */} {/* Top and bottom lines */} {/* Circuit nodes as "digital sand" */} {[10, 22, 34].map((y, i) => ( ))} ); } function renderCode(cx: number, cy: number, accent: string) { return ( {/* < */} {/* / */} {/* > */} ); } function renderResponsive(cx: number, cy: number, accent: string) { return ( {/* Outer desktop */} {/* Tablet */} {/* Phone */} {/* Phone screen */} {/* Phone home button */} ); } function renderServer(cx: number, cy: number, accent: string) { const unitH = 22; return ( {/* Server units */} {[0, 1, 2].map((i) => ( {/* Status LEDs */} {/* Drive bays */} {[0, 1, 2, 3].map((j) => ( ))} ))} {/* Signal waves */} {[10, 18, 26].map((r, i) => ( ))} ); } function renderTemplate(cx: number, cy: number, accent: string) { return ( {/* Grid layout */} {[0, 1, 2, 3].map((i) => { const row = Math.floor(i / 2); const col = i % 2; return ( ); })} {/* Strikethrough diagonal */} ); } function renderSync(cx: number, cy: number, accent: string) { const r = 36; return ( {/* Circular arrows */} {/* Arrowheads */} {/* Data dots flowing */} {/* Center node */} ); } // ─── Icon dispatcher ────────────────────────────────────────────── const iconRenderers: Record< ThumbnailIcon, (_cx: number, _cy: number, _accent: string) => React.ReactNode > = { gauge: renderGauge, bottleneck: renderBottleneck, plugin: renderPlugin, shield: renderShield, cookie: renderCookie, cloud: renderCloud, lock: renderLock, chart: renderChart, leaf: renderLeaf, price: renderPrice, prototype: renderPrototype, gear: renderGear, hourglass: renderHourglass, code: renderCode, responsive: renderResponsive, server: renderServer, template: renderTemplate, sync: renderSync, }; // ─── Main Component ────────────────────────────────────────────── export const BlogThumbnailSVG: React.FC = ({ slug, variant = "square", className, }) => { const config = blogThumbnails[slug]; if (!config) return null; const isBanner = variant === "banner"; const vbWidth = isBanner ? 480 : 240; const vbHeight = isBanner ? 160 : 240; // For banner, we shift the icon more to the right const iconCx = isBanner ? 340 : vbWidth / 2; const iconCy = vbHeight / 2; return ( {/* Background */} {/* Accent strip at top */} {/* Decorative circuit lines */} {/* Corner markers */} {/* Icon - Scale down for banner to fit height better */} {iconRenderers[config.icon](iconCx, iconCy, config.accent)} {/* Keyword label */} {config.keyword} {/* Accent dot */} ); };