mcpField
Q
qt-figma-token-extraction

qt-figma-token-extraction

github.com/theqtcompanyrnd设计与 UI513443 次安装1 周前更新
代码仓库

关于 qt-figma-token-extraction

从 Figma 提取设计令牌并映射到 QML 类型,以 Theme 单例为核心生成 QML 设计系统。支持通过 Figma MCP 或本地 curl 工作流提取令牌。

主要功能

  1. 01提取 Figma 变量和样式
  2. 02将令牌映射到 QML 类型
  3. 03生成 Theme 单例设计系统
  4. 04处理变量模式和别名
  5. 05为生成的 QML 配置 Qt 项目文件

适用场景

  1. 01根据 Figma 令牌创建 QML 主题
  2. 02将颜色和字体样式迁入 Qt 项目
  3. 03从多个 Figma 来源生成设计系统文件

MCP 相关

该技能可使用 Figma MCP 工具读取变量并提取设计令牌,也提供本地 curl 提取流程作为替代方案。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/theqtcompanyrnd/agent-skills --skill qt-figma-token-extraction

安装后在 Claude Code 中输入/qt-figma-token-extraction确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

examples/
FontInterface.qml
Primitives.qml
Spacing.qml
Theme.qml
Typography.qml
references/
token-mapping.md

详细介绍

Figma 令牌提取技能

此技能可从 Figma 文件中提取设计令牌,将其映射到 QML 类型,并生成可直接使用的 QML 设计系统,其中包含统一的 Theme 单例。

技能结构

支持文件会与此 SKILL.md 一同加载:

qt-figma-token-extraction/
├── SKILL.md                        # this file — entry point
├── references/
│   └── token-mapping.md            # Figma variable type → QML type mapping rules
└── examples/
    ├── Primitives.qml      # primitive color palette template
    ├── Theme.qml           # semantic token template (references Primitives)
    ├── FontInterface.qml   # font loaders + icon index template
    ├── Spacing.qml         # spacing and radii template
    └── Typography.qml      # typography scale template

到达步骤 4(类型映射)时,请先阅读 references/token-mapping.md,再生成任何 QML。 在步骤 6 生成 QML 文件时,请将 examples/ 中的文件用作结构模板——它们体现了 Qt Design Studio 实际使用的命名和组织模式。


步骤 0 — 检查 Qt 项目设置

始终调用 AskUserQuestion 工具——即使看起来已经打开了项目,也不要假设当前打开的项目就是目标项目。

调用前,请阅读上下文,使问题更贴合用户的情况:

  • 如果已有项目打开(可以看到文件,且存在 CMakeLists.txt),请在第一个选项中写明项目名称,方便用户确认或更换目标。
  • 如果用户请求的是更新(“更新我的颜色”“重新提取令牌”“同步设计系统”),请省略“创建新项目”选项——更新始终针对现有项目。

对于更新请求——提供两个选项,不提供“创建新项目”选项:

tool: AskUserQuestion
question: "Which project should I update the design tokens in?"
options:
  - "This project — <detected project name or path> (currently open)"
  - "A different existing project — I'll give you the path"

对于初始设置请求——提供全部三个选项:

tool: AskUserQuestion
question: "Which Qt project should I set up the design system in?"
options:
  - "This project — <detected project name or path> (currently open)"
  - "A different existing project — I'll give you the path"
  - "Create a new project"

如果当前没有打开任何项目,请将第一个选项替换为仅含 "一个现有项目 — 我会提供路径"。

**如果项目已存在(已确认或已提供路径):**记录项目路径。继续步骤 1——暂时不要询问 Figma 文件。

**如果需要新建项目:**立即搭建文件夹结构并创建 main.cpp 和 main.qml,然后继续步骤 1:

my-project/
├── CMakeLists.txt      ← set up in Step 7
├── main.cpp            ← create now (template below)
├── main.qml            ← create now (template below)
└── design-system/      ← generated files go here

请使用以下确切内容创建 main.cpp——使用 QGuiApplication,而非 QApplication(Qt Quick 不需要 Widgets):

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    engine.loadFromModule("<ProjectName>", "Main");

    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

将 <ProjectName> 替换为 qt_add_qml_module() 中使用的 URI——两者必须完全一致。

**不要使用旧的 QUrl url(u"qrc:/..."_qs) 模式。**在 Qt 6 中,qt_add_qml_module 会将文件放在 qrc:/qt/qml/<URI>/ 下,而不是像 Qt 5 那样放在 qrc:/<URI>/ 下。使用旧路径会导致加载失败且不显示错误。loadFromModule() 可完全避免此问题,是 Qt 6.5+ 的正确方式。

请创建 Main.qml 作为占位文件——M 必须大写,不能小写。loadFromModule() 区分大小写,并会查找名为 Main 的类型,该类型对应 Main.qml:

import QtQuick

Window {
    width:   640
    height:  480
    visible: true
    title:   "My Qt App"
}

**CMake 设置:**完整的 CMakeLists.txt(包括单例注册)将在步骤 7 中、所有 QML 文件都已确定后编写。现在不要编写。如果用户遇到任何构建配置问题,请建议用户查看 Qt 的 CMake 文档:https://doc.qt.io/qt-6/cmake-get-started.html,而不要在此处直接排查。


步骤 1 — 路由问题

请针对以下每个问题逐一调用 AskUserQuestion 工具。如果当前界面不支持 AskUserQuestion 工具,请以纯文本提出相同问题,并等待用户回答后再继续。暂时不要询问任何 Figma 链接。

调用 1 — 模式:

tool: AskUserQuestion
question: "Does your Figma design system use multiple variable modes?"
options:
  - "Yes — for example Light and Dark themes"
  - "No — single mode only"
  - "I'm not sure"

等待用户回答,然后询问:

调用 2 — 终端:

tool: AskUserQuestion
question: "Are you comfortable running a short command in a terminal on your own computer?"
options:
  - "Yes, I can use a terminal"
  - "No, I prefer not to use a terminal"
答案组合使用的方法(内部)
单个模式 / 不确定 + 任意终端回答MCP 方法——提取期间检查是否存在多个模式,并按需调整
多个模式 + 熟悉终端curl 方法——通过一条命令获取所有模式
多个模式 + 不熟悉终端使用手动切换模式的 MCP 方法

如果用户对模式的回答是“我不确定”,请使用 MCP 方法,并在提取期间检查是否存在多个模式。检查后再说明发现的情况,不要提前解释。

**不要询问文件使用的是 Variables 还是 Styles。**在步骤 2 收到 Figma 文件 URL 后自动检测——调用 get_variable_defs 或检查文件,并报告发现的情况。如果存在 Variables,则提取 Variables;如果只有 Styles,则提取 Styles;如果两者都存在,则两者都提取。


第 2 步 — 收集所有 Figma 文件链接

了解提取方法后,在开始提取之前,一次性询问所有 Figma 文件 URL。这样可以避免之后中断工作流。

询问用户:

“请分享包含设计令牌的所有 Figma 文件 URL。如果令牌分散在多个文件或页面中(例如,颜色在一个文件中,字体排版在另一个文件中),请现在分享所有链接,并告诉我每个文件包含什么内容。”

等待用户提供所有 URL 后再继续。从每个 URL 中提取文件 key——即 /design/ 与下一个 / 之间的字母数字字符串。记录每个文件或页面包含哪些令牌类型。

社区文件说明: 如果任何 URL 指向用户尚未复制到其账户的 Figma 社区文件,请立即提醒用户:提取工具无法直接访问社区文件。请用户先将文件复制到 Figma 草稿中(打开文件 → 复制到你的草稿),然后分享新的 URL。


MCP 方法 — 通过 Figma MCP 提取

(适用于:单模式系统,或用户不熟悉终端的情况)

要求: 已连接 Figma MCP。无需个人访问令牌或本地设置。

注意: 此方法只读取 Figma 中当前激活的变量模式。如果设计系统包含多个模式(例如,浅色/深色),用户需要在每次读取之间切换 Figma 中的模式——可以操作,但步骤更多。不要一开始就提及此限制;只有在提取过程中发现多个模式时,才进行说明。

第 1a 步 — 确认已连接 Figma MCP

开始操作前,先确认 Figma MCP 工具可用。查找名称暗示变量提取、设计上下文读取或文件元数据的工具——不同的 Figma MCP 服务可能使用不同的确切名称(例如 get_variable_defs、getVariableDefinitions、figma_get_variables)。将本技能中的工具名称视为示例,而非固定约定;应按用途匹配,而非按确切字符串匹配。

如果完全没有可用的 Figma 工具,请告诉用户:

“Figma MCP 连接器尚未连接。请在 Claude 界面中连接它(设置 → 连接器或 MCP 配置),然后再回来开始操作。”

确认连接之前不要继续。

第 1b 步 — 检查模式

使用文件节点 ID 调用 get_variable_defs,查看有哪些集合和模式:

Tool: get_variable_defs
Input: { "nodeId": "<root node id or specific variable group node id>" }

如果响应显示有多个模式,且用户需要全部模式,请说明需要用户在每次读取之间切换 Figma 中的模式,然后继续操作。

第 1c 步 — 提取变量

对相关节点调用 get_variable_defs。每次处理一个集合,逐个提取令牌类别——颜色、字体排版、间距、圆角、阴影。对于每个集合,读取当前激活模式的值。

如果需要记录多个模式:

  • 提取并记录当前模式的所有值
  • 请用户切换 Figma 中当前激活的模式(视图菜单 → 变量模式,或画布上的模式切换器)
  • 再次调用 get_variable_defs,并记录新模式的值
  • 对每个模式重复此操作
  • 合并为一个包含模式键的令牌文件(参见第 5 步中的输出格式)
第 1d 步 — 解析别名

如果任何变量值引用了另一个变量(即别名),请将其解析为最终值。不要将尚未解析的别名引用写入输出文件——标记所有无法解析的引用并询问用户。


curl 方法 — 从用户的本地计算机提取

(适用情况:存在多种变量模式,且用户熟悉终端)

需要: 终端访问权限(curl 已内置于 macOS 和 Linux;Windows 10 及更高版本也可使用),以及 Figma Personal Access Token(查看者权限范围即可)。

重要: 运行任何 curl 命令前,请先完成本节中的所有步骤,尤其是 PAT 设置和验证。使用无效令牌运行 curl 会生成损坏的输出文件。

不支持社区文件。 curl 命令仅适用于用户自己账号中的 Figma 文件(用户拥有或受邀访问的文件)。用户正在查看但尚未复制的社区文件会返回 403 错误。如果用户使用的是社区文件,请先让其复制到自己的账号:在 Figma 中打开社区文件 → 点击 复制到你的草稿 → 使用复制后的文件 URL。

第 1a 步 — 设置 Figma Personal Access Token

请先完成此步骤。询问用户:

“运行提取命令前,你需要一个 Figma Personal Access Token。你已经有了吗?”

如果有:继续进行验证(第 1b 步)。

如果没有,请引导用户创建:

  1. 在浏览器或桌面应用中打开 Figma
  2. 点击头像(左上角)→ 设置
  3. 转到 安全 选项卡
  4. 向下滚动到 Personal access tokens → 点击 Generate new token
  5. 为令牌取任意名称(例如“Claude token export”),并将权限范围设为 Viewer
  6. 立即复制令牌 — Figma 只会显示一次
第 1b 步 — 继续之前验证 PAT 是否有效

如果 PAT 最近已验证过(90 天内),用户可以跳过此步骤。否则,请让用户在终端中运行以下验证命令:

curl -H "X-Figma-Token: YOUR_TOKEN" "https://api.figma.com/v1/me"

预期结果:一条包含其 Figma 账号电子邮件地址的 JSON 响应(例如 "email": "[email protected]")。

如果响应包含 "status": 403 或 "Invalid token":说明令牌错误或已过期。请让用户生成新令牌并重试。验证成功前,请勿继续提取。

第 1c 步 — 提取变量

请用户在终端中运行:

curl -H "X-Figma-Token: YOUR_TOKEN" "https://api.figma.com/v1/files/FILE_KEY/variables/local" -o design-tokens-raw.json

这会将完整的原始变量导出内容 — 包含所有集合、所有模式和所有值 — 保存到 design-tokens-raw.json。

第 1d 步 — 分享结果

命令运行完成后,请用户选择以下任一方式:

  • 将 design-tokens-raw.json 上传到对话中,或
  • 将其内容粘贴到对话中

然后继续下面的第 2 步(文本样式)。


提取样式

注意: Figma 样式(文本、颜色、效果)与变量分开存放,需要单独提取。如果用户的设计系统主要使用样式作为令牌来源(而非变量),则此步骤将成为主要提取步骤,而非辅助步骤。如果设计系统同时使用变量和样式,请先完成第 1 步,再执行此步骤。

逐页处理: Figma 文件通常会将不同类型的令牌分散在多个页面中(例如,一个页面放颜色,另一个页面放排版)。不要尝试一次提取所有内容。询问用户每种令牌类型位于哪个页面,然后每次提取一个页面。每处理完一页,先确认找到了哪些内容,再继续下一页。

MCP 方法 — 文本样式

对使用设计系统文本样式的文本框或组件使用 get_design_context。请用户在 Figma 中选择一个包含代表性文本元素的框架 — 标题、正文、标签 — 并读取它:

Tool: get_design_context
Input: { "fileKey": "<key>", "nodeId": "<selected text frame node id>" }

从响应中提取每种文本样式的名称、字体系列、字号、字重、行高和字间距。遍历所有文本角色(H1–H6、正文、标签、说明文字、代码)。如果一个框架中未显示全部样式,请用户选择其他框架。

curl 方法 — 文本样式

文本样式需要调用两次 curl:第一次获取包含节点 ID 的样式列表,第二次获取这些节点的实际属性值。第 1a 步中的 PAT 已通过验证,可直接继续:

curl -H "X-Figma-Token: YOUR_TOKEN" "https://api.figma.com/v1/files/FILE_KEY/styles" -o text-styles-list.json

然后从 text-styles-list.json 中提取 node_id 值,用逗号连接后运行:

curl -H "X-Figma-Token: YOUR_TOKEN" "https://api.figma.com/v1/files/FILE_KEY/nodes?ids=NODE_IDS" -o text-styles-nodes.json

从 text-styles-nodes.json 中提取每种文本样式的字体系列、字号、字重、行高、字间距,以及应用的任何文本装饰或文本转换。

命令完成后,请用户将这两个文件上传或粘贴到对话中。

将文本样式合并到令牌文件中

文本样式会合并到 design-tokens.json 的 typography 部分。将它们标记为 "source": "textStyle",以便与基于变量的排版令牌区分:

"typography": {
  "fontFamilyHeading": { "value": "Titillium Web", "figmaName": "Font/Heading", "type": "STRING", "source": "variable" },
  "h1Size":            { "value": 36,  "unit": "px", "figmaName": "H1/Size",    "type": "FLOAT",  "source": "variable" },
  "h1":  {
    "figmaName": "Heading/H1",
    "source": "textStyle",
    "fontFamily":    "Titillium Web",
    "fontSize":      36,
    "fontWeight":    600,
    "lineHeight":    54,
    "letterSpacing": 0
  },
  "bodyDefault": {
    "figmaName": "Body/Default",
    "source": "textStyle",
    "fontFamily":    "Inter",
    "fontSize":      14,
    "fontWeight":    400,
    "lineHeight":    22,
    "letterSpacing": 0
  }
}

如果设计系统完全通过文本样式定义排版(且没有排版变量),则不会有 source: "variable" 条目——这没有问题,仅使用文本样式就足够了。


第 3 步 — 检查原始输出

无论使用哪种方法,在应用命名约定之前,都要与用户一起检查原始令牌数据:

  • 已提取所有文件: 确认用户提到的每个文件都已提取。若有任何文件缺失,请勿继续。
  • 集合已包含: 集合名称是否与用户预期的各文件内容相符?
  • 已捕获模式: 如果有多种模式,请确认所有模式都已显示,且值正确。
  • 颜色值: 抽查一些十六进制值,并与 Figma 文件核对。
  • 别名解析: 引用原始令牌的语义令牌应已解析出值。如果某个别名无法解析,几乎可以肯定是因为它引用的原始令牌位于尚未提取的文件中——请返回并先提取该文件,再继续。
  • 缺少集合: 如果缺少预期内容,请询问用户它位于哪个 Figma 文件中,并将该文件添加到清单中。

第 4 步 — 映射令牌类型并应用命名约定

生成任何 QML 之前,请先阅读 references/token-mapping.md,以确定每种 Figma 变量类型对应的正确 QML 类型(COLOR → color、FLOAT → int 或 real、STRING → string 等)。在所有生成的文件中一致地应用此映射。

询问用户是否已有命名约定。如果没有,请使用以下 Qt Design Studio 约定并确认:

令牌类型约定示例
原始颜色{family}_{scale}neutral_900、neon_500
原始分组每个系列使用嵌套的 QtObjectPrimitives.neutrals.neutral_900
语义颜色{role}_{variant}background_default、text_muted
语义分组在 Theme 单例上使用扁平结构Theme.background_default
语义变体_default / _muted / _subtlestroke_strong、stroke_muted、stroke_subtle
通知令牌notification_{type}_{variant}notification_alert_default、notification_danger_muted
间距步长x{multiplier}x4(= 8 px)、x8(= 16 px)
圆角半径radius_{size}radius_s、radius_m、radius_full
字体加载器描述性组件名称interFont、titilliumSemiBold、inconsolata
图标名称{icon_name}_{size}close_16、settings_fill_16

所有名称均使用 snake_case。原始 Figma 名称始终保存在 design-tokens.json 的 figmaName 字段中。

JSON 与 QML 的命名: 这些约定适用于生成的 QML 输出。出于 JSON 兼容性考虑,design-tokens.json 使用 camelCase 存储令牌键(例如 backgroundPrimary、cornerRadiusM)——生成 QML 时会在第 6 步将其转换为 snake_case。


步骤 5 — 编写 design-tokens.json

编写一个合并后的 design-tokens.json,包含所有提取的文件。来自不同 Figma 文件的原始令牌和语义令牌分别放在不同的区块中,以保留双层结构,并明确每个令牌所属的层级。单模式令牌使用扁平的 value 字段;多模式令牌则将值嵌套在 modes 下:

{
  "meta": {
    "extractedAt": "<ISO 8601 timestamp>",
    "namingConvention": "camelCase (JSON) / snake_case (QML)",
    "extractionMethod": "MCP | curl",
    "sources": [
      { "figmaFileName": "Global Tokens", "url": "<Figma URL>", "tier": "primitive" },
      { "figmaFileName": "Design Tokens", "url": "<Figma URL>", "tier": "semantic"  }
    ]
  },

  "_comment_primitives": "Raw values from the Global Tokens file — the building blocks",
  "colors": {
    "neutral000": { "value": "#ffffff", "figmaName": "Neutral/000", "type": "COLOR" },
    "neon600":    { "value": "#1f9b5d", "figmaName": "Neon/600",    "type": "COLOR" }
  },

  "_comment_semantic": "Semantic values from the Design Tokens file — reference primitives via resolvedFrom",
  "semanticColors": {
    "backgroundPrimary": {
      "figmaName": "Background/Primary", "type": "COLOR",
      "resolvedFrom": "neutral000",
      "modes": {
        "Light": { "value": "#ffffff" },
        "Dark":  { "value": "#181818" }
      }
    }
  },
  "typography": {
    "fontFamilyHeading": { "value": "Titillium Web", "figmaName": "Font/Heading", "type": "STRING" },
    "h1Size":            { "value": 36, "unit": "px", "figmaName": "H1/Size",      "type": "FLOAT" },
    "h1Weight":          { "value": 600,               "figmaName": "H1/Weight",    "type": "FLOAT" },
    "h1LineHeight":      { "value": 54, "unit": "px", "figmaName": "H1/LineHeight", "type": "FLOAT" }
  },
  "spacing": {
    "x4": { "value": 8,  "unit": "px", "figmaName": "Spacing/X4", "type": "FLOAT" },
    "x8": { "value": 16, "unit": "px", "figmaName": "Spacing/X8", "type": "FLOAT" }
  },
  "radii": {
    "cornerRadiusS":    { "value": 4,    "unit": "px", "figmaName": "Radius/Small", "type": "FLOAT" },
    "cornerRadiusFull": { "value": 9999, "unit": "px", "figmaName": "Radius/Full",  "type": "FLOAT" }
  },
  "shadows": {
    "shadowLow": {
      "offsetX": 0, "offsetY": 1, "blur": 3, "spread": 0,
      "color": "rgba(0,0,0,0.12)", "figmaName": "Shadow/Low"
    }
  }
}

保存到设计系统项目文件夹的根目录。向用户确认路径。


步骤 6 — 生成 QML 文件

以完整的 design-tokens.json 为唯一可信来源,生成 QML 单例文件。将所有文件放在 Qt 项目根目录下的 design-system/ 文件夹中。

首先读取资源模板

编写任何 QML 之前,先读取与每个输出文件对应的资源文件。这些是权威模板——定义了应遵循的确切结构、命名、分组和区块顺序:

输出文件要读取的示例内容说明
Primitives.qmlexamples/Primitives.qml每个颜色系列对应一个嵌套的 QtObject,采用 {family}_{scale} 命名
Theme.qmlexamples/Theme.qml扁平的语义令牌,引用 Primitives,并按角色分组
Spacing.qmlexamples/Spacing.qmlx{n} 间距步长、radius_{size} 圆角半径
FontInterface.qmlexamples/FontInterface.qml内联 component 字体加载器、带有 Unicode 映射的 Icons QtObject
Typography.qmlexamples/Typography.qml字体粗细常量,以及字号/粗细成对的字体比例

每次生成文件之前,立即读取该资源文件——不要依赖先前读取时的记忆。

文件夹结构
design-system/
├── Primitives.qml      ← raw color palette (nested by family: neutrals, accents)
├── Theme.qml           ← semantic color tokens (references Primitives)
├── Spacing.qml         ← spacing steps and corner radii
└── FontInterface.qml   ← font loaders + icon unicode index

按以下顺序生成:先生成 Primitives(没有依赖项),然后生成 Spacing 和 FontInterface(相互独立),最后生成 Theme(引用 Primitives)。

不要手动编写 qmldir。 模块注册由 CMakeLists.txt 中的 qt_add_qml_module() 处理。单例注册使用 set_source_files_properties——在步骤 7 中更新。

生成规则
  • 所有值均来自 design-tokens.json——绝不硬编码令牌文件中没有的值
  • 全程使用 snake_case——background_default、neutral_900、x4、radius_m
  • Primitives.qml 仅存放原始值——不包含语义含义。Theme.qml 仅存放语义令牌——始终引用 Primitives,绝不使用原始十六进制值
  • 根据 references/token-mapping.md 应用类型映射——颜色使用 readonly property color,尺寸使用 readonly property int,字体名称使用 readonly property string
  • 在每个文件顶部添加源注释和 CMake 说明
  • 使用区块注释对相关属性进行分组(// ── Section name ─────)
  • 如果 JSON 中缺少某个令牌,请添加 // TODO: <figmaName> 占位符,不要猜测值
  • 导入: 使用 import QtQuick——在 Qt 6 中,import QtQuick.Window 是多余的(Window 已包含在内),但添加后不会报错
  • 特效和渐变: 使用来自 import QtQuick.Effects 的 MultiEffect(从 Qt 6.5 开始提供)。绝不要使用 Qt5Compat.GraphicalEffects——它需要额外的兼容模块,且并非所有 Qt 6 配置都提供该模块
  • QML 编码技能: 如果有 qt-development-skills:qt-qml 技能,在生成 QML 文件时使用它,以确保采用正确的 Qt 6 模式

第 7 步 — 审核、修复 QML 并更新 CMakeLists.txt

生成所有 QML 文件后,运行验证流程——请勿跳过以下任何检查:

QML 验证:

  • 检查是否存在 // TODO: 占位符——将其标记出来,并询问用户如何解决
  • 验证每个属性类型是否符合 references/token-mapping.md 中的规则
  • 确认每个文件中都包含 pragma Singleton 和 import QtQuick
  • 检查是否有本应从令牌文件读取的值被硬编码

CMakeLists.txt — 必须更新:

请务必在此步骤中更新 CMakeLists.txt——不要留给用户处理。打开该文件,找到 qt_add_qml_module() 块,并确保所有生成的设计系统文件都列在 QML_FILES 下,且已通过 set_source_files_properties 注册。单例无法在 QML 中访问,最常见的原因就是这里配置不当。

命名规则: main.cpp 中的目标名称、URI 和 loadFromModule() 调用必须使用相同的项目名称字符串。使用 project() CMake 调用中的实际项目名称——不要直接使用 MyProject 作为名称。

cmake_minimum_required(VERSION 3.16)
project(<ProjectName> VERSION 0.1 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Version pin must match qt_standard_project_setup REQUIRES below
find_package(Qt6 6.5 REQUIRED COMPONENTS Quick)
qt_standard_project_setup(REQUIRES 6.5)

# MACOSX_BUNDLE is required on macOS — without it, qt_add_qml_module creates
# a directory named <ProjectName>/ which collides with the linker output file
# (EISDIR error). MACOSX_BUNDLE makes the output MyQtApp.app, no collision.
qt_add_executable(<ProjectName> MACOSX_BUNDLE
    main.cpp
)

set_source_files_properties(
    design-system/Primitives.qml
    design-system/Theme.qml
    design-system/Spacing.qml
    design-system/FontInterface.qml
    PROPERTIES QT_QML_SINGLETON_TYPE TRUE
)

qt_add_qml_module(<ProjectName>
    URI <ProjectName>
    VERSION 1.0
    QML_FILES
        Main.qml   # capital M — must match loadFromModule("<ProjectName>", "Main")
        design-system/Primitives.qml
        design-system/Theme.qml
        design-system/Spacing.qml
        design-system/FontInterface.qml
    # NOTE: do NOT add main.cpp here — it belongs only in qt_add_executable()
)

target_link_libraries(<ProjectName> PRIVATE Qt6::Quick)

将每个 <ProjectName> 替换为相同的字符串——例如 MyQtApp——使其与 project() 调用中的名称以及 main.cpp 中的 loadFromModule("<ProjectName>", "Main") 调用相匹配。

更新 CMakeLists.txt 后,向用户确认文件已保存,并向其演示如何在 Main.qml 中使用这些单例:

import QtQuick         // Window is part of QtQuick in Qt 6 — do NOT add import QtQuick.Window
import <ProjectName>   // imports all singletons from the module

Window {
    visible: true
    width: 640
    height: 480
    color: Theme.background_default
}

CMake 问题: 如果用户更新 CMakeLists.txt 后遇到构建错误,建议用户查阅 Qt 的 CMake 文档:https://doc.qt.io/qt-6/cmake-get-started.html,而不是在此处直接排查。


第 8 步 — 总结

简要总结,并请用户检查输出:

  • 各类别提取的令牌总数(颜色、间距、排版、圆角)
  • 已捕获的模式和主题
  • 任何尚未解决的别名或需要处理的 // TODO: 占位符
  • 生成的文件:design-tokens.json、Primitives.qml、Theme.qml、Spacing.qml、FontInterface.qml
  • 提醒用户:必须在 CMakeLists.txt 中为每个单例文件设置 set_source_files_properties(... QT_QML_SINGLETON_TYPE TRUE)
  • 使用本文末尾的令牌类别检查清单确认没有遗漏任何内容
  • 确认设计系统基础已准备就绪——现在可以开始组件生成技能

令牌类别检查清单

  • 基础颜色调色板(所有颜色系列和色阶)
  • 包含所有模式的语义颜色令牌(如有)
  • 字体系列(标题、正文、等宽)
  • 字重(数值:400/500/600/700)
  • 来自变量的字体尺寸阶梯(如果定义为变量,则包含每种角色对应的大小、字重和行高)
  • 文本样式(H1–H6、正文、标签、说明文字、代码——字体系列、大小、字重、行高、字母间距)
  • 间距阶梯(基础单位和所有命名步长)
  • 圆角(S、M、L、Full)
  • 阴影/海拔层级(如有)
  • 图标尺寸令牌(如有)
  • 动画/持续时间令牌(如有)

评论

支持 Markdown