iter: d22 新增头像 avatar 组件

This commit is contained in:
ui-arch-bot
2026-10-23 17:03:49 +08:00
parent 00a6104f84
commit f86da9866c
11 changed files with 198 additions and 10 deletions
+20
View File
@@ -0,0 +1,20 @@
import { h } from '@ui-arch/frame';
import type { AvatarProps } from './types.js';
/*** 头像:有 src 渲染图片(alt 用名称),否则用名称首字做占位;尺寸与语义底色由 props 决定 ***/
export function avatar(props: AvatarProps): HTMLElement {
const size = `${props.size ?? 32}px`;
return h(
'span',
{ class: `ua-avatar ua-avatar-${props.variant ?? 'default'}`, style: `width:${size};height:${size}`, title: props.name },
props.src
? h('img', { class: 'ua-avatar-img', src: props.src, alt: props.name })
: h('span', { class: 'ua-avatar-text', 'aria-label': props.name }, firstChar(props.name)),
);
}
/*** 取首个可见字符(中文取首字、英文取首字母大写) ***/
function firstChar(name: string): string {
const c = name.trim().charAt(0);
return c ? c.toUpperCase() : '?'; // 空名兜底问号,避免空白圆
}
+1
View File
@@ -13,6 +13,7 @@ export { breadcrumb } from './breadcrumb.js';
export { card } from './card.js';
export { badge } from './badge.js';
export { tag } from './tag.js';
export { avatar } from './avatar.js';
export { alert } from './alert.js';
export { toast, showToast } from './toast.js';
export { tooltip } from './tooltip.js';
+8
View File
@@ -170,6 +170,14 @@ export interface BadgeProps {
variant?: 'default' | 'success' | 'warning' | 'danger'; // 语义色;缺省 default
}
/*** 头像入参 ***/
export interface AvatarProps {
name: string; // 名称:生成占位首字,并作为图片 alt 与悬停标题
src?: string; // 图片地址;缺省用首字占位
size?: number; // 直径像素;缺省 32
variant?: 'default' | 'success' | 'warning' | 'danger'; // 占位底色语义档;缺省 default
}
/*** 标签入参(可关闭,与纯展示的 badge 区分) ***/
export interface TagProps {
label: string; // 标签文案
+42 -3
View File
@@ -1,7 +1,7 @@
{
"name": "@ui-arch/ui",
"type": "skin-dom",
"description": "DOM 皮肤组件库:button / textField / textarea / slider / checkbox / switch / select / menu / radioGroup / accordion / breadcrumb / card / badge / tag / alert / toast / tooltip / popover / skeleton / spinner / progress / tabs / pagination / modal / drawer / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。",
"description": "DOM 皮肤组件库:button / textField / textarea / slider / checkbox / switch / select / menu / radioGroup / accordion / breadcrumb / card / badge / tag / avatar / alert / toast / tooltip / popover / skeleton / spinner / progress / tabs / pagination / modal / drawer / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。",
"tags": [
"components",
"dom",
@@ -27,6 +27,7 @@
"card(props, ...children):卡片容器",
"badge(props):徽标,variant = default | success | warning | danger",
"tag(props):可关闭标签,variant 五档语义色,closable + onClose 支持从数据源移除(纯展示请用 badge)",
"avatar(props):头像,有 src 渲染图片(alt 用名称)、无 src 用首字占位,size 可调 + 四档语义底色",
"alert(props):提示条,variant = info | success | warning | danger",
"toast.info/success/warning/error(message, duration?):消息提示工厂,右上角堆叠,默认 3s 自动消失,出入场微动画;showToast(props) 为完整入参版本(closable 显示关闭按钮,同屏最多 4 条)",
"tooltip(props, trigger):悬浮提示,包裹触发器,hover / focus 延迟 150ms 出场,移出 / 失焦 / Esc 收起",
@@ -76,7 +77,8 @@
"PopoverProps",
"SliderProps",
"TagProps",
"DrawerProps"
"DrawerProps",
"AvatarProps"
]
},
"usage": "const checked = signal(false); checkbox({ label: '同意', checked }); const open = signal(false); modal({ title: '确认', open }, '内容')",
@@ -87,7 +89,7 @@
"无障碍基线:装饰性占位(skeleton)aria-hidden、加载指示(spinner)role=status、关闭按钮必须 aria-label、弹层弹窗 aria-haspopup/expanded、读屏可见的状态一律同步 aria-*"
],
"docs": {
"intro": "27 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。",
"intro": "28 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。",
"steps": [
"安装依赖:pnpm add @ui-arch/ui @ui-arch/frame(workspace 内自动链接)",
"引入样式:在应用入口 import '@ui-arch/ui/ui.css',暗色主题在根元素设 data-theme='dark'",
@@ -609,6 +611,43 @@
"标签是内联元素,可直接排进 .row 等容器,自动换行由容器决定"
]
},
{
"id": "avatar",
"title": "头像 Avatar",
"demo": "sec-avatar",
"props": [
{
"n": "name",
"t": "string",
"r": 1,
"d": "名称:生成占位首字,并作为图片 alt 与悬停标题"
},
{
"n": "src",
"t": "string",
"d": "图片地址;缺省用首字占位"
},
{
"n": "size",
"t": "number",
"d": "直径像素;缺省 32",
"df": "32"
},
{
"n": "variant",
"t": "'default' | 'success' | 'warning' | 'danger'",
"d": "占位底色语义档;缺省 default",
"df": "default"
}
],
"example": "avatar({ name: '张三' }); avatar({ name: 'Alice', size: 40, variant: 'success' })",
"steps": [
"只传 name:用名称首字做占位(中文取首字、英文大写),底色走 accent 淡化,暗色自动适配",
"有图片就传 src:渲染 img 并用 name 作 alt,读屏语义完整;图片缺失时由浏览器 alt 兜底",
"尺寸用 size(像素)控制,头像不参与布局拉伸(flex:none),可安全排进 .row 与表格单元格",
"需要区分类别(在线/告警)时用 variant 换底色档,颜色一律来自令牌"
]
},
{
"id": "alert",
"title": "提示条 Alert",
+32
View File
@@ -546,6 +546,38 @@
padding-bottom: 12px;
}
/* —— 头像 —— */
.ua-avatar {
display: inline-flex;
align-items: center;
justify-content: center;
flex: none;
border-radius: 50%;
overflow: hidden;
background: color-mix(in srgb, var(--ua-color-accent) 14%, transparent);
color: var(--ua-color-accent);
font-size: var(--ua-font-size-md);
font-weight: 500;
user-select: none;
}
.ua-avatar-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.ua-avatar-success {
background: color-mix(in srgb, var(--ua-color-success) 16%, transparent);
color: var(--ua-color-success);
}
.ua-avatar-warning {
background: color-mix(in srgb, var(--ua-color-warning) 18%, transparent);
color: var(--ua-color-warning);
}
.ua-avatar-danger {
background: color-mix(in srgb, var(--ua-color-danger) 16%, transparent);
color: var(--ua-color-danger);
}
/* —— 标签(可关闭) —— */
.ua-tag {
display: inline-flex;