Frontend change conventions for apps/web — i18n (bilingual keys), dark mode (the highest-frequency rework source), theming inline SVG/chart colors, loading/empty/error states. Use for any UI change.
73
90%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
next-intl, locales zh (default) and en. Message files: apps/web/messages/{zh,en}.json — a key added to one file MUST be added to the other in the same commit.useTranslations('namespace'). Never hardcode user-facing strings — including chart tooltips, title attributes, and aria-labels (historically the most-missed spots).formatDuration style) must not embed English words; return structured data and translate in the component.This is the project's highest-frequency rework source. Rules:
bg-*-50/100, text-*-500/600, border-*-200 needs a dark: counterpart. Grep your diff for bg-white|bg-.*-50|text-gray- before committing.bg-background, bg-popover, text-muted-foreground, border-border (defined in app/globals.css for both themes).resolvedTheme:const { resolvedTheme } = useTheme(); // next-themes
const palette = resolvedTheme === "dark" ? DARK_COLORS : LIGHT_COLORS;Precedents: components/features/countries/world-traffic-map.tsx (MAP_THEME), components/features/rules/rule-chain-flow.tsx. Recharts axis ticks should use fill: "currentColor" or CSS variables, not hex grays.
app/[locale]/dashboard/components/header/index.tsx) rather than writing light-only classes.Every data view needs loading (skeleton), empty, and error states. Error must be visible and actionable (retry button) — return null on error is a known anti-pattern here (see the chain-flow retry card in rule-chain-flow.tsx for the reference implementation). Route-level failures are caught by app/[locale]/error.tsx / app/global-error.tsx; heavy visualizations should still fail locally, not blank the page.
lib/stats-query-keys.ts — never inline ad-hoc keys.lib/websocket.ts) tags pushes with backendId and the hook drops mismatched messages — preserve this when touching the message path (prevents cross-backend cache bleed on backend switch).memo comparators must compare every prop the component renders from (a missed prop froze the Active Policy whitelist once — include new props in the comparator when you add them).new-york) + Tailwind v4 + lucide-react. Base primitives in components/ui/ — reuse before creating; use the Radix Dialog for modals (no hand-rolled fixed overlays — they lose Esc/focus-trap behavior).6f72cfd
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.