Skip to content

Commit 1a2ea48

Browse files
rbondoc96claude
andauthored
feat: site redesign (#5)
* feat(web): remove resume link * refactor(web): use import extensions * refactor(web): file name casing * refactor(web): clean up the casing * feat: add impeccable PRODUCT.md * feat(web): initial redesign * feat(web): redesign with editorial serif and forest-green accent Replace the Orbitron sci-fi monogram with an editorial system: Fraunces (variable serif) for display over Sora body, and a forest-green accent (replacing the pale salmon) used as punctuation and structure rather than fills. - Swap Orbitron for Fraunces; name becomes the serif hero/wordmark - Forest-green accent tokens, mode-aware (light/dark), AA-verified - Darken muted-foreground in light mode to hold >=4.5:1 - Rebuild the experience timeline: single coupled column with a green spine and nodes, refined company headers, quiet inline tags (no pill flood) - Quiet staggered load entrance with a reduced-motion alternative - Fix Radix Dialog a11y warning on the mobile nav sheet - Remove dead ExperienceCard (carried the old salmon/ghost-card patterns) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(web): capture design system in DESIGN.md Add DESIGN.md (Stitch six-section format) and the .impeccable/design.json sidecar documenting the editorial system: "The Composed Page" north star, Fraunces + Sora pairing, forest-green accent rules, and the timeline signature pattern. Update AGENTS.md design pointer to the decided system. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(web): build projects page backed by sanity Add a `project` document schema (name, url, repoUrl, description, tags) and a full vertical slice mirroring Experience: valibot-validated data module + GROQ query, an RSC renderable, and a route loader. The page renders a calm stacked list (no chronology spine): Fraunces names with a hover arrow when linked, describe-only entries for work that can't link, an optional Source link, and middot tag lists. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(web): unify section-page headers across experience, blog, and home Give Experience and Blog the same left-aligned header as Projects (Fraunces title + muted lead in a max-w-2xl column) and align the Timeline to that column. Drop the duplicate name hero from Experience and relocate the GitHub/LinkedIn icons to the Home identity hero, where identity links belong. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore: ignore local only files * feat(web): hide empty Blog/Projects nav links until populated * feat(web): curate timeline tags to top 5 and align role periods * chore: update CHANGElog --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 80f1faa commit 1a2ea48

61 files changed

Lines changed: 1094 additions & 400 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
# AI
2-
.claude/*.local.*
32
AGENTS.local.md
43
AGENTS.override.md
54
CLAUDE.local.md
@@ -19,6 +18,12 @@ node_modules
1918
# IDEs
2019
.idea
2120

21+
# Impeccable
22+
.impeccable/live
23+
24+
# Local
25+
*.local.*
26+
2227
# OS
2328
.DS_Store
2429

.impeccable/design.json

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
{
2+
"schemaVersion": 2,
3+
"generatedAt": "2026-06-20T00:00:00.000Z",
4+
"title": "Design System: Rodrigo Bondoc",
5+
"extensions": {
6+
"colorMeta": {
7+
"forest-pine": {
8+
"role": "primary",
9+
"displayName": "Forest Pine",
10+
"canonical": "oklch(0.52 0.13 152)",
11+
"tonalRamp": [
12+
"oklch(0.20 0.07 152)",
13+
"oklch(0.30 0.10 152)",
14+
"oklch(0.40 0.12 152)",
15+
"oklch(0.52 0.13 152)",
16+
"oklch(0.62 0.14 152)",
17+
"oklch(0.74 0.15 152)",
18+
"oklch(0.85 0.11 152)",
19+
"oklch(0.94 0.05 152)"
20+
]
21+
},
22+
"ink": {
23+
"role": "neutral",
24+
"displayName": "Ink",
25+
"canonical": "oklch(0.195 0.044 264.6)",
26+
"tonalRamp": [
27+
"oklch(0.15 0.044 264.6)",
28+
"oklch(0.195 0.044 264.6)",
29+
"oklch(0.30 0.04 264.6)",
30+
"oklch(0.44 0.04 262.2)",
31+
"oklch(0.58 0.03 262)",
32+
"oklch(0.72 0.02 260)",
33+
"oklch(0.86 0.012 260)",
34+
"oklch(0.965 0.012 259.7)"
35+
]
36+
},
37+
"paper": {
38+
"role": "neutral",
39+
"displayName": "Paper",
40+
"canonical": "oklch(1 0 0)",
41+
"tonalRamp": [
42+
"oklch(0.18 0.03 264.6)",
43+
"oklch(0.30 0.02 264)",
44+
"oklch(0.50 0.015 262)",
45+
"oklch(0.70 0.012 260)",
46+
"oklch(0.86 0.012 260)",
47+
"oklch(0.94 0.008 260)",
48+
"oklch(0.98 0.004 260)",
49+
"oklch(1 0 0)"
50+
]
51+
}
52+
},
53+
"typographyMeta": {
54+
"display": {
55+
"displayName": "Display",
56+
"purpose": "The name as hero and page titles. Fraunces, optical sizing auto."
57+
},
58+
"headline": { "displayName": "Headline", "purpose": "Timeline company names and serif section headings." },
59+
"body": { "displayName": "Body", "purpose": "Prose and descriptions in Sora; cap at 65–75ch." },
60+
"label": { "displayName": "Label", "purpose": "Inline metadata — tag lists, dates, footer." }
61+
},
62+
"shadows": [
63+
{
64+
"name": "card-rest",
65+
"value": "0 1px 2px rgba(0,0,0,0.05)",
66+
"purpose": "The single soft ambient shadow on cards. Flat everywhere else."
67+
}
68+
],
69+
"motion": [
70+
{
71+
"name": "ease-out-quart",
72+
"value": "cubic-bezier(0.165, 0.84, 0.44, 1)",
73+
"purpose": "Quiet load entrance (enter-rise) and exponential ease-outs."
74+
},
75+
{
76+
"name": "view-transition",
77+
"value": "180ms ease-out",
78+
"purpose": "Root route cross-fade; site-logo wordmark morph at 220ms."
79+
}
80+
],
81+
"breakpoints": [
82+
{ "name": "sm", "value": "640px" },
83+
{ "name": "md", "value": "768px" },
84+
{ "name": "lg", "value": "1024px" },
85+
{ "name": "xl", "value": "1280px" }
86+
]
87+
},
88+
"components": [
89+
{
90+
"name": "Timeline Item",
91+
"kind": "custom",
92+
"refersTo": "card",
93+
"description": "Signature Experience pattern: forest-green spine with solid nodes, Fraunces company header, Sora roles, muted inline tags.",
94+
"html": "<ol class=\"ds-timeline\"><li class=\"ds-timeline-item\"><span class=\"ds-timeline-node\" aria-hidden=\"true\"></span><a class=\"ds-timeline-company\" href=\"#\">Sourcetoad<svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M7 17 17 7\"/><path d=\"M7 7h10v10\"/></svg></a><div class=\"ds-timeline-role\"><span class=\"ds-role-title\">Senior Software Engineer</span><span class=\"ds-role-period\">May 2025 – Present</span></div><p class=\"ds-timeline-desc\">Build and maintain responsive web and mobile apps for clients across industries.</p><p class=\"ds-timeline-tags\">TypeScript · React · PHP · Laravel</p></li></ol>",
95+
"css": ".ds-timeline { list-style: none; margin: 0; padding: 0; font-family: var(--font-sora, 'Sora Variable', sans-serif); color: var(--foreground); } .ds-timeline-item { position: relative; border-left: 1px solid color-mix(in oklch, var(--accent) 30%, transparent); padding-left: 2rem; padding-bottom: 3.5rem; } .ds-timeline-node { position: absolute; top: 0.375rem; left: -6px; height: 0.75rem; width: 0.75rem; border-radius: 9999px; background: var(--accent); box-shadow: 0 0 0 4px var(--background); } .ds-timeline-company { display: inline-flex; align-items: baseline; gap: 0.375rem; font-family: var(--font-fraunces, 'Fraunces Variable', serif); font-weight: 500; font-size: 1.875rem; letter-spacing: -0.02em; color: var(--foreground); text-decoration: none; transition: color 0.3s; } .ds-timeline-company svg { color: var(--muted-foreground); transition: transform 0.3s, color 0.3s; } .ds-timeline-company:hover { color: var(--accent); } .ds-timeline-company:hover svg { color: var(--accent); transform: translate(2px, -2px); } .ds-timeline-role { display: flex; flex-direction: column; margin-top: 1.25rem; } .ds-role-title { font-weight: 500; font-size: 1.125rem; } .ds-role-period { font-size: 0.875rem; color: var(--muted-foreground); } .ds-timeline-desc { margin-top: 1.25rem; max-width: 65ch; font-size: 0.875rem; line-height: 1.625; color: var(--muted-foreground); } .ds-timeline-tags { margin-top: 1.25rem; font-size: 0.75rem; letter-spacing: 0.025em; color: var(--muted-foreground); }"
96+
},
97+
{
98+
"name": "Nav Link",
99+
"kind": "nav",
100+
"refersTo": "nav-link",
101+
"description": "Sora label-size navigation link; underlines on hover, greens on the accent variant.",
102+
"html": "<a class=\"ds-nav-link\" href=\"#\">Experience</a>",
103+
"css": ".ds-nav-link { font-family: var(--font-sora, 'Sora Variable', sans-serif); font-size: 0.875rem; color: var(--foreground); text-decoration: none; transition: color 0.2s; } .ds-nav-link:hover { text-decoration: underline; text-underline-offset: 4px; } .ds-nav-link:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; border-radius: 2px; }"
104+
},
105+
{
106+
"name": "Text Button",
107+
"kind": "button",
108+
"refersTo": "text-button",
109+
"description": "The default quiet control: ink text, no fill, hover underline.",
110+
"html": "<button class=\"ds-btn-text\">View project</button>",
111+
"css": ".ds-btn-text { font-family: var(--font-sora, 'Sora Variable', sans-serif); font-size: 1rem; color: var(--foreground); background: none; border: none; border-radius: var(--radius-md, 8px); padding: 0; cursor: pointer; transition: color 0.2s; } .ds-btn-text:hover { text-decoration: underline; text-decoration-thickness: 1px; } .ds-btn-text:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }"
112+
},
113+
{
114+
"name": "Card",
115+
"kind": "card",
116+
"refersTo": "card",
117+
"description": "Flat-at-rest container: paper surface, 1px hairline, 14px radius, single soft shadow.",
118+
"html": "<div class=\"ds-card\"><h3 class=\"ds-card-title\">Project</h3><p class=\"ds-card-desc\">A short, restful description in Sora.</p></div>",
119+
"css": ".ds-card { background: var(--card); color: var(--card-foreground); border: 1px solid var(--border); border-radius: var(--radius-xl, 14px); box-shadow: 0 1px 2px rgba(0,0,0,0.05); padding: 24px; font-family: var(--font-sora, 'Sora Variable', sans-serif); } .ds-card-title { margin: 0 0 0.5rem; font-weight: 600; letter-spacing: -0.01em; } .ds-card-desc { margin: 0; font-size: 0.875rem; color: var(--muted-foreground); }"
120+
},
121+
{
122+
"name": "Badge (Accent)",
123+
"kind": "chip",
124+
"refersTo": "badge-accent",
125+
"description": "Rare emphasis chip only — Forest Pine fill. Never used in rows; default tags are inline text.",
126+
"html": "<span class=\"ds-badge-accent\">Featured</span>",
127+
"css": ".ds-badge-accent { display: inline-flex; align-items: center; background: var(--accent); color: var(--accent-foreground); border-radius: var(--radius-md, 8px); padding: 2px 10px; font-family: var(--font-sora, 'Sora Variable', sans-serif); font-size: 0.75rem; font-weight: 600; }"
128+
}
129+
],
130+
"narrative": {
131+
"northStar": "The Composed Page",
132+
"overview": "A personal site treated like a well-set magazine page: Fraunces carries the headline voice, Sora handles the reading, and everything else gets out of the way. The register is brand — design is the product — but the personality is precise, understated, and crafted. Confidence comes from restraint and the quality of type and spacing, not from volume. A single forest-green accent is the only color with a voice; the rest is ink on paper. Density is low and deliberate; whitespace is structural. It rejects the generic AI-portfolio look, clutter, corporate sterility, and over-animated gimmickry.",
133+
"keyCharacteristics": [
134+
"Editorial, type-led, calm — Fraunces display over Sora body.",
135+
"Ink-and-paper neutrals with one forest-green accent used as punctuation/structure.",
136+
"Low density, generous and intentional whitespace.",
137+
"Quiet, purposeful motion with a reduced-motion path.",
138+
"Light and dark themes, contrast verified in both (WCAG 2.2 AA)."
139+
],
140+
"rules": [
141+
{
142+
"name": "The Punctuation Rule",
143+
"body": "Forest Pine is structure and accent, never a fill. It may color a 1px spine, a node, an icon, a focus ring, or a hover — never a row of chips or a block of content. Its scarcity is the point.",
144+
"section": "colors"
145+
},
146+
{
147+
"name": "The True-Neutral Rule",
148+
"body": "Paper is white at chroma 0 and ink is a near-black blue. Never warm the background toward cream/sand/parchment.",
149+
"section": "colors"
150+
},
151+
{
152+
"name": "The Two-Voice Rule",
153+
"body": "Fraunces speaks (names, titles); Sora reads (everything else). Don't set body in the serif or headlines in the sans.",
154+
"section": "typography"
155+
},
156+
{
157+
"name": "The No-Eyebrow Rule",
158+
"body": "No tiny tracked-uppercase kicker above sections. Hierarchy comes from serif/sans contrast and size.",
159+
"section": "typography"
160+
},
161+
{
162+
"name": "The Flat-By-Default Rule",
163+
"body": "Surfaces are flat at rest. Reach for a tonal step or a 1px hairline before a shadow. Never pair a 1px border with a wide soft drop shadow.",
164+
"section": "elevation"
165+
}
166+
],
167+
"dos": [
168+
"Do keep Forest Pine to punctuation and structure (spine, node, icon, focus, hover).",
169+
"Do keep the page true ink-on-paper; white at chroma 0, blue-black ink.",
170+
"Do set names and titles in Fraunces, everything readable in Sora.",
171+
"Do render tag/metadata lists as middot-separated Muted Ink text.",
172+
"Do verify body text ≥4.5:1 (large ≥3:1) in both themes, and give every animation a prefers-reduced-motion alternative.",
173+
"Do cap card radius at 14px and keep surfaces flat at rest."
174+
],
175+
"donts": [
176+
"Don't ship the generic AI-portfolio look: cream/sand backgrounds, tracked-uppercase eyebrows, identical icon-heading-text card grids, or hero-metric blocks.",
177+
"Don't let the page get cluttered or maximalist — remove before you add.",
178+
"Don't feel corporate or sterile; keep a point of view.",
179+
"Don't over-animate: no scroll-jacking, no gratuitous or gimmicky motion.",
180+
"Don't flood the accent as fills — no rows of green pills (the original salmon-pill mistake, now forbidden in any hue).",
181+
"Don't pair a 1px border with a wide soft drop shadow on the same element.",
182+
"Don't exceed -0.02em tracking on the serif display, or round cards past 16px."
183+
]
184+
}
185+
}

.impeccable/live/config.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"files": ["apps/web/src/routes/__root.tsx"],
3+
"insertBefore": "</body>",
4+
"commentSyntax": "jsx",
5+
"cspChecked": true
6+
}

AGENTS.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,16 @@ If a tradeoff is required, choose correctness and robustness over short-term con
2626
- Duplicate logic across multiple files is a code smell and should be avoided.
2727
- Don't be afraid to change existing code.
2828
- Don't take shortcuts by just adding local logic to solve a problem.
29+
30+
## Design Context
31+
32+
- `PRODUCT.md` (project root) holds the design strategy: register (`brand`), users,
33+
product purpose, brand personality, anti-references, design principles, and a11y bar.
34+
Read it before any UI/design work.
35+
- **Register:** brand — this is a personal site/portfolio where design is the product.
36+
- **Personality:** precise, understated, crafted; emotional target is calm & refined.
37+
- **Visual system:** Fraunces (variable serif) for display via `--font-fraunces`, Sora
38+
for body. Restrained color on OKLCH tokens (dark/light); the accent is a forest green
39+
(`--accent`, hue ~152) used as punctuation/structure (timeline spine + nodes, link
40+
hover, focus), never as a field. Moved off the prior Orbitron sci-fi direction.
41+
- **A11y bar:** WCAG 2.2 AA, with extra care on reduced-motion.

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# Changelog
22

3+
## 6.0.0 (2026-06-21)
4+
5+
### Redesign
6+
7+
- Redesigned the site around a calmer editorial system using Fraunces, Sora, and a restrained forest-green accent
8+
- Refined section pages, navigation, timeline presentation, and content hierarchy
9+
- Added projects page support backed by Sanity CMS
10+
- Hid empty Blog and Projects navigation links until content is available
11+
12+
## 5.0.0 (2026-06-20)
13+
14+
### TanStack Start Migration
15+
16+
- Migrated the web app from Next.js to TanStack Start
17+
- Updated routing, server functions, and app shell patterns for TanStack Start
18+
- Preserved existing React 19 and Sanity CMS integrations
19+
320
## 4.0.0 (2025-04-19)
421

522
- Migrated to Next.js

0 commit comments

Comments
 (0)