Agent Skills › wannabespace/tamery › tamery-ui

tamery-ui

GitHub

Tamery UI设计规范,规定macOS风格界面开发流程。涵盖颜色、排版、动效及交互模式,强制使用UI Kit组件,禁止硬编码样式,确保视觉一致性与可访问性。

.agents/skills/tamery-ui/SKILL.md wannabespace/tamery

Trigger Scenarios

构建或重构UI组件 审查前端代码样式规范 实现页面布局与动画效果

Install

npx skills add wannabespace/tamery --skill tamery-ui -g -y
More Options

Non-standard path

npx skills add https://github.com/wannabespace/tamery/tree/main/.agents/skills/tamery-ui -g -y

Use without installing

npx skills use wannabespace/tamery@tamery-ui

指定 Agent (Claude Code)

npx skills add wannabespace/tamery --skill tamery-ui -a claude-code -g -y

安装 repo 全部 skill

npx skills add wannabespace/tamery --all -g -y

预览 repo 内 skill

npx skills add wannabespace/tamery --list

SKILL.md

Frontmatter
{
    "name": "tamery-ui",
    "description": "Tamery's UI design system and hard rules — native macOS look, three-level color system, typography tokens, motion recipes, and the kit's known gotchas. Use whenever building, restyling, or reviewing any UI in this repo (components, pages, popovers, menus, animations), before writing the first className."
}

Tamery UI

Native-feeling macOS database client (Electron + React + Tailwind v4 + base-ui kit in packages/ui). Every screen reads like an Apple app, not a web page. Owner-established rules; hard rules are review blockers.

Topic files — read what the task touches; record new decisions in the matching file:

File When
colors.md Colors, surfaces, glass, shadows, cell highlights
typography.md Fonts, type scale, row heights, radius
patterns.md Chrome: menus, tabs, panes, tooltips, toasts, icons, filter field, forms, shortcuts
motion.md Any animation
gotchas.md Before debugging kit components

Hard rules

  1. Search the registry before writing markup. pnpm dlx shadcn@latest search @shadcn -q <term>. A div stack re-implementing a registry component (Item, Empty, InputGroup, Field, ButtonGroup, Attachment…) is a review blocker, including "just this once". Missing from packages/ui → vendor it (shadcn view @shadcn/<name>), rewrite imports to kit conventions, then use. Registry components carry the density, focus rings, hover states and data-slots the app relies on. Long-form text is never hand-parsed: prose via kit Response, fenced code via CodeBlock or ResponseCodeBlock.
  2. No dark: selectors. Theme tokens resolve in both themes; no new theme-pair vars. A token pair lacking contrast → cross-theme constructions in colors.md. Test: several call sites each dialing their own alpha on one token = the token is wrong.
  3. No pixel font sizes. Tokens only (text-2xs…text-base+); a missing size gets a rem token in @theme.
  4. No cursor-pointer. cursor-default on link-based controls; I-beam and col-resize are the only exceptions.
  5. Kit-level fixes in packages/ui for systemic sizing or color problems; page overrides only for page-specific design. Sizes via size props, never per-page h-*.
  6. No bare interactive icons. Hover bg + color shift + tooltip, always (patterns.md).
  7. No sidebar-* color tokens. Regular tokens everywhere.
  8. Global anchor rule: a { text-primary } in globals — row-styled Links must set text-foreground or render blue.
  9. data-mask on all user data. Any element rendering user values (connection names, hosts, connection strings, schema/table/column names, cell values, SQL, filter values) gets it so screen-recording tools can blur it. App chrome never. Put it on the closest element wrapping only the user value.
  10. Verify heights in a row. After touching any control sharing a line with others, measure every element's getBoundingClientRect().height in the browser — equal to the pixel. Classic traps: py-* plus fixed-height children exceeding min-h, borders without bg-clip-padding, hand-set h-* instead of size props.
  11. Refresh belongs to the tab bar, never to the page. TabRefresh owns refreshing the active tab: a refreshable tab type gets a branch there (invalidate its query keys, useRefreshHotkey, render the button) and its page ships no refresh control. A tab type that cannot refresh keeps the button mounted and disabled. Two buttons for one dataset read as two refreshes and both fire on ⌘R.
  12. A className on a kit component is a missing prop. Call sites pass size/variant and own only layout — position, flex sizing, min-h-0, a width, an animation, a behaviour utility. The moment a page re-dials a kit component's surface (padding, radius, background, border, font size, height) the kit is wrong for that context and gets a variant. One override is a smell; a stack of them on one element, or the same override at two call sites, is a review blocker. Rule 4 says where a fix lives; this says what a call site may write. shadcn/no-restyle enforces it (code-style.md).
  13. Every feature is operable from the keyboard, and Escape always walks back to the Navigator. A new surface ships its keyboard flow in the same task: arrows move within a surface, Enter (or Right, into a detail pane) descends, Escape ascends. Tab moves between surfaces, never through one: a list, tree, strip or grid is a single Tab stop, and everything inside it — rows, hover actions (⋯, pin), header buttons, checkboxes, grips — is tabIndex={-1}, reached by its arrows, ⌘. or its own shortcut. A surface never hands focus to a sibling surface from an arrow at its edge: holding an arrow stops at the edge, and leaving is Tab or Escape. Focus is never invisible — a surface that takes focus shows where it is (the grid places its cursor). Escape is a ladder, never a jump — it undoes the innermost state first (clear a search, then leave the field, then close the panel), one step per press, so enough presses from anywhere land on the Navigator. A handler that swallows Escape must have consumed a step (stopPropagation only after handling it), or the ladder breaks above it. An opening surface puts focus somewhere useful (initialFocus) and closing returns it to the trigger; nothing traps focus in a leaf with no way out. Keys are registered with useHotkey/useHotkeys from @tanstack/react-hotkeys (a shortcut listed in core/keyboard/shortcuts.ts through useShortcut/useShortcuts, which wrap them) — never a hand-rolled addEventListener and never a container's onKeyDown (which also drags a11y roles onto plain wrappers). target scopes a binding to one element's ref, so in-surface navigation and app-wide shortcuts use the same hook and show up together in its devtools.
  14. Holding ⌘ reveals the shortcuts. Every shortcut a surface answers to becomes visible when the user holds ⌘ for a beat and disappears on release — hints sit on the controls they fire, drawn with ShortcutKbd from the shortcut's id. A shortcut with nowhere to appear is undiscoverable. Settings → Keyboard also lists every shortcut with what it does (core/keyboard/shortcuts.ts, ordered by core/settings/shortcut-groups.ts), as a reference, never a substitute for the on-control hint: a new or changed shortcut updates its row in the same task. Show only what fires in the current context (gate Electron-only ones on window.electron, hide what is disabled), and reserve or overlay the space — revealing a hint must not reflow its row.
  15. A popup driven by nullable data closes with its fade. A dialog, drawer or popover whose open derives from a nullable value (open={!!item}) never renders its content from that live value: item && <DialogContent> unmounts the popup the moment it closes, so it vanishes with no exit animation, and item?.x in the body fades out an empty box. Copy the last non-null value into state during render and clear it in the root's onOpenChangeComplete(false), once the exit animation has finished:
const [shown, setShown] = useState(item)
if (item && item !== shown) {
  setShown(item)
}
<Dialog open={!!item} onOpenChangeComplete={(open) => !open && setShown(null)}>
  {shown && <DialogContent>…</DialogContent>}

open, closing and actions read the live item; everything the user sees reads shown. 15. Minimum UI, full power. Tamery is a modern database tool: every surface handles every case with the fewest controls. Before adding a control, make an existing one smarter: parse what is pasted or typed, infer from context, default sensibly, expose power through shortcuts and parsing rather than extra fields. Two controls for one job (a second button for what the first already does) is a review blocker; so is a control the user cannot actually use for its job.

Version History

  • 17012db Current 2026-10-19 21:20
  • df6b212 2026-09-28 12:15
  • d50f1d1 2026-09-23 01:15
  • 57e2312 2026-08-28 22:31

    移除reference.md文件,更新hard rules第0条以强调搜索注册表,细化跨主题颜色对比测试方法。

  • 06ecca0 2026-08-20 11:10

Same Skill Collection

.agents/skills/apple-design/SKILL.md
.agents/skills/cleanup/SKILL.md
.agents/skills/design-an-interface/SKILL.md
.agents/skills/design-taste-frontend/SKILL.md
.agents/skills/electron-drive/SKILL.md
.agents/skills/emil-design-eng/SKILL.md
.agents/skills/test-audit/SKILL.md
.agents/skills/thermo-nuclear-code-quality-review/SKILL.md
.agents/skills/user-behavior-qa/SKILL.md
.agents/skills/vercel-react-best-practices/SKILL.md

Metadata

Files
0
Version
17012db
Hash
22b84eaa
Indexed
2026-08-20 11:10

ホーム - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-10-31 19:45
浙ICP备14020137号-1