C1. 設計系統
CourseHub 的元件規格、Design Token、架構分層——所有樣式的單一來源。
V2 注意:CourseHub 是單一源頭,站內同時有編輯與簡報兩種顯示模式,並轉換到 StudentMode(HTML)輸出端,所以**樣式必須可被靜態提取**,不可依賴 runtime context 才能渲染對的色。轉換細節見 C5。
C 群組導覽
| 頁面 | 定位 | 關係 |
|---|
| C1. 統一規劃(本頁) | Design Token、元件規格、架構分層 | 所有樣式的權威來源 |
| C2. 元件對照 | 每個元件的視覺對照,含一般元件與大元件清單 | 驗證統一是否成功的「鏡子」 |
| C3. 轉換規則 | slide-convert Skill 的完整規則文件 | 自動化工具,把前面定義好的東西執行出來 |
CSS 架構分層
三層 CSS 各有明確職責,不重複定義同一元件:
| 層級 | 檔案 | 職責 | 作用域 |
|---|
| L1 主題 | globals.css | CSS 變數定義 + dark / light 主題切換 | 全站 |
| L2 元件 | content-components.css | 所有內容元件的唯一尺寸定義(Card、ActionBadge、HighlightText、Table 等) | Edit + Slide 共用 |
| L3 簡報 | slide-engine.css | Slide 專屬佈局(section 定位、opacity 切換、寬度約束)+ 淺色主題變數 + 需 !important 的 inline style override | .slide-engine |
/* L1 — globals.css */
@theme { --color-primary: #0184ff; ... }
html[data-theme="dark"] { --color-text-primary: #EFEFEF; ... }
/* L2 — content-components.css(權威來源) */
.card { padding: 1.25rem 1.5rem; border-radius: 12px; ... }
.action-badge { font-size: 1.1rem; ... }
.highlight-text { font-size: 2.5rem; ... }
/* L3 — slide-engine.css(只處理佈局 + override) */
.slide-engine { --color-bg-primary: #F5F5ED; ... }
.slide-root > section { position: absolute; opacity: 0; ... }
.slide-engine .prompt-box-v2 > div:first-child { font-size: 1.05rem !important; }
色彩 Token
所有顏色都用 var(--color-*),元件內零硬編碼色碼。
主色
| Token | Light | Dark |
|---|
--color-primary | #0184ff | #0184ff |
--color-primary-light | #33a1ff | #33a1ff |
--color-primary-dark | #0066cc | #0066cc |
--color-accent | #FAD75A | #FAD75A |
文字
| Token | Light | Dark |
|---|
--color-text-primary | #000000 | #EFEFEF |
--color-text-secondary | #666666 | #9A9A9A |
--color-text-tertiary | #999999 | #505050 |
背景 & 邊框
| Token | Light | Dark |
|---|
--color-bg-primary | #F5F5ED | #111111 |
--color-bg-secondary | #F0F0E8 | #090909 |
--color-bg-tertiary | #EBEBE3 | #1A1A1A |
--color-border | #E0E0E0 | #242424 |
字級系統
基礎 1rem = 16px,不使用縮放係數。
標題(Slide 內)
Slide 內 h1/h2/h3 在 Edit Mode 與 Slide Mode 各有一組字級。比例約 0.8x,保證副標永遠比內文(p: 1.2rem / 1.4rem)大。
| 元素 | Edit Mode | Slide Mode | 字重 |
|---|
.slide h1 | 2rem | 2.5rem | 700 |
.slide h2 | 1.6rem | 2rem | 700 |
.slide h3 | 1.3rem | 1.5rem | 700 |
.slide p(內文) | 1.2rem | 1.4rem | 400 |
.highlight-text | 2.5rem | 2.5rem | 700 |
.chapter-title | 2rem | 2.5rem | 700 |
.chapter-section > .slide:first-of-type .highlight-text | 3.5rem(章節封面自動放大) | 700 |
章節封面慣例:每個 .chapter-section 的第一張 .slide 即為章節封面。 封面內的 .highlight-text 會自動套用 3.5rem 章節標題字級 + 主色(暗色模式為文字主色),無需另外加 class。
內文
| 元素 | 字級 | 行高 |
|---|
| Slide section base | 1.25rem | 1.75 |
.slide p | 1.2rem | 1.75 |
| Card h4 | 1.1rem | — |
| Card p | 0.95rem | 1.7 |
| Table | 0.95rem | — |
| Code | 0.85rem / 0.85em | 1.8 |
Slide 區塊垂直節奏
Slide 內所有大區塊(p、card-grid、checkpoint、slide-table)統一用 1.25rem 上下邊距,確保不同元件混用時呼吸節奏一致。新增區塊型元件時必須遵守,不要自己定 0.5rem / 0.75rem 之類的隨意值。
| 元素 | margin | 備註 |
|---|
.slide p | margin-bottom: 1.25rem | 段落之後的呼吸距離 |
.card-grid | margin: 1.25rem 0 | 上下都要 |
.checkpoint | margin: 1.25rem 0 | 上下都要 |
.slide-table | margin: 1.25rem 0 | 上下都要(之前漏了 bottom) |
圓角
| 元素 | 值 |
|---|
| Card | 12px |
| ActionBadge / Button | 10px |
| Checkpoint | 8px |
| Badge (pill) | 999px |
| Code inline | 4px |
陰影
| Token | 值 |
|---|
| light | 0 1px 3px rgba(0,0,0,0.08) |
| medium | 0 4px 12px rgba(0,0,0,0.12) |
| blue | 0 4px 16px rgba(1,132,255,0.2) |
元件規格表
所有元件統一定義在 content-components.css,Edit 和 Slide 共用同一份數值。
A 類 — React 元件(CSS class + Tailwind)
| 元件 | 樣式方式 | 狀態 | 關鍵數值 |
|---|
PromptBox | inline style + CSS override | 統一 | Edit: 0.85rem / Slide: header 1.05rem, textarea 1rem(!important) |
BulletList | Tailwind + CSS override | 統一 | Slide 覆蓋 border-color、background、shadow |
InfoBadge | Tailwind | 統一 | 自然跟隨主題 |
AnimatedLink | Tailwind | 統一 | 自然跟隨主題 |
StarRating | Tailwind + CSS var | 統一 | 自然跟隨主題 |
ClassIntro | CSS var + Tailwind | 統一 | 自然跟隨主題 |
B 類 — CSS class 元件
| Class | 定義位置 | 狀態 | 關鍵數值 |
|---|
.card | content-components.css | 統一 | padding: 1.25rem 1.5rem / radius: 12px / h4: 1.1rem / p: 0.95rem |
.action-badge | content-components.css | 統一 | padding: 0.75rem 1.4rem / font: 1.1rem / radius: 10px |
.highlight-text | content-components.css | 統一 | font: 2.5rem / line-height: 1.35 |
.slide-action-btn | content-components.css | 統一 | padding: 0.6rem 1.2rem / font: 0.9rem / radius: 10px |
.action-link | content-components.css | 統一 | padding: 0.6rem 1.2rem / radius: 10px |
.checkpoint | content-components.css | 統一 | 藍底 rgba(1,132,255,0.06) / radius: 8px |
.slide-table | course-layout.css | 統一 | font: 0.95rem |
.slide-image | course-layout.css | 統一 | 圖片通用樣式 |
.slide-caption | course-layout.css | 統一 | 灰色說明段落(含 --center、--sm) |
.card-grid | content-components.css | 統一 | gap: 1rem / 支援 -2、-3、-4 欄 |
C 類 — Slide 專屬
| 元件 / Class | 說明 |
|---|
ChapterNavigation / PageShow | Slide 專屬導航元件 |
.slide-badge | Slide 模式的投影片編號(hidden,由 PageShow 顯示) |
.break-notice-slide | 休息提示投影片 |
.font-showcase | 字體展示卡片 |
.large-text | 超大文字版面(3rem) |
D 類 — Edit 專屬(轉換時移除)
| 元件 | 說明 |
|---|
TocAutoGen | 目錄 |
.slide-header | Edit 模式的 slide-number + slide-label |
Edit vs Slide 差異表
只列出兩個模式真正不同的地方,其他一切共用。
| 項目 | Edit Mode | Slide Mode |
|---|
| 主題 | data-theme="dark" | .slide-engine 淺色變數 |
| 佈局 | .slide 框 1280×720 + zoom | section absolute + opacity 切換 |
| 寬度約束 | 90% / max-width: 900px | 90% / max-width: 1080px |
| PromptBox | 原生 inline(0.85rem) | CSS override(header 1.05rem, textarea 1rem) |
| BulletList | 原生 Tailwind | CSS override(background、border、shadow) |
| 章節標題 | .chapter-title 2rem 藍色 | .chapter-title 2.5rem 黑色 |
設計原則
同一份 JSX,不管是在 Edit(深色)還是 Slide(白色)裡,都應該正確顯示。不應該靠「轉換時手動改顏色」來修正視覺——那不可維護。
| # | 原則 | 實踐方式 |
|---|
| 1 | 單一來源 | 每個元件只在 content-components.css 定義一次尺寸 |
| 2 | Scope 處理差異 | .slide-engine 只覆蓋佈局和需要 override 的 inline style |
| 3 | 1rem = 16px | 不用縮放係數,所有數值直接寫 |
| 4 | CSS 變數驅動 | 元件內零硬編碼色碼,全用 var(--color-*) |
CSS 變數命名規範
| 系統 | 命名格式 | 定義位置 | 感知 data-theme? |
|---|
| 主題系統 | --color-text-primary | globals.css | 跟隨切換 |
| Shell 短名 | --text-primary | shell.css | 需靠安全網 |
跨 dark/light 的共用元件,一律用 --color-* 系列。