# GitLab Pajamas 设计系统

## GitLab Pajamas 设计系统界面预览

按状态筛选作业，选择作业查看其输出，模拟链接检查失败后恢复成功，并重置原始示例数据。

## GitLab Pajamas 设计系统设计参考

@gitlab/ui 138.0.0 已发布的浅色设计令牌导出和原生 CSS。GL_* 名称是 JavaScript 导出项；其小写 --gl-* 对应项出现在编译后的 CSS 中。示例使用原生样式表和原始 HTML/状态逻辑，而非挂载的 Vue 组件。

### 语义化界面表面、文本和边框

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| GL_BACKGROUND_COLOR_DEFAULT | #fff | 使用设计令牌指定的角色；这是浅色参考导出项。 |
| GL_BACKGROUND_COLOR_SUBTLE | #f7f7f5 | 使用设计令牌指定的角色；这是浅色参考导出项。 |
| GL_BACKGROUND_COLOR_STRONG | #ecebea | 使用设计令牌指定的角色；这是浅色参考导出项。 |
| GL_TEXT_COLOR_DEFAULT | #3a383d | 使用设计令牌指定的角色；这是浅色参考导出项。 |
| GL_TEXT_COLOR_SUBTLE | #646163 | 使用设计令牌指定的角色；这是浅色参考导出项。 |
| GL_TEXT_COLOR_STRONG | #18171d | 使用设计令牌指定的角色；这是浅色参考导出项。 |
| GL_TEXT_COLOR_HEADING | #18171d | 使用设计令牌指定的角色；这是浅色参考导出项。 |
| GL_TEXT_COLOR_LINK | #27599f | 使用设计令牌指定的角色；这是浅色参考导出项。 |
| GL_BORDER_COLOR_DEFAULT | #dcdbd9 | 使用设计令牌指定的角色；这是浅色参考导出项。 |
| GL_BORDER_COLOR_SUBTLE | #ecebea | 使用设计令牌指定的角色；这是浅色参考导出项。 |
| GL_BORDER_COLOR_STRONG | #c1bfbe | 使用设计令牌指定的角色；这是浅色参考导出项。 |
### 界面间距

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| GL_SPACING_SCALE_0 | 0px | 间距比例的数值并非索引乘以同一个常数。 |
| GL_SPACING_SCALE_1 | 0.125rem | 间距比例的数值并非索引乘以同一个常数。 |
| GL_SPACING_SCALE_2 | 0.25rem | 间距比例的数值并非索引乘以同一个常数。 |
| GL_SPACING_SCALE_3 | 0.5rem | 间距比例的数值并非索引乘以同一个常数。 |
| GL_SPACING_SCALE_4 | 0.75rem | 间距比例的数值并非索引乘以同一个常数。 |
| GL_SPACING_SCALE_5 | 1rem | 间距比例的数值并非索引乘以同一个常数。 |
| GL_SPACING_SCALE_6 | 1.5rem | 间距比例的数值并非索引乘以同一个常数。 |
| GL_SPACING_SCALE_7 | 2rem | 间距比例的数值并非索引乘以同一个常数。 |
| GL_SPACING_SCALE_8 | 2.5rem | 间距比例的数值并非索引乘以同一个常数。 |
| GL_SPACING_SCALE_9 | 3rem | 间距比例的数值并非索引乘以同一个常数。 |
### 响应式字号比例

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| GL_FONT_SIZE_100 | 0.75rem | 较大的字号角色使用 clamp；需要流体排版时，请保留该表达式。 |
| GL_FONT_SIZE_200 | 0.8125rem | 较大的字号角色使用 clamp；需要流体排版时，请保留该表达式。 |
| GL_FONT_SIZE_300 | 0.875rem | 较大的字号角色使用 clamp；需要流体排版时，请保留该表达式。 |
| GL_FONT_SIZE_400 | 1rem | 较大的字号角色使用 clamp；需要流体排版时，请保留该表达式。 |
| GL_FONT_SIZE_500 | clamp(1.125rem, 0.9027777778rem + 0.462962963vw, 1.25rem) | 较大的字号角色使用 clamp；需要流体排版时，请保留该表达式。 |
| GL_FONT_SIZE_600 | clamp(1.3125rem, 0.8680555556rem + 0.9259259259vw, 1.5625rem) | 较大的字号角色使用 clamp；需要流体排版时，请保留该表达式。 |
| GL_FONT_SIZE_700 | clamp(1.5rem, 0.8333333333rem + 1.3888888889vw, 1.875rem) | 较大的字号角色使用 clamp；需要流体排版时，请保留该表达式。 |
| GL_FONT_SIZE_800 | clamp(1.75rem, 0.8611111111rem + 1.8518518519vw, 2.25rem) | 较大的字号角色使用 clamp；需要流体排版时，请保留该表达式。 |
### 控件与界面表面圆角

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| GL_BORDER_RADIUS_NONE | 0px | 圆角体现组件形态，而非操作的重要程度。 |
| GL_BORDER_RADIUS_XS | 1px | 圆角体现组件形态，而非操作的重要程度。 |
| GL_BORDER_RADIUS_SM | 0.125rem | 圆角体现组件形态，而非操作的重要程度。 |
| GL_BORDER_RADIUS_MD | 0.25rem | 圆角体现组件形态，而非操作的重要程度。 |
| GL_BORDER_RADIUS_LG | 0.5rem | 圆角体现组件形态，而非操作的重要程度。 |
| GL_BORDER_RADIUS_XL | 0.75rem | 圆角体现组件形态，而非操作的重要程度。 |
| GL_BORDER_RADIUS_FULL | 9999px | 圆角体现组件形态，而非操作的重要程度。 |
| GL_BORDER_RADIUS_DEFAULT | 0.25rem | 圆角体现组件形态，而非操作的重要程度。 |
### 状态颜色参考

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| GL_COLOR_GREEN_50 | #e6f5ea | 克制的成功状态背景层。 |
| GL_COLOR_GREEN_800 | #075048 | 浅色背景层上的成功状态前景色。 |
| GL_COLOR_RED_50 | #feeef0 | 克制的失败状态背景层。 |
| GL_COLOR_RED_800 | #891c2f | 浅色背景层上的失败状态前景色。 |
| GL_COLOR_BLUE_50 | #e8f2fd | 已选作业的界面表面。 |
| GL_COLOR_BLUE_700 | #27599f | 选中状态边框与可见焦点参考。 |
## GitLab Pajamas 设计系统完整指南

实用指南，介绍如何为真实界面选择、应用和评审此系统。

完整指导、实现起点和源代码链接。

## GitLab Pajamas 设计系统流水线信息架构

### 先说明故障背景，再提供恢复操作

> 页眉标明虚构的流水线、分支和提交，为作业检查器提供上下文。Build、Test 和 Publish 以清晰分组呈现，选中作业后可查看其独立输出。链接检查失败时，先展示说明故障原因的路由和退出条件，再显示重试操作。

### 保持紧凑图表清晰易读

这个示例使用阶段列和按钮，而不是假装实现完整的依赖关系图。在窄屏上，各阶段按文档顺序纵向排列。生产环境中的流水线可能需要并行作业、依赖关系、等待、手动触发和已取消等状态；这些都应明确建模，而不是从三个示例标题中推断出来。

## GitLab Pajamas 设计系统语义色彩与状态

### 使用语义化 UI 角色呈现工作区域

浅色导出提供暖色中性色界面表面、层次分明的文本和细微边框。示例使用默认界面表面显示作业卡片，用蓝色界面表面表示选中状态，并以深色区域呈现日志。指南列出确切的包中取值，用户无需从截图中取样像素，也能复现这些配色关系。

### 让状态标签清楚表达含义

每个作业行和徽标中都以文字标明“已通过”或“失败”。勾号或叉号只是对文字的补充；仅使用彩色徽标会造成歧义。品牌紫色不会被用作通用的成功指示色。表格中的状态颜色与选中状态的蓝色有意区分。

## GitLab Pajamas 设计系统字号阶梯与技术文本

### 适用时保留流体表达式

该包提供固定的小字号角色，以及基于 clamp 的较大字号角色。将 clamp 替换为其最大端点会改变响应式行为。原始示例使用适用于应用界面的 24px 标题，以及紧凑的 12–14px 辅助文本角色；这些设置被标明为布局决策，而非额外的包令牌。

### 标识符和输出使用等宽字体

分支和提交信息采用代码样式，作业名称则保留易读的界面文本。输出显示在支持换行的等宽文本块中，该文本块可通过键盘聚焦。较长路径可以换行，避免整页宽度超出手机屏幕；选择作业时会替换文本，而不会注入原始的 HTML。

## GitLab Pajamas 设计系统间距与边框节奏

### 不要根据令牌编号计算取值

GL_SPACING_SCALE_3 为 0.5rem，scale_5 为 1rem；索引是键，而不是直接的乘数。实现该比例尺时应使用导出的取值。参考表保留了精确单位，包括零像素这一档。

### 用边界明确区域划分

浅色边框分隔工作区标题栏和工具栏，较醒目的卡片边界则框出输出检查器。作业按钮有各自的选中边框。让这些边界保持区分，有助于清楚表明选中的对象，也无需为每行元数据再套一层边框。

## GitLab Pajamas 设计系统作业选择与筛选

### 让选中项的标识不受筛选位置影响

脚本使用稳定的字符串 ID，便于关联和实现无障碍功能。筛选器会更改作业列表，并在存在匹配项时选择其中一个。点击作业会同步更新其按下状态、阶段、状态徽标和日志。这样可避免作业标题与其他作业的输出错配。

### 结果消失后保留恢复上下文

模拟失败作业已通过后，“失败的作业”筛选器将没有结果。空状态消息会说明如何恢复列表，同时检查器会保留刚刚完成的结果。这样设计是为了让用户了解该行为何消失，而不会丢失确认信息。

## GitLab Pajamas 设计系统重试与重置行为

### 如实标明模拟操作

操作按钮标为“模拟重试成功”，只会更改本地测试夹具，并将日志替换为文字形式的模拟结果。它不会将作业加入运行队列、创建作业或检查代码仓库。流水线徽标会根据所有作业状态重新计算，而不是在任意点击后直接设为成功。

### 恢复完整的初始测试夹具

重置操作会创建一份初始作业数据的新副本，选中失败的链接作业，恢复“所有作业”筛选器，并重新渲染两个面板。它无需重新加载页面即可清除模拟结果。这样可确保示例能够重复演示，也避免后续查看者误把先前模拟出的成功状态当作初始状态。

1. 选择“失败的作业”并查看失败路由。

2. 模拟成功，查看保留的检查器以及筛选后为空的列表。

3. 重置示例，确认失败状态和原始输出已恢复。

## GitLab Pajamas 设计系统无障碍作业控件

### 使用按钮进行本地选择

每个作业都是真正的按钮，并带有 aria-pressed 属性。状态会显示在持续时间旁边，可见的键盘焦点样式与选中外观彼此独立。筛选器带有可见标签。对于这些简单控件，我们不会声称实现了仅靠键盘操作的自定义图形导航。

### 播报操作结果，但不移动读者焦点

重试或重置后，操作结果会写入状态区域。日志是可选择的文本，也可通过键盘聚焦以便阅读；但每次选择后，应用不会自动将焦点移入日志。这样可以让用户稳定地反复比较不同作业。

## GitLab Pajamas 设计系统 CSS 与 Vue 集成边界

### 明确选择一种集成方式

此源代码导入已发布的 CSS 分发包，并提供原创的 HTML/JavaScript 行为。它不会实例化 GlButton、GlFormSelect 或其他 Vue 导出项。Vue 应用应使用相应的原生组件及其当前 props/events，而不应将此 DOM 实现当作 Vue 示例。

- CSS 分发包：原生外观与语义化变量。

- 原创 HTML：无障碍控件与区域结构。

- 原创 JavaScript：测试夹具数据、选择、筛选与模拟。

### 令牌应与导入的发行版本保持一致

参考取值来自预览所用的同一 138.0.0 版本包。未来应一并审查令牌和组件的变更。下方完整源码包含原创的 CSS 组合方式和测试夹具逻辑，因此下载的指南包含复现所示行为所需的全部内容。

## GitLab Pajamas 设计系统组件示例

### index.html — 流水线工作区

完整的语义化布局与控件。

```
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Pipeline specimen</title>
<body>
<main class="pipeline-example">
  <header>
    <p class="eyebrow">sample-team / documentation</p>
    <div class="title-row">
      <div>
        <h1>Pipeline #1842</h1>
        <p>
          Preview build for <code>docs/update-navigation</code> ·
          <code>7c31a82</code>
        </p>
      </div>
      <span id="pipeline-state" class="state failed">Failed</span>
    </div>
  </header>
  <div class="toolbar">
    <label for="job-filter">Show jobs</label
    ><select id="job-filter" class="gl-form-select">
      <option value="all">All jobs</option>
      <option value="failed">Failed jobs</option>
      <option value="passed">Passed jobs</option></select
    ><button id="reset" class="btn btn-default gl-button">
      Reset specimen
    </button>
  </div>
  <div class="pipeline-layout">
    <section aria-label="Pipeline stages">
      <div id="stages" class="stages"></div>
      <p id="empty" hidden>
        No jobs match this filter. Choose All jobs to restore the pipeline.
      </p>
    </section>
    <section class="job-detail" aria-labelledby="job-title">
      <div class="detail-heading">
        <h2 id="job-title"></h2>
        <span id="job-state" class="state"></span>
      </div>
      <dl>
        <dt>Stage</dt>
        <dd id="job-stage"></dd>
        <dt>Runner</dt>
        <dd>local-example-runner</dd>
        <dt>Execution</dt>
        <dd>Simulated in this page</dd>
      </dl>
      <h3>Job output</h3>
      <pre id="job-log" tabindex="0" aria-label="Selected job output"></pre>
      <button id="retry" class="btn btn-confirm gl-button">
        Simulate successful retry
      </button>
      <p id="feedback" role="status"></p>
    </section>
  </div>
  <footer>
    Native @gitlab/ui 138.0.0 CSS with original HTML and state logic. Fictional
    pipeline; no runner, repository or CI job is started.
  </footer>
</main>

<script type="module" src="/src/main.js"></script>
</body></html>
```

代码参考

- 保存在 Vite 项目根目录。

### main.js — 测试夹具与恢复逻辑

原生 CSS 导入及完整的分阶段任务行为。

```
import "@gitlab/ui/dist/index.css";
import "./pajamas.css";
const initial = [
  {
    id: "lint",
    stage: "Build",
    state: "passed",
    time: "12s",
    log: "$ npm run lint\nNo lint errors.\nJob succeeded.",
  },
  {
    id: "bundle",
    stage: "Build",
    state: "passed",
    time: "31s",
    log: "$ npm run build\nStatic assets generated.\nJob succeeded.",
  },
  {
    id: "links",
    stage: "Test",
    state: "failed",
    time: "18s",
    log: "$ npm run check:links\n/docs/old-navigation returned 404\n1 broken internal link.\nJob failed: exit code 1.",
  },
  {
    id: "accessibility",
    stage: "Test",
    state: "passed",
    time: "24s",
    log: "$ npm run check:a11y\nExample fixture checks passed.\nJob succeeded.",
  },
  {
    id: "preview",
    stage: "Publish",
    state: "passed",
    time: "9s",
    log: "$ npm run package:preview\nLocal preview archive generated.\nJob succeeded.",
  },
];
let jobs = structuredClone(initial),
  selected = "links";
const filter = document.querySelector("#job-filter"),
  stages = document.querySelector("#stages"),
  retry = document.querySelector("#retry"),
  feedback = document.querySelector("#feedback");
function render() {
  stages.replaceChildren();
  let count = 0;
  for (const name of ["Build", "Test", "Publish"]) {
    const matches = jobs.filter(
      (j) =>
        j.stage === name &&
        (filter.value === "all" || j.state === filter.value),
    );
    if (!matches.length) continue;
    const section = document.createElement("div");
    section.className = "stage";
    const h = document.createElement("h2");
    h.textContent = name;
    section.append(h);
    for (const j of matches) {
      count++;
      const b = document.createElement("button");
      b.type = "button";
      b.className = "job";
      b.setAttribute("aria-pressed", String(j.id === selected));
      const strong = document.createElement("strong"),
        small = document.createElement("small");
      strong.textContent = j.id;
      small.textContent =
        (j.state === "passed" ? "✓ Passed" : "× Failed") + " · " + j.time;
      b.append(strong, small);
      b.onclick = () => {
        selected = j.id;
        feedback.textContent = "";
        render();
      };
      section.append(b);
    }
    stages.append(section);
  }
  document.querySelector("#empty").hidden = count !== 0;
  const j = jobs.find((j) => j.id === selected);
  document.querySelector("#job-title").textContent = j.id;
  document.querySelector("#job-stage").textContent = j.stage;
  document.querySelector("#job-log").textContent = j.log;
  const state = document.querySelector("#job-state");
  state.className = "state " + j.state;
  state.textContent = j.state === "passed" ? "Passed" : "Failed";
  retry.hidden = j.state !== "failed";
  const failed = jobs.some((j) => j.state === "failed"),
    overall = document.querySelector("#pipeline-state");
  overall.textContent = failed ? "Failed" : "Passed";
  overall.className = "state " + (failed ? "failed" : "passed");
}
filter.onchange = () => {
  const match = jobs.find(
    (j) => filter.value === "all" || j.state === filter.value,
  );
  if (match) selected = match.id;
  feedback.textContent = "";
  render();
};
retry.onclick = () => {
  const j = jobs.find((j) => j.id === selected);
  j.state = "passed";
  j.time = "15s";
  j.log =
    "$ npm run check:links\nSimulation: updated route found.\nNo broken internal links.\nJob succeeded (local simulation).";
  render();
  feedback.textContent =
    "Simulated retry completed locally. No CI job was started.";
};
document.querySelector("#reset").onclick = () => {
  jobs = structuredClone(initial);
  selected = "links";
  filter.value = "all";
  feedback.textContent = "Specimen restored.";
  render();
};
render();
```

代码参考

- 保存为 src/main.js。不会发起任何 CI 请求。

### pajamas.css — 原始构成

响应式阶段、选中卡片、元数据和自动换行的日志输出。

```
[hidden] {
  display: none !important;
}
* {
  box-sizing: border-box;
}
body {
  margin: 0;
  font-family: Arial, sans-serif;
  font-size: 14px;
  color: var(--gl-text-color-default, #3a383d);
  background: var(--gl-background-color-default, #fff);
}
.pipeline-example {
  padding: 28px;
}
.pipeline-example header {
  padding-bottom: 20px;
  border-bottom: 1px solid var(--gl-border-color-default);
}
.eyebrow {
  font-size: 12px;
  color: var(--gl-text-color-subtle);
  margin-bottom: 16px;
}
.title-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: flex-start;
}
h1 {
  font-size: 24px;
  font-weight: 600;
  margin: 0 0 8px;
}
h2 {
  font-size: 18px;
  font-weight: 600;
  margin: 0;
}
h3 {
  font-size: 14px;
  font-weight: 600;
}
.title-row p {
  margin: 0;
  color: var(--gl-text-color-subtle);
}
code {
  font: 12px monospace;
  background: #f7f7f5;
  color: #3a383d;
  padding: 2px 4px;
  overflow-wrap: anywhere;
}
.toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 20px 0;
}
.toolbar label {
  margin: 0;
  font-weight: 600;
}
.toolbar select {
  max-width: 180px;
}
.toolbar button {
  margin-left: auto;
}
.pipeline-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(300px, 1fr);
  gap: 24px;
}
.stages {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}
.stage h2 {
  font-size: 13px;
  margin-bottom: 12px;
  color: var(--gl-text-color-subtle);
}
.job {
  display: block;
  width: 100%;
  text-align: left;
  background: #fff;
  border: 1px solid var(--gl-border-color-default);
  border-radius: 4px;
  padding: 12px;
  margin-bottom: 8px;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.job[aria-pressed="true"] {
  border-color: #27599f;
  box-shadow: inset 0 0 0 1px #27599f;
  background: #e8f2fd;
}
.job strong {
  display: block;
  font-size: 13px;
  overflow-wrap: anywhere;
}
.job small {
  display: block;
  margin-top: 6px;
  color: var(--gl-text-color-subtle);
}
.job-detail {
  border: 1px solid var(--gl-border-color-default);
  border-radius: 4px;
  padding: 20px;
  min-width: 0;
}
.detail-heading {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: center;
}
.state {
  font-size: 12px;
  font-weight: 600;
  border-radius: 9999px;
  padding: 3px 9px;
  white-space: nowrap;
}
.state.failed {
  background: #feeef0;
  color: #891c2f;
}
.state.passed {
  background: #e6f5ea;
  color: #075048;
}
dl {
  display: grid;
  grid-template-columns: 90px minmax(0, 1fr);
  gap: 8px;
  margin: 20px 0;
  font-size: 12px;
}
dt {
  color: var(--gl-text-color-subtle);
  font-weight: 400;
}
dd {
  margin: 0;
  overflow-wrap: anywhere;
}
pre {
  background: #18171d;
  color: #ecebea;
  padding: 16px;
  border-radius: 4px;
  font: 12px/1.7 monospace;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  min-height: 160px;
  margin-bottom: 16px;
}
#feedback {
  font-size: 12px;
  margin: 12px 0 0;
}
footer {
  margin-top: 28px;
  padding-top: 16px;
  border-top: 1px solid var(--gl-border-color-subtle);
  font-size: 12px;
  color: var(--gl-text-color-subtle);
}
button:focus-visible,
select:focus-visible,
pre:focus-visible {
  outline: 2px solid #27599f;
  outline-offset: 3px;
}
@media (max-width: 1050px) {
  .pipeline-layout {
    grid-template-columns: 1fr;
  }
  .stages {
    gap: 16px;
  }
}
@media (max-width: 550px) {
  .pipeline-example {
    padding: 16px;
  }
  .toolbar {
    flex-wrap: wrap;
  }
  .toolbar button {
    margin-left: 0;
  }
  .stages {
    grid-template-columns: 1fr;
  }
  .stage {
    border-bottom: 1px solid var(--gl-border-color-subtle);
    padding-bottom: 8px;
  }
  .title-row {
    flex-wrap: wrap;
  }
  .job-detail {
    padding: 16px;
  }
}
```

代码参考

- 保存为 src/pajamas.css。明确指定系统字体回退；未捆绑 GitLab 品牌字体。

## GitLab Pajamas 设计系统 AI Agent 配置

### 实现起点

此集成仅导入原生 CSS 发行包。如需采用其 Vue 组件，请另行遵循 GitLab UI 对等依赖要求。

```
npm create vite@latest pajamas-pipeline -- --template vanilla
cd pajamas-pipeline
npm install
npm install @gitlab/ui@138.0.0
# Replace index.html; add src/main.js and src/pajamas.css from the complete examples.
npm run dev
```

### 适用于你项目的提示词

```
使用 Pajamas 语义化界面表面、实际的间距与字体规格参考、稳定的任务 ID 和无障碍选择功能，构建技术任务检查器。使用完整的夹具源代码，保留可见的失败上下文，让筛选后的空状态易于理解，并明确标注所有本地模拟。不要暗示 CSS 或示例重试会创建 GitLab CI 任务。
```

## GitLab Pajamas 设计系统的来源与范围

OpenDesign 是面向 GitLab Pajamas 和 @gitlab/ui 138.0.0 的应用指南。原生包 CSS 为这个原创的 HTML/JavaScript 示例提供样式。此流水线为虚构内容，不会调用 GitLab API、Vue 运行时、CI 运行器或仓库操作。

- Pajamas 配色指南 界面角色与状态含义。

- Pajamas 按钮 操作层级与按钮行为。

- 固定版本的令牌导出 138.0.0 的精确参考值。

- 官方来源 Pajamas 和 GitLab UI 源代码仓库。

## GitLab Pajamas 设计系统相关资源

### HPE Grommet

使用 Grommet 的布局基元、受控表单字段和数值仪表来构建容量预留界面。谨慎使用其主题比例，并将 Grommet 基础主题与单独安装的 HPE 主题区分开来。

### Infor 设计系统

使用真实的 IDS 输入状态、主题别名和准确的资源标识符，构建企业级维护表单。查看当前公开的主题令牌、固定版本的 Web Components 软件包，以及包含验证和重置功能的本地草稿工作流。

### Kajabi Sage

构建一个面向创作者的分享面板，清晰呈现课程信息，提供明确的复制操作，并如实反馈剪贴板状态。探索 Sage 的 Rails 组件结构、已发布的字体排印规范，以及较新的外部加载 Pine 令牌层。


- [实现参考](https://design.gitlab.com/)
- [来源](https://cdn.jsdelivr.net/npm/@gitlab/ui@138.0.0/dist/tokens/build/js/tokens.js)
- [代码参考](https://design.gitlab.com/)
- [Pajamas 配色指南 界面角色与状态含义。](https://design.gitlab.com/product-foundations/color/)
- [Pajamas 按钮 操作层级与按钮行为。](https://design.gitlab.com/components/button/)
- [固定版本的令牌导出 138.0.0 的精确参考值。](https://cdn.jsdelivr.net/npm/@gitlab/ui@138.0.0/dist/tokens/build/js/tokens.js)
- [官方来源 Pajamas 和 GitLab UI 源代码仓库。](https://gitlab.com/gitlab-org/gitlab-services/design.gitlab.com)
