Skip to content

Latest commit

 

History

History
254 lines (185 loc) · 12.6 KB

File metadata and controls

254 lines (185 loc) · 12.6 KB

CLAUDE.md - Ethereum.org Website

Project Overview

This is the official Ethereum.org website - a Next.js application that serves as the primary educational and community hub for Ethereum. The site is built with modern web technologies and focuses on accessibility, internationalization, and performance.

Technology Stack

Core Framework

  • Next.js 16+ - React framework with App Router (Turbopack is the default bundler; webpack available via pnpm dev:webpack / pnpm build:webpack)
  • React 19 - UI library
  • TypeScript 5.5+ - Type safety and development experience
  • Tailwind CSS 4+ - Utility-first CSS framework (CSS-first config in src/styles/global.css)

Key Dependencies

  • next-intl 4+ - Internationalization (i18n) with 25 languages
  • next-mdx-remote 5.0+ - MDX content processing
  • Motion 12+ (motion package, formerly Framer Motion) - Animations and transitions; import from motion/react
  • Radix UI - Accessible component primitives
  • shadcn/ui - Component library built on Radix UI
  • Recharts - Data visualization
  • Viem/Wagmi - Ethereum blockchain integration

Development & Testing

  • Storybook 10+ - Component development and testing
  • Chromatic - Visual regression testing
  • ESLint - Code linting with custom rules
  • Prettier - Code formatting
  • Husky - Git hooks
  • PNPM - Package manager

Project Structure

  • app/ - Next.js App Router pages
    • [locale]/ - Internationalized routes
  • src/
    • components/ - React components
      • ui/ - Design system components
      • icons/ - SVG icon components
    • data/ - Static data and configurations
    • hooks/ - Custom React hooks
    • i18n/ - Internationalization config
    • intl/ - Translation files (25 languages)
    • layouts/ - Page layout components
    • lib/ - Utility functions and types
      • constants.ts - App constants
      • types.ts - TypeScript type definitions
      • utils/ - Utility functions
    • styles/ - Global styles and design tokens
  • public/ - Static assets
    • content/ - Markdown content files
    • images/ - Image assets
  • docs/ - Development documentation
    • solutions/ - Documented solutions to past problems, organized by category with YAML frontmatter (module, tags, problem_type)

Code Conventions

File Naming

  • Components: kebab-case (e.g., button-group.tsx)
  • Utilities: camelCase (e.g., cn.ts, relativePath.ts)
  • Pages: kebab-case following Next.js conventions
  • Assets: kebab-case (e.g., eth-logo.png)

TypeScript Patterns

  • Use interface for object shapes, type for unions/intersections
  • Prefer explicit typing over any (ESLint enforces fixToUnknown)
  • NEVER leave unused variables or parameters - ESLint unused-imports/no-unused-vars will fail the Netlify build. The only allowed unused arg pattern is a single underscore _. Do NOT use _prefixedNames (e.g., _foo) - either use the variable or remove it from the signature entirely.
  • Use generic constraints for reusable components
  • Export types from dedicated files in @/lib/types

Styling Conventions

  • Primary approach: Tailwind CSS utility classes
  • Component variants: Use tailwind-variants (tv) for new and refactored work. Existing class-variance-authority (cva) components don't need bulk migration -- swap to tv opportunistically when you're already touching the component for another reason.
  • Dynamic classes: Use cn() utility (clsx + tailwind-merge)
  • Custom properties: CSS variables in src/styles/ for theme values
  • Responsive design: Mobile-first approach

For UI work, see the design-system skill at .claude/skills/design-system/. It's the canonical knowledge base for component choices, design tokens, RTL/i18n, server/client boundaries, and the "use a variant, not a new component" pattern.

Development Workflows

Available Scripts

# Development
pnpm dev                    # Start development server (Turbopack)
pnpm dev:webpack            # Start development server with webpack
pnpm build                  # Build for production (Turbopack)
pnpm build:webpack          # Build for production with webpack
pnpm start                  # Start production server

# Code Quality
pnpm lint                   # Run ESLint
pnpm lint:fix              # Fix ESLint issues
pnpm type-check            # TypeScript type checking
pnpm format                # Format with Prettier

# Testing
pnpm test:unit             # Playwright unit tests (unit project)
pnpm test:e2e              # Playwright end-to-end tests
pnpm test:visual           # Playwright + Chromatic full-page visual tests

# Storybook
pnpm storybook             # Start Storybook dev server
pnpm build-storybook       # Build Storybook
pnpm chromatic             # Run Chromatic visual tests

# Content Management
pnpm lint:md               # Lint English markdown content
pnpm lint:md:fix           # Auto-fix header IDs and duplicates

Testing Strategy

  • Unit Testing: Playwright unit project (pnpm test:unit) — heaviest coverage is the intl-pipeline sanitizer
  • E2E Testing: Playwright (pnpm test:e2e), see docs/e2e-testing.md
  • Visual Testing: Storybook + Chromatic for component regression; Playwright + Chromatic for full pages (see the page-visual-tests skill)
  • Type Safety: TypeScript strict mode enabled
  • Linting: ESLint with custom rules for imports and TypeScript

Content Management

Internationalization

  • 25 languages supported (canonical list: i18n.config.json); RTL support for Arabic, Urdu
  • JSON UI strings in src/intl/[locale]/; translated markdown content in public/content/translations/[locale]/
  • Non-English markdown is propagated by the intl-pipeline (src/scripts/intl-pipeline/, entry main.ts). Do not hand-propagate English changes into non-English files -- let the pipeline run, or trigger intl-pipeline.yml with stamp_only: true if manifests must catch up urgently (e.g. unblocking a build). Hand-fixing a translation error is fine when the English side hasn't moved, since the manifest mapping stays valid. Spec: tests/specs/PIPELINE-SPEC.md.
  • Glossary: base URL from GLOSSARY_API_URL env var; default in src/scripts/intl-pipeline/config.ts. ETHGlossary is authoritative for Ethereum term translations.

For pipeline mechanics, recovery, manifests, ETHGlossary integration, and the intl/pending-{base} orchestration model, see the intl-pipeline skill at .claude/skills/intl-pipeline/. For translation-quality review (scoring rubric, language-group rules, ETHGlossary-as-authority policy, multi-agent role split), see the intl-review skill at .claude/skills/intl-review/.

Markdown Content

  • Educational content stored in public/content/
  • Processed with next-mdx-remote
  • Custom MDX components for rich content
  • Automatic table of contents generation
  • All h1-h4 headings require a custom {#lower-kebab-id} -- enforced by markdownlint via pre-commit hook. Run pnpm lint:md:fix to auto-add missing IDs. Config: .markdownlint-cli2.jsonc, custom rules: .markdownlint-rules/

Asset Management

  • Images optimized with Next.js Image component
  • SVGs loaded as React components via @svgr/webpack
  • Static assets served from public/
  • Placeholder generation for images

SEO & Meta

  • Sitemap generation in app/sitemap.ts
  • Meta tags and Open Graph optimization
  • Structured data for search engines
  • Security headers (X-Frame-Options: DENY)

Development Guidelines

When Working on Features

  1. Check existing patterns - Look at similar components first
  2. Prioritize Server Components - Use App Router and Server Components when possible
  3. Follow import order - ESLint will enforce, but be proactive
  4. Use TypeScript strictly - No any types, prefer unknown
  5. Test in Storybook - Create stories for new components (filename pattern: .stories.tsx)
  6. Consider i18n - All user-facing text should be translatable. Server components: getTranslations and getLocale from next-intl/server. Client components: useTranslations from next-intl, one namespace-bound function per namespace - to access a second namespace, bind another function (e.g. const tCommon = useTranslations("common")) rather than reaching across namespaces. The legacy @/hooks/useTranslation wrapper (namespace:key syntax) is deprecated for new code
  7. Mobile-first - Design for mobile, enhance for desktop
  8. Accessibility - Use Radix primitives, semantic HTML
  9. Use locale-aware formatting wrappers - Use numberFormat() from src/lib/utils/numbers.ts instead of new Intl.NumberFormat(), and dateTimeFormat() from src/lib/utils/date.ts instead of new Intl.DateTimeFormat() / .toLocaleDateString() / .toLocaleTimeString(). Both enforce correct numbering systems and calendar for Urdu and Arabic locales.

Component Development

  1. Create component in appropriate src/components/ subdirectory
    • Use src/components/ui for shadcn components or pure UI components
  2. Add TypeScript types and proper props interface
  3. Accept ref as a regular prop when needed (React 19); forwardRef only survives in legacy components
  4. Add Storybook story in same directory
  5. Export from appropriate index file
  6. Update documentation if adding new patterns

Content Updates

  1. Markdown files go in public/content/
  2. Images in public/images/ with descriptive names
  3. Translation strings in appropriate src/intl/ JSON files
  4. Data files in src/data/ with TypeScript types

Type-Safe Chain Names

This project enforces type-safe chain names via TypeScript. When working with layer 2 networks or wallet data:

Critical Files:

  • src/data/chains.ts - Canonical source of all chain names (auto-updated weekly)
  • src/lib/types.ts - Defines ChainName type derived from chains.ts
  • src/data/networks/networks.ts - Uses chainName: ChainName
  • src/data/wallets/wallet-data.ts - Uses supported_chains: ChainName[]

Rules:

  1. Always look up exact names - Before adding chainName or supported_chains, search chains.ts for the exact name value
  2. Names are case-sensitive and exact - e.g., use "Zircuit Mainnet" not "Zircuit", use "OP Mainnet" not "Optimism"
  3. Run type checking - Use pnpm type-check to verify chain names are valid before committing
  4. Non-EVM chains - For Starknet and other non-EVM chains, use NonEVMChainName type

Common Mistakes:

  • Using informal names: "Optimism" should be "OP Mainnet"
  • Missing "Mainnet" suffix: "Zircuit" should be "Zircuit Mainnet"
  • Wrong casing: "zksync Mainnet" should be "zkSync Mainnet"

Key Dependencies to Know

UI & Styling

  • @radix-ui/* - Accessible component primitives
  • tailwind-variants - Component variant patterns
  • motion - Animation library (formerly framer-motion; import from motion/react)
  • lucide-react - Icon library

Content & Data

  • gray-matter - Frontmatter parsing
  • recharts - Data visualization

Ethereum Integration

  • viem - Ethereum library
  • wagmi - React hooks for Ethereum
  • @rainbow-me/rainbowkit - Wallet connection

A/B Testing

The site uses a GDPR-compliant, cookie-less A/B testing system built on the Flags SDK precompute pattern, integrated with Matomo. The proxy assigns variants at the edge (header fingerprinting) and rewrites to signed, statically prerendered variant pages under ab-code/[code]/ — experiments never force dynamic rendering. Experiment status, weights, and scheduling live in the Matomo dashboard (no deploys needed). Only the default locale is tested; other locales always get the original.

Key gotcha: variants are matched by array index, not names — the variants array order must match the Matomo experiment order exactly, and the testKey must match the Matomo experiment name exactly.

Full guide (architecture, step-by-step recipe, env vars): docs/ab-testing.md. Code: proxy.ts, src/lib/ab-testing/, src/components/AB/, app/[locale]/ab-code/.

Deployment

  • Platform: Netlify (config in netlify.toml)
  • Next.js Integration: Uses @netlify/plugin-nextjs for seamless Netlify and Next.js compatibility
  • Monitoring: Matomo analytics integration

Internal Infrastructure

The following external-looking services are managed by the ethereum.org team:

  • s3-dcl1.ethquokkaops.io — S3-compatible object storage for app screenshots and media. Used by the data layer to serve images for the /dapps and app listing pages. Downtime here means broken images on the live site.
  • Netlify Blobs (@netlify/blobs) — Key-value store used by the data layer to cache API responses. Accessed via src/data-layer/storage.ts.