
Unkey Design 设计系统文档站基于 Blume 的 UI 组件库与页面模式文档工程实践【免费下载链接】unkeyThe Developer Platform for Modern APIs项目地址: https://gitcode.com/GitHub_Trending/un/unkey本文以 Unkey 仓库中的unkey/design设计文档站点web/apps/design/README.md为核心系统讲解这一基于 Blume 构建的设计系统文档站的架构、运行方式、目录布局与扩展流程。它实时导入web/internal/ui下的unkey/ui组件并通过 iframe 预览机制保证文档展示与真实仪表盘渲染完全一致。读完本文你将掌握如何启动该文档站、理解其文件组织与路由规则、为任意 UI 原语新增文档页面以及如何维护preview.css与仪表盘样式之间的 token 同步让设计文档始终呈现所见即所得的组件效果。一、项目定位为 Unkey UI 原语与页面模式服务的文档站unkey/design是 Unkey 前端工作区web/中的一个独立文档应用专门承载 Unkey 的 UI 原语primitives与页面模式page patterns设计文档。它的核心设计决策有两点构建工具采用 Blume一个面向组件库与设计系统文档场景的文档框架。站点标题、Logo、主题、示例目录等均由 blume.config.ts 统一配置。组件直接来自真实源码站点通过unkey/uiworkspace 依赖指向 web/internal/ui导入组件因此文档站始终渲染它所在 checkout 中真实的组件版本文档与组件实现天然保持同步不会出现文档过期的问题。这一点在 package.json 中体现得很直接unkey/ui: workspace:^、unkey/icons: workspace:^配合fontsource-variable/geist与fontsource-variable/geist-mono字体、React 19共同构成站点运行依赖。二、运行与构建本地开发、端口注入与隔离构建启动开发服务器在仓库根目录执行pnpm --dirweb/apps/design devdev脚本读取PORT与HOST两个环境变量见 package.json 中的脚本定义dev: blume dev --port ${PORT:-4321} --host ${HOST:-localhost}也就是说默认监听localhost:4321但可以通过PORT3000 HOST0.0.0.0 pnpm --dirweb/apps/design dev覆盖。README 特别强调这使代理proxy可以把文档站挂到自己的主机名下方便接入内网或预览环境。构建与 dev server 的冲突pnpm build即blume build拒绝在 dev server 运行期间执行因为两者都会写入同一份生成的.blume/运行时目录同时写入会互相破坏。如果不想停掉 dev server 又想验证构建产物README 给出的替代方案是./node_modules/.bin/blume build --isolated--isolated模式会把产物写到独立的.blume-verify/目录不会发布任何内容仅用于本地验证构建是否可成功。另外 package.json 还提供了pnpm previewblume preview预览已构建产物与pnpm doctorblume doctor检查站点配置健康状态两个辅助脚本。三、目录布局一份文件一份职责README 给出了清晰的顶层文件职责划分blume.config.ts 站点配置title、logo、theme、examples 目录 theme.css 文档外壳docs chrome的设计 token preview.css 注入到每个预览 iframe 的 token docs/section/meta.ts 侧边栏分组标题、图标、页面顺序 docs/section/name.mdx 一个文档页面 examples/name/example.tsx 一个实时示例default export路由规则页面的路由就是它在docs/下的路径。例如docs/primitives/skeleton.mdx会被服务为/primitives/skeleton。站点内容根目录在 blume.config.ts 中通过content.root: docs指定示例源码目录通过examples.source: examples指定。当前仓库中实际存在的章节如下章节目录分组名图标现有页面docs/primitives/Primitivesboxalert-banner、item、resource-list、settings-card、skeletondocs/charts/Chartsgaugemeterdocs/patterns/Patternslayout-templatelayout、resource-list-page、settings-group每个章节的meta.ts通过defineMeta声明分组标题、图标与pages顺序数组。例如 docs/primitives/meta.tsimport { defineMeta } from blume; export default defineMeta({ title: Primitives, icon: box, order: 1, pages: [alert-banner, item, resource-list, settings-card, skeleton], });docs/index.mdx作为总览页用 CardGroup 将 Primitives 与 Patterns 两个入口并列展示docs/index.mdx。四、新增一个文档页面四步标准流程README 把新增页面归纳为四个步骤下面结合仓库中的实际示例以 Skeleton 原语为例逐一展开。步骤 1创建 MDX 页面新建docs/section/name.mdx。Frontmatter 中的title会成为页面的h1description会成为导语段落因此不要在正文里重复这两者。看 docs/primitives/skeleton.mdx 的头部--- title: Skeleton description: Used to show a placeholder while content is loading. ---正文则直接进入## Usage等小节不再重复标题。步骤 2创建默认导出的示例文件创建examples/name/basic.tsx必须有 default export。更多变体可以作为同目录下的兄弟文件继续添加。仓库中 examples/skeleton/ 就有basic.tsx、card.tsx、list.tsx三个示例对应页面上的 Basic / Card / List 三块演示。示例本身就是一个普通的 React 组件例如 examples/skeleton/basic.tsximport { Skeleton } from unkey/ui; export default function BasicSkeleton() { return ( div classNameflex justify-center Skeleton classNameh-4 w-32 / /div ); }步骤 3用Component /引用示例在 MDX 中用Component pathname/basic /引用。Blume 会把该文件同时渲染为实时预览与代码标签页因此预览与代码天然不会漂移。例如 skeleton.mdx 中的Component pathskeleton/basic /页面其余小节Card、List 示例同样用Component pathskeleton/card /、Component pathskeleton/list /引用。步骤 4登记到pages数组把 slug 加入docs/section/meta.ts的pages数组。即使漏加页面也会出现只是排在已登记页面之后。无需 import 的内置组件Blume 在任意.mdx文件中直接提供Card、CardGroup、Steps、Tabs、Badge、FileTree、Accordion、CodeGroup、TypeTable等文档排版组件无需任何 import。这一点在docs/index.mdx中就有实际应用CardGroup cols{2}与Card title... href... icon...。五、Previews 是 iframetoken 同步机制与边界行为这是整个文档站最精巧的机制README 专门用一节讲解值得深入展开。为什么用 iframe每个示例都渲染在独立的 iframe中文档站的样式表永远不会作用到 iframe 内部。因此示例的观感完全取决于注入到 iframe 的preview.css—— 它是示例组件唯一的设计 token 来源。preview.css特意镜像了仪表盘的 token 层使预览呈现的效果与web/apps/dashboard/styles/tailwind.css一致预览展示什么仪表盘就长什么样。两条必须遵守的规则由iframe preview.css 作为唯一 token 源可以推出两条维护规则unkey/ui的类只有被preview.css声明source后才会生成规则。由于unkey/ui位于本应用目录之外Tailwind 默认不会扫描它。preview.css 中通过两条互补的source声明覆盖不同构建深度下的路径解析source ../../internal/ui/src/**/*.tsx; source ../../../../../internal/ui/src/**/*.tsx;注释中解释了原因Blume 会把该文件内联进.blume/src/generated/examples.css同一个目录在不同深度下命名不同两条中解析失败的那条会被忽略从而保证 Tailwind 总能扫到web/internal/ui/src下的组件源码。新的源码路径应当加在这里而不是theme.css。仪表盘tailwind.css里新增的语义 token 必须同步复制进preview.css否则预览会把它渲染成什么都没有。这正是 preview.css 长得如此之长的原因它把 Radix 色阶gray/accent/success/warning/error/info/feature/orange/red/grass/blue 等 1–12 档从unkey/ui/colors.css引入再经由theme映射为 Tailwind 的--color-*语义变量同时声明了:root与.dark两套 HSL 语义值--background、--content、--brand、--border等并补充了 Sonner toast 相关变量与marquee、shimmer、error-blink等动画。边界行为窄视口下的响应式预览iframe 的视口宽度等于内容列的宽度低于md断点。因此一个带有md:前缀响应式类的组件在预览中展示的是它的窄屏布局。设计时要把这一点当作特性而非缺陷预览天然代表移动端/窄列表现恰好可以检查组件在内容列宽度下的可读性。preview.css中的其他细节[data-blume-example]被强制设为width: 100%解决 Blume 默认把示例作为 shrink-to-fit flex 项居中、导致w-full页面级原语坍缩成最长一行宽度的问题见 preview.css 末尾注释。body使用hsl(var(--background))背景与hsl(var(--content))前景并开启scrollbar-gutter: stable防止示例超出框架高度时出现横向跳动。theme.css则只负责文档外壳chrome本身收紧 Blume 营销级标题字号h1 从 3rem 降为 1.875rem、去掉预览面板加载时的过渡动画、移除上一页/下一页导航上多余的分割线并在无标题页面隐藏孤立的页面操作条theme.css。六、站点级配置blume.config.ts 全解blume.config.ts 是站点的总开关各配置项含义如下配置项当前值说明title/descriptionUnkey Design / Design system guidance for building consistent Unkey interfaces.站点标题与描述供搜索引擎与文档外壳使用logo/unkey-logo.svg Unkey Design Docs顶栏 Logo 图片与文字图片位于 web/apps/design/public/unkey-logo.svgcontent.rootdocsMDX 页面根目录examples.source/examples.cssexamples/preview.css示例源码目录与注入 iframe 的样式文件themeaccentblue、radiusmd、modesystem文档外壳主题色、圆角、明暗模式search.providerorama站内全文搜索使用 Oramamarkdown.codeiconstrue、wrapfalse代码块显示语言图标、不自动换行ai.llmsTxttrue启用面向 LLM 的llms.txt输出seo.ogenabledfalse关闭 OG 社交卡片生成feedbackfalse关闭页面反馈组件integrationsunkey:amp-orb-vite-server自定义 Astro 集成当设置了AMP_ORB环境变量时为 Vite dev server 注入allowedHosts.e2b.app、.onamp.dev与 CORS 白名单本地 localhost/127.0.0.1 及*.e2b.app、*.onamp.dev用于在 AMP Orb 沙箱环境中预览其中integrations是一个值得注意的实战细节它通过astro:config:setup钩子按需修改 Vite 配置让文档站在特定的云端沙箱域名下也能正常访问属于配置驱动环境适配的典型写法。七、实战示例Skeleton 页面如何落地以skeleton页面作为完整闭环的样例串联上述所有机制页面文件 docs/primitives/skeleton.mdx 以title: Skeletondescription: Used to show a placeholder while content is loading.开头三个示例basic/card/list位于 examples/skeleton/页面在## Usage中给出最小用法import { Skeleton } from unkey/ui Skeleton classNameh-4 w-32 /页面还沉淀了三条最佳实践对使用者同样适用场景选择Skeleton 是unkey/ui中三种加载原语之一适用于异步数据将填充已知布局如表、卡片网格的场景不要在永久 UI 或空状态上使用否则会误导用户。单次动作用Loading typespinner /不确定时长的等待用Loading typedots /。尺寸Skeleton 尺寸应对齐它替换的内容h-4 w-32对应 128px 文本条可防止真实内容加载进来时的布局偏移圆形头像用rounded-full而默认的rounded-sm已匹配仪表盘中的文本条、按钮与徽章无需改动。无障碍把aria-busytrue放在加载区域而非 skeleton 本身用目标容器的aria-livepolite播报加载完成不要往 skeleton 里放可聚焦控件通过motion-reduce:animate-none尊重prefers-reduced-motion。该页面被 docs/primitives/meta.ts 登记进pages数组首位最终以/primitives/skeleton路由对外提供。八、维护要点小结新增页面走建 MDX → 建默认导出示例 →Component /引用 → 登记 meta.ts四步流程示例的实时预览与代码标签天然一致组件样式依赖preview.css的source声明与 token 映射新增 UI 源码目录或仪表盘语义 token 时优先检查这两处预览 iframe 视口窄于md断点响应式组件在预览中展示窄屏布局这是检验窄列表现的机会本地验证构建用blume build --isolated写入.blume-verify/避免与 dev server 争夺.blume/运行时站点外壳的排版标题密度、过渡动画、TOC 行为由theme.css控制与组件 tokenpreview.css严格分离修改时不要混淆。通过 web/apps/design/README.md 这份文档与仓库中真实的示例、配置和源码你可以把文档站本身也当作一个可维护的工程组件从web/internal/ui实时导入示例即代码token 与仪表盘保持一致最终让每一位阅读设计文档的开发者看到的就是上线后真实的 Unkey 界面。【免费下载链接】unkeyThe Developer Platform for Modern APIs项目地址: https://gitcode.com/GitHub_Trending/un/unkey创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考