|
1 | 1 | Note: CLAUDE.md is a symlink to this file. Edit AGENTS.md directly. |
2 | 2 |
|
3 | | -styled-components documentation website. Next.js 16 App Router, MDX content, styled-components v6. |
| 3 | +styled-components documentation website. Next.js, MDX, styled-components. |
4 | 4 |
|
5 | | -## Principles |
| 5 | +## Read first |
6 | 6 |
|
7 | | -1. Verify before building -- Read the file before editing it. Read the nav config before adding pages. Read the live code scope before using hooks. Assumptions cause build failures. |
| 7 | +Before editing anything that touches styled-components APIs (`createTheme`, `ThemeProvider`, `createGlobalStyle`, `ServerStyleSheet`, `StyleSheetManager`, `stylisPluginRSC`), read `public/llms.txt`. It's the battle-tested v6.4 usage guide with real gotchas: `ThemeProvider` must receive the raw theme object (not the `createTheme` output — passing the output produces self-referential `var(--x, fallback)` CSS), `theme.vars` gives bare custom property names for dark mode overrides, `@property` registration is required for animatable tokens, etc. Trust `llms.txt` over training-data assumptions. |
8 | 8 |
|
9 | | -2. Wire completely -- Adding a docs page requires three changes in one commit: the MDX file, the page component import/render, and the `app/docs.json` nav entry. Missing any one breaks navigation or leaves orphaned content. |
| 9 | +## Principles |
10 | 10 |
|
11 | | -3. Snapshot tests are fragile by design -- They capture rendered CSS including generated class hashes. Any change to styled-components version, font constants, or style values will break snapshots. Run `npx jest -c .jest.config.js --updateSnapshot` and commit the result. |
| 11 | +1. Verify before building -- read the file before editing. Assumptions cause build failures. |
| 12 | +2. Wire completely -- new docs pages need the MDX file, the page component, and a `docs.json` entry. |
| 13 | +3. The SSR registry (`lib/registry.tsx`) is load-bearing. Removing it causes FOUC. |
| 14 | +4. Live code blocks (` ```react `) run in a scoped editor. Hooks must be `React.useState()`, no imports. |
| 15 | +5. Isolate `'use client'` as deeply as possible. The homepage is a server component with client islands. |
12 | 16 |
|
13 | | -4. The SSR registry is load-bearing -- `lib/registry.tsx` wraps the root layout. It looks like a v6.3.0+ RSC artifact that can be removed, but most components use `'use client'`. Removing it causes FOUC. Do not remove without migrating components to server components first. |
| 17 | +## Commands |
14 | 18 |
|
15 | | -5. Live code blocks are not regular code blocks -- Examples using ` ```react ` run in the site's live editor with `React`, `styled`, `css`, `keyframes`, `ThemeProvider`, `createGlobalStyle`, and `render()` in scope. Hooks must be qualified: `React.useRef()`, `React.useState()`. Imports are not supported. |
| 19 | +- `pnpm install` — install |
| 20 | +- `npx next build` — do NOT run while the dev server is active |
| 21 | +- `npx jest -c .jest.config.js` — tests |
16 | 22 |
|
17 | | -## Commands |
| 23 | +## Architecture |
| 24 | + |
| 25 | +**Tokens:** `createTheme` API from `utils/theme.ts` is the single source of truth. Generates `var(--sc-*)` CSS custom properties. Dark mode overrides in `GlobalStyles.tsx` target `--sc-*` vars under `html.dark` and `@media (prefers-color-scheme: dark)`. Font vars (`--font-sans`, `--font-display`, `--font-mono`) are managed by next/font, not the theme. Display font is Figtree; body font is Inter; mono font is Google Sans Code. |
18 | 26 |
|
19 | | -- `yarn` -- install (Yarn PnP, no package-lock.json) |
20 | | -- `npx next build` -- build and verify all pages (static generation) |
21 | | -- `npx jest -c .jest.config.js` -- run tests |
22 | | -- `npx jest -c .jest.config.js --updateSnapshot` -- update snapshots after style changes |
23 | | -- Pre-commit hooks run jest on related files + prettier via lint-staged |
| 27 | +**Theme:** Three states (light/dark/auto). Raw `<script>` in `<head>` before stylesheets sets the class — not `next/script`. `data-theme="dark"` synced for DocSearch. Toggle icon shows current mode. |
24 | 28 |
|
25 | | -## Documentation Structure |
| 29 | +**Navigation:** Sidebar lives in `ClientLayout` (root layout) — persists across navigations via `SidebarFoldProvider` context. Search (DocSearch, module-level singleton) at top, then Home, Agents, Documentation (expands to categories → sections with scroll-spy), Blog, Ecosystem, Releases, Donate. Navbar is just logo + social + theme toggle. Mobile: hamburger for sidebar, theme toggle far-right. `Link` component uses `next/link` for all internal routes; callers pass `variant="inline" | "heading" | "block" | "unstyled"` (the legacy `inline`/`unstyled` boolean props were removed). |
26 | 30 |
|
27 | | -- MDX content: `sections/{category}/{topic}.mdx` |
28 | | -- Page components: `app/docs/{category}/page.tsx` (import MDX, render in order) |
29 | | -- Nav config: `app/docs.json` (section titles must exactly match `##` headings in MDX for anchor generation) |
30 | | -- `##` = top-level section heading, `###` = subsection |
31 | | -- Path alias `@/` maps to project root |
| 31 | +**Homepage:** Two-column hero (copy left, live editor right) inside `LiveProvider`. Transparent background. Proof badges above CTA buttons. 10-year celebration effect (CSS bloom fireworks, respects reduced-motion). Company logos adapt via `brightness(0)` / `invert(1)`. |
32 | 32 |
|
33 | | -## Key Files |
| 33 | +**Docs:** MDX in `sections/`, pages in `app/docs/`, nav config in `docs.json`. Heading IDs on the element itself with `scroll-margin-top`. Scroll-spy is a rAF-throttled scroll listener in the sidebar. |
34 | 34 |
|
35 | | -- `app/layout.tsx` -- root layout with next/font (Karla + JetBrains Mono via CSS vars `--font-body`, `--font-mono`) |
36 | | -- `lib/registry.tsx` -- SSR style collection for client components (ServerStyleSheet + useServerInsertedHTML) |
37 | | -- `utils/fonts.ts` -- font-family constants referencing CSS variables |
38 | | -- `components/Anchor.tsx` -- section heading with anchor link, used by all doc pages |
39 | | -- `components/ReleaseAnchor.tsx` -- release page heading with date pseudo-element |
40 | | -- `app/releases/page.tsx` -- fetches GitHub API releases, renders with markdown-to-jsx |
41 | | -- `utils/scope.ts` -- defines the scope (available globals) for live code editor blocks |
| 35 | +**Z-index:** 10 (celebration/code), 20 (content/hero), 30 (sidebar), 40 (navbar). |
42 | 36 |
|
43 | 37 | ## Gotchas |
44 | 38 |
|
45 | | -- `app/docs.json` titles are converted to URL hashes via `titleToDash`. Mismatched titles = broken sidebar links. |
46 | | -- The releases page uses `markdown-to-jsx` (not MDX). Compatibility issues with React 19 dev mode are tracked upstream. |
47 | | -- `next.config.mjs` has `compiler: { styledComponents: true }` for SWC transform. This is separate from RSC support. |
48 | | -- Font changes require updating `utils/fonts.ts`, `app/layout.tsx` (next/font config), and all test snapshots. |
| 39 | +- `docs.json` titles become URL hashes via `titleToDash`. Mismatches break sidebar links. |
| 40 | +- Live editor `scope.ts` derives component IDs from tag/component names. Counters cause hydration mismatches. |
| 41 | +- Logo is a CSS 3D Platonic solid (`components/LogoConcepts/PlatonicLogo.tsx`). Cycles through 5 solids with chain-matched face transitions, OKLCH spatial coloring, and hover face-highlight effect. |
| 42 | +- Nav/sidebar widths use `sidebarWidth` from `utils/sizes.ts` in plain px — don't use `rem()` for these. |
| 43 | +- Borders use opaque `color-mix(in oklch, text 8%, surface)`, not alpha. |
| 44 | +- `utils/rem.ts` uses legacy 18px base. Prefer token spacing vars. |
| 45 | +- Releases page uses `markdown-to-jsx`, not MDX. |
| 46 | +- `${ClientComponent} &` selector interpolation in a styled template calls the referenced component's `.toString()`, which trips RSC's client-reference guard from a server module. Any styled component using this pattern must stay `'use client'`. Currently applies to `CodeBlock.tsx` (uses `${Note} &`). |
| 47 | +- Import code mixins (`codeTextMixin`, `editorMixin`) from `components/codeMixins.ts`, not from `LiveEdit`. Importing from `LiveEdit` pulls `react-live-runner` + `sucrase` into the client bundle of every consumer. |
| 48 | +- `utils/logoPalette.ts` is the single source of `LOGO_LUM`, `LOGO_CHROMA`, `logoHueRing()`. `PlatonicLogo.tsx` and `CelebrationEffect.tsx` import from it; don't duplicate the constants at call sites. |
| 49 | +- `PlatonicLogo.tsx` faces must NOT use `backface-visibility: hidden`. Per-face axis-angle interpolation during morph transitions can briefly flip a face normal and cull mid-animation. `transform-style: preserve-3d` z-sorts back faces naturally. |
| 50 | +- `CelebrationEffect.tsx` particles are `React.memo`'d; `onAnimationEnd` is a stable `useCallback` that reads `fwId`/`particleId` from `data-*` attributes. Don't close over IDs in per-item arrow functions — it defeats memoization on the particle list. |
0 commit comments