首頁 / Skills / 網頁與介面設計 / 設計系統 Design System(Token 與簡報)
網頁與介面設計

設計系統 Design System(Token 與簡報)

claudekitMITSkill 語言: 英文
授權已核對含腳本中風險
演示真實執行紀錄 · claude-sonnet-5-5 · 2026年10月
Using the design-system skill, define a three-layer design token set (primitive, semantic, component) for a SaaS dashboard primary button, including hover and disabled states, and show the CSS variables.
Skill: design-system

Here's a three-layer token set for a SaaS dashboard primary button. It follows the skill's rules: no raw values in components, and the semantic layer is the theme switch.

/* ==========================================================
   LAYER 1 — PRIMITIVE: raw values, no meaning attached
   ========================================================== */
:root {
  /* Blue scale */
  --color-blue-50:  #EFF6FF;
  --color-blue-500: #3B82F6;
  --color-blue-600: #2563EB;
  --color-blue-700: #1D4ED8;
  --color-blue-800: #1E40AF;

  /* Neutral scale */
  --color-gray-50:  #F9FAFB;
  --color-gray-100: #F3F4F6;
  --color-gray-200: #E5E7EB;
  --color-gray-400: #9CA3AF;
  --color-gray-900: #111827;
  --color-white:    #FFFFFF;

  /* Spacing (4px base) */
  --space-2: 0.5rem;
  --space-4: 1rem;

  /* Radius, type, motion */
  --radius-md: 0.375rem;
  --font-size-sm: 0.875rem;
  --font-weight-medium: 500;
  --duration-fast: 150ms;
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);

  /* Shadow */
  --shadow-sm: 0 1px 2px rgb(17 24 39 / 0.08);
  --shadow-md: 0 4px 8px rgb(17 24 39 / 0.12);
}

/* ==========================================================
   LAYER 2 — SEMANTIC: purpose-based aliases (theme layer)
   ========================================================== */
:root {
  --color-primary:          var(--color-blue-600);
  --color-primary-hover:    var(--color-blue-700);
  --color-primary-active:   var(--color-blue-800);
  --color-on-primary:       var(--color-white);

  --color-muted:            var(--color-gray-100);
  --color-muted-foreground: var(--color-gray-400);
  --color-muted-border:     var(--color-gray-200);

  --color-focus-ring:       var(--color-blue-500);

  --control-padding-y:      var(--space-2);
  --control-padding-x:      var(--space-4);
  --control-radius:         var(--radius-md);
  --elevation-low:          var(--shadow-sm);
  --elevation-mid:          var(--shadow-md);
  --transition-interactive: var(--duration-fast) var(--ease-standard);
}

/* Dark theme: only semantic values are remapped */
[data-theme="dark"] {
  --color-primary:          var(--color-blue-500);
  --color-primary-hover:    var(--color-blue-600);
  --color-primary-active:   var(--color-blue-700);
  --color-on-primary:       var(--color-gray-900);
  --color-muted:            var(--color-gray-900);
  --color-muted-foreground: var(--color-gray-400);
  --color-muted-border:     var(--color-gray-400);
}

/* ==========================================================
   LAYER 3 — COMPONENT: button-specific, references semantic only
   ========================================================== */
:root {
  /* Default */
  --button-primary-bg:      var(--color-primary);
  --button-primary-fg:      var(--color-on-primary);
  --button-primary-border:  transparent;
  --button-primary-shadow:  var(--elevation-low);

  /* Hover */
  --button-primary-bg-hover:     var(--color-primary-hover);
  --button-primary-fg-hover:     var(--color-on-primary);
  --button-primary-shadow-hover: var(--elevation-mid);

  /* Active (pressed) */
  --button-primary-bg-active:     var(--color-primary-active);
  --button-primary-shadow-active: none;

  /* Disabled */
  --button-primary-bg-disabled:     var(--color-muted);
  --button-primary-fg-disabled:     var(--color-muted-foreground);
  --button-primary-border-disabled: var(--color-muted-border);
  --button-primary-shadow-disabled: none;

  /* Shape & type */
  --button-primary-padding: var(--control-padding-y) var(--control-padding-x);
  --button-primary-radius:  var(--control-radius);
  --button-primary-font-size:   var(--font-size-sm);
  --button-primary-font-weight: var(--font-weight-medium);
  --button-primary-focus-ring:  var(--color-focus-ring);
}

Usage: the component rule consumes only layer-3 tokens.

.btn-primary {
  padding: var(--button-primary-padding);
  font-size: var(--button-primary-font-size);
  font-weight: var(--button-primary-font-weight);
  border: 1px solid var(--button-primary-border);
  border-radius: var(--button-primary-radius);
  background: var(--button-primary-bg);
  color: var(--button-primary-fg);
  box-shadow: var(--button-primary-shadow);
  transition: background var(--transition-interactive),
              box-shadow var(--transition-interactive);
  cursor: pointer;
}
.btn-primary:hover:not(:disabled) {
  background: var(--button-primary-bg-hover);
  color: var(--button-primary-fg-hover);
  box-shadow: var(--button-primary-shadow-hover);
}
.btn-primary:active:not(:disabled) {
  background: var(--button-primary-bg-active);
  box-shadow: var(--button-primary-shadow-active);
}
.btn-primary:focus-visible {
  outline: 2px solid var(--button-primary-focus-ring);
  outline-offset: 2px;
}
.btn-primary:disabled,
.btn-primary[aria-disabled="true"] {
  background: var(--button-primary-bg-disabled);
  color: var(--button-primary-fg-disabled);
  border-color: var(--button-primary-border-disabled);
  box-shadow: var(--button-primary-shadow-disabled);
  cursor: not-allowed;
}

State matrix (matches the skill's spec pattern):

Property Default Hover Active Disabled
Background blue-600 blue-700 blue-800 gray-100
Text white white white gray-400
Border none none none gray-200
Shadow sm md none none

Notes

  • Layer rule: components reference semantic tokens, and semantic tokens reference primitives. Nothing skips a layer.
  • Rebranding: change --color-primary and the button follows, with no component edits.
  • Dark theme: the dark block flips --color-on-primary to dark text because blue-500 with white text is only about 3.7:1 contrast. Verify contrast against your final palette.
  • Disabled state: it has a visible border and muted text, so it doesn't rely on color alone.

I haven't run the skill's generate-tokens.cjs or validate-tokens.cjs scripts, and I haven't written these tokens to a file. If you want, I can put them in the starter JSON format, generate tokens.css, and run the validator over src/.

Real run in an isolated folder with only this skill installed. Only the Skill and Read tools were enabled; the model answered from SKILL.md without opening the reference files, and no bundled script was run.

它做什麼

協助模型建立設計 Token 並維持一致用法:三層結構(基礎值、語意別名、元件 Token)、CSS 變數、間距與字級體系、元件狀態規範(懸停、按下、停用),以及 Tailwind 整合。另附一套簡報系統,內含敘事策略、版型、字體、配色、文案公式等資料表,用來產生 HTML 簡報。

運作方式

  1. SKILL.md 說明 Token 架構,並指向各層、元件規範、狀態與 Tailwind 的參考文件。
  2. generate-tokens.cjs 把 JSON Token 檔轉成 CSS 變數或 Tailwind 片段;validate-tokens.cjs 檢查程式碼中的寫死數值。
  3. 製作簡報時,search-slides.py 在隨附 CSV 中檢索敘事結構與版型,generate-slide.py 輸出 HTML 簡報,驗證腳本檢查是否遵守 Token。

適合什麼場景

從零建立設計 Token 體系、整理元件狀態、把設計決策落成 CSS 變數,以及製作風格一致的募資簡報。

說明與風險

含 Node.js 與 Python 腳本,會讀取本機檔案。會寫檔的有兩個:`generate-tokens.cjs` 把 CSS 寫到你以 `-o` 指定的路徑(同名檔案會直接覆寫、不詢問,缺少的資料夾會自動建立);`generate-slide.py` 把 HTML 簡報寫到你指定的路徑,或寫入它自己的預設輸出資料夾。請指向暫存目錄或受版本控制的位置。腳本本身不發出網路請求,`fetch-background.py` 只組出 Pexels 的圖片網址與搜尋連結;產生的簡報在瀏覽器開啟時會從公共 CDN 載入 Chart.js 與字體。不需要帳號或金鑰。注意:SKILL.md 提到了本套件未附帶的專案檔案與工具(如 `docs/brand-guidelines.md`、`assets/design-tokens.json`、`/slides:create` 指令與同層的 `brand` Skill),因此製作簡報時,你的專案最好已有這些檔案,或自行建立。本站收錄的版本不含測試檔。請務必替 `generate-slide.py` 指定 `-o`:它的預設資料夾是依 Skill 的安裝位置往上推算 4 層,安裝在使用者層級目錄時會落到專案之外。