开发

组件开发流程

开发 QtShadcn 组件的工作流:先研究 shadcn/ui 官方规范再实现(M2 教训)。

QtShadcn 组件开发流程

When to Use

  • 开发 qtshadcn 组件库(~/dev/qt/qtshadcn)新组件(对应 GitHub issues,每批一个,实现完关 issue)
  • 需要实现 shadcn/ui 风格(Design Token 驱动)的 QML 组件

铁律:先研究再实现

开发任何组件必须研究 shadcn/ui 参考实现,禁止凭印象直接写。 M2 教训:凭印象写的 Button 尺寸整体小一档、漏 link variant、圆角 8px(应为 6px)等,全靠事后对照返工。

1. 抓官方文档(含 variants/sizes 列表)

# 网速慢用代理 7897或7890
curl -sL -x http://127.0.0.1:7897 "https://ui.shadcn.com/docs/components/<name>" -o /tmp/shadcn-<name>.html
python3 -c "
import re, html
text = open('/tmp/shadcn-<name>.html').read()
m = re.search(r'<main[^>]*>(.*?)</main>', text, re.S)
body = m.group(1) if m else text
body = re.sub(r'<script.*?</script>', '', body, flags=re.S)
body = re.sub(r'<[^>]+>', ' ', body)
print(html.unescape(re.sub(r'\s+', ' ', body)))
"

2. 抓源码(gh api 认证,免限流)

shadcn-ui/ui 仓库 2026 年已重构:

  • v2/v3 稳定路径(广为人知的 cva 定义):apps/www/registry/default/ui/<name>.tsx
  • v4 新路径apps/v4/registry/__components__/base-luma.tsx(主题变体文件,内部 import("@/styles/base-luma/ui/<name>")),styles 路径 apps/v4/styles/base-luma/ui/<name>.tsx
# 先列目录找路径(路径常变)
gh api "repos/shadcn-ui/ui/contents/apps/v4/registry/__components__" --jq '.[].name'
# 再拿文件内容
gh api "repos/shadcn-ui/ui/contents/apps/v4/registry/__components__/base-luma.tsx" --jq '.content' | base64 -d

注意:GitHub Contents API 未认证会限流(尤其走代理 IP);raw.githubusercontent 路径随重构 404,用 gh api 列目录确认。

3. 梳理规范清单(输出对照表再写码)

维度必须确认
variants完整列表(Button: default/secondary/destructive/outline/ghost/link)
sizes全部尺寸 + 像素值(Button: xs=32 / sm=36 / default=40 / lg=44 / icon=40)
交互状态hover / pressed / disabled(opacity-50) / loading / focus(ring)
样式细节圆角(rounded-md=6px)、字重(font-medium=500)、padding、hover 语义
API属性 / 事件 / 变体枚举命名
无障碍/键盘继承 QQC 基类行为(键盘导航/Focus/Accessible 白拿)

4. 对照实现(QtShadcn 项目规范)

  • 组件命名 Shadcn* 前缀,文件 src/qml/Components/ShadcnXxx.qml,加进 src/CMakeLists.txtQML_FILES
  • 基于 QQC 基类(import QtQuick.Controls.Basic,style-specific import 是 token 自绘前提),只替换 background/contentItem
  • variant → token 映射集中在 src/qml/Theme/VariantTokens.qml:新增 variant = 枚举 + 映射表各加一项(顺序对齐);用 QtObject 属性定义(var 对象字面量在 qmlcache 下不可靠)
  • 颜色经 theme.tokens[token名] 查询(保持 mode 切换绑定;存颜色值会变静态)
  • 文字居中:QQC 会把 contentItem 拉伸到内容区全宽 → Item 包装 + RowLayout anchors.centerIn(水平垂直都稳);Row 子项 AlignTop 会偏上
  • 动画用 Shape + Animator(禁 Canvas 动画);文案 qsTr();import 无版本号;Layout 子项用 Layout.* 不用裸 width

5. showcase 验证

  • examples/showcase/Main.qml 展示全部 variant × size × 状态(含 disabled/loading/拉伸宽度)
  • make build 构建;python 后台启动 + poll 存活 + stderr 干净 + screencapture 截图给用户确认
  • 确认后 commit + 关对应 GitHub issue

M2 Button 实测偏差教训(防再犯)

  • 尺寸:Medium=40 / Large=44 / Small=36 / XS=32 / Icon=40(shadcn h-10/h-11/h-9/h-8/size-10)
  • 漏 link variant:text-primary + hover 下划线,无背景无 hover 块
  • 圆角:button 用 rounded-md = 6px(theme.radius 8 用于卡片/容器)
  • 字重 font-medium = 500
  • disabled / loading:opacity 50%
  • hover 语义:default/secondary/destructive 变暗(90% 透明度等效黑 8% overlay);outline/ghost 用 accent 背景 + accentForeground 文字;link 仅下划线
  • 按钮组:无 border 的 variant(如 Primary)中间需 1px 分隔线(前景色 15% 透明度);spacing: -1 合并边框;圆角只留两端

项目速查

  • 技术方案:设计 → 技术方案(11 节 = 组件开发流程)
  • 组件计划:GitHub issues #1-10(每批一个,实现完关对应 issue)
  • 构建:Qt 6.5+ / CMake 3.24+;token 自绘须 QQuickStyle::setStyle("Basic")(macOS 默认 native style 拒绝自定义 contentItem)
  • 规范技能:qt-qml(Qt 官方 agent-skills,QML 最佳实践)
Copyright © 2026