rework of experience
All checks were successful
Build and Deploy Gabriel Kaszewski Portfolio / build-and-deploy-local (push) Successful in 1m8s
All checks were successful
Build and Deploy Gabriel Kaszewski Portfolio / build-and-deploy-local (push) Successful in 1m8s
This commit is contained in:
378
docs/superpowers/plans/2026-04-24-experience-timeline.md
Normal file
378
docs/superpowers/plans/2026-04-24-experience-timeline.md
Normal file
@@ -0,0 +1,378 @@
|
||||
# Experience Timeline Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Replace the horizontal experience card carousel with a full-width vertical timeline that surfaces job descriptions and sub-phase breakdowns from static data.
|
||||
|
||||
**Architecture:** Extend the `Job` type with optional `summary` and `sub_phases` fields, update `data.ts` with CV content, then replace the card carousel with a new `ExperienceTimeline` server component. No client-side JS — all content is statically rendered.
|
||||
|
||||
**Tech Stack:** Next.js (App Router), TypeScript, TailwindCSS
|
||||
|
||||
---
|
||||
|
||||
## File Map
|
||||
|
||||
| Action | File | Responsibility |
|
||||
|--------|------|---------------|
|
||||
| Modify | `lib/types.ts` | Add `JobSubPhase`, extend `Job` |
|
||||
| Modify | `lib/data.ts` | Add `summary` + `sub_phases` to WPP and GIAP entries |
|
||||
| Create | `components/experience-timeline.tsx` | Renders the full vertical timeline (server component) |
|
||||
| Modify | `components/experience.tsx` | Swap card loop for `<ExperienceTimeline>` |
|
||||
| Delete | `components/experience-card.tsx` | Replaced by timeline component |
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Extend types
|
||||
|
||||
**Files:**
|
||||
- Modify: `lib/types.ts`
|
||||
|
||||
- [ ] **Step 1: Add `JobSubPhase` and extend `Job`**
|
||||
|
||||
Replace the entire contents of `lib/types.ts` with:
|
||||
|
||||
```typescript
|
||||
export interface Skill {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface JobSubPhase {
|
||||
label: string;
|
||||
start_date: string;
|
||||
end_date: string | null;
|
||||
bullets: string[];
|
||||
}
|
||||
|
||||
export interface Job {
|
||||
id: number;
|
||||
position: string;
|
||||
company: string;
|
||||
still_working: boolean;
|
||||
start_date: string;
|
||||
end_date: string | null;
|
||||
technologies: string[];
|
||||
summary?: string;
|
||||
sub_phases?: JobSubPhase[];
|
||||
}
|
||||
|
||||
export interface Project {
|
||||
id: number;
|
||||
name: string;
|
||||
short_description: string;
|
||||
description: string;
|
||||
technologies: string[];
|
||||
thumbnails: string[];
|
||||
category: 'Web' | 'Mobile' | 'Desktop' | 'Api' | 'Game';
|
||||
github_url?: string | null;
|
||||
visit_url?: string | null;
|
||||
download_url?: string | null;
|
||||
commercial?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify TypeScript is happy**
|
||||
|
||||
```bash
|
||||
npx tsc --noEmit
|
||||
```
|
||||
|
||||
Expected: no errors (existing job entries have no `sub_phases` yet, so optional fields are fine).
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add lib/types.ts
|
||||
git commit -m "feat: add JobSubPhase type and extend Job with summary and sub_phases"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Update job data
|
||||
|
||||
**Files:**
|
||||
- Modify: `lib/data.ts`
|
||||
|
||||
- [ ] **Step 1: Update the WPP entry (id: 8)**
|
||||
|
||||
Replace the WPP job object in the `jobs` array:
|
||||
|
||||
```typescript
|
||||
{
|
||||
id: 8,
|
||||
position: "Software Engineer",
|
||||
company: "WPP Media | Choreograph | Wavemaker",
|
||||
still_working: true,
|
||||
start_date: "2023-09-13",
|
||||
end_date: null,
|
||||
summary:
|
||||
"Advanced from frontend UI development to backend systems engineering, leading infrastructure-agnostic design initiatives.",
|
||||
sub_phases: [
|
||||
{
|
||||
label: "Backend & Infrastructure",
|
||||
start_date: "2025-03-01",
|
||||
end_date: null,
|
||||
bullets: [
|
||||
"Engineered and optimized backend applications and internal tools using Python, FastAPI, and Django.",
|
||||
"Streamlined CI/CD workflows and containerized applications with GitLab Pipelines, Docker, and Kubernetes across GCP and Azure environments.",
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Frontend Architecture",
|
||||
start_date: "2023-09-13",
|
||||
end_date: "2025-03-01",
|
||||
bullets: [
|
||||
"Architected scalable microfrontends utilizing Angular and Module Federation, seamlessly integrating standalone internal tools into a unified enterprise shell application.",
|
||||
"Ensured seamless integration of UI components with Kubernetes-based deployments and Azure Pipelines.",
|
||||
],
|
||||
},
|
||||
],
|
||||
technologies: [
|
||||
"Angular",
|
||||
"Azure",
|
||||
"Azure Pipelines",
|
||||
"Django",
|
||||
"Docker",
|
||||
"FastAPI",
|
||||
"GCP",
|
||||
"Gitlab CI",
|
||||
"Gitlab Pipelines",
|
||||
"Kubernetes",
|
||||
"PostgreSQL",
|
||||
"Python",
|
||||
"React",
|
||||
"SCSS",
|
||||
"TailwindCSS",
|
||||
"Typescript",
|
||||
],
|
||||
},
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update the GIAP entry (id: 2)**
|
||||
|
||||
Replace the GIAP job object:
|
||||
|
||||
```typescript
|
||||
{
|
||||
id: 2,
|
||||
position: "Full Stack Developer",
|
||||
company: "GIAP",
|
||||
still_working: false,
|
||||
start_date: "2021-05-19",
|
||||
end_date: "2023-02-03",
|
||||
sub_phases: [
|
||||
{
|
||||
label: "Desktop / Backend",
|
||||
start_date: "2021-05-19",
|
||||
end_date: "2022-02-01",
|
||||
bullets: [
|
||||
"Architected and optimized complex PostGIS/PostgreSQL cross-database comparison queries utilizing Common Table Expressions (CTEs), drastically reducing execution time from over 5 minutes to under 15 seconds.",
|
||||
"Developed a robust GIS data assertion module using Python and Qt to automatically validate spatial data against strict compliance standards.",
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Frontend",
|
||||
start_date: "2022-02-01",
|
||||
end_date: "2023-02-03",
|
||||
bullets: [
|
||||
"Engineered a comprehensive, public-facing web application for the City of Gdańsk (geogdansk.pl) leveraging React, TypeScript, Redux, and the ArcGIS JS API.",
|
||||
],
|
||||
},
|
||||
],
|
||||
technologies: [
|
||||
"Python",
|
||||
"React",
|
||||
"Typescript",
|
||||
"PostgreSQL",
|
||||
"PostGIS",
|
||||
"ArcGIS JS API",
|
||||
"Redux",
|
||||
"Qt",
|
||||
"QGIS",
|
||||
"Git",
|
||||
],
|
||||
},
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify TypeScript is happy**
|
||||
|
||||
```bash
|
||||
npx tsc --noEmit
|
||||
```
|
||||
|
||||
Expected: no errors.
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add lib/data.ts
|
||||
git commit -m "feat: add sub_phases and summary to WPP and GIAP job entries"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Create ExperienceTimeline component
|
||||
|
||||
**Files:**
|
||||
- Create: `components/experience-timeline.tsx`
|
||||
|
||||
- [ ] **Step 1: Create the component**
|
||||
|
||||
```tsx
|
||||
import { Job } from "@/lib/types";
|
||||
import Chip from "./chip";
|
||||
import formatDate from "@/utils/format-date";
|
||||
|
||||
const ExperienceTimeline = ({ jobs }: { jobs: Job[] }) => (
|
||||
<div className="relative w-full max-w-3xl mx-auto flex flex-col gap-0">
|
||||
<div className="absolute left-[9px] top-3 bottom-3 w-px bg-gradient-to-b from-white/30 to-white/0" />
|
||||
{jobs.map((job) => (
|
||||
<div key={job.id} className="flex gap-6 pb-10 last:pb-0">
|
||||
<div className="flex flex-col items-center shrink-0 w-5 pt-1.5 z-10">
|
||||
<div className="w-3 h-3 rounded-full bg-white/40 border border-white/20 shadow-[0_0_8px_rgba(255,255,255,0.2)]" />
|
||||
</div>
|
||||
<div className="flex-1 bg-white/5 border border-white/10 rounded-2xl p-5 hover:border-white/20 transition-colors">
|
||||
<div className="flex justify-between items-start flex-wrap gap-1 mb-1">
|
||||
<h4 className="text-lg font-semibold text-white">{job.position}</h4>
|
||||
<span className="text-xs text-white/40">
|
||||
{formatDate(job.start_date)} –{" "}
|
||||
{job.still_working ? "Present" : formatDate(job.end_date!)}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm text-white/60 mb-4">{job.company}</p>
|
||||
|
||||
{job.summary && (
|
||||
<p className="text-sm text-white/50 italic mb-4">{job.summary}</p>
|
||||
)}
|
||||
|
||||
{job.sub_phases && job.sub_phases.length > 0 && (
|
||||
<div className="flex flex-col gap-3 mb-4">
|
||||
{job.sub_phases.map((phase) => (
|
||||
<div
|
||||
key={phase.label}
|
||||
className="bg-white/[0.03] border border-white/[0.07] rounded-xl px-4 py-3"
|
||||
>
|
||||
<div className="flex justify-between items-center flex-wrap gap-1 mb-2">
|
||||
<span className="text-[11px] font-semibold uppercase tracking-widest text-white/50">
|
||||
{phase.label}
|
||||
</span>
|
||||
<span className="text-[10px] text-white/30">
|
||||
{formatDate(phase.start_date)} –{" "}
|
||||
{phase.end_date ? formatDate(phase.end_date) : "Present"}
|
||||
</span>
|
||||
</div>
|
||||
<ul className="list-disc list-inside space-y-1">
|
||||
{phase.bullets.map((b) => (
|
||||
<li key={b} className="text-xs text-white/50 leading-relaxed">
|
||||
{b}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="border-t border-white/10 pt-4 mt-2">
|
||||
<p className="text-[10px] uppercase tracking-widest text-white/30 mb-2">
|
||||
Technologies
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{job.technologies.map((tech) => (
|
||||
<Chip key={tech} text={tech} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default ExperienceTimeline;
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify TypeScript is happy**
|
||||
|
||||
```bash
|
||||
npx tsc --noEmit
|
||||
```
|
||||
|
||||
Expected: no errors.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add components/experience-timeline.tsx
|
||||
git commit -m "feat: add ExperienceTimeline server component"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Wire up timeline in Experience section and remove old card
|
||||
|
||||
**Files:**
|
||||
- Modify: `components/experience.tsx`
|
||||
- Delete: `components/experience-card.tsx`
|
||||
|
||||
- [ ] **Step 1: Replace `experience.tsx`**
|
||||
|
||||
```tsx
|
||||
import { Job } from "@/lib/types";
|
||||
import ExperienceTimeline from "@/components/experience-timeline";
|
||||
|
||||
const Experience = ({ jobs }: { jobs: Job[] }) => (
|
||||
<div
|
||||
id="experience"
|
||||
className="flex flex-col items-center gap-8 p-4 w-full"
|
||||
>
|
||||
<h3 className="mt-4 text-5xl font-bold tracking-tight text-white">
|
||||
Experience
|
||||
</h3>
|
||||
<ExperienceTimeline jobs={jobs} />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Experience;
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Delete the old card component**
|
||||
|
||||
```bash
|
||||
rm components/experience-card.tsx
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify no remaining imports of ExperienceCard**
|
||||
|
||||
```bash
|
||||
grep -r "experience-card\|ExperienceCard" /mnt/drive/dev/gabrielkaszewski-next --include="*.tsx" --include="*.ts" | grep -v node_modules
|
||||
```
|
||||
|
||||
Expected: no output.
|
||||
|
||||
- [ ] **Step 4: Verify TypeScript is happy**
|
||||
|
||||
```bash
|
||||
npx tsc --noEmit
|
||||
```
|
||||
|
||||
Expected: no errors.
|
||||
|
||||
- [ ] **Step 5: Start dev server and visually verify the timeline renders correctly**
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open `http://localhost:3000` and scroll to the Experience section. Verify:
|
||||
- Vertical line and dots are visible
|
||||
- WPP shows summary + two sub-phase blocks with bullets
|
||||
- digimonkeys.com shows only dates + chips (no sub-phases)
|
||||
- GIAP shows two sub-phase blocks with bullets
|
||||
- Tech chips render under each entry
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add components/experience.tsx
|
||||
git commit -m "feat: replace experience card carousel with vertical timeline"
|
||||
```
|
||||
@@ -0,0 +1,87 @@
|
||||
# Experience Section — Vertical Timeline Redesign
|
||||
|
||||
## Overview
|
||||
|
||||
Replace the horizontal card carousel in the Experience section with a full-width vertical timeline. The new design surfaces job descriptions and sub-phase breakdowns directly from static data — no JavaScript required.
|
||||
|
||||
## Constraints
|
||||
|
||||
- No client-side JavaScript. All content is statically rendered.
|
||||
- Data lives in `lib/data.ts`; the `Job` type in `lib/types.ts` is extended to support the new fields.
|
||||
|
||||
## Data Model Changes
|
||||
|
||||
### `lib/types.ts`
|
||||
|
||||
Add `JobSubPhase` and extend `Job`:
|
||||
|
||||
```typescript
|
||||
export interface JobSubPhase {
|
||||
label: string;
|
||||
start_date: string;
|
||||
end_date: string | null; // null = present
|
||||
bullets: string[];
|
||||
}
|
||||
|
||||
export interface Job {
|
||||
id: number;
|
||||
position: string;
|
||||
company: string;
|
||||
still_working: boolean;
|
||||
start_date: string;
|
||||
end_date: string | null;
|
||||
technologies: string[];
|
||||
summary?: string; // optional one-liner shown below company name
|
||||
sub_phases?: JobSubPhase[]; // optional; if absent, no bullets shown
|
||||
}
|
||||
```
|
||||
|
||||
### `lib/data.ts`
|
||||
|
||||
Update all three job entries:
|
||||
|
||||
**WPP** — add `summary` + two sub-phases:
|
||||
- Backend & Infrastructure (Mar 2025 – Present)
|
||||
- Frontend Architecture (Sep 2023 – Mar 2025)
|
||||
|
||||
**digimonkeys.com** — no changes to content (no summary, no sub_phases).
|
||||
|
||||
**GIAP** — add two sub-phases:
|
||||
- Desktop / Backend (May 2021 – Feb 2022)
|
||||
- Frontend (Feb 2022 – Feb 2023)
|
||||
|
||||
Bullet text sourced from CV verbatim (slightly trimmed for display).
|
||||
|
||||
## Component Changes
|
||||
|
||||
### Remove
|
||||
|
||||
- `components/experience-card.tsx` — replaced entirely.
|
||||
|
||||
### Add
|
||||
|
||||
- `components/experience-timeline.tsx` — renders the full timeline list as a server component. Accepts `jobs: Job[]`. Renders each entry as a timeline card with dot, vertical line, header, optional sub-phases, and tech chips. Pure JSX, no `useState`/`useEffect`.
|
||||
|
||||
### Update
|
||||
|
||||
- Wherever the Experience section renders `ExperienceCard` in a scroll container — replace with `<ExperienceTimeline jobs={jobs} />`. Remove the horizontal scroll wrapper.
|
||||
|
||||
## Visual Design
|
||||
|
||||
- Vertical connecting line: left-aligned, gradient from accent color to transparent.
|
||||
- Each entry: glassmorphism card (`bg-white/5`, `border-white/10`, `rounded-2xl`), matching the existing site style.
|
||||
- Sub-phases rendered as nested cards inside the entry card (`bg-white/[0.03]`, `border-white/[0.07]`, `rounded-xl`).
|
||||
- Sub-phase header: label in small uppercase accent color + date right-aligned.
|
||||
- Bullets: `<ul>` with `text-sm text-white/60`.
|
||||
- Tech chips: existing `<Chip>` component reused.
|
||||
- Divider line between summary/phases and chips: `border-t border-white/10`.
|
||||
|
||||
## Entries (final)
|
||||
|
||||
| Job | Sub-phases | Bullets |
|
||||
|-----|-----------|---------|
|
||||
| WPP (Sep 2023–Present) | Backend & Infra, Frontend Arch | Yes |
|
||||
| digimonkeys.com (May 2021–Present) | None | No |
|
||||
| GIAP (May 2021–Feb 2023) | Desktop/Backend, Frontend | Yes |
|
||||
|
||||
Freelance period (Feb 2023–Sep 2023) is intentionally excluded.
|
||||
Reference in New Issue
Block a user