-> Added claude contexts
This commit is contained in:
332
CLAUDE.md
Normal file
332
CLAUDE.md
Normal file
@@ -0,0 +1,332 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is a **Next.js 16** blog/portfolio application built with **TypeScript**, **Tailwind CSS**, and **React 19**. The project uses **App Router** with Static Site Generation (SSG) for blog posts stored as Markdown files.
|
||||
|
||||
**Design Philosophy:** Industrial/SCP-inspired aesthetic with terminal/cyberpunk elements. Sharp edges, thick borders, monospace fonts, darker color palettes (slate/zinc/cyan/emerald tones). No modern Material UI feel - think government documents, classified files, brutal utilitarian design.
|
||||
|
||||
## Development Commands
|
||||
|
||||
```bash
|
||||
# Development server (runs on port 3030)
|
||||
npm run dev
|
||||
|
||||
# Production build
|
||||
npm run build
|
||||
|
||||
# Start production server
|
||||
npm run start
|
||||
|
||||
# Lint code
|
||||
npm run lint
|
||||
|
||||
# Validate all markdown posts (frontmatter, format, tags)
|
||||
npm run validate-posts
|
||||
```
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Next.js 16 App Router Structure
|
||||
|
||||
```
|
||||
app/
|
||||
├── @breadcrumbs/ # Parallel route for breadcrumb navigation
|
||||
│ ├── default.tsx # Auto-generated breadcrumbs
|
||||
│ ├── blog/[...slug]/ # Post-specific breadcrumbs with titles
|
||||
│ ├── tags/[tag]/ # Tag-specific breadcrumbs
|
||||
│ └── about/ # Static breadcrumbs
|
||||
├── blog/
|
||||
│ ├── page.tsx # Blog listing with all posts
|
||||
│ └── [...slug]/ # Dynamic post routes (supports nested paths)
|
||||
│ ├── page.tsx # Post rendering with SSG
|
||||
│ └── not-found.tsx # Custom 404 for missing posts
|
||||
├── about/page.tsx
|
||||
├── layout.tsx # Root layout with metadata, fonts, breadcrumbs slot
|
||||
└── page.tsx # Landing page (hero + featured posts)
|
||||
```
|
||||
|
||||
**Key Architectural Patterns:**
|
||||
|
||||
1. **Parallel Routes:** `@breadcrumbs` slot renders dynamic navigation based on current route without prop drilling
|
||||
2. **Catch-all Routes:** `[...slug]` supports nested blog posts (e.g., `/blog/tech/article-name`)
|
||||
3. **Static Generation:** `generateStaticParams()` pre-renders all blog posts at build time
|
||||
4. **Server Components by Default:** All components are RSC unless marked with `'use client'`
|
||||
|
||||
### Markdown System
|
||||
|
||||
```
|
||||
content/blog/ # Markdown files (supports nested directories)
|
||||
├── example.md
|
||||
└── tech/
|
||||
└── article.md
|
||||
|
||||
lib/
|
||||
├── markdown.ts # Core markdown utilities
|
||||
│ ├── getPostBySlug() # Read single post with path sanitization
|
||||
│ ├── getAllPosts() # Get all posts, sorted by date, recursive
|
||||
│ ├── getRelatedPosts() # Find similar posts by tags
|
||||
│ └── validateFrontmatter()
|
||||
├── types/frontmatter.ts # TypeScript interfaces for Post, FrontMatter
|
||||
└── utils.ts # formatDate(), formatRelativeDate(), generateExcerpt()
|
||||
```
|
||||
|
||||
**Frontmatter Schema:**
|
||||
```yaml
|
||||
---
|
||||
title: string # Required
|
||||
description: string # Required
|
||||
date: "YYYY-MM-DD" # Required, ISO format
|
||||
author: string # Required
|
||||
tags: [string, string?, string?] # Max 3 tags
|
||||
image?: string # Optional hero image
|
||||
draft?: boolean # Exclude from listings if true
|
||||
---
|
||||
```
|
||||
|
||||
**Security:** Path sanitization prevents directory traversal attacks. All file reads use `path.resolve()` and validate paths stay within `content/blog/`.
|
||||
|
||||
### Components Organization
|
||||
|
||||
```
|
||||
components/
|
||||
├── blog/
|
||||
│ └── MarkdownRenderer.tsx # Client component for rendering markdown
|
||||
│ # Custom components: images (Next Image),
|
||||
│ # links (external vs internal), code blocks
|
||||
├── layout/
|
||||
│ ├── Breadcrumbs.tsx # Client component, uses usePathname()
|
||||
│ └── BreadcrumbsSchema.tsx # Schema.org structured data for SEO
|
||||
└── [future components]
|
||||
```
|
||||
|
||||
## Coding Standards for Next.js 16
|
||||
|
||||
### File Naming Conventions
|
||||
|
||||
**Files and Directories:**
|
||||
- Use **kebab-case** for all file names: `user-profile.tsx`, `blog-post.tsx`
|
||||
- Special Next.js files: `page.tsx`, `layout.tsx`, `not-found.tsx`, `loading.tsx`
|
||||
|
||||
**Component Names (inside files):**
|
||||
- Use **PascalCase**: `export function UserProfile()`, `export default BlogPost`
|
||||
|
||||
**Variables, Functions, Props:**
|
||||
- Use **camelCase**: `const userSettings = {}`, `function handleSubmit() {}`
|
||||
- Hooks: `useTheme`, `useMarkdown`
|
||||
|
||||
**Constants:**
|
||||
- Use **SCREAMING_SNAKE_CASE**: `const API_BASE_URL = "..."`
|
||||
|
||||
**Why kebab-case for files?**
|
||||
- Cross-platform compatibility (Windows vs Unix)
|
||||
- URL-friendly (file names often map to routes)
|
||||
- Easier to parse and read
|
||||
|
||||
### Theme Management & Reusability
|
||||
|
||||
**Recommended Pattern:** Use `next-themes` library for dark/light mode
|
||||
|
||||
```typescript
|
||||
// Root layout.tsx
|
||||
import { ThemeProvider } from 'next-themes'
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html suppressHydrationWarning>
|
||||
<body>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="dark"
|
||||
enableSystem={false}
|
||||
storageKey="blog-theme"
|
||||
>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
**Client Component for Toggle:**
|
||||
```typescript
|
||||
// components/theme-toggle.tsx
|
||||
'use client'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export function ThemeToggle() {
|
||||
const { theme, setTheme } = useTheme()
|
||||
const [mounted, setMounted] = useState(false)
|
||||
|
||||
// Prevent hydration mismatch
|
||||
useEffect(() => setMounted(true), [])
|
||||
if (!mounted) return <div>...</div>
|
||||
|
||||
return <button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
|
||||
Toggle
|
||||
</button>
|
||||
}
|
||||
```
|
||||
|
||||
**Tailwind Configuration:**
|
||||
```javascript
|
||||
// tailwind.config.js
|
||||
module.exports = {
|
||||
darkMode: 'class', // Use 'class' strategy for next-themes
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
// Define custom colors for consistency
|
||||
'dark-primary': '#18181b',
|
||||
'accent': { DEFAULT: '#164e63', hover: '#155e75' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**CSS Variables Pattern:**
|
||||
```css
|
||||
/* globals.css */
|
||||
:root {
|
||||
--bg-primary: 255 255 255;
|
||||
--text-primary: 15 23 42;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--bg-primary: 24 24 27;
|
||||
--text-primary: 241 245 249;
|
||||
}
|
||||
|
||||
/* Use in components */
|
||||
.card {
|
||||
@apply bg-[rgb(var(--bg-primary))] text-[rgb(var(--text-primary))];
|
||||
}
|
||||
```
|
||||
|
||||
### Provider Pattern Best Practices
|
||||
|
||||
1. **Server Component Boundary:** Keep `layout.tsx` as Server Component, wrap only `children` with Client Provider
|
||||
2. **Avoid Hydration Mismatches:** Always use `suppressHydrationWarning` on `<html>` tag
|
||||
3. **Client-Only Rendering:** Use `useEffect` + `mounted` state for theme-dependent UI
|
||||
4. **Context Consumption:** Only components using `useTheme()` need `'use client'` directive
|
||||
5. **No Prop Drilling:** Context makes theme accessible anywhere without passing props
|
||||
|
||||
### Next.js 16 Specific Patterns
|
||||
|
||||
**Async Server Components:**
|
||||
```typescript
|
||||
// app/blog/page.tsx
|
||||
export default async function BlogPage() {
|
||||
const posts = await getAllPosts() // Server-side data fetching
|
||||
return <div>{posts.map(...)}</div>
|
||||
}
|
||||
```
|
||||
|
||||
**Static Generation with Dynamic Routes:**
|
||||
```typescript
|
||||
// app/blog/[...slug]/page.tsx
|
||||
export async function generateStaticParams() {
|
||||
const posts = await getAllPosts()
|
||||
return posts.map(post => ({ slug: post.slug.split('/') }))
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }) {
|
||||
const post = getPostBySlug(params.slug.join('/'))
|
||||
return { title: post.frontmatter.title, ... }
|
||||
}
|
||||
```
|
||||
|
||||
**Parallel Routes for Layout Composition:**
|
||||
```typescript
|
||||
// app/layout.tsx
|
||||
export default function RootLayout({
|
||||
children,
|
||||
breadcrumbs, // From @breadcrumbs parallel route
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
breadcrumbs: React.ReactNode
|
||||
}) {
|
||||
return <>
|
||||
{breadcrumbs}
|
||||
{children}
|
||||
</>
|
||||
}
|
||||
```
|
||||
|
||||
## Project-Specific Patterns
|
||||
|
||||
### Markdown Processing
|
||||
|
||||
- **Always validate paths:** Use `sanitizePath()` to prevent directory traversal
|
||||
- **Draft support:** Posts with `draft: true` are excluded from `getAllPosts()`
|
||||
- **Recursive directories:** Blog posts can be organized in subdirectories (`content/blog/tech/post.md`)
|
||||
- **Reading time:** Auto-calculated at 200 words/minute
|
||||
- **Date handling:** Use Romanian locale (`ro-RO`) for date formatting
|
||||
|
||||
### SEO & Metadata
|
||||
|
||||
- **Every page exports `metadata`:** Use Next.js 16's `Metadata` type
|
||||
- **Dynamic metadata:** Use `generateMetadata()` for blog posts
|
||||
- **Structured data:** Include Schema.org `BreadcrumbList` and `BlogPosting`
|
||||
- **OpenGraph images:** Reference `post.frontmatter.image` for social sharing
|
||||
|
||||
### Styling Guidelines
|
||||
|
||||
**Color Palette:**
|
||||
- Backgrounds: `zinc-900`, `slate-900`, `slate-800`
|
||||
- Accents: `cyan-900`, `emerald-900`, `teal-900`
|
||||
- Text: `slate-100`, `slate-300`, `slate-500`
|
||||
- Borders: `border-2`, `border-4` (thick, sharp)
|
||||
|
||||
**Design Tokens:**
|
||||
- **NO rounded corners:** Use `rounded-none` or omit (default is sharp)
|
||||
- **Monospace fonts:** Apply `font-mono` for terminal aesthetic
|
||||
- **Uppercase labels:** Use `uppercase tracking-wider` for headers
|
||||
- **Border-heavy design:** Thick borders (`border-4`) over shadows
|
||||
- **Classification labels:** Add metadata like "FILE#001", "DOCUMENT LEVEL-1"
|
||||
|
||||
**Typography:**
|
||||
- Primary font: `JetBrains Mono` (monospace)
|
||||
- Headings: `font-mono font-bold uppercase`
|
||||
- Body: `font-mono text-sm`
|
||||
- Code blocks: Sharp borders, dark background, no syntax highlighting (for terminal feel)
|
||||
|
||||
## Available Subagents
|
||||
|
||||
Use these specialized agents via `/spec-implementation-and-review` command:
|
||||
|
||||
- `nextjs-specialist` - Next.js 15/16, App Router, SSG, API routes
|
||||
- `ui-implementer` - UI implementation with shadcn/ui, Tailwind
|
||||
- `ui-css-specialist` - CSS layouts, styling, responsive design
|
||||
- `react-frontend-expert` - React components, hooks, state management
|
||||
- `nodejs-typescript-engineer` - TypeScript, Node.js backend
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
1. **Hydration Mismatches with Themes:** Always use `suppressHydrationWarning` on `<html>` and check `mounted` state before rendering theme-dependent UI
|
||||
2. **Image Paths:** Use `/` prefix for public assets (`/blog/image.jpg` not `blog/image.jpg`)
|
||||
3. **Dynamic Routes:** Remember to return `slug` as array in `generateStaticParams()` for catch-all routes
|
||||
4. **Client Components:** Minimize `'use client'` usage - only add when using hooks, event handlers, or browser APIs
|
||||
5. **Path Security:** Always use `sanitizePath()` when reading markdown files
|
||||
6. **Date Formats:** Use `YYYY-MM-DD` in frontmatter, convert to Romanian locale for display
|
||||
7. **Port Configuration:** Dev server runs on port **3030** (not default 3000)
|
||||
|
||||
## Type Safety
|
||||
|
||||
- All utilities in `lib/` are fully typed
|
||||
- Frontmatter structure enforced via `FrontMatter` interface
|
||||
- Use `Post` type for blog post objects
|
||||
- Avoid `any` - use `unknown` if type is truly unknown, then narrow
|
||||
|
||||
## Performance Notes
|
||||
|
||||
- **SSG by default:** All blog posts pre-rendered at build time
|
||||
- **Image optimization:** Use Next.js `<Image>` component
|
||||
- **Font optimization:** Google Fonts loaded via `next/font`
|
||||
- **No client-side data fetching:** Markdown loaded server-side only
|
||||
- **Static exports:** Pages are fully static HTML (no server required for hosting)
|
||||
Reference in New Issue
Block a user