diff --git a/portfolio-view/src/App.tsx b/portfolio-view/src/App.tsx index 378bb9a..5ffabde 100644 --- a/portfolio-view/src/App.tsx +++ b/portfolio-view/src/App.tsx @@ -1,6 +1,8 @@ import { Header } from './components/layout/Header' import { Footer } from './components/layout/Footer' import { HeroSection } from './components/hero/HeroSection' +import { TechStackSection } from './components/tech/TechStackSection' +import { ArchitectureSection } from './components/architecture/ArchitectureSection' import { ProjectsSection } from './components/projects/ProjectsSection' import { ChatWidget } from './components/chat/ChatWidget' @@ -10,6 +12,8 @@ function App() { + + diff --git a/portfolio-view/src/components/architecture/ArchitectureSection.tsx b/portfolio-view/src/components/architecture/ArchitectureSection.tsx new file mode 100644 index 0000000..68ef4cc --- /dev/null +++ b/portfolio-view/src/components/architecture/ArchitectureSection.tsx @@ -0,0 +1,169 @@ +const ACCENT = '#22d3ee' +const BOX_BG = '#27272a' // zinc-800 +const BOX_BORDER = '#3f3f46' // zinc-700 +const TEXT = '#fafafa' +const TEXT_MUTED = '#a1a1aa' + +type BoxProps = { x: number; y: number; w: number; h: number; label: string; sub?: string } + +function ServiceBox({ x, y, w, h, label, sub }: BoxProps) { + return ( + + + + {label} + + {sub && ( + + {sub} + + )} + + ) +} + +function InfraBox({ x, y, w, h, label, sub }: BoxProps) { + return ( + + + + {label} + + {sub && ( + + {sub} + + )} + + ) +} + +export function ArchitectureSection() { + // Layout constants + const W = 760 + const H = 440 + + // Gateway + const gw = { x: 280, y: 30, w: 200, h: 52 } + const gwCx = gw.x + gw.w / 2 + const gwCy = gw.y + gw.h + + // Services row — evenly spaced + const svcY = 145 + const svcH = 52 + const svcW = 140 + const services = [ + { label: 'auth-service', sub: 'JWT / OAuth2', x: 20 }, + { label: 'post-service', sub: 'CRUD / feed', x: 185 }, + { label: 'rag-service', sub: 'AI / RAG', x: 350 }, + { label: 'analytics-service', sub: 'metrics', x: 515 }, + ] + + // Infra row + const infraY = 310 + const infraH = 52 + const infraW = 160 + const infra = [ + { label: 'PostgreSQL', sub: 'persistence', x: 60 }, + { label: 'Kafka', sub: 'event bus', x: 295 }, + { label: 'Consul', sub: 'service mesh',x: 530 }, + ] + + return ( + + + {/* Header */} + + + System Design + + + Platform Architecture + + + + {/* Diagram */} + + + + + + + + + {/* ── Gateway → Services connections ── */} + {services.map((s) => { + const sx = s.x + svcW / 2 + const sy = svcY + return ( + + ) + })} + + {/* ── Services → Infra connections ── */} + {services.map((s) => { + const sx = s.x + svcW / 2 + const sy = svcY + svcH + // Each service connects to the nearest infra node + const targets = infra.map((inf) => inf.x + infraW / 2) + const nearest = targets.reduce((prev, cur) => + Math.abs(cur - sx) < Math.abs(prev - sx) ? cur : prev + ) + return ( + + ) + })} + + {/* ── Gateway box ── */} + + + {/* ── Service boxes ── */} + {services.map((s) => ( + + ))} + + {/* ── Section label: Shared Infrastructure ── */} + + SHARED INFRASTRUCTURE + + + {/* ── Infra boxes ── */} + {infra.map((inf) => ( + + ))} + + {/* ── Legend ── */} + + + request routing + + infra dependency + + + + + + ) +} diff --git a/portfolio-view/src/components/tech/TechStackSection.tsx b/portfolio-view/src/components/tech/TechStackSection.tsx new file mode 100644 index 0000000..f9671e7 --- /dev/null +++ b/portfolio-view/src/components/tech/TechStackSection.tsx @@ -0,0 +1,164 @@ +const TECH = [ + { + label: 'Java', + icon: ( + + + + + + + + + + ), + }, + { + label: 'Spring Boot', + icon: ( + + + + + + + ), + }, + { + label: 'React', + icon: ( + + + + + + + ), + }, + { + label: 'TypeScript', + icon: ( + + + + + + ), + }, + { + label: 'PostgreSQL', + icon: ( + + + + + + + + + + ), + }, + { + label: 'Docker', + icon: ( + + + + + + + + + + ), + }, + { + label: 'Kafka', + icon: ( + + + + + + + + + + + ), + }, + { + label: 'Nginx', + icon: ( + + + + + ), + }, + { + label: 'GitLab CI/CD', + icon: ( + + + + + + + + ), + }, + { + label: 'Linux', + icon: ( + + + + + + + + + + + + + ), + }, +] + +export function TechStackSection() { + return ( + + + {/* Section header */} + + + Stack + + + Tech Stack + + + + {/* Grid: 3 cols mobile → 5 cols desktop */} + + {TECH.map(({ label, icon }) => ( + + + {icon} + + + {label} + + + ))} + + + + ) +}
+ System Design +
+ Stack +