内容
ThemeKit
> **原生、品牌中立的 SwiftUI 设计系统** — 117 个受令牌约束的组件,仅通过单个强调色即可重新皮肤:浅色/深色,按子树,每个核心依赖项为零。
[](https://githubamercan/ThemeKit/actions/workflows/ci.yml)


项](https://img.shields.io/badge/核心依赖项-0-success.svg)
[](LICENSE)
[](https://www/package/@isamercan/themekit-mcp)
**[文档](isamercan/ThemeKit/documentation/themekit) · [维基](https://github.com/isamercan/ThemeKit/wiki [npm (MCP)](https://www.npmjs.com/packageamercan/themekit-mcp) ·版本](https://githubamercan//releases) · [问题](https://github.com/isan/ThemeKit · [变更日志](CHANGE)**
<p align=" <img src="Screenshots/Banner.png" alt="ThemeKit — 原UI 设计系统:117 个组件,全令牌化化,SwiftLiquid Glass,浅色 + 深色" width="820">
</p>
>幅完全由 **ThemeKit 自身**(令牌 + 组件 — 与绘制画廊图块的同一个渲染管道。
一个主题驱动的、中立**UI 组件库。每个字体排版、间距、半径和阴影都是一个**设计令牌**,在运行时从活动的 `Theme整个 UI 可以从单个强调色重新皮肤 — 而无需触及组件代码。**不硬编码 — 交换主题内容都会跟随swift
import ThemeKit
功能
- 🎨 **Figma → Swift — MCP 的 `design` (别名 `figma_to_swift)将 Figma 节点转换为具有映射报告的匹配、已验证 API 的 ThemeKit 代码(请参见 — Figma → SwiftUI 和 MCP** 部分 🪄 **** — 将 Theme自由形式的 `design.md` (或捆绑样式 — Linear、、iOS、BrutPastel),重新皮肤 **每个以匹配,通过离线启解析器(选的 LLM 路径 🤖 **AI 原生** — 一个 24 工具 **MCP 服务器**,一个 Claude Code **代理技能**,和一个 **`llms.txt`** ,因此代理生成正确的、基于令牌的 UI — 所有这些都来自一个源。
- 🧩 **设计令牌无处不在** — 来自 JSON 的半径/间距,字体排版/阴影;一个语(`fg-herord-sm`),每个不同的值。
🌈 **33 个主题预设** — ThemeKit主题加上 32成的颜色集(daisyUI](httpsaisyui.com/docs/themes/) 启发),上的整个 Ant 色板都会重新着- 📸 ** + 渲染测试**每个组件都通过` 渲染为主题感知的 PNG;保护令牌、主题、验证和渲染。
-组件** — Atoms / Molecules / Organisms,所有这些都受令牌约束 **运行时主题化 一个 Swift 令牌生成器 + 一个实时配置任何强调色(base-100`)转换为设备上的完整 Ant调色板(无需需烘焙文件)。
- **验证**纯粹的、可谓词 + SwiftUI。
- **** — 动态减少动作在整个过程中受到尊重。
- **本地 — 默认英语字符串通过捆绑的字符串目录土耳其语默认字符串仍然可 **零依赖核心 Lottie 是一个可选独立的产品。
-C 目录**,一个一个测试套## 要求
|---|---|
| iOS · macOS 14| Swift 工具.2 |
项 | 无) · `lottie 4.4+ (仅 L插件) |
##Swift 包管理器。在 **Xcode** 中:*文件包依赖* 并输入存储,或将其添加到您的`:
dependencies: [
.package(url: "https.com/isamercanKit.git", "0.3"),
],
targets: [
.target(
name: "MyApp",
dependencies: [
.product(name: "ThemeKit", package: "ThemeKit"),
// 可选 — 仅当您需要 Lottie 支持的动画时:
// .product(name: "ThemeKitLottie", package: "ThemeKit"),
]
),
]
```
###| 产品 | 依赖途 |
| `Theme | 无 | 完整设计系统(核心) |
| `ThemeKitLottie` | `lottie-ios` | 添加 Lottie(After Effects / JSON)动画视图;仅在导入时拉取 |
## 快速在根目录安装使用令牌绑进行构建:
@main
App: App {
init() { Theme.shared.applyPersistedConfig() } 选:恢复上次使用的主题
var some Scene {
{
ContentView().themeKit() // 注入并在主题更改时重新绘制
}
}
}
struct ContentView: View {
@ThemeContext private var theme
: some View {
VStack(spacing: theme.spacing)) {
Text("欢迎").textStyle(.headingBase)
PrimaryButton("开始使用") { await signIn() }
.padding(theme.spacing(.base))
(theme.background(.Primary))
cornerRadius(.base)
.themeShadowated)
}
}
Theme.shared.loadTheme(named: // 运行时切换
```
##主题化
主题化不仅是一个全局开关 — Theme` 都可以注入到单个子树中theme(_:)`,内的每个组件皮肤为它。 `Theme.shared`全局状态;应用程序的其余部分保持其```swift
let Theme(); ocean.load: "oceanTheme")
let grape = Theme();(primaryHex: "#7C3AED 设备上生成Stack {
Booking // 应用程序主题
BookingCard(...).theme(ocean) // 海洋主题 — 此子树
(...).theme(grape // 葡萄主题 — 仅限此```
相同的组件,四个注入的主题,一个屏幕 — 品牌颜色跟随注入的主题,而语义颜色(信息,成功...)保持一致:
<p align="center"><img src="Screenshots/ThemeInjection.png" width="760" alt="在四个注入下渲染的相同排显示"></p>
每个组件都读取 `@.theme)` (Theme.shared`),因此这是附加的并且向后兼容。 在画廊主题注入** 页面用。
##预设
Theme 33 个主题预设 — **默认** 加上 **32 个受 [daisyUI](https://.com/docs/themes启发的颜色集** (cupcake,dracyberpunk,wave,nord,)。每个都是一个Preset` 配方:色为整个 Ant 样式调色着色,其 `base-100` 成为表面色调,因此每个主题都独特的外观 — **cupcake 保持色,cyber色,dracula 板岩**。 相同的组件,四个注入的主题:
<p align="center"><="ScreenshotsShowcase.png" width="820" alt="在四个主题预设的相同的 ThemeKit 组件 — Cupcake,Syn,Cyberpunk 和 Nord"></p>
实时应用一个,或将捆绑ThemePicker`** 放入任何屏幕以进行主题切换(它是在演示应用程序的 **主题** 选项卡中):
```swift
ThemePreset.named("")?.apply()实时重新着.shared
@State active: String? = "cupcake"
ThemePicker(selection: $active) // 所有 33 个主题的可点击网格
```
<p align="center"><img src="Screenshots/ThemePresets.png" width" alt="ThemePicker 33 个主题预设的网格片都以其自己的颜色绘制"></p>
## 截图
设备上的演示应用程序 — 组件目录,化,设计令廊以及使用 组件完全构建的完整预订流程。
<table>
<tr>
<td align="center" valign="top"25%"><img src="Screenshots/app-components.png" width="185" alt="组件目录屏幕"><br><sub><b>组件目录</b></sub></td>
<td align="center" valign="top" width="25%"><img src="Screenshots/app-the" width="185" alt="实时"><br><b> · 33 个预设</sub></td>
="center" valign=" width="25%"><img src="Screenshots/app-colors.png" width alt="设计廊屏幕"><brb>画廊</b></sub></td="center"" width="img src="S-theme-generator.png="185" alt生成器屏幕"><sub><b>器</b></sub></td>
</<tr>
<td align" valign="top"25%"><imgScreenshots/app-button.png" width="185按钮组件演示><sub><b>按钮 · 变体</sub></td>
="center" valign="top" width%"><img src="Screenshots/app-datatable.png" width="185" alt="数据表组件演示><sub><b>数据表 · 排序/分页</b></sub></td>
<td align="center" valign="top" width="25%"><img src="Screenshots/app-example.png" width="185"示例应用程序 — 酒店搜索"><br><sub><b>示例 · 搜索</b></sub></td>
<td align="center" valign="top" width="25%"><img src="Screenshots/app-hotel" width="185" alt=" 酒店详情><sub><b · 详情</b></sub></td>
>
</table 来自捆 [演示](# 应用程序的真实屏幕 — 每个读取实时设计令牌Kit 组件。
## 组件
117 个牌约束的组件,按复杂性分组:
原子** (29)— `Badge` , `Chip` , `Avatar` , `Icon` , `Rating` , `Spinner` ,
`StatusDot` , `Skeleton` , `ProgressBar` , ` , `RollingNumber` ...
- **分子** (45)— `TextInput` , `OTPInput` , `Select` , `Checkbox` ,
`RadioGroup` ,` , `Range , `SearchBar` , `Tooltip` ,按钮...
- ** (43)—` , `Carousel `DataTable` , `Accordion` ,` ,
`Timeline` , `Result , `Upload`Tour` , `` , `` ...
每个组件都在C 目录](# 中按类别## 组件画廊库中ImageRenderer` 渲染 `<img>`任何地方都,包括 GitHub )—
使用 `make screenshots` 重新式叠加层(Dialog,Drawer,
BottomSheet ...)和媒体组件最好在 [演示应用程序](#demo实时查看。
<!--ERY:START -->
### 原子
<table>
<td align=" valign="top="33%"><img src="Screenshots/Avatar.png" width="184="头像"><br><b>头像</b></sub></<td align=" valign="top"%"><img src="Screenshots/Badge width="223" alt="徽章"><sub><b>徽章</b></td>
<td align="center" valign="top" width="33%"><="Screenshots/" width="233" alt="芯片"><sub><b>芯片</b></sub>
</tr>
<tr>
<td align=" valign="top"33%"><img src="Screenshots/CountBadge.png" width="68" alt="计数徽章><sub><b>计数徽章</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Divider.png" width="240" alt="分割线"><br><sub><b>分割线</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Icon.png" width="182" alt="图标"><br><sub><b>图标</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/Indicator.png" width="68" alt="指示器"><br><sub><b>指示器</b></sub></td>
<td align" valign="top" width="33%"><="Screenshots/InputLabel.png" width="93="输入标签"><br><sub><b>输入标签</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Kbd.png" width alt="键"><br><b>键盘快捷键</b></sub></td>
</tr>
<tr align="center" valign="top" width="33%"><img src="Screenshots/ProgressBar.png" width="240" alt="进度条"><br><sub><b>进度条</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/RadialProgress.png" width="128" alt="径向进度条"><br><sub><b>径向</b></sub></td>
<td align="center" valign="top" width="33%"><="Screenshots/Rating.png" width="184" alt="评分><sub><b>b></sub></td>
</<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/RollingNumber.png" width="138" alt"><br><sub><b>滚动数字</b></sub></td>
<td align="="top="33%"><img src="Screenshots/ScoreBadge.png" width="64" alt="分数徽章"><br><sub><b>分数徽章</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Skeleton.png" width="240" alt="骨架屏"><br><sub><b>骨架屏</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/Spinner.png" width="64" alt="加载动画"><br><sub><b>加载动画</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/StatusDot.png" width="211" alt="状态点"><br><sub><b>状态点</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Swap.png" width="72" alt="交换"><br><sub><b>交换</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/Tag.png" width="201" alt="标签"><br><sub><b>标签</b></sub></td>
<td align="center" valign="top" width="33%"><img src="/TextLink.png"161" alt"><br><sub><b></b></sub></td>
<td align=" valign="top" width="33%"><="Screenshots/Title.png" width" alt="height"><br><sub><b>标题</b></sub></td>
</tr>
<tr align="center" valign=" width="33%"><img src="/InlineText.png" width="240" alt="内联文本"><br><b>内联文本</sub></td>
<td align=" valign="top" width="33 src="Screenshots/BorderBeam.png" width="232" alt="边框br><sub><b>边框束</b></sub></td>
<td align="center" valign="top="33%"><img src="SJoin.png" width="234"连接"><br><sub><b</b></sub></td>
>
<tr>
<td align="=" width="33 src="Screenshots/Mask.png="240" alt="遮罩"><br><sub><b>遮罩</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/TextRotate.png" width="177" alt="文本旋转"><br><sub><b>文本旋转</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Ga width="240" alt盘"><br><sub><仪表盘</b></sub></td>
</tr>
<tr>
<td" valign="top" width="33%"><img src="Screenshots/ShareButton.png" width="146"分享按钮"><br><sub><分享按钮</b></sub></td>
</tr>
</table>
### 分子
<table>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/Button.png" width="240" alt="按钮"><br><sub><b>按钮</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/ThemeButton.png" width="240" alt="主题按钮"><br><sub><b>主题按钮</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Checkbox.png" width="212" alt="复选框"><br><sub><b>复选框</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/CheckboxGroup.png" width="240" alt="复选框组"><br><sub><b>复选框组</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/RadioButton.png" width="171" alt="单选按钮"><br><sub><b>单选按钮</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/RadioGroup.png" width="240" alt="单选按钮组"><br><sub><b>单选按钮组</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/ToggleGroup.png" width="72" alt="切换组"><br><sub><b>切换组</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/ThemeToggle.png" width="128" alt="主题切换"><br><sub><b>主题切换</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/SegmentedControl.png" width="240" alt="分段控件"><br><sub><b>分段控件</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/QuantityStepper.png" width="168" alt="数量步进器"><br><sub><b>数量步进器</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Stat.png" width="240" alt="统计"><br><sub><b>统计</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Steps.png" width="240" alt="步骤"><br><sub><b>步骤</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/Slider.png" width="240" alt="滑块"><br><sub><b>滑块</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Breadcrumbs.png" width="240" alt="面包屑"><br><sub><b>面包屑</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/TextInput.png" width="240" alt="文本输入"><br><sub><b>文本输入</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/FileInput.png" width="240" alt="文件输入"><br><sub><b>文件输入</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Pagination.png" width="240" alt="分页"><br><sub><b>分页</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Fieldset.png" width="240" alt="字段集"><br><sub><b>字段集</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/DateField.png" width="240" alt="日期字段"><br><sub><b>日期字段</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Select.png" width="240" alt="选择"><br><sub><b>选择</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/MultiSelect.png" width="240" alt="多选"><br><sub><b>多选</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/TreeSelect.png" width="240" alt="树形选择"><br><sub><b>树形选择</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Autocomplete.png" width="240" alt="自动补全"><br><sub><b>自动补全</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/SearchBar.png" width="240" alt="搜索栏"><br><sub><b>搜索栏</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/OTPInput.png" width="240" alt="OTP输入"><br><sub><b>OTP输入</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/InputNumber.png" width="240" alt="数字输入"><br><sub><b>数字输入</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/RangeSlider.png" width="240" alt="范围滑块"><br><sub><b>范围滑块</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/MultiLineTextInput.png" width="240" alt="多行文本输入"><br><sub><b>多行文本输入</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Tooltip.png" width="60" alt="提示"><br><sub><b>提示</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Chips.png" width="132" alt="芯片"><br><sub><b>芯片</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/FilterGroup.png" width="240" alt="过滤组"><br><sub><b>过滤组</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/ProgressIndicator.png" width="240" alt="进度指示器"><br><sub><b>进度指示器</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/ThemeController.png" width="240" alt="主题控制器"><br><sub><b>主题控制器</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/Calendar.png" width="240" alt="日历"><br><sub><b>日历</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/ColorField.png" width="240" alt="颜色字段"><br><sub><b>颜色字段</b></sub></td>
</tr>
</table>
### 有机体
<table>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/Accordion.png" width="240" alt="折叠面板"><br><sub><b>折叠面板</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/AlertToast.png" width="240" alt="警报提示"><br><sub><b>警报提示</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Callout.png" width="240" alt="标注"><br><sub><b>标注</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/Card.png" width="240" alt="卡片"><br><sub><b>卡片</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/ChatBubble.png" width="240" alt="聊天气泡"><br><sub><b>聊天气泡</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Counter.png" width="172" alt="计数器"><br><sub><b>计数器</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/Coupon.png" width="240" alt="优惠券"><br><sub><b>优惠券</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/EmptyState.png" width="240" alt="空状态"><br><sub><b>空状态</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/InfoBanner.png" width="240" alt="信息横幅"><br><sub><b>信息横幅</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/KeyValueTable.png" width="240" alt="键值表格"><br><sub><b>键值表格</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/ListRow.png" width="240" alt="列表行"><br><sub><b>列表行</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/NotificationCard.png" width="240" alt="通知卡片"><br><sub><b>通知卡片</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/PageHeader.png" width="240" alt="页面头部"><br><sub><b>页面头部</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/RatingSummary.png" width="240" alt="评分摘要"><br><sub><b>评分摘要</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/ResultView.png" width="240" alt="结果视图"><br><sub><b>结果视图</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/SegmentedTabBar.png" width="240" alt="分段标签栏"><br><sub><b>分段标签栏</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Timeline.png" width="240" alt="时间线"><br><sub><b>时间线</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Upload.png" width="240" alt="上传"><br><sub><b>上传</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/PromoBanner.png" width="240" alt="促销横幅"><br><sub><b>促销横幅</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/ListView.png" width="240" alt="列表视图"><br><sub><b>列表视图</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/MenuCard.png" width="240" alt="菜单卡片"><br><sub><b>菜单卡片</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/NavigationBar.png" width="240" alt="导航栏"><br><sub><b>导航栏</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/FAB.png" width="88" alt="浮动操作按钮"><br><sub><b>浮动操作按钮</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Hero.png" width="240" alt="英雄"><br><sub><b>英雄</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/SelectionCards.png" width="240" alt="选择卡片"><br><sub><b>选择卡片</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/CardStack.png" width="240" alt="卡片堆栈"><br><sub><b>卡片堆栈</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Gallery.png" width="240" alt="画廊"><br><sub><b>画廊</b></sub></td>
</tr>
<tr>
<td align="center" valign="top" width="33%"><img src="Screenshots/Footer.png" width="240" alt="页脚"><br><sub><b>页脚</b></sub></td>
<td align="center" valign="top" width="33%"><img src="Screenshots/Diff.png" width="240" alt="差异"><br><sub><b>差异</b></sub></td>
</tr>
</table>
### 覆盖层(动画)
_入口预览由实时组件渲染。从 live components 中选择 SelectBox、BottomSheet、Tour 和 Feedback 使用 OS 拥有的演示(原生 Menu / .sheet),这些演示无法被离屏渲染器捕获 — 使用 `make record-gif NAME=SelectBox` 记录它们(启动模拟器,您点击打开下拉菜单;参见 [docs/SCREENSHOTS.md](docs/SCREENSHOTS.md))。_
<table>
<tr>
<td align="center" width="33%"><img src="Screenshots/Dialog.gif" width="260" alt="对话框"><br><sub><b>对话框</b></sub></td>
<td align="center" width="33%"><img src="Screenshots/Drawer.gif" width="260" alt="抽屉"><br><sub><b>抽屉</b></sub></td>
<td align="center" width="33%"><img src="Screenshots/Popconfirm.gif" width="260" alt="弹出确认"><br><sub><b>弹出确认</b></sub></td>
</tr>
<tr>
<td align="center" width="33%"><img src="Screenshots/AlertToast.gif" width="260" alt="警报提示"><br><sub><b>警报提示</b></sub></td>
<td align="center" width="33%"><img src="Screenshots/Tooltip.gif" width="260" alt="提示"><br><sub><b>提示</b></sub></td>
</tr>
</table>
<!-- GALLERY:END -->
## 标记系统
```
Sources/ThemeKit/
├─ Theme/ # Theme.shared, tokens, generator, configurator API
│ ├─ Theme.swift # ObservableObject singleton (Theme.shared)
│ ├─ ColorTokens.generated.swift # Foreground/Background/Border/Text color keys
│ ├─ ThemeModel.swift # RadiusKey / SpacingKey
│ ├─ Typography.swift # TextStyle ramp (Montserrat, Dynamic Type)
│ ├─ Shadows.swift # ShadowStyle + .themeShadow()
│ ├─ SemanticColor.swift # named palette colors
│ ├─ ThemeGenerator.swift # runtime palette generator (Swift port)
│ ├─ ThemeConfig.swift # Codable theme recipe
│ ├─ ThemeKit.swift # .themeKit() root modifier
│ ├─ ThemeContext.swift # @ThemeContext property wrapper
│ └─ ThemedHostingController.swift
├─ Components/ # Atoms / Molecules / Organisms (all token-bound)
├─ Validation/ # Validators / ValidationRule / Validator / InfoMessage
├─ Accessibility/ # Reduce Motion + Dynamic Type helpers
├─ Extensions/ # Color(hex:), AspectRatio, Motion, Grid
├─ Utils/ # Haptics, Impression, Localization bridge
├─ Documentation.docc/ # DocC catalog
└─ Resources/
├─ *.json # defaultTheme / oceanTheme / sunsetTheme (+ Dark)
├─ Localizable.xcstrings # String Catalog (en source + tr)
└─ Fonts/Montserrat.ttf # bundled, registered at runtime
```
### 标记组
| 组 | 真实来源 | 键 |
|---|---|---|
| 颜色 | `Resources/*.json` | `Theme.ForegroundColorKey` · `BackgroundColorKey` · `BorderColorKey` · `TextColorKey` |
| 圆角 | `Resources/*.json` | `Theme.RadiusKey` (`rd-xs`…`rd-4xl`) |
| 间距 | `Resources/*.json` | `Theme.SpacingKey` (`sp-xs`…`sp-4xl`) |
| 字体排版 | 代码 (`Typography.swift`) | `TextStyle` — Display / Heading / Label / Body / Overline / Link |
| 阴影 | 代码 (`Shadows.swift`) | `ShadowStyle` — elevated / tabBar / soft |
颜色 / 圆角 / 间距因主题(JSON)而异。字体排版和阴影在不同主题中保持一致。
## 主题
`default` (蓝色) · `ocean` (青绿色) · `sunset` (橙色) — 每个主题都有一个深色变体。**标记名称**是语义化的;只有值因主题而异。添加主题只需将 `<name>Theme.json` 文件放入 `Resources/` 目录中。
## 自定义应用主题(配置器导出)
库中包含一个**运行时标记生成器** (`ThemeGenerator`,`tools/gen_tokens.py` 的 Swift 端口):从少量输入中,它重新生成整个调色板、中性色阶、表面、边框、文本和圆角/间距/字体/阴影坡道 — 在设备上,无需 Python 和预先烘焙的调色板文件。
Demo 的 **主题配置器** (颜色选项卡)允许您调整一个强调色 + 色调 + 缩放旋钮 + 字体 + 深色,并导出一个 `ThemeConfig` 配置文件。要应用一个:
```swift
// a) 一行代码(粘贴配置器的“应用 (Swift)”导出)
Theme.shared.applyGenerated(primaryHex: "ff0d87", tint: 0.13, radiusScale: 1.0, font: "Montserrat")
// b) 将可编码的配置文件作为资源(配置器的 `theme.json`)
let cfg = try ThemeConfig(jsonData: Data(contentsOf: themeJSONURL))
Theme.shared.apply(cfg)
Theme.shared.persistConfig() // 记住启动之间的配置
// c) 无生成器:捆绑预先烘焙的标记 JSON(“复制完整标记 JSON”)
Theme.shared.setTheme(jsonData: Data(contentsOf: tokensURL))
```
`ThemeConfig` 是 `Codable` / `Sendable` / `Equatable` — 保留它,同步它,A/B 测试它。
### 实时主题工作原理
组件从 `Theme.shared` 单例中解析标记(无需每次调用的环境查找),因此 SwiftUI 无法推断任意视图是否依赖于主题。`.themeKit()` 弥补了这一缺陷:它将 `Theme` 注入环境中**并且**(默认情况下)在主题更改时重新构建子树,其键控于 `Theme.revision`,因此每个视图都重新读取生成的标记。
- 从**设置屏幕**切换主题 → 保留默认设置(`reactToRuntimeChanges: true`);整个 UI 都重新绘制。
- 在会话期间编辑主题(实时编辑器/检查器)→ 使用 `.themeKit(reactToRuntimeChanges: false)`,以便编辑器不会被拆除,并且只将 `.id(Theme.shared.revision)` 作用域到实时预览子树。
### 子树主题 (`\.theme`)
组件还从 `\.theme` 环境值中读取主题,该值**默认为 `Theme.shared`** (因此未主题化的组件永远不会崩溃)。注入一个不同的 `Theme` 实例以重新主题化一个分支 — 一个屏幕中的第二个品牌或预览/快照中的固定主题 — 而无需修改全局状态:
```swift
SomeComponent()
.theme(brandBTheme) // 仅限此子树
```
此功能正在迁移:试点组件 (`Card`, `Tag`) 今日读取 `\.theme`;其余组件仍直接读取 `Theme.shared` 并逐渐迁移。
### 字体
`Montserrat` 字体已捆绑。`System` / `SystemRounded` / `SystemSerif` / `SystemMono` 无需其他操作。其他字体家族必须由宿主应用注册(添加 `.ttf` + `UIAppFonts`),然后将 PostScript 家族名称作为 `font:` 传递。
## 无障碍
- **动态字体** — 字体坡道根据用户的首选文本大小缩放:每个 `TextStyle` 都通过 `relativeTo:` 锚定到语义 `Font.TextStyle`。在默认大小下,无需更改;仅当用户选择时才增长/缩小。按屏幕限制(如果需要):`MyScreen().dynamicTypeSize(...DynamicTypeSize.accessibility2)`。
- **减少动画** — 装饰性/连续动画被抑制,而功能性动画被保留:`BorderBeam`、`Skeleton`、`RollingNumber`、`StatusDot`、`Carousel` 自动播放,OTP 光标全部平息;`Spinner` 继续旋转。
无需调用者配置 — 组件直接读取环境。
## 验证
一个纯逻辑层(无 SwiftUI,无主题)加一个单独的表示层:
```swift
let messages = Validator.validate(email, [.required(), .email()]) // [InfoMessage]
InfoMessageList(messages) // SwiftUI 渲染
```
馈送您自己的逻辑 — 自定义谓词、正则表达式、类型化 `Regex` 或异步(服务器端)检查:
```swift
.regex("^[a-z]+$", caseInsensitive: true, "仅限字母")
ValidationRule("仅限 AAA") { $0 == "AAA" }
let unique = AsyncValidationRule("用户名已占用") { await api.isAvailable($0) }
```
`FormValidator` 将字段、规则、焦点和消息绑定在一起以获取整个表单。
## 本地化
用户界面默认字符串(验证消息、占位符、辅助功能标签...)来自捆绑的 **字符串目录** (`Resources/Localizable.xcstrings`)。源语言是 **英语**;还提供 **土耳其** 翻译,消费者可以添加自己的。
每个此类字符串也可通过 API 参数**覆盖** — 例如 `ValidationRule.required("自定义消息")` — 因此目录仅提供默认设置。
> 注意:普通的 `swift build` 复制 `.xcstrings` 文件原样(SwiftPM CLI **不运行**目录编译器),因此仅英语在那里解析。Xcode / `xcodebuild` 编译它,因此所有捆绑的本地化在真正的应用程序中解析。
## ⭐ 高级 — Figma → SwiftUI & MCP
ThemeKit 构建于 AI 辅助工作流之上,因此生成的 UI 使用**正确**的组件 + 修饰符,并从令牌中解析颜色,而非硬编码值。一个源(`make skill`)供给三个界面,因此它们不会与代码偏离:
| 界面 | 功能 | 使用方法 |
|---|---|---|
| **MCP 服务器** ([`mcp/`](mcp/)) | 24 个按需工具 — `get_component_api`、`get_design_tokens`、`search_components`、`validate_code`、`a11y_audit`、`compose_screen`、`diff_theme`、`render_preview`、`theme_preview`、`scaffold_screen`、`design_to_code`(别名 `figma_to_swiftui`)… — 代理拉取聚焦、验证的上下文,同时进行编码。 | `claude mcp add themekit -- npx -y @isamercan/themekit-mcp`(或从仓库:`cd mcp && npm i && npm run build`)。在任何 MCP 编辑器中都有效 — Cursor、Windsurf、Claude Code。 |
| **代理技能** ([`skills/themekit/`](skills/themekit/)) | 一个 Claude Code 技能:习语 + 模式,每个组件的初始化和修饰符,主题预设 — 生成正确的 ThemeKit 代码。 | `/plugin marketplace add isamercan/ThemeKit` → `/plugin install themekit@themekit`,**或**复制 `skills/themekit/` 到 `.claude/skills/`(零安装)。 |
| **`llms.txt`** | 关于每个组件、修饰符和主题的结构化 LLM 上下文 — [llms.txt](https://llmstxt.org) 标准,在仓库根目录。 | 指向任何 `llms.txt` 感知的编辑器(Cursor、Windsurf、Copilot…)到 [`llms.txt`](llms.txt)。 |
然后只需询问:*"构建一个注册屏幕。使用 ThemeKit 技能。"* 与 **Claude Code、Cursor、Windsurf、GitHub Copilot** 和任何支持 MCP 或 `llms.txt` 的工具一起使用。
### Figma → SwiftUI
明星工具,`design_to_code`(别名 `figma_to_swiftui`),将 Figma 节点转换为 ThemeKit SwiftUI,具有**验证**的 API 而不是猜测:它将填充 / 间距 / 半径快照到设计令牌,将节点映射到组件(通过 `figma-mapping.json` 配置驱动,然后是启发式),并返回代码和映射报告。未映射的节点被标记 — 从不静默丢弃。
```text
Card {
VStack(spacing: Theme.SpacingKey.md.value) {
Badge("Sale").badgeStyle(.error)
PrimaryButton("Continue") { }
// ⚠️ 未映射:Mystery Widget(INSTANCE)
}
}
// 3/4 节点映射 · 填充 #f04438 → fg-error(ΔE 0.0)· 项目间距 16 → sp-md
```
在 MCP 服务器的环境中设置 `FIGMA_TOKEN` — 这是**可选**的,只有此工具需要它;所有其他工具都无需它。有关完整的工具列表和 `figma-mapping.json` 架构,请参见 [`mcp/README.md`](mcp/README.md)。
**触发它** — 粘贴 Figma 链接并询问代理;它直接从 URL 中拉取 `fileKey` + `nodeId`(URL 中的 `node-id=25795-9030` 变成 `25795:9030`):
```text
使用 themekit MCP。将此 Figma 节点转换为 ThemeKit SwiftUI:
https://www.figma.com/design/<FILE_KEY>/App?node-id=<NODE-ID>
```
或显式命名工具,以便代理直接选择它(当配置了多个 MCP 服务器时很有用):
```text
连接 themekit MCP 并使用此 URL 调用 design_to_code:
https://www.figma.com/design/<FILE_KEY>/App?node-id=<NODE-ID>
```
指向**单个屏幕/帧** — 它将 Figma 组件 `INSTANCE` 视为不透明的叶子,不会扩展嵌套实例的板(参见 [`mcp/README.md`](mcp/README.md#how-to-trigger-it-from-chat))。
## 文档
📖 **实时文档:[isamercan.github.io/ThemeKit](https://isamercan.github.io/ThemeKit/documentation/themekit)** — DocC 目录,从 `main` 在每次推送后发布。
📚 **[Wiki](https://github.com/isamercan/ThemeKit/wiki)** — 安装、FAQ、故障排除、版本控制和贡献指南。
一个 DocC 目录随软件包一起提供(`Sources/ThemeKit/Documentation.docc`)。在 Xcode 中通过 **Product ▸ Build Documentation**(⌃⌘D)或命令行构建它:
```sh
xcodebuild docbuild -scheme ThemeKit -destination 'generic/platform=iOS'
```
它按类别整理每个组件,并包括 **Theming**、**Accessibility** 和 **Validation** 的指南文章。无需额外依赖。
## 演示
`Demo/` — 一个 SwiftUI 应用(本地软件包引用)包含 **Components**(画廊)、**Themes**(`ThemePicker` + 实时预览)、**Colors**(令牌画廊 + 实时主题配置器)、**Type**、**Layout**(间距 / 半径 / 阴影令牌)和 **Example**(从真实组件构建的完整流程),以及一个浅色/深色切换器。
## 添加/更新令牌
颜色生成以保持 JSON ↔ Swift 同步:
1. 更新 `tools/gen_tokens.py` 中的令牌映射。
2. 重新运行:`python3 tools/gen_tokens.py .`(重新生成 `Resources/*.json` + `ColorTokens.generated.swift`)。
半径/间距位于 `Resources/*.json`(+ `RadiusKey` / `SpacingKey` 枚举); typography / shadows 在 `Typography.swift` / `Shadows.swift` 中。
## 测试
```sh
swift test
```
测试套件涵盖令牌生成器、每个捆绑主题的主题完整性、验证、本地化、辅助功能映射和组件渲染烟雾测试。
## 路线图
- **子树 `.theme` 迁移** — 试点组件(`Card`、`Tag`)今天读取 `.theme`;其余部分正在逐步迁移,以便任何子树都可以重新主题化,而无需触摸 `Theme.shared`。
- **API 稳定到 `1.0`** — 公共 API 仍在 `0.x`;在那之前,次要版本可能包含破坏性更改(参见 [Versions & Releases](https://github.com/isamercan/ThemeKit/wiki/Versions-and-Releases) wiki)。
<!-- 在此处添加即将到来的组件、平台或 API 里程碑。 -->
> **已交付:** 软件包是公开的(MIT),MCP 服务器在 npm 上(`@isamercan/themekit-mcp`),Claude Code 插件可安装(`/plugin marketplace add isamercan/ThemeKit`),DocC 文档实时。
## 贡献
```sh
make ci # 格式化-lint + lint + 构建 + 测试(完整的关卡)
swift test # 测试套件
make screenshots # 重新渲染组件 PNG + 重建 README 画廊
make skill # 重新生成 MCP 数据、代理技能和 llms.txt
```
颜色生成 — 编辑 `tools/gen_tokens.py`,然后 `python3 tools/gen_tokens.py .`(参见 [添加/更新令牌](#添加--更新令牌))。保持构建和测试绿色;预推送钩子运行相同的关卡。
## 许可证
[MIT](LICENSE) © 2026 İsa Mercan。免费用于商业和私人使用 — 保留版权声明;软件不提供任何保证。
## 致谢
- **主题预设** — 32 个内置颜色集灵感来自 [daisyUI](https://daisyui.com/docs/themes/)。
- **调色板** — 遵循 Ant Design 风格的色调缩放。
- **Montserrat** — 捆绑的字体家族(SIL Open Font License)。
- **Lottie** ([`lottie-ios`](https://github.com/airbnb/lottie-ios)) — 为可选的 `ThemeKitLottie` 插件提供支持。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器