new-ui-surface

GitHub

指导构建符合Matchday设计语言的前端组件,强调复用现有UI原语、严格遵循设计Token规范及无障碍访问标准,并包含自动化测试要求。

.claude/skills/new-ui-surface/SKILL.md openfootmanager/openfootmanager

触发场景

需要创建新的前端界面元素 开发符合特定设计规范的UI组件

安装

npx skills add openfootmanager/openfootmanager --skill new-ui-surface -g -y
更多选项

非标准路径

npx skills add https://github.com/openfootmanager/openfootmanager/tree/develop/.claude/skills/new-ui-surface -g -y

不安装直接使用

npx skills use openfootmanager/openfootmanager@new-ui-surface

指定 Agent (Claude Code)

npx skills add openfootmanager/openfootmanager --skill new-ui-surface -a claude-code -g -y

安装 repo 全部 skill

npx skills add openfootmanager/openfootmanager --all -g -y

预览 repo 内 skill

npx skills add openfootmanager/openfootmanager --list

SKILL.md

Frontmatter
{
    "name": "new-ui-surface",
    "description": "Build a new frontend component, panel, dashboard tab, or screen that matches the Matchday design language, works in light and dark, is keyboard and screen-reader accessible, reuses existing primitives, and ships with a Testing Library test.",
    "when_to_use": "Creating any new React component, adding a dashboard tab, building a modal or panel, redesigning an existing screen, or when a UI change needs to look and behave like the rest of the app.",
    "allowed-tools": "Read, Edit, Write, Grep, Glob, Bash(npx vitest run src\/components*), Bash(npx tsc --noEmit)",
    "argument-hint": "[what you are building]"
}

Building a new UI surface

The app has one visual voice — "Matchday", a broadcast-graphics look. New surfaces should be indistinguishable from existing ones. Reuse first, then compose, then style.

1. Reuse before you build

Read src/components/ui/index.ts before writing markup. It already exports:

Card / CardHeader / CardBody · Button · Badge · ProgressBar · Select · Checkbox · DatePicker · CountryFlag · TeamLocation · PlayerAvatar · TeamLogo · InjuryBadge · JerseyIcon · ThemeToggle · PitchToken · AssetImage · GeneratedAvatar · GeneratedCrest · CountryCombobox

Also check before writing a helper:

  • src/lib/ — formatting and domain helpers (finance.ts, playerSquad.ts, playerRoles.ts, countries.ts, dateFormatting.ts, seasonContext.ts, playerOvr.ts, …)
  • src/hooks/useAdvanceTime, useFetchedSquad, useUndoRedo, useAssetDataUrl, …
  • src/services/ — every backend call. Components never call invoke() directly.

A new component belongs in src/components/ui/ only if a second feature will use it. Otherwise put it in the feature folder (src/components/squad/, src/components/transfers/, …).

2. Design tokens

Colours and fonts come from the @theme block in src/App.css. Nothing else defines them.

Use Token
Primary action, positive state primary-500…900 (emerald)
Highlight, award, emphasis accent-400 (#ffd60a gold), accent-500…900
Success success-400/500/600
Dark surfaces navy-900 (deepest) → navy-800navy-700navy-600
Headings font-heading (Barlow Condensed), usually uppercase tracking-wider
Body font-sans (Inter)
  • Never a hex literal or an arbitrary value (bg-[#10b981]) in a component.
  • Every colour class needs its dark: partner. Light and dark both ship.
  • Light surfaces are white / gray-100; their dark counterparts are navy-800 / navy-900.

src/components/ui/Button.tsx is the reference for how variants, sizes, and states are composed — read it before inventing a new pattern.

3. Accessibility floor

Not optional, and cheap if done while writing rather than after.

  • Focus is visible. Every interactive element: focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-<token> plus dark:focus:ring-offset-navy-800. Removing an outline without replacing it is a bug.
  • Semantic elements. <button> for actions, <a> for navigation, <table> for tabular data, headings in order. A div with onClick is not keyboard reachable.
  • Icon-only controls get an accessible namearia-label={t("…")}, a translated string.
  • Modals trap focus, close on Escape, restore focus to the trigger, and are labelled (role="dialog" + aria-labelledby).
  • Lists and tables that sort or filter announce their state (aria-sort, aria-live for result counts).
  • Colour is never the only signal. Pair it with a label, icon, or shape — this matters for the form/condition/morale indicators especially.
  • Contrast holds in both themes. Gold on white and mid-emerald on navy are the usual failures.
  • Respect prefers-reduced-motion for anything that animates on its own.

4. Strings

Every visible string — and every aria-label, title, placeholder, and alt — is a translation key in all 11 locales. Use /add-ui-string; don't hand-roll it.

5. State

  • Zustand stores in src/store/. Never mutate store state from a component — copy, then set. (fix/hometab-store-mutation is the regression that made this a rule.)
  • Backend data flows through src/services/*Service.ts.
  • Derive, don't duplicate. If a value can be computed from the store, compute it.

6. Test it

Co-locate Foo.test.tsx next to Foo.tsx. Write it first.

// Query by role and accessible name. If this line fails, the component
// is not accessible — the test is doing double duty.
const save = screen.getByRole("button", { name: /save/i });
  • Query by role/label, never by class or test id.
  • Pure logic goes in a *.helpers.ts file and gets unit-tested directly — src/components/squad/SquadTab.helpers.ts is the pattern.
  • Cover the keyboard path, not just the click path, for anything interactive.
npx vitest run src/components/<area>
npx tsc --noEmit

7. Invariants, if you touch squad, tactics, or the pitch

  • XI slot alignment — starting-XI array entry i is formation slot i. Substitutions insert at the vacated index; never append or re-sort. Slot geometry comes from buildPitchRows(formation) in src/components/squad/SquadTab.helpers.ts, and PitchToken is the shared token component.
  • Deployed vs natural positionplayer.position is the natural position and is never mutated. Where a player is currently deployed comes from getDeployedPosition(team, slot). Role pickers and validators use the deployed slot; player descriptions use the natural position.

Checklist

  • Searched src/components/ui/index.ts, src/lib/, src/hooks/ before writing anything new
  • Token classes only — no hex literals, no arbitrary values
  • Every colour class has a dark: partner; checked in both themes
  • Visible focus ring on every interactive element
  • Semantic elements; icon-only controls have translated aria-labels
  • All strings routed through /add-ui-string (all 11 locales)
  • No store mutation from a component
  • Co-located test querying by role, written before the component
  • npx vitest run src/components/<area> and npx tsc --noEmit green

版本历史

  • 9d401d6 当前 2026-07-30 22:45

同 Skill 集合

.claude/skills/add-domain-field/SKILL.md
.claude/skills/add-mcp-tool/SKILL.md
.claude/skills/add-tauri-command/SKILL.md
.claude/skills/add-ui-string/SKILL.md
.claude/skills/preflight/SKILL.md

元信息

文件数
0
版本
29f5c11
Hash
919285f9
收录时间
2026-07-30 22:45

首页 - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-05 00:52
浙ICP备14020137号-1 $访客地图$