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 (
);
};