Skip to content

Latest commit

 

History

History
212 lines (160 loc) · 8.43 KB

File metadata and controls

212 lines (160 loc) · 8.43 KB

CLAUDE.md

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

Project Overview

Lemon Blog is a modern, static blog platform built with Next.js App Router and Tailwind CSS. It features:

  • Static Site Generation: All blog posts are generated as static pages at build time
  • Markdown Content: Articles are stored as Markdown files in /content/articles
  • Syntax Highlighting: Code blocks with Prism.js syntax highlighting (rehype-prism-plus)
  • Dark Mode: Full dark/light mode support with system preference detection
  • Responsive Design: Mobile-first design with Tailwind CSS
  • SEO Optimized: Built-in metadata and OpenGraph support
  • Image Service: Unified image service supporting Unsplash, GIPHY, and Storyset
  • Cover Images: Automatic cover image extraction from article content

Development Commands

# Install dependencies
npm install

# Start development server (also copies article images)
npm run dev

# Build for production (also copies article images)
npm run build

# Start production server
npm run start

# Lint code
npm run lint

# Fix linting issues
npm run lint:fix

# Type checking
npm run type-check

# Bundle analysis
npm run analyze

Important: The dev and build commands automatically run scripts/copy-images.js before starting. This script copies images from content/articles/{slug}/img/ and content/articles/img/ to public/articles/ for static serving.

Project Architecture

Key Architectural Patterns

Image Path Resolution: The blog supports two image storage patterns:

  1. Per-article: content/articles/{slug}/img/*/articles/{slug}/img/*
  2. Shared: content/articles/img/*/articles/img/*

Relative image paths in markdown (e.g., img/photo.jpg) are automatically converted to absolute paths during build time via fixImagePaths() in src/lib/posts.ts.

Image Service Architecture (src/lib/images/):

  • index.ts: Unified imageService class with caching
  • unsplash.ts: Unsplash photo integration
  • giphy.ts: GIPHY GIF integration
  • storyset.ts: Storyset illustration integration
  • All services follow a consistent pattern: search, random, and optimized URL generation

Cover Image Extraction: The first image in markdown content is automatically extracted as the cover image. This supports both markdown syntax ![alt](url) and HTML <img> tags. The extracted image is removed from the content to avoid duplication.

Directory Structure

src/
├── app/                    # Next.js App Router pages
│   ├── blog/              # Blog-related pages
│   │   ├── [slug]/        # Dynamic blog post pages
│   │   └── page.tsx       # Blog listing page
│   ├── layout.tsx         # Root layout with Navbar and Footer
│   └── page.tsx           # Homepage
├── components/            # Reusable React components
│   ├── Navbar.tsx         # Navigation with dark mode toggle
│   ├── Footer.tsx         # Site footer
│   ├── BannerImage.tsx    # Smart image component with Unsplash/GIPHY/Storyset support
│   ├── ArticleCard.tsx    # Blog post card component
│   └── ImageOptimizer.tsx # Image optimization utilities
├── lib/                   # Utility functions and configurations
│   ├── posts.ts           # Markdown processing, image path fixing, cover extraction
│   ├── images/            # Image service (Unsplash, GIPHY, Storyset)
│   └── styles.css         # Custom styles for syntax highlighting
└── types/
    └── post.ts            # Post type definition

content/articles/          # Markdown blog posts
├── {slug}.md              # Article markdown files
├── {slug}/img/            # Per-article images (copied to public/articles/{slug}/img/)
└── img/                   # Shared article images (copied to public/articles/img/)

scripts/
└── copy-images.js         # Copies article images to public directory

public/articles/           # Generated by copy-images.js (do not edit manually)

Key Files and Their Purpose

  • src/lib/posts.ts: Core utilities including fixImagePaths(), extractCoverImageSync(), getAllPosts(), getPostBySlug()
  • src/lib/images/index.ts: Unified image service with getArticleImage(), searchImages(), getRandomImage()
  • src/app/blog/[slug]/page.tsx: Dynamic route with generateStaticParams() for static generation
  • src/components/BannerImage.tsx: Smart image component supporting multiple sources with fallback
  • scripts/copy-images.js: Build-time script that copies images from content to public
  • next.config.ts: Static export configuration with output: 'export'

Content Management

Adding New Blog Posts

  1. Create a new .md file in /content/articles/
  2. Include required frontmatter:
    ---
    title: "Article Title"
    date: "YYYY-MM-DD"
    description: "Brief description"
    author: "Author Name"
    tags: ["tag1", "tag2"]
    ---
  3. Add images to either content/articles/{slug}/img/ (per-article) or content/articles/img/ (shared)
  4. Reference images in markdown as img/filename.jpg - paths will be auto-converted
  5. The first image in content becomes the cover image automatically

Frontmatter Fields

  • title: Required. The article title
  • date: Required. Publication date (YYYY-MM-DD format)
  • description: Required. Brief description for SEO and previews
  • author: Required. Author name (defaults to "Anonymous")
  • tags: Optional. Array of string tags for categorization (also used for image matching)

Image Handling

For article images (displayed in content):

  • Place in content/articles/{slug}/img/ or content/articles/img/
  • Reference as ![alt](img/filename.jpg) in markdown
  • Paths are automatically converted to /articles/... at build time

For cover images:

  • First image in markdown is auto-extracted as cover
  • Supports ![alt](url) and <img src="url"> syntax
  • Removed from content after extraction to avoid duplication
  • Can be overridden via coverImage property in Post type

For BannerImage component:

  • Accepts customImage prop to override automatic selection
  • Falls back to Unsplash/GIPHY/Storyset based on tags if no custom image
  • Supports preferredSource prop ('unsplash', 'giphy', 'storyset')

Styling and Design

  • Tailwind CSS v4: Utility-first CSS framework with new PostCSS-based architecture
  • Dark Mode: Class-based dark mode with system preference detection
  • Typography: Custom prose styles using @tailwindcss/typography plugin
  • Responsive: Mobile-first responsive design
  • Components: Consistent design system with reusable components

Deployment

The project is configured for one-click deployment to Vercel:

  1. Push to GitHub
  2. Connect repository to Vercel
  3. Vercel automatically builds and deploys

Build Configuration

  • Static Export: output: 'export' in next.config.ts
  • Image Optimization: unoptimized: true required for static export
  • Turbopack: Enabled for faster builds
  • Trailing Slash: Enabled for consistent URL structure
  • Remote Patterns: Configured for Unsplash, via.placeholder, and wildcard HTTPS

Development Notes

Working with Markdown

  • Uses gray-matter for frontmatter parsing
  • Uses remark and rehype for Markdown processing pipeline
  • rehype-prism-plus provides syntax highlighting with line numbers
  • Image paths are fixed before markdown processing via fixImagePaths()
  • First image is extracted as cover, then removed from content

State Management

  • Dark mode preference stored in localStorage
  • Theme state managed in Navbar component (client component)
  • System preference detection on first load
  • Image service uses in-memory Map for caching

Type Safety

  • All types defined in src/types/post.ts
  • Client-safe type exports (no server-only types in client components)
  • TypeScript strict mode enabled

Dependencies Key

  • Next.js 16: React framework with App Router
  • React 19: Latest React with concurrent features
  • Tailwind CSS v4: Latest utility-first CSS with PostCSS integration
  • gray-matter: Frontmatter parser for Markdown
  • remark/rehype: Markdown processor ecosystem
  • rehype-prism-plus: Syntax highlighting with Prism.js
  • date-fns: Date formatting utilities
  • @tailwindcss/typography: Prose styles for article content
  • @tailwindcss/aspect-ratio: Aspect ratio utilities