From 9cbcfb227fc003da15003ca7dbcc5703d1e9f94f Mon Sep 17 00:00:00 2001 From: Imran Jami Date: Wed, 13 Aug 2025 17:10:54 -0700 Subject: [PATCH 1/8] header update --- CLAUDE.md | 126 ++++++++++++++++++++++++++++++ components/CustomHeader/index.tsx | 105 +++++++++++++++++++++++++ package.json | 1 + pnpm-lock.yaml | 30 ++++--- theme.config.tsx | 30 +------ 5 files changed, 257 insertions(+), 35 deletions(-) create mode 100644 CLAUDE.md create mode 100644 components/CustomHeader/index.tsx diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..429e43e56 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,126 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Repository Overview +This is the Optimism Documentation website repository that powers docs.optimism.io - the official technical documentation for the Optimism Collective, covering the OP Stack, Superchain, and interoperability features. + +## Tech Stack +- **Framework**: Next.js 14.2.21 with React 18.2.0 +- **Documentation Engine**: Nextra 2.13.2 (docs theme) +- **Language**: TypeScript +- **Package Manager**: pnpm (required - do not use npm or yarn) +- **Content Format**: MDX (Markdown with React components) +- **Deployment**: Netlify + +## Essential Commands + +### Development +```bash +pnpm dev # Start development server at localhost:3001 +pnpm build # Create production build +``` + +### Quality Checks (Run before committing) +```bash +pnpm lint # Run all linting (ESLint + spellcheck + breadcrumbs + redirects + metadata) +pnpm fix # Auto-fix all fixable issues (runs on pre-push automatically) +``` + +### Individual Linting Commands +```bash +pnpm spellcheck:lint # Check spelling +pnpm spellcheck:fix # Add words to dictionary (words.txt) +pnpm lint:eslint # Run ESLint +pnpm lint:breadcrumbs # Validate breadcrumb structure +pnpm lint:redirects # Check redirect configuration +pnpm lint:metadata # Validate page metadata +``` + +## Architecture & Structure + +### Content Organization +``` +pages/ # All documentation content (MDX files) +├── app-developers/ # Application developer guides +├── operators/ # Node & chain operator documentation +├── stack/ # OP Stack protocol documentation +├── superchain/ # Superchain network documentation +├── interop/ # Interoperability documentation +└── connect/ # Contributing guides and resources +``` + +### Key Directories +- `components/`: Reusable React components for documentation +- `public/`: Static assets, images, and tutorial files +- `utils/`: Utility scripts for linting, validation, and build processes +- `providers/`: React context providers for global state + +## Important Patterns + +### MDX Page Structure +All documentation pages use MDX format with frontmatter metadata: +```mdx +--- +title: Page Title +lang: en-US +description: Page description for SEO +--- + +import { ComponentName } from '@/components/ComponentName' + +# Content here... +``` + +### Component Imports +Use the configured path alias for component imports: +```typescript +import { ComponentName } from '@/components/ComponentName' +``` + +### Adding New Documentation +1. Create MDX file in appropriate `pages/` subdirectory +2. Include required frontmatter (title, lang, description) +3. Run `pnpm lint` to validate metadata and content +4. Use existing components from `components/` directory when possible + +### Spell Checking +- Custom dictionary maintained in `words.txt` +- Add technical terms using `pnpm spellcheck:fix` +- Spell checking runs automatically in the lint pipeline + +## Git Workflow +- **Pre-push hook**: Automatically runs `pnpm fix` via Husky +- **Auto-commit**: Fixes are automatically committed if changes are made +- **No pre-commit hooks**: Only validation on push + +## Special Features +- **Kapa.ai Widget**: AI assistant integrated for documentation queries +- **Algolia Search**: Full-text search across documentation +- **Feelback**: User feedback collection system +- **Growth Book**: A/B testing framework for feature experiments + +## Common Tasks + +### Adding a New Page +1. Create `.mdx` file in appropriate `pages/` directory +2. Add frontmatter with title, lang, and description +3. Write content using Markdown and import React components as needed +4. Run `pnpm dev` to preview +5. Run `pnpm lint` before committing + +### Updating Components +- Components are in `components/` directory +- Follow existing patterns and TypeScript types +- Test component changes across multiple pages that use them + +### Working with Images +- Place images in `public/img/` directory +- Reference using `/img/filename.ext` in MDX files +- Optimize images before adding to repository + +## Notes +- The repository uses automated quality checks - always run `pnpm lint` before pushing +- Netlify handles deployment automatically on merge to main +- TypeScript is configured with relaxed strict mode - follow existing patterns +- MDX allows mixing Markdown with React components - leverage this for interactive content \ No newline at end of file diff --git a/components/CustomHeader/index.tsx b/components/CustomHeader/index.tsx new file mode 100644 index 000000000..5c823bea2 --- /dev/null +++ b/components/CustomHeader/index.tsx @@ -0,0 +1,105 @@ +import React, { useState, useEffect } from 'react'; +import Link from 'next/link'; +import { useRouter } from 'next/router'; +import { Search } from '../Search'; +import { AskAIButton } from '../AskAIButton'; +import { useTheme } from 'nextra-theme-docs'; +import { MoonIcon, SunIcon } from '@heroicons/react/24/outline'; + +const CustomHeader = () => { + const router = useRouter(); + const { theme, setTheme } = useTheme(); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + const navItems = [ + { title: 'Get started', href: '/get-started' }, + { title: 'Superchain', href: '/superchain' }, + { title: 'Interoperability', href: '/interop' }, + { title: 'App Devs', href: '/app-developers' }, + { title: 'Operators', href: '/operators' }, + { title: 'OP Stack', href: '/stack' }, + ]; + + const isActive = (href: string) => { + return router.pathname.startsWith(href); + }; + + if (!mounted) return null; + + return ( +
+ {/* Top Section: Logo, Search, Ask AI */} +
+ {/* Logo */} + + + + + + + + {/* Search Bar - centered */} +
+ +
+ + {/* Right side: Ask AI + Theme Toggle */} +
+ + +
+
+ + {/* Bottom Section: Navigation Links */} + +
+ ); +}; + +export default CustomHeader; \ No newline at end of file diff --git a/package.json b/package.json index 97163bd87..9ad08ac64 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@feelback/react": "^0.3.4", "@growthbook/growthbook-react": "^1.3.1", "@headlessui/react": "^2.1.8", + "@heroicons/react": "^2.2.0", "@remixicon/react": "^4.6.0", "algoliasearch": "^4.23.3", "clsx": "^2.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1af8e1d27..b4184220d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,6 +34,9 @@ importers: '@headlessui/react': specifier: ^2.1.8 version: 2.1.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@heroicons/react': + specifier: ^2.2.0 + version: 2.2.0(react@18.2.0) '@remixicon/react': specifier: ^4.6.0 version: 4.6.0(react@18.2.0) @@ -63,10 +66,10 @@ importers: version: 4.2.3(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0)) nextra: specifier: 2.13.2 - version: 2.13.2(patch_hash=a4rp2hgojklggjmthmkiyqaek4)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 2.13.2(patch_hash=81936321c37741ec218dc19817c4a4939f4655b8371e793561fc236bebccc249)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) nextra-theme-docs: specifier: 2.13.2 - version: 2.13.2(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(nextra@2.13.2(patch_hash=a4rp2hgojklggjmthmkiyqaek4)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 2.13.2(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(nextra@2.13.2(patch_hash=81936321c37741ec218dc19817c4a4939f4655b8371e793561fc236bebccc249)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: specifier: ^18.2.0 version: 18.2.0 @@ -130,7 +133,7 @@ importers: version: 15.0.1 remark-code-import: specifier: ^1.2.0 - version: 1.2.0(patch_hash=heylvfasxh3ubj2edns2svea2m) + version: 1.2.0(patch_hash=f6b78667b2fd0da0247b6e898a35f71bfde2a83adfa62fa6017a02dc7fb5d436) remark-frontmatter: specifier: ^5.0.0 version: 5.0.0 @@ -139,7 +142,7 @@ importers: version: 3.0.1 remark-lint-frontmatter-schema: specifier: ^3.15.4 - version: 3.15.4(patch_hash=jaxvkozlhcbn7zjsiti5ocoubi) + version: 3.15.4(patch_hash=32c1574b8fd989888047ea0226d42029f451eb7c875349c28b6259a73cc7e59f) remark-lint-heading-style: specifier: ^3.1.2 version: 3.1.2 @@ -653,6 +656,11 @@ packages: react: ^18 react-dom: ^18 + '@heroicons/react@2.2.0': + resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==} + peerDependencies: + react: '>= 16 || ^19.0.0-rc' + '@humanwhocodes/config-array@0.11.13': resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} @@ -4718,6 +4726,10 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + '@heroicons/react@2.2.0(react@18.2.0)': + dependencies: + react: 18.2.0 + '@humanwhocodes/config-array@0.11.13': dependencies: '@humanwhocodes/object-schema': 2.0.1 @@ -7617,7 +7629,7 @@ snapshots: - '@babel/core' - babel-plugin-macros - nextra-theme-docs@2.13.2(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(nextra@2.13.2(patch_hash=a4rp2hgojklggjmthmkiyqaek4)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + nextra-theme-docs@2.13.2(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(nextra@2.13.2(patch_hash=81936321c37741ec218dc19817c4a4939f4655b8371e793561fc236bebccc249)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@headlessui/react': 1.7.17(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@popperjs/core': 2.11.8 @@ -7631,13 +7643,13 @@ snapshots: next: 14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0) next-seo: 6.4.0(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) next-themes: 0.2.1(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - nextra: 2.13.2(patch_hash=a4rp2hgojklggjmthmkiyqaek4)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + nextra: 2.13.2(patch_hash=81936321c37741ec218dc19817c4a4939f4655b8371e793561fc236bebccc249)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) scroll-into-view-if-needed: 3.1.0 zod: 3.22.4 - nextra@2.13.2(patch_hash=a4rp2hgojklggjmthmkiyqaek4)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + nextra@2.13.2(patch_hash=81936321c37741ec218dc19817c4a4939f4655b8371e793561fc236bebccc249)(next@14.2.21(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@headlessui/react': 1.7.17(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@mdx-js/mdx': 2.3.0 @@ -7959,7 +7971,7 @@ snapshots: hast-util-raw: 9.0.1 vfile: 6.0.1 - remark-code-import@1.2.0(patch_hash=heylvfasxh3ubj2edns2svea2m): + remark-code-import@1.2.0(patch_hash=f6b78667b2fd0da0247b6e898a35f71bfde2a83adfa62fa6017a02dc7fb5d436): dependencies: strip-indent: 4.0.0 to-gatsby-remark-plugin: 0.1.0 @@ -8032,7 +8044,7 @@ snapshots: unified: 10.1.2 unified-lint-rule: 2.1.2 - remark-lint-frontmatter-schema@3.15.4(patch_hash=jaxvkozlhcbn7zjsiti5ocoubi): + remark-lint-frontmatter-schema@3.15.4(patch_hash=32c1574b8fd989888047ea0226d42029f451eb7c875349c28b6259a73cc7e59f): dependencies: '@apidevtools/json-schema-ref-parser': 11.1.0 ajv: 8.12.0 diff --git a/theme.config.tsx b/theme.config.tsx index 143030bac..a3798144e 100644 --- a/theme.config.tsx +++ b/theme.config.tsx @@ -9,29 +9,13 @@ import '@feelback/react/styles/feelback.css'; import { Search } from './components/Search'; import { Footer } from './components/Footer'; import { AskAIButton } from './components/AskAIButton'; +import CustomHeader from './components/CustomHeader'; import { useFeature } from '@growthbook/growthbook-react'; const config: DocsThemeConfig = { - logo: ( - <> - - - - - - ), + navbar: { + component: CustomHeader + }, darkMode: true, // banner: { // key: 'viem/op-stack', @@ -42,12 +26,6 @@ const config: DocsThemeConfig = { // // ) // }, - search: { - component: Search - }, - navbar: { - extraContent: AskAIButton - }, docsRepositoryBase: 'https://github.com/ethereum-optimism/docs/blob/main/', footer: { text: