CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Personal portfolio/resume website for Shreyas Gokhale. Built on the Astro Nano theme with Astro 4, Tailwind CSS, TypeScript, and MDX. No frontend frameworks.
Commands
| Command | Purpose |
|---|---|
npm run dev | Dev server at localhost:4321 |
npm run build | Type-check (astro check), build, then generate Pagefind search index |
npm run lint | ESLint |
npm run lint:fix | ESLint with auto-fix |
Architecture
Internationalization (i18n)
The site supports English (default, no prefix) and German (/de/ prefix). Configured via Astro’s built-in i18n in astro.config.mjs.
Routing: English at /, German at /de/. Blog-style content (Scribbles, Subroutines, GSoC, FAQ, Tags) is English-only.
Translation module:
src/i18n/ui.ts— All UI strings keyed by locale (en/de)src/i18n/utils.ts— Helpers:getLangFromUrl(),useTranslations(),getLocalizedPath(),hasLocalizedVersion(),getAlternateLocale(),getLocaleForDateFormatting()
Page architecture: Shared page components in src/components/pages/ accept a lang prop. Thin wrappers in src/pages/ (English) and src/pages/de/ (German) render them.
Content translation: Side-by-side files with .de.md suffix (e.g., gropyus.md + GROPYUS.de.md). German files have lang: de in frontmatter. Collections are filtered by (e.data.lang ?? "en") === lang.
Language switcher: src/components/LanguageSwitcher.astro — flag emoji in nav bar. Always visible; on English-only pages, links to /de/ home.
Adding a new German page:
- Create shared component in
src/components/pages/ - Create thin wrapper in
src/pages/de/ - Add translated content files with
.de.mdsuffix andlang: de
Content
All content collections live in src/content/ with schemas defined in src/content/config.ts.
Key Files
src/consts.ts- Site metadata, social links, nav items, hub cards, andRESUME_SECTIONSordersrc/types.ts- Shared TypeScript types (Site,Metadata,Socials)src/lib/utils.ts- Utility functions (cn,formatDate,dateRange,readingTime)src/remark-highlight.js- Custom remark plugin for==highlight==syntaxsrc/lib/skillIcons.ts- Skill icon mappingssrc/lib/tags.ts- Tag domain mapping (getTagDomain,getTagClasses,DOMAIN_LABELS)
Content Collections
Defined via Zod schemas in config.ts.
| Collection | Schema fields | Notes |
|---|---|---|
work | company, role, dateStart, dateEnd, location, tags?, draft?, lang? | One .md per job. German: .de.md suffix |
education | company, role, dateStart, dateEnd, tags?, lang? | One .md per degree |
projects | title, description, date, draft?, demoURL?, repoURL?, tags?, lang? | One .md per project |
about | lang? | about.md (EN) and about-de.md (DE), body used as resume summary |
skills | category, domain?, order?, lang? | One .md per category (e.g. embedded.md). Body is a markdown list of skills. domain maps to tag colors. order controls display order. |
languages | language, proficiency, order?, lang? | One .md per language (e.g. english.md). order controls display order. |
scribbles | title, description?, date, tags?, draft? | Blog-style posts |
subroutines | title, description?, date, tags?, draft? | Technical writeups |
gsoc | title, description?, date, tags?, draft? | GSoC 2020 posts |
now | updated? | Single now page |
Resume Section Order
The resume page (src/pages/resume/index.astro) renders sections dynamically based on RESUME_SECTIONS in src/consts.ts. To reorder, add, or remove resume sections, edit this array:
export const RESUME_SECTIONS: string[] = [
"summary", "skills", "work", "education", "languages", "projects",
];Valid keys: summary, skills, languages, work, education, projects.
Path Aliases
@* maps to ./src/* (configured in tsconfig.json). Use @components/, @lib/, @layouts/, @consts, @types, etc.
Styling
- Tailwind with
@tailwindcss/typographyplugin - Dark mode via class strategy (
darkMode: ["class"]) - Fonts: Inter (sans), Lora (serif) via Fontsource; Sentient (display) via Fontshare CDN
- Print-specific CSS classes used in homepage layout
ESLint Rules
- Semicolons required, double quotes enforced, template literals allowed