Agent Skills
› wannabespace/conar
› tamery-ui
tamery-ui
GitHubTamery UI设计规范,涵盖macOS原生风格、颜色、排版及交互模式。提供组件使用硬规则,如禁用dark选择器、强制Token化尺寸,并指导如何调用shadcn registry组件以确保一致性。
Trigger Scenarios
构建或重构UI组件
审查前端代码样式合规性
调整页面主题或动画
Install
npx skills add wannabespace/conar --skill tamery-ui -g -y
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
- Search the registry before writing markup.
pnpm dlx shadcn@latest search @shadcn -q <term>. Adivstack re-implementing a registry component (Item,Empty,InputGroup,Field,ButtonGroup,Attachment…) is a review blocker, including "just this once". Missing frompackages/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 kitResponse, fenced code viaCodeBlockorResponseCodeBlock. - 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. - No pixel font sizes. Tokens only (
text-2xs…text-base+); a missing size gets a rem token in@theme. - No
cursor-pointer.cursor-defaulton link-based controls; I-beam and col-resize are the only exceptions. - Kit-level fixes in
packages/uifor systemic sizing or color problems; page overrides only for page-specific design. Sizes via size props, never per-pageh-*. - No bare interactive icons. Hover bg + color shift + tooltip, always (patterns.md).
- No
sidebar-*color tokens. Regular tokens everywhere. - Global anchor rule:
a { text-primary }in globals — row-styledLinks must settext-foregroundor render blue. data-maskon 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.- Verify heights in a row. After touching any control sharing a line with others, measure every element's
getBoundingClientRect().heightin the browser — equal to the pixel. Classic traps:py-*plus fixed-height children exceedingmin-h, borders withoutbg-clip-padding, hand-seth-*instead of size props. - Refresh belongs to the tab bar, never to the page.
TabRefreshowns 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 anddisabled. Two buttons for one dataset read as two refreshes and both fire on ⌘R. - A className on a kit component is a missing prop. Call sites pass
size/variantand 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. - 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. 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 (
stopPropagationonly 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 withuseHotkey/useHotkeysfrom@tanstack/react-hotkeys— never a hand-rolledaddEventListenerand never a container'sonKeyDown(which also drags a11y roles onto plain wrappers).targetscopes 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. - 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 the kit
shortcuts.tsxglyphs, never gathered into a cheatsheet the user has to find. A shortcut with nowhere to appear is undiscoverable. Show only what fires in the current context (gate Electron-only ones onwindow.electron, hide what is disabled), and reserve or overlay the space — revealing a hint must not reflow its row.
Version History
- df6b212 Current 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


