Repository Public
1import { getDict, type Locale } from "@/lib/i18n";23function Cell({ title, sub, tone = "solid", className = "" }: { title: string; sub?: string; tone?: "solid" | "accent" | "ext"; className?: string }) {4 const tones = { solid: "border-line-strong bg-surface", accent: "border-accent/60 bg-accent-soft", ext: "border-dashed border-line-strong" };5 return (6 <div className={`rounded-xl border px-4 py-3.5 ${tones[tone]} ${className}`}>7 <p className="text-[0.9375rem] font-medium leading-tight">{title}</p>8 {sub ? <p className="mt-1.5 font-mono text-[0.6875rem] leading-snug tracking-[0.04em] text-mute">{sub}</p> : null}9 </div>10 );11}1213const Wire = ({ dashed = false, label }: { dashed?: boolean; label?: string }) => (14 <div className="flex items-center justify-center gap-3 py-1" aria-hidden={label ? undefined : true}>15 <svg width="2" height="30" viewBox="0 0 2 30" aria-hidden="true" className="overflow-visible">16 <line x1="1" y1="0" x2="1" y2="30" stroke={dashed ? "#1D5FD1" : "#0C1322"} strokeOpacity={dashed ? 1 : 0.3} strokeDasharray={dashed ? "4 7" : undefined} className={dashed ? "trace" : undefined} />17 </svg>18 {label ? <span className="font-mono text-[0.6875rem] tracking-[0.08em] text-accent">{label}</span> : null}19 </div>20);2122/** Layered logical diagram in real text (readable, translatable, zoomable). Roles and boundaries only. */23export function ArchitectureDiagram({ locale, nodeCount, memoryMax }: { locale: Locale; nodeCount: number; memoryMax: number | null }) {24 const t = getDict(locale).architecture.diagram;25 const c = getDict(locale).common;26 return (27 <figure aria-label={t.alt}>28 <div className="mx-auto max-w-3xl">29 <Cell title={t.internet} tone="ext" className="mx-auto max-w-[16rem] text-center" />30 <Wire />31 <Cell title={t.external} sub={t.externalSub} tone="ext" className="mx-auto max-w-[24rem] text-center" />32 <Wire dashed label={t.tunnel} />33 <div className="relative rounded-2xl border border-dashed border-line-strong p-4 pt-10 md:p-6 md:pt-11">34 <span className="label absolute left-4 top-3 md:left-6">{t.boundary}</span>35 <div className="grid gap-3 sm:grid-cols-2">36 <Cell title={t.gateway} sub={t.gatewaySub} tone="accent" />37 <Cell title={t.monitor} sub={t.monitorSub} />38 </div>39 <Wire />40 <div className="rounded-xl border border-line-strong bg-surface-2 px-4 py-2.5 text-center font-mono text-[0.75rem] tracking-[0.06em] text-body">{t.switch}</div>41 <Wire />42 <div className="grid gap-3 sm:grid-cols-3">43 <Cell title={t.nodes} sub={`${nodeCount} · ${t.nodesSub}${memoryMax ? ` · max ${memoryMax} ${c.gb}` : ""}`} className="sm:col-span-2" />44 <Cell title={t.storage} sub={t.storageSub} />45 </div>46 <div className="mt-3 grid gap-3 sm:grid-cols-3">47 <Cell title={t.serving} sub={t.servingSub} className="sm:col-span-2" />48 </div>49 </div>50 </div>51 </figure>52 );53}54