Files
portfolio/.claude/rules/components.md
denshooter 7f9d39c275
All checks were successful
CI / CD / test-build (push) Successful in 10m59s
CI / CD / deploy-dev (push) Successful in 1m54s
CI / CD / deploy-production (push) Has been skipped
perf: eliminate Three.js/WebGL, fix render-blocking CSS, add dev team agents
- Replace ShaderGradientBackground WebGL shader (3 static spheres) with pure
  CSS radial-gradient divs — moves from ClientProviders (deferred JS) to
  app/layout.tsx as a server component rendered in initial HTML. Eliminates
  @shadergradient/react, three, @react-three/fiber from the JS bundle.
  Removes chunks/7001 (~20s CPU eval) and the 39s main thread block.

- Remove optimizeCss/critters: it was converting <link rel="stylesheet"> to a
  JS-deferred preload, which PageSpeed read as a 410ms sequential CSS chain.
  Both CSS files now load as parallel <link> tags from initial HTML (~150ms).

- Update browserslist safari >= 15 → 15.4 (Array.prototype.at, Object.hasOwn
  are native in 15.4+; eliminates unnecessary SWC compatibility transforms).

- Delete orphaned app/styles/ghostContent.css (never imported anywhere, 3.7KB).

- Add .claude/ dev team setup: 5 subagents (frontend-dev, backend-dev, tester,
  code-reviewer, debugger), 3 skills (/add-section, /review-changes,
  /check-quality), 3 path-scoped rules, settings.json with auto-lint hook.

- Update CLAUDE.md with server/client orchestrator pattern, SSR animation
  safety rules, API route conventions, and improved command reference.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-05 23:40:01 +01:00

38 lines
1.3 KiB
Markdown

---
paths:
- "app/components/**/*.tsx"
- "app/_ui/**/*.tsx"
---
# Component Rules
## SSR animation safety (critical)
**Never** use `initial={{ opacity: 0 }}` on server-rendered elements.
This bakes `style="opacity:0"` into HTML — content is invisible if hydration fails.
Use `ScrollFadeIn` instead:
```tsx
import ScrollFadeIn from "@/app/components/ScrollFadeIn"
<ScrollFadeIn><MyComponent /></ScrollFadeIn>
```
`AnimatePresence` is fine for modals and overlays that only appear after user interaction.
## Design system
- Colors: only `liquid-*` tokens — no hardcoded hex or raw Tailwind palette colors
- Cards: `bg-gradient-to-br from-liquid-*/15 via-liquid-*/10 to-liquid-*/15 backdrop-blur-sm border-2 rounded-xl`
- Headlines: `uppercase tracking-tighter` with accent dot `<span className="text-emerald-600">.</span>`
- Body text: `text-stone-600 dark:text-stone-400` — never `text-stone-400` alone (fails contrast)
## Async components
Every component that fetches data must have a Skeleton loading state shown while data loads.
## i18n
- Client: `useTranslations("namespace")` from `next-intl`
- Server: `getTranslations("namespace")` from `next-intl/server`
- New client sections need a wrapper in `ClientWrappers.tsx` with scoped `NextIntlClientProvider`
## TypeScript
- No `any` — define interfaces in `lib/directus.ts` or `types/`
- No emojis in code