Files
blog-nextjs/CLAUDE.md
gbanyan 9c7f2463aa Add new post and update CLAUDE.md with deployment docs
- New post: 不是所有眼淚,都該被濃縮成重點
- CLAUDE.md: add deployment workflow and content submodule instructions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 12:50:36 +08:00

4.2 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

  • npm run dev - Start dev server (runs Contentlayer2 + Next.js with Turbopack concurrently)
  • npm run build - Full production build: sync-assets → contentlayer2 build → next build → pagefind indexing → copy pagefind to public
  • npm run lint - ESLint via next lint
  • npm run sync-assets - Copy content/assets/ to public/assets/ (also runs automatically before build)

No test framework is configured.

Architecture

Content pipeline: content/ git submodule (MDX/Markdown) → Contentlayer2 (contentlayer.config.ts) → typed Post/Page objects imported from contentlayer2/generated → consumed by pages and lib/posts.ts helpers.

Routing (App Router):

  • / — Home page with latest posts
  • /blog — Blog index with search, sort, pagination
  • /blog/[slug] — Single post with TOC, reading progress, prev/next navigation
  • /pages/[slug] — Static content pages (from content/pages/)
  • /tags, /tags/[tag] — Tag index and per-tag post lists
  • /api/og — Dynamic OG image generation (@vercel/og)
  • /feed.xml — RSS feed (route handler)

Key data flow:

  • lib/config.tssiteConfig object built from NEXT_PUBLIC_* env vars (all site metadata, social links, accent colors, pagination)
  • lib/posts.ts — Query helpers: getAllPostsSorted(), getPostBySlug(), getPageBySlug(), getAllTagsWithCount(), getRelatedPosts(), getPostNeighbors()
  • lib/mastodon.ts — Mastodon API client for sidebar feed widget
  • lib/rehype-callouts.ts — Custom rehype plugin for GitHub-style [!NOTE] callout blocks

Layout hierarchy: app/layout.tsx (fonts, theme CSS vars, ThemeProvider, JSON-LD) → components/layout-shell.tsx (header, sidebar, footer, back-to-top) → page content.

Markdown processing (configured in contentlayer.config.ts):

  • Remark: GFM
  • Rehype: callouts → pretty-code (shiki, dual theme) → slug → autolink-headings → image path rewriter (../assets//assets/)
  • Image paths in markdown are relative (../assets/foo.jpg); a rehype plugin rewrites them to /assets/foo.jpg at build time

Styling

  • Tailwind CSS v3 with darkMode: 'class' (toggled by next-themes)
  • Accent color system via CSS variables set in app/layout.tsx from env vars: --color-accent, --color-accent-soft, --color-accent-text-light, --color-accent-text-dark
  • Tailwind extends these as accent, accent-soft, accent-textLight, accent-textDark in tailwind.config.cjs
  • Typography plugin (@tailwindcss/typography) with custom prose / prose-dark overrides
  • English headings use Playfair Display serif (--font-serif-eng); body uses Inter + CJK fallback stack
  • Config files use CommonJS (.cjs): tailwind.config.cjs, postcss.config.cjs

Content Submodule

The content/ directory is a git submodule pointing to a separate personal-blog repository. It contains posts/, pages/, and assets/. After pulling new content, run npm run sync-assets to update public/assets/. The build script does this automatically.

Path Aliases

@/* maps to project root (configured in tsconfig.json). Contentlayer generated types at .contentlayer/generated are aliased as contentlayer2/generated.

Deployment

Push to main on the Gitea remote (git.gbanyan.net) triggers CI/CD automatically (server-side hook). No Dockerfile or workflow file in this repo.

Content-only update (new/edited posts) — both steps are required to trigger deploy:

  1. Commit and push inside content/ submodule: git -C content add . && git -C content commit -m "..." && git -C content push
  2. Update main repo submodule pointer and push: git add content && git commit -m "Update content submodule" && git push

Pushing only to content/ (personal-blog) does NOT trigger deployment. The main repo must also be pushed because CI/CD is bound to blog-nextjs, not personal-blog.

Code changes: Commit and push in the main repo as usual — git push to main triggers the pipeline.

Language

The site's default locale is zh-TW. UI text, labels, and timestamps are in Traditional Chinese.