Skip to content

Commit e818a4b

Browse files
cbenge509claude
andcommitted
chore: complete code simplification pass
- Remove unused types file (src/types/index.ts) - Remove unused EXTERNAL_LINK_CLASSES export from card-styles - Document card container function purposes (cardContainerClasses, cardSurfaceContainerClasses) - Unify project card props types with shared ProjectData interface - Extract reusable Breadcrumb navigation component - Create collection sorting utilities (byOrder, byYearDesc, byPublishDateDesc, byPatentDateDesc, byOrderOrYearDesc) - Create test helper for AstroContainer (renderComponent, getTestContainer) - Centralize Hero profile data in profile.ts - Document ExternalLink variants in JSDoc - Update simplify.md to mark all items complete Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 8bad93f commit e818a4b

21 files changed

+1779
-271
lines changed

simplify.md

Lines changed: 1284 additions & 0 deletions
Large diffs are not rendered by default.

src/components/Breadcrumb.astro

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
import type {HTMLAttributes} from 'astro/types';
3+
4+
/**
5+
* Breadcrumb navigation component for consistent page hierarchy display.
6+
* Renders Home link followed by current page name.
7+
*
8+
* @example
9+
* ```astro
10+
* <Breadcrumb currentPage="About" />
11+
* <Breadcrumb currentPage="Publications" class="mb-12" />
12+
* ```
13+
*/
14+
interface Props extends HTMLAttributes<'nav'> {
15+
/** Current page name to display */
16+
currentPage: string;
17+
}
18+
19+
const {currentPage, class: className, ...attrs} = Astro.props;
20+
---
21+
22+
<nav
23+
aria-label="Breadcrumb"
24+
class:list={['mb-8', className]}
25+
{...attrs}
26+
>
27+
<ol class="flex items-center gap-2 text-sm text-text-secondary dark:text-text-secondary-dark">
28+
<li>
29+
<a
30+
href="/"
31+
class="min-h-11 inline-flex items-center hover:text-accent dark:hover:text-accent-dark transition-colors duration-150 focus-ring rounded"
32+
>
33+
Home
34+
</a>
35+
</li>
36+
<li aria-hidden="true">/</li>
37+
<li aria-current="page" class="text-text dark:text-text-dark">
38+
{currentPage}
39+
</li>
40+
</ol>
41+
</nav>

src/components/Breadcrumb.test.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import {experimental_AstroContainer as AstroContainer} from 'astro/container';
2+
import {describe, it, expect} from 'vitest';
3+
import Breadcrumb from './Breadcrumb.astro';
4+
5+
describe('Breadcrumb', () => {
6+
it('renders current page name', async () => {
7+
const container = await AstroContainer.create();
8+
const result = await container.renderToString(Breadcrumb, {
9+
props: {currentPage: 'About'},
10+
});
11+
expect(result).toContain('About');
12+
});
13+
14+
it('renders Home link', async () => {
15+
const container = await AstroContainer.create();
16+
const result = await container.renderToString(Breadcrumb, {
17+
props: {currentPage: 'Test'},
18+
});
19+
expect(result).toContain('href="/"');
20+
expect(result).toContain('Home');
21+
});
22+
23+
it('has aria-label for accessibility', async () => {
24+
const container = await AstroContainer.create();
25+
const result = await container.renderToString(Breadcrumb, {
26+
props: {currentPage: 'Test'},
27+
});
28+
expect(result).toContain('aria-label="Breadcrumb"');
29+
});
30+
31+
it('marks current page with aria-current', async () => {
32+
const container = await AstroContainer.create();
33+
const result = await container.renderToString(Breadcrumb, {
34+
props: {currentPage: 'Publications'},
35+
});
36+
expect(result).toContain('aria-current="page"');
37+
});
38+
39+
it('has focus-ring on Home link', async () => {
40+
const container = await AstroContainer.create();
41+
const result = await container.renderToString(Breadcrumb, {
42+
props: {currentPage: 'Test'},
43+
});
44+
expect(result).toContain('focus-ring');
45+
});
46+
47+
it('has separator with aria-hidden', async () => {
48+
const container = await AstroContainer.create();
49+
const result = await container.renderToString(Breadcrumb, {
50+
props: {currentPage: 'Test'},
51+
});
52+
expect(result).toContain('aria-hidden="true"');
53+
expect(result).toContain('/');
54+
});
55+
56+
it('applies custom class', async () => {
57+
const container = await AstroContainer.create();
58+
const result = await container.renderToString(Breadcrumb, {
59+
props: {currentPage: 'Test', class: 'custom-breadcrumb'},
60+
});
61+
expect(result).toContain('custom-breadcrumb');
62+
});
63+
64+
it('has minimum touch target on Home link', async () => {
65+
const container = await AstroContainer.create();
66+
const result = await container.renderToString(Breadcrumb, {
67+
props: {currentPage: 'Test'},
68+
});
69+
expect(result).toContain('min-h-11');
70+
});
71+
});

src/components/ExternalLink.astro

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,28 @@ import {cn} from '../utils/cn';
77
*
88
* Features:
99
* - Always opens in new tab with security attributes
10-
* - Automatic aria-label enhancement
10+
* - Automatic aria-label enhancement with "(opens in new tab)"
1111
* - Multiple visual variants and sizes
1212
* - Optional prefix icons (PDF, GitHub, external)
1313
* - Arrow suffix indicator
1414
* - Dark mode support
1515
* - Focus ring for keyboard navigation
1616
*
17+
* VARIANTS:
18+
* - `text`: Inline link within text, subtle hover. Use in paragraphs.
19+
* - `button`: Solid filled button. Use for primary CTAs (Hero, Contact).
20+
* - `button-outlined`: Border button. Use for secondary CTAs next to solid buttons.
21+
* - `card-action`: Small link in cards. Use for PDF/Code/DOI links in cards.
22+
* - `badge`: Pill-shaped with backdrop blur. Use for floating overlays on images.
23+
*
24+
* SIZES: xs | sm | base | lg
25+
* - Button variants: affect padding and min-height
26+
* - Text/card-action: affect gap and font-size only
27+
*
28+
* COLOR SCHEMES (button variant only):
29+
* - `accent`: Blue background, white text (primary CTA)
30+
* - `neutral`: Surface background, text color, accent hover
31+
*
1732
* @example
1833
* ```astro
1934
* <!-- Text link -->
@@ -85,52 +100,43 @@ const {
85100
...attrs
86101
} = Astro.props;
87102
103+
// Base classes shared by button variants
104+
const buttonBase = 'inline-flex items-center justify-center rounded-lg transition-colors duration-150';
105+
106+
// Button color schemes
107+
const buttonColors: Record<string, string> = {
108+
accent: 'bg-accent dark:bg-accent text-white hover:bg-accent-hover dark:hover:bg-accent-hover',
109+
neutral: cn(
110+
'bg-surface dark:bg-surface-dark',
111+
'text-text dark:text-text-dark',
112+
'hover:bg-accent hover:text-white dark:hover:bg-accent-dark'
113+
),
114+
};
115+
88116
// Variant-specific classes (including rounding - don't add generic rounded later)
89117
const variantClasses: Record<string, string> = {
90118
text: cn(
91-
'inline-flex items-center',
119+
'inline-flex items-center rounded',
92120
'text-text dark:text-text-dark',
93121
'hover:text-accent dark:hover:text-accent-dark',
94-
'transition-colors duration-150',
95-
'rounded'
122+
'transition-colors duration-150'
96123
),
97-
button:
98-
colorScheme === 'accent'
99-
? cn(
100-
'inline-flex items-center justify-center',
101-
'rounded-lg font-medium',
102-
'bg-accent dark:bg-accent text-white',
103-
'hover:bg-accent-hover dark:hover:bg-accent-hover',
104-
'transition-colors duration-150'
105-
)
106-
: cn(
107-
'inline-flex items-center justify-center',
108-
'rounded-lg font-medium',
109-
'bg-surface dark:bg-surface-dark',
110-
'text-text dark:text-text-dark',
111-
'hover:bg-accent hover:text-white dark:hover:bg-accent-dark',
112-
'transition-colors duration-150'
113-
),
124+
button: cn(buttonBase, 'font-medium', buttonColors[colorScheme]),
114125
'button-outlined': cn(
115-
'inline-flex items-center justify-center',
116-
'rounded-lg',
126+
buttonBase,
117127
'border border-border dark:border-border-dark',
118128
'text-text dark:text-text-dark',
119-
'hover:bg-surface-dark/5 dark:hover:bg-surface/5',
120-
'transition-colors duration-150'
129+
'hover:bg-surface-dark/5 dark:hover:bg-surface/5'
121130
),
122131
'card-action': cn(
123-
'inline-flex items-center',
132+
'inline-flex items-center rounded',
124133
'text-accent dark:text-accent-dark',
125134
'hover:underline',
126-
'px-1 -mx-1',
127-
'rounded'
135+
'px-1 -mx-1'
128136
),
129137
badge: cn(
130-
'inline-flex items-center',
131-
'rounded-full font-medium',
132-
'bg-bg/90 dark:bg-bg-dark/90',
133-
'backdrop-blur-sm',
138+
'inline-flex items-center rounded-full font-medium',
139+
'bg-bg/90 dark:bg-bg-dark/90 backdrop-blur-sm',
134140
'text-text dark:text-text-dark',
135141
'hover:bg-accent hover:text-white dark:hover:bg-accent-dark',
136142
'transition-colors duration-150'

src/components/FeaturedProjectCard.astro

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {Image} from 'astro:assets';
44
import ProjectTag from './ProjectTag.astro';
55
import ExternalLink from './ExternalLink.astro';
66
import placeholderImage from '../assets/images/projects/placeholder.svg';
7-
import {CATEGORY_TO_VARIANT, CATEGORY_LABELS} from '../utils/project-categories';
7+
import {CATEGORY_TO_VARIANT, CATEGORY_LABELS, type ProjectData} from '../utils/project-categories';
88
99
/**
1010
* Featured Project Card component for displaying highlighted projects
@@ -28,17 +28,7 @@ import {CATEGORY_TO_VARIANT, CATEGORY_LABELS} from '../utils/project-categories'
2828
*/
2929
export interface Props extends HTMLAttributes<'article'> {
3030
/** Project data from content collection */
31-
project: {
32-
title: string;
33-
description: string;
34-
image: ImageMetadata;
35-
category: 'leader' | 'builder' | 'winner' | 'research';
36-
skills: string[];
37-
tools: string[];
38-
githubUrl?: string;
39-
achievement?: string;
40-
affiliation?: string;
41-
};
31+
project: ProjectData;
4232
/** Project slug for linking to detail page */
4333
slug: string;
4434
}

src/components/Hero.astro

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import type {HTMLAttributes} from 'astro/types';
33
import {Image} from 'astro:assets';
44
import profileImage from '../assets/images/profile/portfolio_image.jpg';
5-
import {getSocialLink} from '../data/profile';
5+
import {getSocialLink, HERO_PROFILE} from '../data/profile';
66
import ExternalLink from './ExternalLink.astro';
77
88
/**
@@ -30,17 +30,8 @@ interface Props extends HTMLAttributes<'section'> {
3030
3131
const {class: className, showImage = true, ...attrs} = Astro.props;
3232
33-
// Profile data - could be externalized to content collection later
34-
const profile = {
35-
name: 'Cris Benge',
36-
role: 'Head of Federal Innovation, Google',
37-
credentials: [
38-
{label: 'Senior Leadership', type: 'education' as const},
39-
{label: 'Research', type: 'education' as const},
40-
{label: 'Data Science', type: 'education' as const},
41-
{label: 'TS/SCI w/ Polygraph', type: 'clearance' as const},
42-
],
43-
};
33+
// Profile data from centralized source
34+
const profile = HERO_PROFILE;
4435
---
4536

4637
<section

0 commit comments

Comments
 (0)