开发
M3 组件规范对照表
M3(Card/Input/Badge/Switch/Tabs/Dialog)shadcn/ui v4 官方规范 vs QtShadcn 实现差距对照。铁律产物:先输出对照表,确认后再写码。
M3 组件规范对照表
来源:shadcn/ui 官方文档 + 源码(
apps/v4/registry/bases/base/ui/*.tsx+apps/v4/registry/styles/style-luma.css),抓取于 2026-08-18。 依据:组件开发流程铁律(先研究 → 输出对照表 → 确认 → 实现)。
0. 公共决策(跨组件)
0.1 新增 Design Tokens(ThemeManager)
shadcn 语义中 M3 组件需要但当前 tokens 缺失的项:
| 新 Token | light | dark | 对应 shadcn 默认值 | 用途 |
|---|---|---|---|---|
card | #ffffff | #09090b | bg-card | Card 底色(= background) |
cardForeground | #09090b | #fafafa | text-card-foreground | Card 正文色(= foreground) |
input | #e4e4e7 | #27272a | bg-input | Input 底色(= 本主题 border 值) |
popover | #ffffff | #09090b | bg-popover | Dialog/浮层底色(= background) |
popoverForeground | #09090b | #fafafa | text-popover-foreground | 浮层正文色(= foreground) |
QtShadcnTheme.qml同步暴露只读属性:cardcardForegroundinputpopoverpopoverForeground- light/dark 两套 tokens 各加 5 项(值如上,与背景/边框体系自洽)
0.2 圆角体系决策(v4 激进大圆角 vs 项目既有体系)
v4 luma 风格大量使用 rounded-3xl(24px) / rounded-4xl(32px),与本项目 M2 已定体系
(控件 6px / 容器 8px)冲突。决策:遵循项目既有体系,不跟 v4 大圆角:
| 组件 | v4 官方 | QtShadcn 采用 | 理由 |
|---|---|---|---|
| Card 容器 | rounded-4xl (32px) | theme.radius (8px) | 项目既定「radius 8 用于卡片/容器」 |
| Input | rounded-3xl (24px) | 6px(控件级) | 与 ShadcnButton 一致 |
| Badge | rounded-3xl (24px) | 胶囊 radius: 999 | badge 惯例为胶囊(v4 24px 亦近胶囊) |
| Switch | rounded-full | rounded-full | 开关天然胶囊,无冲突 |
| TabsList | rounded-full | theme.radius (8px) | 容器级;胶囊与按钮族不协调 |
| Dialog | rounded-4xl (32px) | theme.radius (8px) | 容器级 |
若后续想对齐 v4 大圆角,仅需改各组件圆角属性,不影响 token 体系。
1. ShadcnCard(纯组合组件,无 QQC 基类)
结构(对齐 shadcn 组合方式)
Card(容器)
├── CardHeader (padding、间距,可含 title/description/action)
│ ├── CardTitle (font-medium, text-base=16px)
│ ├── CardDescription (text-sm=14px, mutedForeground)
│ └── CardAction (右上角动作区,可选)
├── CardContent (内容区)
└── CardFooter (flex 横向,底部按钮区)
shadcn 规范值
| 项 | v4 官方值 | 换算/决策 |
|---|---|---|
| 容器底色 | bg-card text-card-foreground | 新 token card / cardForeground |
| 容器描边 | ring-1 ring-foreground/5(light)/10(dark) | 1px,前景色 5%/10% 透明 |
| 阴影 | shadow-md | 轻阴影 |
| 圆角 | rounded-4xl (32px) | 8px(theme.radius) |
| 内边距 | --card-spacing: spacing(6) = 24px;size="sm" 时 spacing(4) = 16px | 支持 size: default/sm |
| 文本 | text-sm(14px);Title text-base(16px) font-medium;Description text-sm mutedForeground | |
| Header/Content/Footer 横向 padding | px-(--card-spacing) | 24px(sm 16px) |
| Footer | flex items-center | 子项水平排列、垂直居中 |
QML 实现要点
- 纯组合:
ShadcnCard容器 +ShadcnCardHeader+ShadcnCardTitle+ShadcnCardDescription+ShadcnCardContent+ShadcnCardFooter六个 QML 类型 - 容器:
Rectangle+radius: theme.radius+color: theme.card+border.width: 1+border.color: Qt.rgba(theme.foreground, 0.05)+ 阴影(layer或简单矩形叠层) - 子组件用
Item派生、default property接子项、leftPadding/rightPadding/topPadding/bottomPadding由外部padding属性控制(对齐 shadcn:Header/Content/Footer 各自带 padding,Card 管 gap) - 内容流:Header/Content/Footer 垂直堆叠(
Column),间距gap-1.5(6px) 等对齐 - 提供
size: "default" | "sm"属性(sm 内边距 16px)
2. ShadcnInput(基于 QQC.TextField)
shadcn 规范值
| 项 | v4 官方值 | 换算/决策 |
|---|---|---|
| 高度 | h-9 | 36px |
| 圆角 | rounded-3xl (24px) | 6px(控件级) |
| 底色 | bg-input/50 | theme.input 50% 透明 |
| 边框 | border-transparent(常态) | 1px 透明,聚焦切 ring |
| 聚焦态 | focus-visible:border-ring focus-visible:ring-3 ring-ring/30 | border=ring + 3px 外环 30% 透明 |
| 内边距 | px-3 py-1 | 左右 12px / 上下 4px |
| 字号 | text-base(16) / md:text-sm(14) | 用 14px(桌面) |
| placeholder | text-muted-foreground | mutedForeground |
| disabled | opacity-50 | 50% 透明(与 Button 一致) |
| file 按钮 | file:text-foreground | 不支持(桌面无需) |
QML 实现要点
import QtQuick.Controls.Basic,基于TextField,重写background+placeholderTextColor- 背景
Rectangle:radius: 6,常态color: Qt.rgba(theme.input, 0.5)+ 1px 透明边框;activeFocus时border.color: theme.ring+ 外扩 ring 环(3px、30% 透明,同 Button 焦点环做法) placeholderTextColor: theme.mutedForeground- 禁用态
opacity: 0.5(!enabled) implicitWidth: 200(shadcn 无默认宽,w-full 由外部决定)
3. ShadcnBadge
shadcn 规范值
| 项 | v4 官方值 | 换算/决策 |
|---|---|---|
| 高度 | h-5 | 20px |
| 圆角 | rounded-3xl (24px) | 胶囊(radius: 20) |
| 内边距 | px-2 py-0.5 | 左右 8px / 上下 2px |
| 字号/字重 | text-xs(12px) font-medium | 12px / Font.Medium |
| 描边 | border border-transparent | 1px 透明(outline variant 换 border token) |
variants(v4 官方,6 种)
| variant | 底色 | 文字 | hover(包裹 <a> 时) |
|---|---|---|---|
| default | primary | primaryForeground | bg-primary/80 |
| secondary | secondary | secondaryForeground | bg-secondary/80 |
| destructive | bg-destructive/10(透明底红字) | destructive | bg-destructive/20 |
| outline | 透明 | foreground | bg-muted + mutedForeground |
| ghost | 透明 | foreground | bg-muted |
| link | 透明 | primary | 下划线(underline-offset-4) |
注意 v4 变化:destructive 是「透明底 + 红字」(旧版是实心红底白字),按 v4 实现。
QML 实现要点
- 无 QQC 基类:
Item/Rectangle容器 + 内部Text(对齐 Button 的居中做法) - variant → token 查表:新增
VariantTokens.badge表(bg/fg 字符串,沿用现有机制);destructive 需特殊处理(底色 = destructive 10% 透明,非实心) - 支持
text属性;implicitWidth: text + 16,implicitHeight: 20 - 复用
theme.tokens[]查询保持 mode 切换绑定
4. ShadcnSwitch(基于 QQC.Switch)
shadcn 规范值(size: default / sm)
| 项 | default | sm |
|---|---|---|
| 轨道 | 44×20px(w-11 h-5) | 28×16px(w-7 h-4) |
| 滑块 | 24×16px(w-6 h-4) | 16×12px(w-4 h-3) |
| checked 滑块位移 | translate-x-[calc(100%-8px)] = 16px | 8px |
| 轨道圆角 | rounded-full | rounded-full |
| 轨道 checked | bg-primary border-primary | 同左 |
| 轨道 unchecked | bg-input/90 border-transparent | 同左 |
| 滑块色 | bg-background shadow-sm | 同左(dark checked 用 primaryForeground) |
QML 实现要点
- 基于
QQC.Switch(Basic style),重写background+indicator(或contentItem) - 轨道:
Rectangle宽高随 size(44×20 / 28×16),radius: height/2;checked→theme.primary+ 1pxprimary边框;!checked→Qt.rgba(theme.input, 0.9)+ 透明边框 - 滑块:
Rectangle(24×16 / 16×12),radius: height/2,color: theme.background;x绑定:checked ? width - thumb.width - 2*border : 2(用Behavior on x或NumberAnimation150ms 过渡) - 聚焦环:
activeFocus时 3px ring 外环(同 Input) - disabled:
opacity: 0.5
5. ShadcnTabs(基于 QQC.TabBar / TabButton / StackLayout)
结构
ShadcnTabs(容器)
├── ShadcnTabsList(TabBar 视觉:胶囊底 or line)
│ ├── ShadcnTabsTrigger(TabButton,选中态 + 指示器)
│ └── ...
└── ShadcnTabsContent(StackLayout 页区)
shadcn 规范值
| 项 | v4 官方值(default variant) | 决策 |
|---|---|---|
| TabsList 底色 | bg-muted rounded-full p-1 h-9 | bg-muted + theme.radius(8) + p-4 + 高 36 |
| TabsList line variant | gap-1 bg-transparent | 下划线式(v4 新增) |
| Trigger | rounded-full px-3 py-1 text-sm font-medium | 6px 圆角、12px padding、14px/Medium |
| Trigger 常态 | text-foreground/60(dark: mutedForeground) | foreground 60% 透明 |
| Trigger hover | text-foreground | 全不透明 |
| Trigger 选中(default) | bg-background text-foreground | 白底 + 前景色 |
| Trigger 选中(line) | 下划线 after:h-0.5 after:bg-foreground(bottom -5px) | 2px 下划线指示器 |
| TabsContent | text-sm flex-1 | 14px |
QML 实现要点
ShadcnTabs:暴露currentIndex/currentItem/currentTitle,管 Trigger 与 Content 的联动ShadcnTabsList:TabBar(Basic),重写background;position对齐 shadcn(列表在上)ShadcnTabsTrigger:TabButton,重写background(选中 bg-background / 常态透明)+ 内容 Text(60%→100% 透明切换)+ line variant 下划线指示器(Rectangle2px,x动画可选)ShadcnTabsContent:StackLayout(或TabBar+ 关联 StackLayout),currentIndex绑定- 提供
variant: default/line、orientation(横向为主,vertical 后期)
6. ShadcnDialog(基于 QQC.Dialog)
结构
ShadcnDialog(Popup 封装)
├── ShadcnDialogOverlay (bg-black/30 + backdrop-blur)
├── ShadcnDialogContent (popover 底 + 圆角 + 阴影 + 居中)
│ ├── ShadcnDialogHeader(Title + Description)
│ │ ├── ShadcnDialogTitle
│ │ └── ShadcnDialogDescription
│ ├── (业务内容)
│ └── ShadcnDialogFooter(按钮区,右对齐)
└── ShadcnDialogClose (右上角 X,ghost 图标按钮)
shadcn 规范值
| 项 | v4 官方值 | 换算/决策 |
|---|---|---|
| 遮罩 | bg-black/30 backdrop-blur-sm | 黑 30% + 背景模糊 |
| 容器底色 | bg-popover text-popover-foreground | 新 token popover/popoverForeground |
| 容器宽 | max-w-md = 448px,max-w-[calc(100%-2rem)] | 448px,小屏留 32px 边距 |
| 容器圆角 | rounded-4xl (32px) | 8px(theme.radius) |
| 容器内边距 | p-6(24px),gap-6(24px) | 24px |
| 阴影 | shadow-xl ring-1 ring-foreground/5 | 重阴影 + 1px 前景 5% 环 |
| 标题 | text-base font-medium leading-none | 16px / Medium |
| 描述 | text-sm text-muted-foreground | 14px / mutedForeground |
| Footer | flex justify-end gap-2 | 右对齐 |
| 关闭按钮 | 右上角 ghost 图标按钮(X),absolute top-4 right-4 | ShadcnButton.Ghost + Icon(M4 前用文本 ✕) |
| 动画 | fade-in + zoom-in-95,duration 100ms | opacity + scale 动画 |
QML 实现要点
- 基于
QQC.Dialog(Basic),modal: true;重写overlay(黑 30% + blur) - 内容:
ShadcnDialogContent容器(popover 底 + 8px 圆角 + 1px 环 + 阴影 + 448px 宽),居中于 overlay standardButtons: Dialog.NoButton,关闭由右上角 X / Esc(QQC 自带)触发- Header/Footer 组合组件对齐 Card 风格;
closeButtonVisible属性控制 X 显示(shadcnshowCloseButton) - 动画:进入时 opacity 0→1 + scale 0.95→1(100ms),退出反向
7. 各组件 API 草案(与 shadcn 对齐)
// Card
ShadcnCard { size: "default" } // default | sm
ShadcnCardHeader {
ShadcnCardTitle { text: "标题" }
ShadcnCardDescription { text: "描述" }
}
ShadcnCardContent { /* 业务内容 */ }
ShadcnCardFooter {
ShadcnButton { text: "确定" }
}
// Input
ShadcnInput {
placeholderText: "请输入"
onAccepted: ...
}
// Badge
ShadcnBadge { text: "New"; variant: ShadcnBadge.Variant.Default }
// Default / Secondary / Destructive / Outline / Ghost / Link
// Switch
ShadcnSwitch { checked: true; size: ShadcnSwitch.Size.Default } // Default | Small
// Tabs
ShadcnTabs {
currentIndex: 0
ShadcnTabsList { // variant: "default" | "line"
ShadcnTabsTrigger { text: "账户" }
ShadcnTabsTrigger { text: "密码" }
}
ShadcnTabsContent { /* 页 1 */ }
ShadcnTabsContent { /* 页 2 */ }
}
// Dialog
ShadcnDialog {
id: dialog
title: "确认删除"
ShadcnDialogContent {
ShadcnDialogHeader {
ShadcnDialogTitle { text: dialog.title }
ShadcnDialogDescription { text: "此操作不可撤销。" }
}
ShadcnDialogFooter {
ShadcnButton { text: "取消"; onClicked: dialog.close() }
ShadcnButton { text: "删除"; variant: ShadcnButton.Variant.Destructive; onClicked: dialog.close() }
}
}
}
8. 实现顺序与验证
- ThemeManager 加 5 个新 token + QtShadcnTheme 暴露属性(先行,供后续组件使用)
- Card → Input → Badge → Switch → Tabs → Dialog(每个:实现 → QML_FILES 注册 → showcase 新页 → 全状态展示)
- showcase「组合示例」:新建项目对话框(Dialog + Card + Input + Button + Tabs 组合),验证 M3 集成
make build+ 运行截图确认 + commit + 关闭 GitHub issues