Files
portfolio/components/architecture-breakdown.tsx

180 lines
6.8 KiB
TypeScript

"use client";
import * as React from "react";
import { Reveal } from "@/components/reveal";
export type ArchitectureLayer = {
title: string;
subtitle?: string;
bullets: string[];
};
export type ArchitectureInterface = {
label: string;
detail: string;
};
export type ArchitectureBreakdownData = {
title?: string;
subtitle?: string;
layers: ArchitectureLayer[];
flow: Array<{ from: string; to: string; note?: string }>;
interfaces: ArchitectureInterface[];
};
export function ArchitectureBreakdown({
title = "Architecture",
subtitle = "How the system is structured and how state moves through it.",
data,
}: {
title?: string;
subtitle?: string;
data: ArchitectureBreakdownData;
}) {
return (
<section className="relative overflow-hidden">
<div className="glass-strong noise-overlay rounded-3xl p-6 sm:p-8 shadow-sm relative overflow-hidden">
<div className="flex flex-col gap-2">
<h2 className="text-xl sm:text-2xl font-semibold tracking-tight">
{title}
</h2>
<p className="text-sm sm:text-[15px] text-black/60 max-w-3xl">
{subtitle}
</p>
</div>
{/* Layers */}
<div className="mt-6 sm:mt-8 grid gap-4 lg:grid-cols-3">
{data.layers.map((layer, idx) => (
<Reveal key={`${layer.title}-${idx}`}>
<div className="glass rounded-3xl p-5 sm:p-6 h-full">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<div className="text-[11px] uppercase tracking-[0.18em] text-black/45">
Layer {String(idx + 1).padStart(2, "0")}
</div>
<h3 className="mt-2 text-base sm:text-lg font-semibold tracking-tight">
{layer.title}
</h3>
{layer.subtitle ? (
<p className="mt-1 text-sm text-black/60">
{layer.subtitle}
</p>
) : null}
</div>
<div className="shrink-0">
<span className="glass px-2.5 py-1 rounded-full text-[11px] text-black/55 tabular-nums">
{String(idx + 1).padStart(2, "0")}/03
</span>
</div>
</div>
<ul className="mt-4 grid gap-2 text-sm text-black/70">
{layer.bullets.map((b, bi) => (
<li key={`${layer.title}-b-${bi}`} className="flex gap-2">
<span className="mt-[7px] h-1.5 w-1.5 rounded-full bg-black/25" />
<span className="min-w-0">{b}</span>
</li>
))}
</ul>
</div>
</Reveal>
))}
</div>
{/* Flow */}
<div className="mt-6 sm:mt-8">
<Reveal>
<div className="glass rounded-3xl p-5 sm:p-6">
<div className="flex flex-col sm:flex-row sm:items-end sm:justify-between gap-2">
<div>
<div className="text-[11px] uppercase tracking-[0.18em] text-black/45">
Data flow
</div>
<h3 className="mt-2 text-base sm:text-lg font-semibold tracking-tight">
State moves as a pipeline
</h3>
<p className="mt-1 text-sm text-black/60 max-w-3xl">
Configuration is authored on desktop, executed deterministically, then mirrored back as
LED feedback so the device stays readable at a glance.
</p>
</div>
</div>
<div className="mt-5 grid gap-3">
{data.flow.map((step, i) => (
<div
key={`${step.from}-${step.to}-${i}`}
className="glass rounded-2xl px-4 py-3"
>
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2">
<div className="min-w-0">
<div className="text-sm text-black/75">
<span className="font-semibold">{step.from}</span>
<span className="mx-2 text-black/30"></span>
<span className="font-semibold">{step.to}</span>
</div>
{step.note ? (
<div className="mt-1 text-[13px] text-black/60">
{step.note}
</div>
) : null}
</div>
<div className="shrink-0 text-[12px] text-black/45 tabular-nums">
Step {String(i + 1).padStart(2, "0")}
</div>
</div>
</div>
))}
</div>
</div>
</Reveal>
</div>
{/* Interfaces */}
<div className="mt-6 sm:mt-8">
<Reveal>
<div className="glass rounded-3xl p-5 sm:p-6">
<div className="text-[11px] uppercase tracking-[0.18em] text-black/45">
Interfaces
</div>
<h3 className="mt-2 text-base sm:text-lg font-semibold tracking-tight">
Stable contracts between modules
</h3>
<p className="mt-1 text-sm text-black/60 max-w-3xl">
The system stays maintainable because boundaries are explicit and small.
</p>
<div className="mt-5 grid gap-3 sm:grid-cols-2">
{data.interfaces.map((it, idx) => (
<div
key={`${it.label}-${idx}`}
className="glass rounded-2xl p-4"
>
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<div className="text-sm font-semibold text-black/75">
{it.label}
</div>
<div className="mt-1 text-sm text-black/60">
{it.detail}
</div>
</div>
<span className="glass px-2.5 py-1 rounded-full text-[11px] text-black/50 tabular-nums">
{String(idx + 1).padStart(2, "0")}
</span>
</div>
</div>
))}
</div>
</div>
</Reveal>
</div>
{/* Specular highlight */}
<div className="pointer-events-none specular absolute -top-24 -right-24 h-64 w-64 rounded-full opacity-50 blur-2xl" />
</div>
</section>
);
}