Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .scd/plans/20261109-231834-d1-tokens-assets/decisions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
status: approved
version: 1
created_at: 2026-11-09T23:18:34+08:00
updated_at: 2026-11-09T23:18:34+08:00
recorded_timezone: Asia/Shanghai
---

# 决策与事件

- 事件ID:DEC-1
- 类型:开工
- 文件及文档版本:本目录四份 v1;依据 Issue #123 契约与 Initiative #122 图版本 2
- 目标Git SHA:main HEAD(同步后)
- 用户实际依据:对 Initiative 确认摘要回复"ok";执行指令"全部完成 scdexcute"(覆盖图版本 2 全部 READY 波次的普通交付授权)
- 任务或Issue范围:Issue #123 范围内文件;NOTICES 仅 tokens/components 两节,#124/#125 各自追加
- occurred_at:null # 会话内指令,无消息ID
- recorded_at:2026-11-09T23:18:34+08:00
- 未决选择:无
17 changes: 17 additions & 0 deletions .scd/plans/20261109-231834-d1-tokens-assets/implementation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
status: approved
version: 1
created_at: 2026-11-09T23:18:34+08:00
updated_at: 2026-11-09T23:18:34+08:00
recorded_timezone: Asia/Shanghai
---

# 实施计划

1. 分支 delivery/123-design-tokens-assets
2. 下载 plugin87 main 分支 tokens/ 与 components/ 全部文件(git tree API 清点后逐个 raw 下载)
3. NOTICES 两节(plugin87 MIT,来源 URL,无改动声明)
4. 测试排除:collectPayloadFiles 跳过路径段 /data/;断言计数不变(79)
5. design-tokens.md 末尾加"数据资产与用法"段
6. 验证:node --test tests/*.test.mjs 全绿;隔离会话 A3
7. PR #123 → 独立验收 → 合并 → 关 Issue → 图版本 3
14 changes: 14 additions & 0 deletions .scd/plans/20261109-231834-d1-tokens-assets/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
status: approved
version: 1
created_at: 2026-11-09T23:18:34+08:00
updated_at: 2026-11-09T23:18:34+08:00
recorded_timezone: Asia/Shanghai
---

# 任务索引

- 任务与Issue:Delivery Issue #123(design-tokens-assets),Initiative #122 图版本 2
- 所需文档及版本:requirements.md v1、implementation.md v1、decisions.md v1
- 基线来源:main 同步后 HEAD;Initiative #122 确认摘要与 Issue #123 契约
- 批准与开工事件:decisions.md DEC-1(Initiative 项目确认 + 用户"全部完成 scdexcute"执行授权)
17 changes: 17 additions & 0 deletions .scd/plans/20261109-231834-d1-tokens-assets/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
status: approved
version: 1
created_at: 2026-11-09T23:18:34+08:00
updated_at: 2026-11-09T23:18:34+08:00
recorded_timezone: Asia/Shanghai
---

# 需求(来自 Issue #123 契约,APPROVED)

- data/tokens/ 收录 plugin87 14 个 DTCG 令牌 JSON;data/components/ 收录 11 份组件规范
- 建立 data/THIRD-PARTY-NOTICES.md(来源/许可/改动),本节点先写 tokens/components 两节
- tests/chinese-skill-payload.test.mjs 排除 skills/*/data/,authored 计数保持精确
- references/design-tokens.md 挂接数据路径并补组件规范用法段(中文)
- 验收 A1:14 令牌 JSON 可解析含 $type/$value;11 组件规范完整
- 验收 A2:全量测试绿
- 验收 A3:隔离会话从 data/tokens 给出按钮语义色具体值
10 changes: 10 additions & 0 deletions skills/scd-uiux/data/THIRD-PARTY-NOTICES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# 第三方数据来源与许可

本目录收录第三方开源项目的机器可读设计资产。来源、许可与改动记录如下;各上游项目保留其原始版权与许可。

## plugin87/ux-ui-agent-skills(MIT License)

- 来源:<https://github.com/plugin87/ux-ui-agent-skills>(main 分支,按文件原样收录)
- 许可:MIT License,版权归属上游作者
- 收录范围:`tokens/`(14 个 DTCG 令牌 JSON)、`components/`(11 份组件规范 Markdown)
- 改动:无(原样搬运);后续如有改动在各节记录
237 changes: 237 additions & 0 deletions skills/scd-uiux/data/components/atoms.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
# Atoms

The smallest, indivisible UI elements. Each atom maps directly to design tokens and has a single, focused responsibility.

---

## 1. Button

The primary interactive control for triggering actions.

**Anatomy:** `[icon?] [label] [icon?]` within a pressable container.

**Variants:**
| Variant | Use Case | Token Mapping |
|---------|----------|---------------|
| Primary | Main CTA, one per visible area | `component.button.primary-*` |
| Secondary | Supporting actions | `component.button.secondary-*` |
| Ghost | Tertiary, toolbar, inline actions | `component.button.ghost-*` |
| Destructive | Delete, remove, irreversible | `component.button.destructive-*` |
| Link | Navigation-styled as button | `semantic.text.link` + underline |

**Sizes:**
| Size | Height | Padding | Font | Icon |
|------|--------|---------|------|------|
| sm | 32px | 12px × 8px | body-sm (14px) | 16px |
| md | 40px | 16px × 10px | body-base (16px) | 20px |
| lg | 48px | 24px × 12px | body-lg (18px) | 24px |

**States (8):**
1. **Default**: resting state
2. **Hover**: cursor over; background shifts one shade
3. **Focus**: keyboard focus; apply `focus-ring` shadow token
4. **Active/Pressed**: mouse down; background shifts two shades
5. **Disabled**: `opacity: 0.5`, `cursor: not-allowed`, `pointer-events: none`
6. **Loading**: replace icon with spinner, add `aria-busy="true"`, disable interaction
7. **Error**: N/A for a standalone button; a submit button reflects form error via the form, not its own style
8. **Selected**: `interactive.selected-bg` + `aria-pressed`/`aria-selected`, for toggle/segmented buttons only

**Accessibility:**
- Native `<button>` element always; never `<div>`
- Icon-only: add `aria-label`
- Loading: `aria-busy="true"`, announce via live region
- Disabled: use `disabled` attribute (removes from tab order) or `aria-disabled="true"` (keeps in tab order for discoverability)
- Minimum target size: 24×24px (WCAG 2.5.8)

---

## 2. Input

Single-line text entry field.

**Anatomy:** `[leading-icon?] [prefix?] [input] [suffix?] [trailing-icon?] [clear?]`

**Variants:** Text, Email, Password (toggle visibility), Number, Search, URL, Tel

**Sizes:**
| Size | Height | Padding | Font |
|------|--------|---------|------|
| sm | 32px | 12px × 8px | body-sm |
| md | 40px | 12px × 10px | body-base |
| lg | 48px | 16px × 12px | body-lg |

**States (8):**
1. **Default**: `input.border` (gray-200)
2. **Hover**: `input.border-hover` (gray-300)
3. **Focus**: `input.border-focus` (blue-500) + focus ring
4. **Active**: N/A for text entry (no pressed state); typing reflects via the caret/value
5. **Disabled**: `input.bg-disabled` + reduced opacity
6. **Loading**: during async validation/lookup, a trailing spinner + `aria-busy="true"`
7. **Error**: `input.border-error` (red-500) + error icon + message + `aria-invalid`
8. **Selected**: filled/has-value styling; read-only is a variant of default (non-editable, no hover)

**Accessibility:**
- Always associate with `<label>` via `for`/`id`
- Error messages: `aria-describedby` linking to error text + `aria-invalid="true"`
- Required: `aria-required="true"` + visual indicator (asterisk)
- Password toggle: `aria-label="Show password"` / `"Hide password"`

---

## 3. Label

Text label associated with a form control.

**Anatomy:** `[label-text] [required-indicator?] [optional-indicator?]`

**Token Mapping:** `textStyle.label` (14px/medium), `semantic.text.primary`

**Accessibility:**
- Use `<label for="input-id">` so clicking the label focuses the input
- Required: append `<span aria-hidden="true">*</span>` + `aria-required` on input
- Group labels: use `<legend>` inside `<fieldset>`

---

## 4. Icon

Decorative or informational pictogram.

**Sizes:** 12px, 16px, 20px, 24px, 32px

**Token Mapping:** Inherits `currentColor` from parent.

**Accessibility:**
- **Decorative**: `aria-hidden="true"` (most icons next to text labels)
- **Informational**: `role="img"` + `aria-label="Description"`
- **Interactive**: wrap in `<button>` with `aria-label`

---

## 5. Badge

A small status descriptor for counts or labels.

**Anatomy:** `[dot?] [text] [remove-button?]`

**Variants:**
| Variant | Use Case | Tokens |
|---------|----------|--------|
| Neutral | Default tags | `component.badge.neutral-*` |
| Primary | Active/selected | `component.badge.primary-*` |
| Success | Positive status | `component.badge.success-*` |
| Warning | Attention needed | `component.badge.warning-*` |
| Error | Critical/failed | `component.badge.error-*` |
| Dot | Minimal indicator | 8px circle, no text |

**Sizes:** sm (20px height), md (24px height)

**Token Mapping:** `radius.badge` (full), `spacing.badge-padding-*`

**Accessibility:**
- Notification badges: `aria-label="3 unread messages"` (don't rely on number alone)
- Status badges: pair with descriptive text, not just color

---

## 6. Avatar

A circular representation of a user or entity.

**Anatomy:** `[image | initials | fallback-icon]` within a circle.

**Sizes:** xs (24px), sm (32px), md (40px), lg (48px), xl (64px), 2xl (96px)

**Token Mapping:** `component.avatar.*`, `radius.avatar` (full)

**Fallback Hierarchy:**
1. User-uploaded image
2. Initials (first + last name initial)
3. Generic person icon

**Accessibility:**
- Image avatars: `alt="[User name]"` or `alt=""` if name is adjacent
- Initials: `aria-label="[Full name]"`
- Status indicator (online dot): announce via `aria-label`, not just color

---

## 7. Checkbox

A control for binary or tri-state selection.

**Anatomy:** `[checkbox-box] [label] [help-text?]`

**Sizes:** sm (16px box), md (20px box), lg (24px box)

**States:** Unchecked, Checked, Indeterminate, Hover, Focus, Disabled

**Accessibility:**
- Prefer native `<input type="checkbox">`
- Indeterminate: set via JS `el.indeterminate = true` + `aria-checked="mixed"`
- Group: wrap in `<fieldset>` with `<legend>`
- See `aria-patterns.md` → Checkbox

---

## 8. Radio

A control for selecting exactly one option from a group.

**Anatomy:** `[radio-circle] [label] [help-text?]`

**Sizes:** sm (16px), md (20px), lg (24px)

**States:** Unselected, Selected, Hover, Focus, Disabled

**Accessibility:**
- Always in a `<fieldset>` with `<legend>` describing the group
- Arrow keys navigate between radios
- See `aria-patterns.md` → Radio Group

---

## 9. Toggle (Switch)

An on/off control for immediate state changes.

**Anatomy:** `[track] [thumb]` with optional `[label]` and `[status-text]`

**Sizes:**
| Size | Track | Thumb |
|------|-------|-------|
| sm | 36×20px | 16px |
| md | 44×24px | 20px |
| lg | 52×28px | 24px |

**States:** Off, On, Hover, Focus, Disabled

**Accessibility:**
- Use `role="switch"` with `aria-checked`
- Label must describe what the switch controls
- Avoid using for form submissions; use checkbox instead
- See `aria-patterns.md` → Switch

---

## 10. Tooltip

A non-interactive text popup for supplementary information.

**Anatomy:** `[trigger-element]` → `[tooltip-container] [arrow] [text]`

**Placement:** Top (default), Right, Bottom, Left. Auto-flip when near viewport edge.

**Token Mapping:** `surface: gray-900`, `text: white`, `radius: tooltip (md)`, `shadow: md`

**Behavior:**
- Show on hover (300ms delay) and focus
- Hide on mouse leave, blur, Escape, scroll
- Max width: 240px (prevent tooltip walls)
- No interactive content inside

**Accessibility:**
- `role="tooltip"` + `aria-describedby` on trigger
- Must appear on keyboard focus, not just hover
- Content is supplementary, not essential
- See `aria-patterns.md` → Tooltip
71 changes: 71 additions & 0 deletions skills/scd-uiux/data/components/data-display.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Data-Display Components

Components that present structured or browsable data: Calendar, Carousel, and Tree. Each uses a documented WAI-ARIA pattern (`accessibility/aria-patterns.md`) and renders via the [Framework Adapter Protocol](../frameworks/adapter-protocol.md). For tabular data see `components/organisms.md` (Data Table); for charts see `components/data-viz.md`.

---

## 1. Calendar / Date Grid

Standalone month grid for picking or displaying dates. The popover-wrapped picker variant lives in `components/forms-advanced.md` (Date Picker); this is the grid itself.

**Anatomy:** `[header: ‹ prev | month year | next ›] [weekday row] [day grid 6×7] [footer: Today / Clear?]`

**Variants:**
| Variant | Use |
|---------|-----|
| Single date | Pick one day |
| Range | Start→end selection with in-range fill (`semantic.interactive.selected-bg` at reduced opacity) |
| Multi-month | 2-3 grids side-by-side for range picking |
| With time | Grid + time selector below |
| Display-only | Read-only schedule/availability heatmap |

**Sizes:** cell hit area ≥ `sizing.control.xs` (24px); md grid uses `sizing.control.md` cells. Gap from `spacing` scale.

**States (8):** default, hover (cell `interactive.hover-bg`), focus (roving `shadow.focus-ring`), selected (`interactive.selected-bg`), today (ringed via `border.strong` / `aria-current`), disabled (out-of-range, `opacity.disabled`), range-endpoint, in-range (subtle fill).

**Accessibility:**
- `role="grid"` (or `role="application"` for rich range UX); column headers `role="columnheader"` with `abbr` for weekday.
- **Roving tabindex**: one cell tabbable; Arrow keys move day/week, PageUp/Down month, Shift+PageUp/Down year, Home/End week edges, Enter/Space select.
- Selected cell `aria-selected="true"`; today `aria-current="date"`. Announce month/year change on navigation (live region).
- Never convey availability by color alone; pair with icon/label/`aria-disabled`.

---

## 2. Carousel / Slideshow

Sequentially browsable set of slides (media, cards, testimonials).

**Anatomy:** `[viewport (overflow clip)] → [slide track] [prev ‹] [next ›] [pagination dots] [play/pause?]`

**Variants:** single-slide, multi-item (n visible), peek (partial next), fade vs. slide transition, auto-advancing vs. manual, looping vs. bounded.

**Sizes:** slide width via `sizing.aspectRatio` or container fraction; control hit area ≥ 44px recommended.

**Behavior:** transition uses `tokens/motion.json` (`transition.standard`, `ease-out`). Snap to slide boundaries. On multi-item, advance by page or by item (document which).

**States:** default, hover (reveal/enlarge controls), focus (control `shadow.focus-ring`), active slide (dot filled), transitioning, auto-playing (timer), paused, disabled control (at non-looping bound).

**Accessibility:**
- Container `role="region"` (or `group`) with `aria-roledescription="carousel"` + `aria-label`. Slide group `aria-roledescription="slide"` + `aria-label="N of M"`.
- **WCAG 2.2.2**: any auto-advance must be pausable/stoppable; show a visible Pause control and **pause on hover/focus**. Respect `prefers-reduced-motion` (disable autoplay + use fade/instant).
- Prev/Next/dots are real `<button>`s with labels; rotation region `aria-live="off"` while auto, `"polite"` after user interaction.
- Off-screen slides `aria-hidden`/`inert` so they're skipped by Tab and SR.

---

## 3. Tree View

Hierarchical, expandable list (file explorers, nav, nested categories).

**Anatomy:** `[node: ▸ twisty | icon? | label | badge/count?] [indent guides] [nested group]`

**Variants:** single-select, multi-select (tri-state checkboxes), with icons, draggable-reorder, lazy-loaded branches.

**Sizes:** row height `sizing.control.sm`/`md`; indent step from `spacing` scale (consistent per level).

**States (8):** default, hover (`interactive.hover-bg`), focus (roving `shadow.focus-ring`), selected (`interactive.selected-bg`), expanded, collapsed, loading (branch spinner + `aria-busy`), disabled.

**Accessibility:**
- `role="tree"` → `role="treeitem"` → nested `role="group"`. Each item: `aria-expanded` (parents only), `aria-level`, `aria-setsize`, `aria-posinset`; selection via `aria-selected`. Multi-select checkboxes use `aria-checked="mixed"` for partial.
- **Roving tabindex**: Up/Down move visible items, Right expands/enters, Left collapses/exits to parent, Home/End to first/last, type-ahead to label, Enter/Space activate/select, `*` expands siblings.
- Twisty is decorative if the row is the control; expose state through `aria-expanded`, never the glyph alone.
Loading
Loading