This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Personal development blog built with Gatsby 5. Content is sourced from Contentful CMS, styled with Vanilla Extract, and deployed statically to Netlify.
- Gatsby 5: React-based static site generator
- Contentful: Headless CMS for blog posts and asset management
- Vanilla Extract: CSS-in-TypeScript styling
- PrismJS: Code block syntax highlighting
- TypeScript: Strict mode enabled
# Start development server (http://localhost:8000)
pnpm develop
# or
pnpm start
# Production build
pnpm build
# Serve built site locally
pnpm serve
# Type check
pnpm typecheck
# Clean Gatsby cache
pnpm cleanRequired variables in .env file:
CONTENTFUL_SPACE_IDCONTENTFUL_ACCESS_TOKENGOOGLE_ANALYTICS_ID
- Queries
BlogPostcontent type from Contentful via GraphQL - Rich Text content rendered using
@contentful/rich-text-react-renderer - Custom rendering logic defined in
src/const/render-options.ts - Custom renderers provided for BLOCKS, INLINES, and MARKS elements
- Main Page (
src/pages/index.tsx): Lists all blog posts - Post Pages (
src/pages/{contentfulBlogPost.slug}.tsx): Dynamically generated using Gatsby's File System Route API- Queries post data via GraphQL (title, date, slug, category, thumbnail, content)
- Composed of
PostHeaderandPostBodycomponents
Core Files:
src/const/render-options.ts: Defines Contentful Rich Text rendering optionssrc/const/node-renderers.ts: Custom node renderers (images, links, headings, etc.)src/const/tag-map.ts: Maps Contentful block/inline types to HTML tagssrc/const/enums.ts: BLOCKS, INLINES, MARKS enum definitionssrc/const/classnames/: Vanilla Extract CSS class name definitions
Special Handling:
- Code blocks: Inline/block differentiation via
language::metadata- Inline code:
<Code>component - Block code:
<CodeBlock>component + PrismJS highlighting
- Inline code:
- Heading elements: Auto-generate text-based IDs (spaces converted to
-) - Images: Optimized with Gatsby Image plugin, rendered with figcaption
- External links: Automatically add
target="_blank"andrel="noopener noreferrer"
src/
├── components/
│ ├── common/
│ │ ├── layout/ # Header, Footer, Layout (applied via wrapPageElement in gatsby-browser/ssr)
│ │ ├── content/ # Code, CodeBlock (PrismJS integration)
│ │ ├── ThemeToggle.tsx # Theme mode switcher (light/dark/system)
│ │ └── Seo.tsx # SEO head tags
│ ├── main/ # Category, Introduction (for main page)
│ └── post/ # PostHeader, PostBody, PostItem, PostList, TableOfContents, Comments
└── contexts/
└── ThemeContext.tsx # Theme state management with localStorage & OS sync
- Type-safe CSS-in-TS implementation using Vanilla Extract (
.css.tsfiles) src/styles/responsive.css.ts: Responsive media query definitions- Component-specific CSS files co-located in same directory (e.g.,
PostBody.tsx↔PostBody.css.ts)
- Theme system with 3 modes: light, dark, system (syncs with OS preference)
- CSS variable-based theming using
createGlobalThemeContractfrom Vanilla Extract - Core theme files:
src/styles/theme.css.ts: Theme contract and color tokens for light/dark modessrc/styles/global.css.ts: Global styles with theme variablessrc/styles/prism-theme.css: PrismJS syntax highlighting themes for light/dark
- Theme applied via
[data-theme="light|dark"]attribute on<html>element - ThemeContext manages state, localStorage persistence, and OS theme synchronization
gatsby-plugin-canonical-urls: Canonical URL configurationgatsby-plugin-sitemap: Auto-generate sitemap.xmlgatsby-plugin-robots-txt: Generate robots.txtgatsby-plugin-gtag: Google Analytics v4
- Gatsby GraphQL Typegen enabled (
graphqlTypegen: true) - Auto-generated types:
src/gatsby-types.d.ts - Custom types:
src/types/type.d.ts(Post, PostItem, PostDetail) - JSX runtime:
react-jsx(automatic import)
- Use Node.js version 20 (Gatsby 5 supports Node 18 and 20, not Node 24+)
- Run
nvm use 20before starting development - See
.nvmrcfile for version specification
- Run
- Use pnpm as package manager (see packageManager field in package.json)
- PrismJS theming: Two imports required in
gatsby-browser.tsxprismjs/themes/prism-tomorrow.min.css: Base PrismJS theme with syntax colors./src/styles/prism-theme.css: Custom overrides for light/dark mode switching- Both imports must coexist - removing either will break code highlighting
- Layout component automatically applied to all pages via
wrapPageElementin gatsby-browser/ssr - May need to restart dev server after Contentful content changes
- Main components/hooks: Use
export default - Sub-components, utilities, types: Use named exports
export {} - Exception: Files in
src/pages/must use inline exports (export default function,export const query,export const Head) for Gatsby's File System Route API
Example (for non-page files):
// Main component - default export
const MyComponent = () => { ... }
export default MyComponent;
// Sub utilities - named exports
export { helperFunction, UtilityType };Exception example (for src/pages/*.tsx files only):
// Gatsby page files MUST use inline exports
export default function PageName() { ... }
export const query = graphql`...`;
export const Head: HeadFC = () => <SEO />;gatsby-browser.tsx - PrismJS imports (lines 4-5):
- NEVER remove
import 'prismjs/themes/prism-tomorrow.min.css'- provides base syntax highlighting colors - NEVER remove
import './src/styles/prism-theme.css'- applies light/dark mode overrides - Both imports must remain for proper code block theming across all theme modes