From c3def2c5c478f31663deb1c9615241e06614aed2 Mon Sep 17 00:00:00 2001
From: Claude
Date: Fri, 2 Oct 2026 03:22:35 +0000
Subject: [PATCH] Add project-specific diagrams to each project card
Co-Authored-By: Claude Sonnet 5.5
Claude-Session: https://claude.ai/code/session_01Msa87P1aZQSV9MWhEu3VfJ
---
keith-portfolio/PRD.md | 1 +
.../src/components/ProjectDiagram.tsx | 149 ++++++++++++++++++
keith-portfolio/src/data/content.ts | 22 ++-
.../src/sections/ProjectsSection.tsx | 43 +++--
4 files changed, 193 insertions(+), 22 deletions(-)
create mode 100644 keith-portfolio/src/components/ProjectDiagram.tsx
diff --git a/keith-portfolio/PRD.md b/keith-portfolio/PRD.md
index fe5cba5..a09db17 100644
--- a/keith-portfolio/PRD.md
+++ b/keith-portfolio/PRD.md
@@ -36,6 +36,7 @@ Phase 1 has no forms, no logins, no secrets, so risk is low. External links use
## Phase 1 status (done)
- Content comes from Keith's existing portfolio: profile, 8 capabilities, 3 roles + 5 earlier roles, 4 projects, 10 certifications, contact details (all in `src/data/content.ts`).
+- Each project card has its own illustrative diagram (drawn from the deliverables in Keith's portfolio text; swap for real screenshots when available).
- Sections: Hero (portrait), scrolling photo/skills rows, About, Capability, Experience, Projects (stacking cards), Credentials, Contact.
- Photos and the Kanit font ship inside the site (no outside image hosts needed).
- Tested at 360, 390, 768, 1024, 1440 and 1920 px wide: no sideways scroll, no console errors, all images load.
diff --git a/keith-portfolio/src/components/ProjectDiagram.tsx b/keith-portfolio/src/components/ProjectDiagram.tsx
new file mode 100644
index 0000000..3b73c3a
--- /dev/null
+++ b/keith-portfolio/src/components/ProjectDiagram.tsx
@@ -0,0 +1,149 @@
+import type { CSSProperties, ReactNode } from 'react';
+
+export type DiagramKind = 'network' | 'server' | 'sccm' | 'voice';
+
+const INK = '#D7E2EA';
+const TEAL = '#2BB3A6';
+const MUTED = 'rgba(215,226,234,0.55)';
+const FILL = '#14161a';
+
+function Box({ x, y, w, h, label, sub, accent }: { x: number; y: number; w: number; h: number; label: string; sub?: string; accent?: boolean }) {
+ return (
+
+
+ {label}
+ {sub && {sub}}
+
+ );
+}
+
+function Line({ x1, y1, x2, y2, dashed }: { x1: number; y1: number; x2: number; y2: number; dashed?: boolean }) {
+ return ;
+}
+
+function Arrow({ x1, y, x2, label }: { x1: number; y: number; x2: number; label?: string }) {
+ return (
+
+
+
+ {label && {label}}
+
+ );
+}
+
+function Dot({ cx, cy, r = 14 }: { cx: number; cy: number; r?: number }) {
+ return ;
+}
+
+function Wifi({ cx, cy }: { cx: number; cy: number }) {
+ return (
+
+
+
+
+
+ );
+}
+
+const diagrams: Record = {
+ network: {
+ label: 'Network topology: Fortinet firewall connects to Fortinet 48P switches, which connect to access points.',
+ body: (
+ <>
+
+
+
+
+
+
+
+ {[90, 210, 390, 510].map((x, i) => (
+
+
+
+
+
+ ))}
+ Access point uplift
+ Network topology upgrade
+ >
+ ),
+ },
+ server: {
+ label: 'Server upgrade: virtual machines and services move from the existing server to the upgraded server, with updated network settings.',
+ body: (
+ <>
+
+ Existing server
+
+
+
+
+ Upgraded server
+
+
+
+
+
+ >
+ ),
+ },
+ sccm: {
+ label: 'SCCM implementation: install and configure SCCM, prepare settings, then establish the task-sequence process for endpoints.',
+ body: (
+ <>
+
+
+
+
+
+
+
+
+
+ {[150, 250, 350, 450].map((x) => (
+
+
+
+
+
+ ))}
+ Endpoints built through the task sequence
+ >
+ ),
+ },
+ voice: {
+ label: 'Microsoft Teams calling: number porting, dial-plan and call-flow design, then users supported by training, documentation and adoption monitoring.',
+ body: (
+ <>
+
+
+
+
+
+
+
+ {[100, 300, 500].map((x) => (
+
+
+
+
+
+ ))}
+ User training
+ Documentation
+ Adoption monitoring
+ Microsoft Teams calling
+ >
+ ),
+ },
+};
+
+export default function ProjectDiagram({ kind, className, style }: { kind: DiagramKind; className?: string; style?: CSSProperties }) {
+ const d = diagrams[kind];
+ return (
+
+ );
+}
diff --git a/keith-portfolio/src/data/content.ts b/keith-portfolio/src/data/content.ts
index afb4950..3feff10 100644
--- a/keith-portfolio/src/data/content.ts
+++ b/keith-portfolio/src/data/content.ts
@@ -3,6 +3,8 @@ import leadership from '../assets/leadership.webp';
import systems from '../assets/systems.webp';
import signalMark from '../assets/signal-mark.webp';
+import type { DiagramKind } from '../components/ProjectDiagram';
+
export const images = { portrait, leadership, systems, signalMark };
export const profile = {
@@ -85,32 +87,36 @@ export const projects = [
name: 'Network project',
body: 'Fortinet Firewall upgrade, Fortinet 48P Switches upgrade, Fortinet access point uplift, and network topology upgrade.',
delivered: ['Fortinet firewall upgrade', 'Fortinet 48P switches upgrade', 'Fortinet access point uplift', 'Network topology upgrade'],
- images: [systems, leadership] as [string, string],
- position: ['center', 'center'] as [string, string],
+ diagram: 'network' as DiagramKind,
+ photo: systems,
+ photoPosition: 'center',
},
{
category: 'Infrastructure',
name: 'Server upgrade',
body: 'Upgraded the server with existing VMs and services, migrated data, and configured updated network settings.',
delivered: ['Server upgraded with existing VMs and services', 'Data migrated', 'Updated network settings configured'],
- images: [leadership, systems] as [string, string],
- position: ['70% 40%', '20% 60%'] as [string, string],
+ diagram: 'server' as DiagramKind,
+ photo: leadership,
+ photoPosition: '70% 40%',
},
{
category: 'Endpoint',
name: 'SCCM implementation',
body: 'Installed and configured SCCM, prepared the required settings, and established the task-sequence process.',
delivered: ['SCCM installed and configured', 'Required settings prepared', 'Task-sequence process established'],
- images: [systems, leadership] as [string, string],
- position: ['80% 20%', '30% 70%'] as [string, string],
+ diagram: 'sccm' as DiagramKind,
+ photo: systems,
+ photoPosition: '80% 20%',
},
{
category: 'Voice',
name: 'Microsoft Teams calling',
body: 'Delivered number-porting support, call-flow and dial-plan design, user training, documentation, and adoption monitoring.',
delivered: ['Number-porting support', 'Call-flow and dial-plan design', 'User training and documentation', 'Adoption monitoring'],
- images: [leadership, systems] as [string, string],
- position: ['50% 80%', '60% 30%'] as [string, string],
+ diagram: 'voice' as DiagramKind,
+ photo: leadership,
+ photoPosition: '50% 80%',
},
];
diff --git a/keith-portfolio/src/sections/ProjectsSection.tsx b/keith-portfolio/src/sections/ProjectsSection.tsx
index 6d4e798..9d6b7f4 100644
--- a/keith-portfolio/src/sections/ProjectsSection.tsx
+++ b/keith-portfolio/src/sections/ProjectsSection.tsx
@@ -2,6 +2,7 @@ import { useRef } from 'react';
import { motion, useScroll, useTransform } from 'framer-motion';
import { Check } from 'lucide-react';
import FadeIn from '../components/FadeIn';
+import ProjectDiagram from '../components/ProjectDiagram';
import { projects } from '../data/content';
type Project = (typeof projects)[number];
@@ -34,21 +35,35 @@ function ProjectCard({ project, index, total }: { project: Project; index: numbe
{project.body}
-
-
-

-

+
+
+

+
+
Delivered
+
+ {project.delivered.map((d) => (
+ -
+
+ {d}
+
+ ))}
+
+
-
-
Delivered
-
- {project.delivered.map((d) => (
- -
-
- {d}
-
- ))}
-
+