Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .agent-state/decisions.ndjson
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
{"ts":"2026-06-09T23:13:09.916Z","sha":"2c9a43adaccebc7bda8227d07a70e0df990c4356","subject":"feat: DOCX-first resume pipeline with visual QC and recruiter-driven restructure","decision":"DOCX compiled from typed TS data via turbodocx, not pandoc or raw docx lib","why":"pandoc drops CSS; docx lib broke Apple Pages previously (fdcd220); turbodocx was the validated path and QC now guards it","resolves":["user directive to make DOCX the sole","properly-styled distributable"],"overrides":[]}
{"ts":"2026-06-09T23:31:36.852Z","sha":"c0b9051bfacb93637f99b9d9744051e0552ca15a","subject":"feat: DOCX-first resume pipeline with visual QC and recruiter-driven restructure (#152)","decision":"DOCX compiled from typed TS data via turbodocx, not pandoc or raw docx lib","why":"pandoc drops CSS; docx lib broke Apple Pages previously (fdcd220); turbodocx was the validated path and QC now guards it","resolves":["user directive to make DOCX the sole","properly-styled distributable"],"overrides":[],"source":"gh-pr-merge"}
65 changes: 65 additions & 0 deletions docs/design/redesign-2026-06.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Site Redesign Spec — "The Engineer Who Runs Your Entire Platform Alone"

**Date:** 2026-06-09
**Inputs:** `.ui-design/reviews/ai-look-diagnosis_20260609.md` (what reads as AI-generated and why), `docs/resume-review/recruiter-review-2026-06-09.md` (positioning), `src/content/resume.ts` (facts — nothing invented).
**Thesis:** a recruiter lands and within 6 seconds reads *who* (Staff Platform & DevOps engineer), *what proof* (sole operator at Flipside 5yr, ~$100K/mo cut, 10K-line codegen platform), *what action* (resume + contact). OSS users get package detail one scroll down.

## A. Information architecture — single opinionated scroll

The six-tab shell dies. Tabs hid the proof-bearing material (Work, Open Source) behind clicks and forced every section into one identical wrapper — the structural "generated IA" tell. Replacement: one vertical narrative with four sticky anchor links (`Work · Open Source · Skills · Contact`), name left, Résumé button right, scroll-spy underline.

Section roster:

| Was | Becomes |
|---|---|
| About tab | Folded: summary ¶1 → hero proof line; ¶2 → Open Source lead |
| Work tab | **Section 1.** Keeps master-detail sidebar (the one already-human section) |
| Projects tab | **Section 2: "Open Source."** Featured-vs-rest hierarchy, package tables promoted |
| Skills tab | **Section 3.** Prose lead + spec-sheet rows, zero badges |
| Earlier Career tab | Folded into Work as a quiet `Before 2017` prose block |
| Education tab | One line in the footer/contact band |

Scroll-depth contract: depth 0 = who + proof + action (above fold); depth 1 = Work receipts (Flipside selected, cost cut + tm_cli leading); depth 2 = Open Source with the featured package table.

## B. Hero

- **Mesh shader killed** (v0/Paper-design signature; drops `@paper-design/shaders-react` from the bundle). One static low-opacity amber radial glow, bottom-left, replaces the entire 4-layer ambient stack (`body::before` dot grid, `body::after` orbs, hero dot grid all die).
- **Name static** — Instrument Serif at display size in `--foreground`; `.hero-name` animated gradient deleted.
- **Left-aligned editorial column**, not centered-over-ambient (centered is itself the template look).
- **Eyebrow above the name**: `STAFF PLATFORM & DEVOPS ENGINEER` (mono, amber, tracked) — the role is what recruiters scan first.
- **Hero proof line** (new `about.heroLine`, assembled from existing facts): "The sole infrastructure engineer at Flipside Crypto for five years — modernized AWS to ~99% serverless, built a 10,000-line Python platform generating 146 Terraform modules, and cut cloud spend by ~$100K/month."
- **Stats: borderless typographic band** — serif number, mono label, hairline vertical rules. `15` (drop the `+`), `~70%`, `5`, `5`. No cards, no backdrop-blur.
- **Status: quiet mono line**, no pill, no pulse.
- **Motion: one wrapper fade-up** (0.5s), replacing five staggered child entrances. Bottom gradient-fade strip deleted.

## C. Sections

**Work** — keep sidebar/detail; de-card the detail pane (left rule + padding instead of stock Card chrome). Cloud providers (AWS/GCP/Azure) stay as small amber chips; remaining tech renders as one mono comma list. First two highlights of the selected role get lead emphasis. `Before 2017` prose block (from `earlierCareer.summary`) closes the section; `EarlierCareer.tsx` badge cloud deleted.

**Open Source** — lead with summary ¶2. **Featured project full-width** (paranoid-passwd: the supply-chain stack reads most senior) with its real package list as an aligned two-column table — the single best anti-AI signal gets the most room. Remaining four in a compact 2-col list: name, tagline, one-liner, package names inline as code, tech as a short mono list. Hash-rotated accent bars (`accentFor`) die; left rules are colored **by category** (security=amber, agents=steel, data=green, 3D=purple) so color means something.

**Skills** — prose lead: "Day to day: AWS and GCP, Terraform and Terragrunt, Kubernetes across EKS/GKE/AKS, Python and Go, and the CI/CD and secrets plumbing that ties them together." Then label/comma-list spec-sheet rows (mono uppercase labels, hairline separators). Zero Badge components.

**Footer/Contact** — one compact band: `Let's talk.` + email, inline social links, résumé buttons, location + one-line education, `© 2026 Jon Bogaty · v… · updated …` (version stamp kept — good human touch). The 3-column grid, the `DevOps · SRE · …` middot chain, and "All rights reserved" die.

## D. Copy (chrome strings)

Nav: `Work / Open Source / Skills / Contact`. Section heading `Projects` → `Open Source`. `Earlier Career` → `Before 2017`. CTAs: `Download Résumé` / `View Résumé`. Footer heading → `Let's talk.` No middot chains (single connective use allowed), no triadic rhythm, no stacked descriptors.

## E. Motion budget

One hero fade-up. Hover/focus transitions and the sidebar active state are interaction feedback and stay. Everything else static. `gradientShift`, `pulseDot` keyframes deleted. `prefers-reduced-motion` still honored.

## F. Build order

1. `index.css` de-slop (delete ambient layers, hero-name, pulse; add static glow)
2. `HeroSection.tsx` rewrite (shader out, band in, one motion)
3. `resume.ts`: add `heroLine`, `15+` → `15`
4. `App.tsx`: tabs → sections
5. `SectionTabs.tsx` → `SiteNav.tsx` (scroll-spy anchors)
6. `JobList.tsx` refine + absorb Earlier Career
7. `ProjectGrid.tsx` → `OpenSource.tsx` (featured/rest)
8. `SkillGrid.tsx` → `SkillSheet.tsx` (spec sheet)
9. `SiteFooter.tsx` compact
10. Delete `AboutSection.tsx` / `EarlierCareer.tsx` / `EducationList.tsx`; `pnpm rm @paper-design/shaders-react`
11. Screenshot every section at 1440px + 390px, read each, compare against this spec
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
"@fontsource/instrument-serif": "^5.2.8",
"@fontsource/inter": "^5.2.8",
"@fontsource/jetbrains-mono": "^5.2.8",
"@paper-design/shaders-react": "^0.0.71",
"astro": "^6.1.10",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
Expand Down
24 changes: 0 additions & 24 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified public/Jon_Bogaty_Resume.docx
Binary file not shown.
101 changes: 33 additions & 68 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,90 +1,55 @@
import { useRef } from 'react'
import { HeroSection } from '@/components/HeroSection'
import { SectionTabs } from '@/components/SectionTabs'
import { SiteFooter } from '@/components/SiteFooter'
import { AboutSection } from '@/components/sections/AboutSection'
import { EarlierCareer } from '@/components/sections/EarlierCareer'
import { EducationList } from '@/components/sections/EducationList'
import { SiteNav } from '@/components/SiteNav'
import { JobList } from '@/components/sections/JobList'
import { ProjectGrid } from '@/components/sections/ProjectGrid'
import { SkillGrid } from '@/components/sections/SkillGrid'
import { Tabs, TabsContent } from '@/components/ui/tabs'
import { OpenSource } from '@/components/sections/OpenSource'
import { SkillSheet } from '@/components/sections/SkillSheet'
import resume from '@/content/resume'

// Explicit, reader-value ordering (not alphabetical, not JSON order)
const TABS = [
{ key: 'about', label: 'About' },
{ key: 'projects', label: 'Projects' },
{ key: 'work', label: 'Work' },
{ key: 'skills', label: 'Skills' },
{ key: 'earlierCareer', label: 'Earlier Career' },
{ key: 'education', label: 'Education' },
] as const

/**
* One opinionated scroll, not tabs: who + proof + action above the fold,
* the Work receipts at depth 1, the open-source package detail at depth 2.
* Each section gets its own layout — no shared shell.
*/
export default function App() {
const heroSentinelRef = useRef<HTMLDivElement>(null)

return (
<Tabs defaultValue="about" className="min-h-screen flex flex-col !gap-0">
<div className="min-h-screen flex flex-col">
<div id="top" />

<SiteNav name={resume.about.name} />

<HeroSection
name={resume.about.name}
label={resume.about.label}
tagline={resume.about.tagline}
heroLine={resume.about.heroLine}
status={resume.about.status}
stats={resume.about.stats}
/>

<div ref={heroSentinelRef} aria-hidden className="h-px" />

<SectionTabs tabs={[...TABS]} name={resume.about.name} heroSentinelRef={heroSentinelRef} />

<main className="flex-1">
<TabsContent value="about" className="mt-0">
<div className="mx-auto max-w-6xl px-4 sm:px-6 py-10">
<h2 className="font-heading text-2xl text-foreground mb-6">About</h2>
<AboutSection data={resume.about} />
</div>
</TabsContent>

<TabsContent value="projects" className="mt-0">
<div className="mx-auto max-w-6xl px-4 sm:px-6 py-10">
<h2 className="font-heading text-2xl text-foreground mb-6">Projects</h2>
<ProjectGrid items={resume.projects} />
</div>
</TabsContent>

<TabsContent value="work" className="mt-0">
<div className="mx-auto max-w-6xl px-4 sm:px-6 py-10">
<h2 className="font-heading text-2xl text-foreground mb-6">Work</h2>
<JobList jobs={resume.work} />
</div>
</TabsContent>

<TabsContent value="skills" className="mt-0">
<div className="mx-auto max-w-6xl px-4 sm:px-6 py-10">
<h2 className="font-heading text-2xl text-foreground mb-6">Skills</h2>
<SkillGrid categories={resume.skills} />
</div>
</TabsContent>

<TabsContent value="earlierCareer" className="mt-0">
<div className="mx-auto max-w-6xl px-4 sm:px-6 py-10">
<h2 className="font-heading text-2xl text-foreground mb-6">Earlier Career</h2>
<EarlierCareer data={resume.earlierCareer} />
</div>
</TabsContent>

<TabsContent value="education" className="mt-0">
<div className="mx-auto max-w-6xl px-4 sm:px-6 py-10">
<h2 className="font-heading text-2xl text-foreground mb-6">Education</h2>
<EducationList items={resume.education} />
</div>
</TabsContent>
<section id="work" className="mx-auto max-w-5xl px-4 sm:px-6 py-14 scroll-mt-14">
<h2 className="font-heading text-3xl text-foreground mb-8">Work</h2>
<JobList jobs={resume.work} earlierCareer={resume.earlierCareer} />
</section>

<section
id="open-source"
className="border-t border-border/60 mx-auto max-w-5xl px-4 sm:px-6 py-14 scroll-mt-14"
>
<h2 className="font-heading text-3xl text-foreground mb-8">Open Source</h2>
<OpenSource items={resume.projects} lead={resume.about.summary[1]} />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If resume.about.summary has fewer than 2 elements, resume.about.summary[1] will be undefined. Since OpenSource expects lead to be a non-nullable string, this can cause a type mismatch or runtime issues. Use a nullish coalescing operator to provide a safe fallback.

Suggested change
<OpenSource items={resume.projects} lead={resume.about.summary[1]} />
<OpenSource items={resume.projects} lead={resume.about.summary[1] ?? ''} />

</section>

<section
id="skills"
className="border-t border-border/60 mx-auto max-w-5xl px-4 sm:px-6 py-14 scroll-mt-14"
>
<h2 className="font-heading text-3xl text-foreground mb-8">Skills</h2>
<SkillSheet categories={resume.skills} />
</section>
</main>

<SiteFooter />
</Tabs>
</div>
)
}
Loading
Loading