iter(g63): card 支持标题操作区、底部操作区与悬停态

This commit is contained in:
HIsheR
2026-10-26 12:28:56 +08:00
parent fd1de1a5c8
commit 835967e507
7 changed files with 125 additions and 11 deletions
+14 -4
View File
@@ -1,12 +1,22 @@
import { h } from '@ui-arch/frame';
import type { CardProps } from './types.js';
/*** 卡片容器:可选标题 + 任意子内容 ***/
/*** 卡片容器:可选标题行(含右侧操作区)+ 任意子内容 + 可选底部操作区,bordered / hoverable 控制外观 ***/
export function card(props: CardProps, ...children: unknown[]): HTMLElement {
const cls = `ua-card${props.bordered === false ? ' ua-card-borderless' : ''}${props.hoverable ? ' ua-card-hoverable' : ''}`;
const head = props.title || props.extra
? h(
'div',
{ class: 'ua-card-head' },
props.title ? h('h3', { class: 'ua-card-title' }, props.title) : h('span', {}), // 无标题时占位,保证操作区仍靠右
props.extra ? h('span', { class: 'ua-card-extra' }, props.extra) : null,
)
: null;
return h(
'div',
{ class: 'ua-card' },
props.title ? h('h3', { class: 'ua-card-title' }, props.title) : null,
{ class: cls },
head,
...children,
);
props.footer ? h('div', { class: 'ua-card-foot' }, props.footer) : null, // 底部操作区:右对齐,仅传了才渲染
) as HTMLElement;
}
+5 -1
View File
@@ -40,7 +40,11 @@ export interface TextFieldProps {
/*** 卡片入参 ***/
export interface CardProps {
title?: string; // 标题;缺省不渲染标题行
title?: string; // 标题;缺省不渲染标题行
extra?: unknown; // 标题行右侧操作区(按钮 / 链接);缺省不渲染
footer?: unknown; // 底部操作区;缺省不渲染
bordered?: boolean; // 是否显示边框;缺省 true
hoverable?: boolean; // 悬停浮起(可点击卡片);缺省 false
}
/*** 皮肤层列定义:内核列定义 + 纯渲染字段(对齐 / 文案格式化),不参与排序筛选语义 ***/
+24 -1
View File
@@ -698,13 +698,36 @@
"n": "...children",
"t": "unknown[]",
"d": "任意子节点:字符串 / DOM / 响应式函数"
},
{
"n": "extra",
"t": "unknown",
"d": "标题行右侧操作区(按钮 / 统计文案);缺省不渲染"
},
{
"n": "footer",
"t": "unknown",
"d": "底部操作区;缺省不渲染"
},
{
"n": "bordered",
"t": "boolean",
"d": "是否显示边框;缺省 true"
},
{
"n": "hoverable",
"t": "boolean",
"d": "悬停浮起(可点击卡片);缺省 false"
}
],
"example": "card({ title: '用户表' }, dataTable({ data, columns }))",
"steps": [
"card 是容器组件:第一个参数是 props,其余参数是任意子节点",
"传 title 显示标题行,否则只有内容区",
"子节点可以混合字符串、DOM 节点与响应式函数"
"子节点可以混合字符串、DOM 节点与响应式函数",
"title 与 extra 同处标题行:有 extra 时右侧对齐,没标题也能只放操作区",
"footer 渲染在内容之后的底部区,右对齐并带上分隔线,适合放主次按钮",
"bordered:false 去边框(嵌在已有边界的容器里),hoverable 让整卡悬停浮起(自带 reduced-motion 兜底)"
]
},
{
+39 -1
View File
@@ -58,11 +58,41 @@
border-radius: var(--ua-radius-lg);
background: var(--ua-color-surface);
}
.ua-card-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--ua-space-2);
margin-bottom: var(--ua-space-3);
}
.ua-card-title {
margin: 0 0 var(--ua-space-3);
margin: 0;
font-size: var(--ua-font-size-lg);
font-weight: 500;
}
.ua-card-extra {
display: inline-flex;
align-items: center;
gap: var(--ua-space-1);
}
.ua-card-foot {
display: flex;
justify-content: flex-end;
gap: var(--ua-space-1);
margin-top: var(--ua-space-3);
padding-top: var(--ua-space-2);
border-top: 1px solid var(--ua-color-border);
}
.ua-card-borderless {
border: none;
}
.ua-card-hoverable {
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.ua-card-hoverable:hover {
transform: translateY(-2px);
box-shadow: 0 10px 24px color-mix(in srgb, var(--ua-color-text) 14%, transparent);
}
.ua-table table {
width: 100%;
border-collapse: collapse;
@@ -3394,3 +3424,11 @@ button.ua-step-dot:hover {
.ua-tree-row .ua-tree-box {
margin-right: 2px;
}
@media (prefers-reduced-motion: reduce) {
.ua-card-hoverable {
transition: none;
}
.ua-card-hoverable:hover {
transform: none;
}
}