Files
blog-nextjs/CLAUDE.md
gbanyan 1b495d2d2d Remove next-view-transitions and use native View Transition API
- Remove external next-view-transitions dependency
- Use Next.js 16 native navigation and Safari 18+ native View Transition API
- Add ViewTransitionProvider for minimal wrapping with Safari 18+ detection
- Updated all Link imports from external package to next/link
- Removed link-wrapper.tsx and view-transitions-wrapper.tsx

This resolves Safari compatibility issues while maintaining transitions on modern browsers.
2026-03-14 23:00:21 +08:00

7.6 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 v4 with CSS-first configuration (no tailwind.config.cjs)
  • Dark mode via @custom-variant dark in styles/globals.css (class-based, toggled by next-themes)
  • Theme customization via @theme block in styles/globals.css: colors, fonts, easing, durations, shadows, keyframes, animations
  • 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
  • Typography plugin (@tailwindcss/typography) loaded via @plugin directive; prose dark mode handled by custom .dark .prose CSS overrides
  • English headings use Playfair Display serif (--font-serif-eng); body uses Inter + CJK fallback stack
  • PostCSS config: postcss.config.mjs using @tailwindcss/postcss

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

Two Git remotes are involved: git.gbanyan.net (SSH, primary push target) and gitea.gbanyan.net (HTTPS, Gitea web UI). A crontab on the server automatically mirrors git.gbanyan.netgitea.gbanyan.net. Push to main on 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.

Design Context

Users

  • Medical professionals & students: Seek clinical insights, case studies, and medical education content
  • General public: Interested inpersonal reflections, medicine explainedaccessibly, and lifestyle content
  • Tech enthusiasts & developers: Drawn to HomeLab, technical tutorials, and developer environment content
  • Patients & advocates: Those with similar conditions (Usher syndrome, hearing/vision impairments) seeking understanding and community

Context: Readers visit for deep, reflective content—often in quiet environments, seeking to learn, reflect, or connect with personal experiences. They value clarity, authenticity, and quality over speed.

Job to be done: Gain meaningful knowledge, find resonance with personal experiences, understand complex topics (medical/technical) in approachable terms.

Brand Personality

  • Voice: Reflective, professional, and thoughtful—like a trusted physician who also happens to be a developer
  • 3-word personality: Professional & refined, Thoughtful & reflective, Technical & practical, Approachable & human
  • Emotional goals: Calm & contemplative, Inspired & curious

Not: Corporate, salesy, alarmist (like news sites), or overly technical/clinical.

Aesthetic Direction

Visual tone: Warm & organic with academic & scholarly sensibility, combined with modern technical clarity

References:

  • Medium (medium.com): Readability-focused, minimal distractions, clean typography
  • Personal tech blogs: Individual personality, character, and hands-on authenticity
  • Library aesthetic: Quiet, thoughtful, knowledge-rich environment

Anti-references (explicitly avoid):

  • News sites: Cluttered, headline-focused, clickbait design
  • Social media feeds: Infinite scroll, attention-grabbing tactics, dopamine-driven design
  • Corporate/SaaS: Too polished, salesy, or uniform corporate branding
  • Dry technical docs: Lacking personality, purely functional

Theme: Both light and dark modes equally important—light for daytime readability, dark for late-night focused reading. Accent colors should be warm (avoid reds/yellows which feel urgent/alerting).

Design Principles

  1. Calm-first design: Space, breathing room, and typography hierarchy should prioritize relaxed reading over visual stimulation. Avoid jarring transitions or animation that distracts from content.

  2. Warm technicality: Blend technical precision with human warmth—clean, efficient interfaces that don't feel cold or sterile. The HomeLab/developer content should feel hands-on, not just theoretical.

  3. Academic elegance: Typography and layout should honor the scholarly nature of medical writing and technical explanations—clear hierarchy, proper spacing, and readability first.

  4. Inclusive accessibility: Consider hearing/vision impairments (user has Usher syndrome): high contrast, readable text, motion sensitivity support, clear navigation, and no time-based content hiding.

  5. Consistent rhythm: Maintain consistent spacing, sizing, and interaction patterns across pages to create a predictable, trustworthy experience. Subtle interactions > flashy animations.