|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +Personal portfolio website for Cris Benge (AI Researcher) built with Astro 5.x, Tailwind CSS v4, and TypeScript in strict mode. Deployed to GitHub Pages at cbenge509.github.io. |
| 8 | + |
| 9 | +## Commands |
| 10 | + |
| 11 | +```bash |
| 12 | +# Development |
| 13 | +npm run dev # Start dev server at localhost:4321 |
| 14 | +npm run build # Build for production |
| 15 | +npm run preview # Preview production build |
| 16 | + |
| 17 | +# Linting (uses Google TypeScript Style via gts) |
| 18 | +npm run lint # Run gts lint |
| 19 | +npm run fix # Auto-fix lint issues |
| 20 | +npm run check # Check formatting |
| 21 | + |
| 22 | +# Testing |
| 23 | +npm run test # Run unit tests (Vitest) |
| 24 | +npm run test:coverage # Unit tests with coverage |
| 25 | +npm run test:e2e # Run E2E tests (Playwright, all browsers) |
| 26 | +npm run test:e2e:ui # Playwright with UI mode |
| 27 | + |
| 28 | +# Run single test file |
| 29 | +npx vitest run src/components/Hero.test.ts |
| 30 | +npx playwright test e2e/hero.spec.ts |
| 31 | +npx playwright test e2e/hero.spec.ts --project=chromium # Single browser |
| 32 | + |
| 33 | +# Type checking |
| 34 | +npx tsc --noEmit --project tsconfig.ci.json # CI-style (excludes test files) |
| 35 | +``` |
| 36 | + |
| 37 | +## Architecture |
| 38 | + |
| 39 | +### Tech Stack |
| 40 | +- **Astro 5.x** - Static site generator |
| 41 | +- **Tailwind CSS v4** - Uses `@tailwindcss/vite` plugin (NOT `@astrojs/tailwind`) |
| 42 | +- **TypeScript** - Strict mode, no `any` types |
| 43 | +- **Vitest** - Unit tests (co-located with components) |
| 44 | +- **Playwright** - E2E tests (Chromium, Firefox, WebKit) |
| 45 | +- **gts** - Google TypeScript Style for linting/formatting |
| 46 | + |
| 47 | +### Directory Structure |
| 48 | +``` |
| 49 | +src/ |
| 50 | +├── components/ # Astro components with co-located *.test.ts files |
| 51 | +├── content/ # Content collections (projects, publications, patents, education, certifications, awards) |
| 52 | +├── layouts/ # BaseLayout.astro |
| 53 | +├── pages/ # Route pages |
| 54 | +├── styles/ # global.css with Tailwind v4 @theme config |
| 55 | +├── utils/ # Utilities (cn.ts for class merging) |
| 56 | +└── types/ # Type definitions |
| 57 | +e2e/ # Playwright E2E tests (*.spec.ts) |
| 58 | +test/fixtures/ # Test mock data (content/, props/) |
| 59 | +``` |
| 60 | + |
| 61 | +### Content Collections |
| 62 | +All content lives in `src/content/` with Zod schemas defined in `config.ts`: |
| 63 | +- **projects** (content) - Portfolio projects with categories: leader, builder, winner, research |
| 64 | +- **publications** (content) - Academic papers with authors, venue, abstract |
| 65 | +- **patents** (content) - Patent filings with status tracking |
| 66 | +- **education** (data) - Degrees and institutions |
| 67 | +- **certifications** (data) - Professional certs by category |
| 68 | +- **awards** (data) - Competition/professional awards |
| 69 | + |
| 70 | +### Key Patterns |
| 71 | + |
| 72 | +**Component Props**: Always extend HTMLAttributes for accessibility passthrough |
| 73 | +```typescript |
| 74 | +interface Props extends HTMLAttributes<'section'> { |
| 75 | + title: string; |
| 76 | +} |
| 77 | +const { title, class: className, ...attrs } = Astro.props; |
| 78 | +``` |
| 79 | + |
| 80 | +**Dark Mode**: Class-based using `data-theme` attribute on `<html>`, inline script in `<head>` prevents FOUC. Use `dark:` prefix for all color utilities. |
| 81 | + |
| 82 | +**Hydration**: Only `ThemeToggle` uses `client:load`. All other interactivity uses vanilla JS with `<script>` tags and `data-component` attributes. |
| 83 | + |
| 84 | +**Class Composition**: Use `cn()` utility (clsx + tailwind-merge) for combining classes. |
| 85 | + |
| 86 | +**Asset Paths**: Use RELATIVE paths (`../assets/images/...`), never path aliases - Astro Image optimization requires this. |
| 87 | + |
| 88 | +### Testing Patterns |
| 89 | + |
| 90 | +**Unit tests**: Co-located `*.test.ts` using AstroContainer |
| 91 | +```typescript |
| 92 | +import { experimental_AstroContainer as AstroContainer } from 'astro/container'; |
| 93 | +const container = await AstroContainer.create(); |
| 94 | +const result = await container.renderToString(Component, { props: {...} }); |
| 95 | +``` |
| 96 | + |
| 97 | +**E2E tests**: Always emulate reduced motion for accessibility tests |
| 98 | +```typescript |
| 99 | +test.beforeEach(async ({ page }) => { |
| 100 | + await page.emulateMedia({ reducedMotion: 'reduce' }); |
| 101 | +}); |
| 102 | +``` |
| 103 | + |
| 104 | +**Coverage thresholds**: 90% for statements, branches, functions, lines |
| 105 | + |
| 106 | +### CI Pipeline (GitHub Actions) |
| 107 | +Runs security (npm audit, Semgrep), lint, build, unit tests, E2E tests (all browsers), Lighthouse CI. Deploy to GitHub Pages on master push. |
| 108 | + |
| 109 | +### Pre-commit Hooks |
| 110 | +Husky runs: `gts lint`, `gts check`, npm audit (warn), Semgrep (if installed) |
| 111 | + |
| 112 | +## Critical Rules |
| 113 | + |
| 114 | +- TypeScript strict mode - no `any` types |
| 115 | +- Every component needs co-located unit test |
| 116 | +- All interactive elements need `.focus-ring` class and 44px minimum touch targets |
| 117 | +- Never use `Astro.url.href` for canonical URLs (returns localhost in dev) |
| 118 | +- CI type checking uses `tsconfig.ci.json` which excludes test files intentionally |
| 119 | +- Tailwind v4 config is CSS-based in `global.css` using `@theme` directive |
0 commit comments