From bc745cfa8b0124c36406526dc1410b56ad09bac2 Mon Sep 17 00:00:00 2001 From: RJ Date: Wed, 12 Nov 2025 16:17:55 +0200 Subject: [PATCH] -> Added claude contexts --- .../skills/nextjs-coding-standards/SKILL.md | 758 ++++++++++++++++++ CLAUDE.md | 332 ++++++++ next-env.d.ts | 2 +- 3 files changed, 1091 insertions(+), 1 deletion(-) create mode 100644 .claude/skills/nextjs-coding-standards/SKILL.md create mode 100644 CLAUDE.md diff --git a/.claude/skills/nextjs-coding-standards/SKILL.md b/.claude/skills/nextjs-coding-standards/SKILL.md new file mode 100644 index 0000000..d5dc7b3 --- /dev/null +++ b/.claude/skills/nextjs-coding-standards/SKILL.md @@ -0,0 +1,758 @@ +--- +name: nextjs-coding-standards +description: Next.js 16 coding standards including file naming conventions, API patterns, theming, styling guidelines, and directory structure. Use when writing or reviewing code. +allowed-tools: Read, Grep, Glob +--- + +# Next.js 16 Coding Standards + +Reference this skill when writing or reviewing code to ensure consistency with project conventions. + +--- + +## File Naming Conventions + +### Files and Directories + +**Use kebab-case for all file names:** +``` +✅ user-profile.tsx +✅ blog-post-card.tsx +✅ theme-toggle.tsx + +❌ UserProfile.tsx +❌ blogPostCard.tsx +❌ ThemeToggle.tsx +``` + +**Why kebab-case?** +- Cross-platform compatibility (Windows vs Unix) +- URL-friendly (file names often map to routes) +- Easier to parse and read +- Industry standard for Next.js projects + +**Special Next.js Files:** +``` +page.tsx # Route pages +layout.tsx # Layout components +not-found.tsx # 404 pages +loading.tsx # Loading states +error.tsx # Error boundaries +route.ts # API route handlers +``` + +### Component Names (Inside Files) + +**Use PascalCase for component names:** +```typescript +// File: user-profile.tsx +export function UserProfile() { + return
...
+} + +// File: blog-post-card.tsx +export default function BlogPostCard() { + return
...
+} +``` + +### Variables, Functions, Props + +**Use camelCase:** +```typescript +// Variables +const userSettings = {} +const isLoading = false + +// Functions +function handleSubmit() {} +function formatDate(date: string) {} + +// Props +interface ButtonProps { + onClick: () => void + isDisabled: boolean + className?: string +} + +// Custom Hooks +function useTheme() {} +function useMarkdown() {} +``` + +### Constants + +**Use SCREAMING_SNAKE_CASE:** +```typescript +const API_BASE_URL = "https://api.example.com" +const MAX_RETRIES = 3 +const DEFAULT_LOCALE = "ro-RO" +``` + +--- + +## Next.js 16 API Patterns + +### Route Handlers + +**Use Route Handlers (not legacy API Routes):** + +```typescript +// app/api/posts/route.ts +import { NextRequest, NextResponse } from 'next/server' + +// Export named functions for HTTP methods +export async function GET(request: NextRequest) { + const posts = await getAllPosts() + return NextResponse.json({ posts }) +} + +export async function POST(request: NextRequest) { + const body = await request.json() + // Process request + return NextResponse.json({ success: true }, { status: 201 }) +} +``` + +### Type-Safe Validation with Zod + +**Always validate input with Zod:** + +```typescript +import { z } from 'zod' +import { NextRequest, NextResponse } from 'next/server' + +const bodySchema = z.object({ + title: z.string().min(1).max(200), + content: z.string(), + tags: z.array(z.string()).max(3), +}) + +export async function POST(request: NextRequest) { + const json = await request.json() + const parsed = bodySchema.safeParse(json) + + if (!parsed.success) { + return NextResponse.json( + { error: 'Validation failed', details: parsed.error }, + { status: 400 } + ) + } + + // parsed.data is fully typed + const { title, content, tags } = parsed.data + // ... business logic +} +``` + +**Key Points:** +- Use `safeParse()` instead of `parse()` to avoid try/catch +- Return structured error responses +- Use appropriate HTTP status codes +- Infer TypeScript types from Zod schemas + +### Error Handling + +**Return meaningful status codes:** +```typescript +200 // Success +201 // Created +400 // Bad Request (validation errors) +401 // Unauthorized +403 // Forbidden +404 // Not Found +500 // Internal Server Error +``` + +**Structured error responses:** +```typescript +return NextResponse.json( + { + error: 'Resource not found', + code: 'NOT_FOUND', + timestamp: new Date().toISOString() + }, + { status: 404 } +) +``` + +--- + +## Theming Patterns + +### next-themes Setup + +**Root Layout (Server Component):** + +```typescript +// app/layout.tsx +import { ThemeProvider } from 'next-themes' + +export default function RootLayout({ children }) { + return ( + + + + {children} + + + + ) +} +``` + +**Critical:** Always add `suppressHydrationWarning` to `` tag. + +### Theme Toggle Component + +**Avoid hydration mismatches with mounted state:** + +```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
+ } + + return ( + + ) +} +``` + +**Pattern:** Always check `mounted` state before rendering theme-dependent UI. + +### CSS Variables for Theme Tokens + +**Define in globals.css:** + +```css +@layer base { + :root { + --bg-primary: 255 255 255; + --bg-secondary: 248 250 252; + --text-primary: 15 23 42; + --text-secondary: 51 65 85; + } + + .dark { + --bg-primary: 24 24 27; + --bg-secondary: 15 23 42; + --text-primary: 241 245 249; + --text-secondary: 203 213 225; + } +} +``` + +**Use in components:** + +```tsx +
+ Theme-aware component +
+``` + +### Tailwind Configuration + +**Enable class-based dark mode:** + +```javascript +// tailwind.config.js +module.exports = { + darkMode: 'class', // Required for next-themes + theme: { + extend: { + colors: { + 'dark-primary': '#18181b', + 'accent': { + DEFAULT: '#164e63', + hover: '#155e75', + }, + }, + }, + }, +} +``` + +**Use dark: variant:** + +```tsx +
+ Automatically switches based on theme +
+``` + +--- + +## Styling Guidelines (Tailwind CSS) + +### Utility-First Philosophy + +**Prefer inline utilities over custom CSS:** + +```tsx +// ✅ Good: Inline utilities +
+

Title

+
+ +// ❌ Avoid: @apply (increases bundle size) +/* styles.css */ +.card { + @apply border-4 border-slate-800 p-6 bg-zinc-900; +} +``` + +**Exception:** Only use `@apply` for truly global base styles in `globals.css`. + +### Component Extraction + +**Extract to React components when reused:** + +```typescript +// ✅ Extract repeated patterns to components +export function Card({ children, className = "" }) { + return ( +
+ {children} +
+ ) +} + +// Usage + +

Title

+
+``` + +**Don't extract:** One-off components or single-use patterns. + +### Class Organization + +**Group utilities logically:** + +```tsx +// Layout → Spacing → Colors → Typography → Effects +
+``` + +**Tip:** Use Prettier plugin for automatic Tailwind class sorting. + +### Responsive Design + +**Mobile-first approach:** + +```tsx +// Base classes = mobile, add breakpoints for larger screens +
+``` + +**Standard breakpoints:** +``` +sm: 640px // Small tablets +md: 768px // Tablets +lg: 1024px // Laptops +xl: 1280px // Desktops +2xl: 1536px // Large screens +``` + +### Conditional Styling + +**For complex conditions, use variants:** + +```typescript +const cardVariants = { + default: "border-slate-800 bg-zinc-900", + highlighted: "border-cyan-600 bg-cyan-950", + error: "border-red-600 bg-red-950", +} + + +``` + +--- + +## Directory Structure Standards + +### Project Organization + +``` +app/ +├── (auth)/ # Route groups (no URL segment) +│ ├── login/ +│ └── register/ +├── api/ # API routes +│ └── posts/ +│ └── route.ts +├── blog/ +│ ├── page.tsx +│ └── [slug]/ +│ └── page.tsx +├── @breadcrumbs/ # Parallel routes +│ └── default.tsx +├── layout.tsx # Root layout +├── globals.css +└── page.tsx + +components/ +├── blog/ # Domain-specific components +│ ├── post-card.tsx +│ └── markdown-renderer.tsx +├── layout/ # Layout components +│ ├── header.tsx +│ └── footer.tsx +└── ui/ # Reusable UI primitives + ├── button.tsx + └── card.tsx + +lib/ +├── api/ # API clients, fetch wrappers +│ └── client.ts +├── types/ # TypeScript type definitions +│ └── post.ts +├── markdown.ts # Business logic modules +├── seo.ts +└── utils.ts # Pure utility functions + +public/ +├── blog/ # Blog-specific assets +│ └── images/ +└── icons/ + +content/ # Content files (outside app/) +└── blog/ + └── posts.md +``` + +### lib/ Organization + +**Modules in lib/:** +- Substantial business logic (markdown.ts, seo.ts) +- API clients and data fetching +- Database connections +- Authentication logic + +**Utils in lib/utils.ts:** +- Pure helper functions +- Formatters (formatDate, formatCurrency) +- Validators (isEmail, isValidUrl) +- String manipulations + +**Types in lib/types/:** +- Shared TypeScript interfaces +- API response types +- Domain models +- Colocated with their modules when possible + +### Component Organization + +**By domain/feature:** +``` +components/ +├── blog/ # Blog-specific +│ ├── post-card.tsx +│ ├── post-list.tsx +│ └── markdown-renderer.tsx +├── auth/ # Auth-specific +│ ├── login-form.tsx +│ └── signup-form.tsx +└── ui/ # Reusable primitives + ├── button.tsx + ├── card.tsx + └── input.tsx +``` + +**Not by type:** +``` +❌ Don't organize like this: +components/ +├── forms/ +├── buttons/ +├── cards/ +└── modals/ +``` + +### Public Assets + +**Organize by feature:** +``` +public/ +├── blog/ +│ ├── images/ +│ └── thumbnails/ +├── icons/ +│ ├── social/ +│ └── ui/ +└── fonts/ +``` + +**Naming conventions:** +- Use descriptive names: `hero-background.jpg` not `img1.jpg` +- Use kebab-case: `user-avatar.png` +- Include dimensions for images: `logo-512x512.png` + +--- + +## TypeScript Best Practices + +### Type Safety + +**Avoid `any`:** +```typescript +// ❌ Bad +function processData(data: any) { } + +// ✅ Good +function processData(data: unknown) { + if (typeof data === 'string') { + // TypeScript knows data is string here + } +} + +// ✅ Better: Use specific types +interface PostData { + title: string + content: string +} +function processData(data: PostData) { } +``` + +### Infer Types from Zod + +**Don't duplicate types:** + +```typescript +import { z } from 'zod' + +// Define schema once +const postSchema = z.object({ + title: z.string(), + content: z.string(), + tags: z.array(z.string()), +}) + +// Infer TypeScript type +type Post = z.infer + +// Now you have both runtime validation and compile-time types +``` + +### Type Imports + +**Use type imports for types only:** + +```typescript +// ✅ Good: Explicit type import +import type { Metadata } from 'next' +import type { Post } from '@/lib/types/post' + +// ✅ Mixed: Regular and type imports +import { getAllPosts } from '@/lib/markdown' +import type { Post } from '@/lib/types/post' +``` + +--- + +## Next.js 16 Specific Patterns + +### Async Server Components + +**Fetch data directly in components:** + +```typescript +// app/blog/page.tsx +export default async function BlogPage() { + // Server-side data fetching (no useEffect needed) + const posts = await getAllPosts() + + return ( +
+ {posts.map(post => ( + + ))} +
+ ) +} +``` + +### Static Generation + +**Use generateStaticParams for dynamic routes:** + +```typescript +// app/blog/[slug]/page.tsx +export async function generateStaticParams() { + const posts = await getAllPosts() + return posts.map(post => ({ + slug: post.slug.split('/'), // For catch-all routes + })) +} + +export async function generateMetadata({ params }) { + const post = getPostBySlug(params.slug.join('/')) + return { + title: post.frontmatter.title, + description: post.frontmatter.description, + } +} + +export default async function PostPage({ params }) { + const post = getPostBySlug(params.slug.join('/')) + return
{/* render post */}
+} +``` + +### Client Components + +**Minimize 'use client' usage:** + +```typescript +// ❌ Unnecessary client component +'use client' +export function StaticCard({ title }) { + return
{title}
+} + +// ✅ Keep as server component (default) +export function StaticCard({ title }) { + return
{title}
+} + +// ✅ Only use 'use client' when necessary +'use client' +import { useState } from 'react' + +export function InteractiveCard({ title }) { + const [isOpen, setIsOpen] = useState(false) + return ( +
setIsOpen(!isOpen)}> + {title} +
+ ) +} +``` + +**When to use 'use client':** +- Using React hooks (useState, useEffect, etc.) +- Using event handlers (onClick, onChange, etc.) +- Using browser APIs (window, localStorage, etc.) +- Using context consumers + +### Parallel Routes + +**Use 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}
+ + ) +} +``` + +--- + +## Common Pitfalls + +### 1. Hydration Mismatches + +**Problem:** Theme-dependent content renders differently on server vs client. + +**Solution:** Use mounted state pattern (see Theming section). + +### 2. Image Paths + +**Problem:** Incorrect public asset paths. + +```typescript +// ❌ Wrong + + +// ✅ Correct + // Leading slash +``` + +### 3. Dynamic Route Params + +**Problem:** Forgetting slug should be an array for catch-all routes. + +```typescript +// app/blog/[...slug]/page.tsx +export async function generateStaticParams() { + // ❌ Wrong + return posts.map(post => ({ slug: post.slug })) + + // ✅ Correct + return posts.map(post => ({ slug: post.slug.split('/') })) +} +``` + +### 4. Over-using Client Components + +**Problem:** Adding 'use client' unnecessarily. + +**Solution:** Keep components as Server Components by default. Only add 'use client' when you need hooks, events, or browser APIs. + +### 5. Date Formats + +**Problem:** Inconsistent date formatting. + +**Solution:** Use consistent ISO format (YYYY-MM-DD) in data, format for display: + +```typescript +// In frontmatter +date: "2025-01-15" + +// For display +formatDate(post.frontmatter.date) // "15 ianuarie 2025" (Romanian) +``` + +--- + +## Reference + +For project-specific architecture and design philosophy, see `CLAUDE.md` at the root of this repository. + +This skill focuses on coding conventions and standards. For architecture patterns, markdown processing, and industrial design aesthetic guidelines, refer to the main documentation. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..9fbb92f --- /dev/null +++ b/CLAUDE.md @@ -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 ( + + + + {children} + + + + ) +} +``` + +**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
...
+ + return +} +``` + +**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 `` 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
{posts.map(...)}
+} +``` + +**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 `` 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 `` 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) diff --git a/next-env.d.ts b/next-env.d.ts index 9edff1c..c4b7818 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.