diff --git a/conformance_test.go b/conformance_test.go index 48be882..3372b38 100644 --- a/conformance_test.go +++ b/conformance_test.go @@ -125,6 +125,12 @@ func TestGoldenCardEvents(t *testing.T) { } func TestGoldenUIVocabularies(t *testing.T) { + golden(t, "ui_avatar", []UINode{ + {Type: UIAvatar, Avatar: &UIAvatarSpec{Name: "weichen", Sub: "OWNER"}}, + {Type: UIAvatar, Avatar: &UIAvatarSpec{ + Stack: []UIAvatarSpec{{Name: "甲", Tone: "ok"}, {Name: "乙", Tone: "warn"}, {Name: "丙"}}, + }}, + }) golden(t, "ui_vocabularies", []UINode{ {Type: UIProgress, Progress: &UIProgressSpec{Label: "市场可行性 78%", Value: 0.78, Tone: "ok"}}, {Type: UICompare, Compare: &UICompareSpec{ diff --git a/testdata/golden/ui_avatar.json b/testdata/golden/ui_avatar.json new file mode 100644 index 0000000..eff0f2d --- /dev/null +++ b/testdata/golden/ui_avatar.json @@ -0,0 +1,27 @@ +[ + { + "type": "avatar", + "avatar": { + "name": "weichen", + "sub": "OWNER" + } + }, + { + "type": "avatar", + "avatar": { + "stack": [ + { + "name": "甲", + "tone": "ok" + }, + { + "name": "乙", + "tone": "warn" + }, + { + "name": "丙" + } + ] + } + } +] diff --git a/ts/types.ts b/ts/types.ts index 96b638a..e754c42 100644 --- a/ts/types.ts +++ b/ts/types.ts @@ -152,7 +152,7 @@ export interface HITLResponse { export type UINodeType = | 'section' | 'list' | 'kv' | 'form' | 'markdown' | 'doc-ref' | 'actions' | 'chart-lite' - | 'progress' | 'compare' | 'tree' | 'table' | 'steps' | 'tabs' | 'timeline'; + | 'avatar' | 'progress' | 'compare' | 'tree' | 'table' | 'steps' | 'tabs' | 'timeline'; export interface UINode { type: UINodeType; @@ -166,6 +166,7 @@ export interface UINode { chart?: { kind: 'bar' | 'line'; labels: string[]; series: number[] }; children?: UINode[]; + avatar?: { name?: string; sub?: string; tone?: string; stack?: { name?: string; sub?: string; tone?: string }[] }; progress?: { label?: string; value: number; tone?: string }; compare?: { left: { title?: string; tone?: string; nodes?: UINode[] }; diff --git a/ui.go b/ui.go index 7296e70..7428f43 100644 --- a/ui.go +++ b/ui.go @@ -17,6 +17,7 @@ const ( UIChartLite UINodeType = "chart-lite" // —— 收件箱/工作区扩展词汇(提案 D28;graph 远期,追溯视图按"对象为中心 + // 分组泳道 + 逐层展开"约束设计,禁止力导向裸图)—— + UIAvatar UINodeType = "avatar" // 头像(成员/责任人展示;UI 能力平台,插件可用) UIProgress UINodeType = "progress" // 进度条(摄取/生成/填充度) UICompare UINodeType = "compare" // 左右对比(基线 vs 新内容、diff 确认) UITree UINodeType = "tree" // 树(文档树/笔记树骨架;节点带状态灯/徽标/计数) @@ -27,24 +28,33 @@ const ( ) type UINode struct { - Type UINodeType `json:"type"` - Title string `json:"title,omitempty"` - Items []string `json:"items,omitempty"` // list - KV [][2]string `json:"kv,omitempty"` // kv - Fields []UIField `json:"fields,omitempty"` // form - Markdown string `json:"markdown,omitempty"` - DocID ID `json:"docId,omitempty"` // doc-ref - Actions []UIAction `json:"actions,omitempty"` - Chart *UIChart `json:"chart,omitempty"` - Children []UINode `json:"children,omitempty"` // section + Type UINodeType `json:"type"` + Title string `json:"title,omitempty"` + Items []string `json:"items,omitempty"` // list + KV [][2]string `json:"kv,omitempty"` // kv + Fields []UIField `json:"fields,omitempty"` // form + Markdown string `json:"markdown,omitempty"` + DocID ID `json:"docId,omitempty"` // doc-ref + Actions []UIAction `json:"actions,omitempty"` + Chart *UIChart `json:"chart,omitempty"` + Children []UINode `json:"children,omitempty"` // section - Progress *UIProgressSpec `json:"progress,omitempty"` // progress - Compare *UICompareSpec `json:"compare,omitempty"` // compare - Tree *UITreeSpec `json:"tree,omitempty"` // tree - Table *UITableSpec `json:"table,omitempty"` // table - Steps *UIStepsSpec `json:"steps,omitempty"` // steps - Tabs *UITabsSpec `json:"tabs,omitempty"` // tabs - Timeline *UITimelineSpec `json:"timeline,omitempty"` // timeline + Avatar *UIAvatarSpec `json:"avatar,omitempty"` // avatar + Progress *UIProgressSpec `json:"progress,omitempty"` // progress + Compare *UICompareSpec `json:"compare,omitempty"` // compare + Tree *UITreeSpec `json:"tree,omitempty"` // tree + Table *UITableSpec `json:"table,omitempty"` // table + Steps *UIStepsSpec `json:"steps,omitempty"` // steps + Tabs *UITabsSpec `json:"tabs,omitempty"` // tabs + Timeline *UITimelineSpec `json:"timeline,omitempty"` // timeline +} + +// UIAvatar:头像(成员/责任人;Name 取首字,Tone 走语义色;Stack 为叠放组)。 +type UIAvatarSpec struct { + Name string `json:"name,omitempty"` + Sub string `json:"sub,omitempty"` // 名字旁的小注(角色/状态) + Tone string `json:"tone,omitempty"` // ok/warn/danger/info/留空=品牌色 + Stack []UIAvatarSpec `json:"stack,omitempty"` // 叠放头像组(多成员) } // UIProgress:0–1 归一进度或 n/m 计数(Value=Done/Total 任一形式,前端按 <1 判定)。 @@ -88,9 +98,9 @@ type UITableColumn struct { } type UITableRow struct { - ID string `json:"id,omitempty"` - Cells [][2]string `json:"cells"` // 与 Columns.Key 对应的有序单元格 - Actions []UIAction `json:"actions,omitempty"` // 行级操作(走命令总线) + ID string `json:"id,omitempty"` + Cells [][2]string `json:"cells"` // 与 Columns.Key 对应的有序单元格 + Actions []UIAction `json:"actions,omitempty"` // 行级操作(走命令总线) } type UITableSpec struct { @@ -146,7 +156,7 @@ type UIField struct { type UIAction struct { ID string `json:"id"` Label string `json:"label"` - Style string `json:"style,omitempty"` // primary | default | danger + Style string `json:"style,omitempty"` // primary | default | danger Command string `json:"command,omitempty"` // 绑定命令总线命令 id;空则降级为发消息 }