@qijenchen/design-system 0.1.0-beta.73 → 0.1.0-beta.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.js +1 -1
- package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
- package/dist/components/DataTable/data-table.d.ts +27 -6
- package/dist/components/DataTable/data-table.d.ts.map +1 -1
- package/dist/components/DataTable/data-table.js +57 -34
- package/dist/components/DataTable/data-table.js.map +1 -1
- package/ds-canonical/fork/governance.lock +7 -7
- package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +2 -0
- package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +2 -0
- package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +2 -0
- package/ds-canonical/fork/skills/prototype/references/audit-checks.md +1 -0
- package/ds-canonical/fork/skills/scan-similar-bugs/SKILL.md +2 -0
- package/ds-canonical/fork/skills/visual-audit/SKILL.md +2 -0
- package/ds-canonical/fork/skills/visual-audit/references/audit-architecture.md +1 -0
- package/ds-canonical/hooks/check_plugin_fork_health.sh +2 -2
- package/ds-canonical/hooks/check_story_invariants.sh +26 -0
- package/ds-canonical/hooks/lib/_app_shell_primary_header_consistency.sh +31 -4
- package/ds-canonical/hooks/session_start_governance_check.sh +1 -1
- package/ds-canonical/hooks/tests/test_check_app_shell_primary_header_consistency.sh +46 -2
- package/ds-canonical/hooks/tests/test_check_story_invariants.sh +30 -0
- package/ds-canonical/skills/design-system-audit/SKILL.md +2 -2
- package/llms-full.txt +1 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/src/components/Accordion/accordion.principles.stories.tsx +3 -3
- package/src/components/Alert/alert.principles.stories.tsx +5 -5
- package/src/components/AppShell/_demo-helpers.tsx +23 -6
- package/src/components/AppShell/app-shell.principles.stories.tsx +9 -8
- package/src/components/AppShell/app-shell.spec.md +9 -8
- package/src/components/AppShell/app-shell.stories.tsx +5 -3
- package/src/components/AspectRatio/aspect-ratio.principles.stories.tsx +1 -1
- package/src/components/Avatar/avatar.principles.stories.tsx +3 -3
- package/src/components/Badge/badge.principles.stories.tsx +3 -3
- package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +3 -3
- package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +1 -1
- package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +3 -3
- package/src/components/BulkActionBar/bulk-action-bar.spec.md +4 -2
- package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +2 -2
- package/src/components/BulkActionBar/bulk-action-bar.tsx +3 -2
- package/src/components/Button/button.principles.stories.tsx +3 -3
- package/src/components/Calendar/calendar.principles.stories.tsx +3 -3
- package/src/components/Carousel/carousel.principles.stories.tsx +2 -2
- package/src/components/Chart/chart.principles.stories.tsx +4 -4
- package/src/components/Checkbox/checkbox.principles.stories.tsx +2 -2
- package/src/components/Chip/chip.principles.stories.tsx +3 -3
- package/src/components/Coachmark/coachmark.principles.stories.tsx +3 -3
- package/src/components/Combobox/combobox.anatomy.stories.tsx +2 -2
- package/src/components/Combobox/combobox.principles.stories.tsx +5 -5
- package/src/components/Command/command.principles.stories.tsx +7 -7
- package/src/components/DataTable/data-table.principles.stories.tsx +3 -3
- package/src/components/DataTable/data-table.spec.md +23 -15
- package/src/components/DataTable/data-table.stories.tsx +29 -25
- package/src/components/DataTable/data-table.tsx +92 -44
- package/src/components/DateGrid/date-grid.principles.stories.tsx +4 -4
- package/src/components/DatePicker/date-picker.principles.stories.tsx +5 -5
- package/src/components/DescriptionList/description-list.principles.stories.tsx +5 -5
- package/src/components/Dialog/dialog.principles.stories.tsx +4 -4
- package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +1 -1
- package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +5 -5
- package/src/components/Empty/empty.principles.stories.tsx +2 -2
- package/src/components/Field/field.principles.stories.tsx +4 -4
- package/src/components/FileItem/file-item.principles.stories.tsx +5 -5
- package/src/components/FileUpload/file-upload.principles.stories.tsx +4 -4
- package/src/components/FileViewer/file-viewer.principles.stories.tsx +5 -5
- package/src/components/HoverCard/hover-card.principles.stories.tsx +5 -5
- package/src/components/Input/input.principles.stories.tsx +4 -4
- package/src/components/LinkInput/link-input.principles.stories.tsx +5 -5
- package/src/components/Menu/menu-item.principles.stories.tsx +7 -7
- package/src/components/Notice/notice.principles.stories.tsx +7 -7
- package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
- package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +5 -5
- package/src/components/PeoplePicker/people-picker.principles.stories.tsx +3 -3
- package/src/components/Popover/popover.principles.stories.tsx +1 -1
- package/src/components/ProfileCard/profile-card.principles.stories.tsx +1 -1
- package/src/components/ProgressBar/progress-bar.principles.stories.tsx +2 -2
- package/src/components/RadioGroup/radio-group.principles.stories.tsx +2 -2
- package/src/components/Rating/rating.principles.stories.tsx +3 -3
- package/src/components/ScrollArea/scroll-area.principles.stories.tsx +4 -4
- package/src/components/Select/select.principles.stories.tsx +5 -5
- package/src/components/SelectMenu/select-menu.principles.stories.tsx +8 -8
- package/src/components/SelectionControl/selection-item.principles.stories.tsx +7 -7
- package/src/components/Separator/separator.principles.stories.tsx +4 -4
- package/src/components/Sheet/sheet.principles.stories.tsx +2 -2
- package/src/components/Sidebar/sidebar.principles.stories.tsx +4 -4
- package/src/components/Sidebar/sidebar.spec.md +1 -1
- package/src/components/Skeleton/skeleton.principles.stories.tsx +5 -5
- package/src/components/Slider/slider.principles.stories.tsx +3 -3
- package/src/components/Steps/steps.principles.stories.tsx +4 -4
- package/src/components/Switch/switch.principles.stories.tsx +1 -1
- package/src/components/Tabs/tabs.principles.stories.tsx +3 -3
- package/src/components/Tag/tag.principles.stories.tsx +3 -3
- package/src/components/Textarea/textarea.principles.stories.tsx +2 -2
- package/src/components/TimePicker/time-picker.principles.stories.tsx +5 -5
- package/src/components/Toast/toast.principles.stories.tsx +2 -2
- package/src/components/Tooltip/tooltip.principles.stories.tsx +3 -3
- package/src/components/TreeView/tree-view.principles.stories.tsx +5 -5
- package/src/components/TreeView/tree-view.stories.tsx +1 -1
- package/src/tokens/color/color.spec.md +2 -0
|
@@ -110,11 +110,11 @@
|
|
|
110
110
|
},
|
|
111
111
|
{
|
|
112
112
|
"file": "skills/bug-fix-rhythm/SKILL.md",
|
|
113
|
-
"sha256": "
|
|
113
|
+
"sha256": "4bca87df4f2777fe76f8e302698d373fb0ba60699922fb8b35c8aefae1c51ae0"
|
|
114
114
|
},
|
|
115
115
|
{
|
|
116
116
|
"file": "skills/code-quality-audit/SKILL.md",
|
|
117
|
-
"sha256": "
|
|
117
|
+
"sha256": "fb65ebf0c72f7b475640f4861a1bfa2e9140727e2ff051fbd58f8348c0dc187d"
|
|
118
118
|
},
|
|
119
119
|
{
|
|
120
120
|
"file": "skills/delivery-handoff/references/flow-diagram.md",
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
},
|
|
151
151
|
{
|
|
152
152
|
"file": "skills/product-ui-audit/SKILL.md",
|
|
153
|
-
"sha256": "
|
|
153
|
+
"sha256": "cef077d82f906fd26d1507bbab00f5215a75583780aa893805d3018eef000a05"
|
|
154
154
|
},
|
|
155
155
|
{
|
|
156
156
|
"file": "skills/propose-options/SKILL.md",
|
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
},
|
|
159
159
|
{
|
|
160
160
|
"file": "skills/prototype/references/audit-checks.md",
|
|
161
|
-
"sha256": "
|
|
161
|
+
"sha256": "6f17d6b4bc6ae94eedef8c39b68d4ab1baec92ef1035eeab462e17239c2803e3"
|
|
162
162
|
},
|
|
163
163
|
{
|
|
164
164
|
"file": "skills/prototype/references/benchmark-sources.md",
|
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
},
|
|
187
187
|
{
|
|
188
188
|
"file": "skills/scan-similar-bugs/SKILL.md",
|
|
189
|
-
"sha256": "
|
|
189
|
+
"sha256": "79c5125f6d65d9d530c09ba2f19afe60174278448b122f4d4a66f9280c1312ca"
|
|
190
190
|
},
|
|
191
191
|
{
|
|
192
192
|
"file": "skills/ux-audit/SKILL.md",
|
|
@@ -198,7 +198,7 @@
|
|
|
198
198
|
},
|
|
199
199
|
{
|
|
200
200
|
"file": "skills/visual-audit/references/audit-architecture.md",
|
|
201
|
-
"sha256": "
|
|
201
|
+
"sha256": "48c931ad559c1e37ecebd08d289509692c79d9c92d2574f65e89bf286b7c95cf"
|
|
202
202
|
},
|
|
203
203
|
{
|
|
204
204
|
"file": "skills/visual-audit/references/visual-checklist.md",
|
|
@@ -210,7 +210,7 @@
|
|
|
210
210
|
},
|
|
211
211
|
{
|
|
212
212
|
"file": "skills/visual-audit/SKILL.md",
|
|
213
|
-
"sha256": "
|
|
213
|
+
"sha256": "0af4957c5ab08f8c04bbc944900ae45b719eed879e667de1fd139392e57c4525"
|
|
214
214
|
}
|
|
215
215
|
]
|
|
216
216
|
}
|
|
@@ -3,6 +3,8 @@ name: bug-fix-rhythm
|
|
|
3
3
|
description: Batch-end-verify rhythm + parallel tool batch + user-listed N-rule MUST-ALL + claim runtime verify. Invoke when entering multi-fix session 或 user 列 numbered rules. Replaces M32(c)(d)(h1)(h2) sub-invariants(2026-05-12 split per Knowledge-Prune Checkpoint 2)。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
> **⚠️ Fork 工具註記(build 自動加)**:本 skill 提到的 `scripts/*.mjs` 或非標準 `npm run <audit>` 是 **DS-author repo 的機械工具,未隨 fork 套件附帶**(Claude Code 不掃 node_modules,fork 也無這些 executor + dep)。你的 product fork 用本 skill 的**方法論**(human / AI judgment)+ 既有 committed governance hook 的機械強制即可;要 mechanical 腳本層(截圖 / CI gate)請自行設置對應工具,或把該檢查 PR 回 DS repo 跑。
|
|
7
|
+
|
|
6
8
|
# /bug-fix-rhythm — 多 fix session 的 rhythm canonical
|
|
7
9
|
|
|
8
10
|
**目的**:當 session 有 ≥ 2 fixes(常見 visual bug session / user 列 N 條 numbered 規則),走 batch-end-verify rhythm,而非 per-fix verify cycle waste。**M32 split 後 (c)(d)(h1)(h2) 的 home**。
|
|
@@ -3,6 +3,8 @@ name: code-quality-audit
|
|
|
3
3
|
description: Clean code 量化稽核 — `any` 使用 / dead export / file size / long function / circular dep / magic number。補 `/design-system-audit` 只管「design canonical」的缺口。Invoke via /code-quality-audit scope=all(release / 季度)OR scope=changed(daily)OR scope=component:X(focused)。Auto-chain by `/design-system-audit --deep` Dim 27 + `/component-quality-gate` Ship phase + `/new-component` Phase 4.5。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
> **⚠️ Fork 工具註記(build 自動加)**:本 skill 提到的 `scripts/*.mjs` 或非標準 `npm run <audit>` 是 **DS-author repo 的機械工具,未隨 fork 套件附帶**(Claude Code 不掃 node_modules,fork 也無這些 executor + dep)。你的 product fork 用本 skill 的**方法論**(human / AI judgment)+ 既有 committed governance hook 的機械強制即可;要 mechanical 腳本層(截圖 / CI gate)請自行設置對應工具,或把該檢查 PR 回 DS repo 跑。
|
|
7
|
+
|
|
6
8
|
# Code Quality Audit — Clean Code 量化稽核
|
|
7
9
|
|
|
8
10
|
Scope:**tsx / ts code hygiene**,跟 design canonical 正交。
|
|
@@ -3,6 +3,8 @@ name: product-ui-audit
|
|
|
3
3
|
description: Audit product / consumer UI code (非 design-system 本身) against DS usage discipline + mindset adherence. Catches element misuse / design principle violations / token leakage / geometry bugs / a11y gaps across 7 dimensions. Invoke via /product-ui-audit when user says「audit 這個 UI」「檢查 X feature 用對 DS 嗎」「這段 code 符合設計原則嗎」,or auto-invoked by /prototype Phase 3.5 gate.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
> **⚠️ Fork 工具註記(build 自動加)**:本 skill 提到的 `scripts/*.mjs` 或非標準 `npm run <audit>` 是 **DS-author repo 的機械工具,未隨 fork 套件附帶**(Claude Code 不掃 node_modules,fork 也無這些 executor + dep)。你的 product fork 用本 skill 的**方法論**(human / AI judgment)+ 既有 committed governance hook 的機械強制即可;要 mechanical 腳本層(截圖 / CI gate)請自行設置對應工具,或把該檢查 PR 回 DS repo 跑。
|
|
7
|
+
|
|
6
8
|
# Product UI Audit Workflow
|
|
7
9
|
|
|
8
10
|
Purpose: design-system-audit audits the **DS itself**(spec / cva / SSOT 三方漂移);product-ui-audit audits **consumer UI code**(不是 DS 本身,是 app / exploration / feature code — 即「consumer 用 DS 的地方」)。防止:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
> **⚠️ Fork 工具註記(build 自動加)**:本 skill 提到的 `scripts/*.mjs` 或非標準 `npm run <audit>` 是 **DS-author repo 的機械工具,未隨 fork 套件附帶**(Claude Code 不掃 node_modules,fork 也無這些 executor + dep)。你的 product fork 用本 skill 的**方法論**(human / AI judgment)+ 既有 committed governance hook 的機械強制即可;要 mechanical 腳本層(截圖 / CI gate)請自行設置對應工具,或把該檢查 PR 回 DS repo 跑。
|
|
1
2
|
# Phase 3.5 Self-audit checklist(/prototype 用)
|
|
2
3
|
|
|
3
4
|
對齊 CLAUDE.md `# 稽核 canonical` M6(stakeholder-visible 產出 → 強制進階模式)。比稿本質是「給 stakeholder 選視覺方向」,6 維任一沒 audit 好就 present = 比稿品質失準。
|
|
@@ -3,6 +3,8 @@ name: scan-similar-bugs
|
|
|
3
3
|
description: Auto-invoke after fix commits — extracts root-cause anti-pattern, greps DS-wide for same pattern, runs visual verify, batches related fixes. Closes M10 mechanical gap. Invoke via /scan-similar-bugs.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
> **⚠️ Fork 工具註記(build 自動加)**:本 skill 提到的 `scripts/*.mjs` 或非標準 `npm run <audit>` 是 **DS-author repo 的機械工具,未隨 fork 套件附帶**(Claude Code 不掃 node_modules,fork 也無這些 executor + dep)。你的 product fork 用本 skill 的**方法論**(human / AI judgment)+ 既有 committed governance hook 的機械強制即可;要 mechanical 腳本層(截圖 / CI gate)請自行設置對應工具,或把該檢查 PR 回 DS repo 跑。
|
|
7
|
+
|
|
6
8
|
# /scan-similar-bugs — Fix-time DS-wide Exhaustive Scan
|
|
7
9
|
|
|
8
10
|
**目的**:任何 bug fix 提交後,**機械化掃 DS-wide 找同 pattern**,而非靠 model 記得 M10。
|
|
@@ -3,6 +3,8 @@ name: visual-audit
|
|
|
3
3
|
description: Pixel-level visual audit for design-system components based on user-provided screenshots. Catches bug classes that code/spec audits cannot see — asymmetric padding / broken overlay positioning / gap-eaten-by-hover-bg / baseline misalignment / overflow indicator obscuring content / wrong zoom step / dark-mode token mismatch. Requires a screenshot to run; refuses to proceed on guesses. Invoke via /visual-audit when user says「視覺對齊不對」「排版有問題」「gap 好像錯了」「看起來歪了」or uploads a Storybook screenshot asking「這樣對嗎」,auto-invoked by `/design-system-audit` Phase 3 (post-fix visual verify) and `/component-quality-gate` Ship phase.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
> **⚠️ Fork 工具註記(build 自動加)**:本 skill 提到的 `scripts/*.mjs` 或非標準 `npm run <audit>` 是 **DS-author repo 的機械工具,未隨 fork 套件附帶**(Claude Code 不掃 node_modules,fork 也無這些 executor + dep)。你的 product fork 用本 skill 的**方法論**(human / AI judgment)+ 既有 committed governance hook 的機械強制即可;要 mechanical 腳本層(截圖 / CI gate)請自行設置對應工具,或把該檢查 PR 回 DS repo 跑。
|
|
7
|
+
|
|
6
8
|
# Visual Audit — screenshot-based pixel-level 稽核
|
|
7
9
|
|
|
8
10
|
## 存在意義
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
> **⚠️ Fork 工具註記(build 自動加)**:本 skill 提到的 `scripts/*.mjs` 或非標準 `npm run <audit>` 是 **DS-author repo 的機械工具,未隨 fork 套件附帶**(Claude Code 不掃 node_modules,fork 也無這些 executor + dep)。你的 product fork 用本 skill 的**方法論**(human / AI judgment)+ 既有 committed governance hook 的機械強制即可;要 mechanical 腳本層(截圖 / CI gate)請自行設置對應工具,或把該檢查 PR 回 DS repo 跑。
|
|
1
2
|
# Visual audit — Layer A + Layer B 架構 + Interactive state coverage canonical
|
|
2
3
|
|
|
3
4
|
(Extracted from SKILL.md 2026-05-04 — file budget consolidation,SKILL.md 留 1-line summary + pointer 本檔。)
|
|
@@ -113,12 +113,12 @@ if [ -z "$REMOTE_VERSION" ] || [ "$REMOTE_VERSION" = "null" ]; then exit 0; fi
|
|
|
113
113
|
if [ "$LOCAL_VERSION" != "$REMOTE_VERSION" ]; then
|
|
114
114
|
cat << EOF
|
|
115
115
|
|
|
116
|
-
📦 DS
|
|
116
|
+
📦 DS governance update available:
|
|
117
117
|
Local installed: $LOCAL_VERSION
|
|
118
118
|
Latest published: $REMOTE_VERSION
|
|
119
119
|
|
|
120
120
|
Run in terminal (1 command):
|
|
121
|
-
npm run sync-all # npm +
|
|
121
|
+
npm run sync-all # npm install @beta(治理本體)+ 刷新接線骨架(committed launchers + settings + skills);npm-only,免 plugin
|
|
122
122
|
|
|
123
123
|
|
|
124
124
|
(Per user 2026-05-27 directive「DS 增刪改自動同步」— this hook detects staleness on session start.)
|
|
@@ -708,6 +708,31 @@ rule_handcraft_overlay_header() {
|
|
|
708
708
|
fi
|
|
709
709
|
}
|
|
710
710
|
|
|
711
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
712
|
+
# R10 — link_canonical(2026-06-22 codify per user;color.spec.md「Action — Primary」)
|
|
713
|
+
# canonical 文字連結 = text-primary + hover:text-primary-hover(hover 換色,無底線);
|
|
714
|
+
# 禁 `text-primary hover:underline`(用底線取代換色)。真元件(Breadcrumb / LinkInput /
|
|
715
|
+
# Button / RadioGroup)已遵循;本 rule 防 story LinkTo 導覽連結復發 drift(曾累積 232 處)。
|
|
716
|
+
# P1 WARN(story 導覽 style 低風險,不 block)。豁免:檔首 `// @link-style-allow:`。
|
|
717
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
718
|
+
rule_link_canonical() {
|
|
719
|
+
[ "$EVENT" = "PostToolUse" ] && return 0
|
|
720
|
+
printf '%s' "$NEW_CONTENT" | grep -q '@link-style-allow:' && return 0
|
|
721
|
+
# text-primary …(中間可隔 tailwind class:cursor-pointer / font-medium 等)… hover:underline。
|
|
722
|
+
# 中間段限 class-char [a-z0-9:_-] → 不誤判描述用 label「text-primary · hover:underline」(· 非 class-char)。
|
|
723
|
+
if printf '%s' "$NEW_CONTENT" | grep -qE 'text-primary([[:space:]]+[a-z0-9:_-]+)*[[:space:]]+hover:underline'; then
|
|
724
|
+
{
|
|
725
|
+
echo ""
|
|
726
|
+
echo "╔═══ R10 link_canonical — 連結 hover 樣式 drift ═══"
|
|
727
|
+
echo "[P1 WARN] ${FILE_PATH}"
|
|
728
|
+
echo " 偵測到 'text-primary hover:underline' = 用底線取代換色,偏離 canonical。"
|
|
729
|
+
echo " canonical(color.spec.md「Action — Primary」)= text-primary + hover:text-primary-hover(換色,無底線)。"
|
|
730
|
+
echo " 修:hover:underline → hover:text-primary-hover。豁免:檔首 // @link-style-allow: <reason>"
|
|
731
|
+
} >&2
|
|
732
|
+
# P1 warn:not block
|
|
733
|
+
fi
|
|
734
|
+
}
|
|
735
|
+
|
|
711
736
|
# ─── Run rules ───
|
|
712
737
|
rule_anatomy
|
|
713
738
|
rule_slot_split
|
|
@@ -718,5 +743,6 @@ rule_description_jargon
|
|
|
718
743
|
rule_story_baseline_reference
|
|
719
744
|
rule_story_archetype_registry
|
|
720
745
|
rule_handcraft_overlay_header
|
|
746
|
+
rule_link_canonical
|
|
721
747
|
|
|
722
748
|
exit $WORST
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# 2026-05-21 ship per user directive「該程式化的就程式化」+「確認當有 global header 時,
|
|
5
5
|
# sidebar 內的 header 應該要拿掉」+ world-class GitHub/Gmail/Figma 共識。
|
|
6
6
|
#
|
|
7
|
-
# Detects
|
|
7
|
+
# Detects 3 violations in AppShell consumer code:
|
|
8
8
|
# V1) `layout="primary-header"` without `globalHeader=...` prop
|
|
9
9
|
# → 缺 globalHeader 而 layout=primary-header 是邏輯矛盾(per app-shell.spec.md
|
|
10
10
|
# 「primary-header = primary-sidebar + 一條 global header」)
|
|
@@ -12,6 +12,14 @@
|
|
|
12
12
|
# V2) `layout="primary-header"` + 任何 `<SidebarHeader>...</SidebarHeader>` 在同 file
|
|
13
13
|
# → WorkspaceBrand 已該在 globalHeader,sidebar 內不該再有 SidebarHeader
|
|
14
14
|
# (per app-shell.spec.md「WorkspaceBrand 放置 SSOT」+ world-class GitHub/Gmail/Figma 一致)
|
|
15
|
+
# 例外:同 file 用 useSidebar/isMobile = mobile-only 補品牌的正確 responsive fork(豁免)
|
|
16
|
+
#
|
|
17
|
+
# V3) `layout="primary-header"` + 任何 `<SidebarFooter>...</SidebarFooter>` 在同 file(2026-06-18 beta.74)
|
|
18
|
+
# → primary-header 帳號入口家在 globalHeader 右(收成 Sheet 鏡像到 Sheet header 右),**不該**用
|
|
19
|
+
# sidebar footer〔那是 primary-sidebar 帳號家慣例〕→ 誤用 = 模式混淆
|
|
20
|
+
# (per app-shell.spec.md「帳號入口(Account entry)放置 SSOT」+ Material modal nav drawer
|
|
21
|
+
# 「account switcher 放 drawer header」)。與 V2 不同:primary-header 任何 breakpoint(含 mobile
|
|
22
|
+
# Sheet)帳號家都在 header 區 → V3 不設 isMobile 豁免;非帳號用途 footer 走 escape allowlist。
|
|
15
23
|
#
|
|
16
24
|
# 對齊 .claude/rules/self-verify.md「Pre-edit」階段 + check_chrome_header_handcraft.sh /
|
|
17
25
|
# check_overlay_handcraft.sh 等既有 SSOT-enforcement hook idiom。
|
|
@@ -40,8 +48,12 @@ esac
|
|
|
40
48
|
# Escape allowlist
|
|
41
49
|
if grep -q "@app-shell-primary-header-allow:" "$TARGET"; then exit 0; fi
|
|
42
50
|
|
|
43
|
-
# 偵測 layout="primary-header"
|
|
44
|
-
|
|
51
|
+
# 偵測 layout="primary-header"(三種 JSX 形式:layout="x" / layout={"x"} / layout={'x'})
|
|
52
|
+
# 2026-06-18 beta.74 fix(adversarial audit P1):舊 `["\047]` 想用 octal \047 表單引號,但 BRE char-class
|
|
53
|
+
# **不** interpret octal → 單引號 JSX `layout={'primary-header'}` 整個 hook 靜默 skip(false-negative)。
|
|
54
|
+
# 改 grep -E + 字面單/雙引號 alternation(`('\''|")`)— 三種引號形式皆match。⚠️ 驗證用 /usr/bin/grep,
|
|
55
|
+
# 互動 shell 的 wrapped grep 對 octal 給相反結果會藏 bug。
|
|
56
|
+
if ! grep -Eq 'layout="primary-header"|layout=\{('\''|")primary-header('\''|")\}' "$TARGET"; then exit 0; fi
|
|
45
57
|
|
|
46
58
|
VIOLATIONS=()
|
|
47
59
|
|
|
@@ -54,10 +66,25 @@ fi
|
|
|
54
66
|
# 例外(2026-06-18 responsive 精修,M34 hook-intent 對齊):同 file 也用 useSidebar/isMobile =
|
|
55
67
|
# mobile-only 補品牌的「正確 responsive fork」(小螢幕 Sheet 蓋住 globalHeader → Sheet 內補同組 primitive,
|
|
56
68
|
# desktop 仍無 SidebarHeader,非真重複)→ 不 flag。見 app-shell.spec.md WorkspaceBrand SSOT「Responsive 精修」子句。
|
|
57
|
-
|
|
69
|
+
# ⚠️ 限制(2026-06-18 beta.74 audit 記錄):V2 是 token-presence 啟發式(file 含 useSidebar/isMobile 即豁免),
|
|
70
|
+
# 非「isMobile 真的 guard 該 <SidebarHeader>」的 AST 級判斷 → 罕見假陰性(unguarded SidebarHeader 但 file
|
|
71
|
+
# 因別處用 isMobile → 漏擋)。bash 無法精準 AST;靠 code review + escape allowlist 兜底,目前唯一 consumer(stories)正確。
|
|
72
|
+
# 要嚴格需 TS AST lint rule(future)。
|
|
73
|
+
# tag boundary `([^A-Za-z]|$)`(2026-06-18 audit P2#4):避免 prefix-extended 名(<SidebarHeaderXyz>)誤觸
|
|
74
|
+
if grep -Eq '<SidebarHeader([^A-Za-z]|$)' "$TARGET" && ! grep -qE 'useSidebar|isMobile' "$TARGET"; then
|
|
58
75
|
VIOLATIONS+=("V2 Sidebar 內含 SidebarHeader:primary-header mode WorkspaceBrand 該在 globalHeader,sidebar 內不該重複(per spec.md「WorkspaceBrand 放置 SSOT」+ world-class GitHub/Gmail/Figma 共識)。若是 mobile-only responsive 補品牌請用 useSidebar().isMobile 條件渲染(自動豁免);若 sidebar header 是其他內容(非 brand),加 escape allowlist `// @app-shell-primary-header-allow:` 並說明 reason")
|
|
59
76
|
fi
|
|
60
77
|
|
|
78
|
+
# V3:layout="primary-header" + <SidebarFooter> 同 file → 帳號入口家在 globalHeader 右,不該用 sidebar footer。
|
|
79
|
+
# 與 V2 不同 — primary-header 收成 Sheet 時帳號鏡像到 Sheet **header** 右(非 footer),故任何 breakpoint 都不該
|
|
80
|
+
# 有 SidebarFooter 放帳號 → V3 不設 isMobile 豁免(per app-shell.spec.md「帳號入口(Account entry)放置 SSOT」
|
|
81
|
+
# Responsive 精修「不放 SidebarFooter」+ Material modal nav drawer「account switcher 放 drawer header」)。
|
|
82
|
+
# demo 天然不誤觸:layout="primary-header" 在 stories,<SidebarFooter> 在 _demo-helpers.tsx,分檔。
|
|
83
|
+
# 非帳號用途 footer(storage meter / collapse 等)→ escape allowlist 兜底。
|
|
84
|
+
if grep -Eq '<SidebarFooter([^A-Za-z]|$)' "$TARGET"; then
|
|
85
|
+
VIOLATIONS+=("V3 Sidebar 內含 SidebarFooter:primary-header mode 帳號入口家在 globalHeader 右(收成 Sheet 鏡像到 Sheet header 右),不該用 sidebar footer〔那是 primary-sidebar 慣例〕(per spec.md「帳號入口(Account entry)放置 SSOT」+ Material modal nav drawer)。若 footer 是非帳號用途,加 escape allowlist \`// @app-shell-primary-header-allow:\` 並說明 reason")
|
|
86
|
+
fi
|
|
87
|
+
|
|
61
88
|
if [[ ${#VIOLATIONS[@]} -gt 0 ]]; then
|
|
62
89
|
echo "🚨 AppShell primary-header consistency violation" >&2
|
|
63
90
|
echo "Target: $TARGET" >&2
|
|
@@ -265,7 +265,7 @@ fi
|
|
|
265
265
|
ENV_SMOKE=""
|
|
266
266
|
# (a) plugin-mode 完整性 — CLAUDE_PLUGIN_ROOT 在 ds-repo native mode 可能 UNSET → 先 guard 才用
|
|
267
267
|
if [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ ! -d "${CLAUDE_PLUGIN_ROOT:-}/hooks" ]; then
|
|
268
|
-
ENV_SMOKE="${ENV_SMOKE}\n - Plugin mode:\$CLAUDE_PLUGIN_ROOT 有設但 hooks/ 找不到 → plugin install 可能不完整(
|
|
268
|
+
ENV_SMOKE="${ENV_SMOKE}\n - Plugin mode:\$CLAUDE_PLUGIN_ROOT 有設但 hooks/ 找不到 → plugin install 可能不完整(C-prime 主路徑 = committed-config + \`npm run sync-all\`〔npm-only〕;刻意用 plugin 才跑 /plugin marketplace update)。"
|
|
269
269
|
fi
|
|
270
270
|
# (b) node 在 PATH — audit scripts 依賴
|
|
271
271
|
if ! command -v node >/dev/null 2>&1; then
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# Tests for check_app_shell_primary_header_consistency.sh
|
|
3
3
|
#
|
|
4
|
-
# Hook(PreToolUse Edit/Write):偵測 AppShell consumer
|
|
4
|
+
# Hook(PreToolUse Edit/Write):偵測 AppShell consumer 3 violations:
|
|
5
5
|
# V1 layout="primary-header" 缺 globalHeader prop
|
|
6
|
-
# V2 layout="primary-header" + 同 file 含 <SidebarHeader>
|
|
6
|
+
# V2 layout="primary-header" + 同 file 含 <SidebarHeader>(useSidebar/isMobile 豁免)
|
|
7
|
+
# V3 layout="primary-header" + 同 file 含 <SidebarFooter>(帳號家在 header 右,非 footer;無 isMobile 豁免)
|
|
7
8
|
#
|
|
8
9
|
# Hook 透過 stdin 讀 tool_input(INPUT=$(cat) + jq;2026-05-31 改 env→stdin 對齊 sibling helper + 讓 dispatcher 能呼叫)
|
|
9
10
|
# 且需 TARGET file 真實存在於 disk(`[[ ! -f "$TARGET" ]] && exit 0`)。
|
|
@@ -143,6 +144,49 @@ const { isMobile } = useSidebar()
|
|
|
143
144
|
'
|
|
144
145
|
expect_pass_silent "8. responsive isMobile + SidebarHeader → silent(mobile-only 補品牌豁免)"
|
|
145
146
|
|
|
147
|
+
# 9. layout="primary-header" + <SidebarFooter> → block (V3)
|
|
148
|
+
# (2026-06-18 beta.74:primary-header 帳號家在 header 右,sidebar footer 是 primary-sidebar 慣例;無 isMobile 豁免)
|
|
149
|
+
run_hook_on_file "src/ph-footer.tsx" '
|
|
150
|
+
<AppShell layout="primary-header" globalHeader={<GH />}>
|
|
151
|
+
<Sidebar>
|
|
152
|
+
<SidebarFooter>account</SidebarFooter>
|
|
153
|
+
</Sidebar>
|
|
154
|
+
</AppShell>
|
|
155
|
+
'
|
|
156
|
+
expect_block "9. V3 primary-header + SidebarFooter → block" "V3 Sidebar 內含 SidebarFooter"
|
|
157
|
+
|
|
158
|
+
# 10. layout="primary-header" + mobile header-right account(SidebarHeader 補品牌+帳號,無 SidebarFooter)→ silent
|
|
159
|
+
# (2026-06-18:帳號鏡像 globalHeader 到 Sheet header 右,無 footer = 合規;V2 isMobile 豁免 + V3 無 footer)
|
|
160
|
+
run_hook_on_file "src/ph-header-account.tsx" '
|
|
161
|
+
const { isMobile } = useSidebar()
|
|
162
|
+
<AppShell layout="primary-header" globalHeader={<GH />}>
|
|
163
|
+
<Sidebar>
|
|
164
|
+
{isMobile && <SidebarHeader><WorkspaceBrand /><AccountMenu /></SidebarHeader>}
|
|
165
|
+
</Sidebar>
|
|
166
|
+
</AppShell>
|
|
167
|
+
'
|
|
168
|
+
expect_pass_silent "10. primary-header + header-right account, no footer → silent"
|
|
169
|
+
|
|
170
|
+
# 11. single-quote JSX layout={'primary-header'} missing globalHeader → block (V1)
|
|
171
|
+
# (2026-06-18 beta.74 regression:octal \047 gate bug → 單引號 JSX 整個 hook 靜默 skip;fix 後三種引號形式皆偵測)
|
|
172
|
+
run_hook_on_file "src/single-quote.tsx" "
|
|
173
|
+
<AppShell layout={'primary-header'}>
|
|
174
|
+
<Sidebar />
|
|
175
|
+
</AppShell>
|
|
176
|
+
"
|
|
177
|
+
expect_block "11. single-quote layout JSX gate (octal fix regression) → V1 block" "V1 缺 globalHeader prop"
|
|
178
|
+
|
|
179
|
+
# 12. prefix-extended component name <SidebarFooterPanel> with primary-header → silent (tag-boundary guard, V3 no false-positive)
|
|
180
|
+
# (2026-06-18 beta.74 audit P2#4:`<SidebarFooter` 不該 match `<SidebarFooterPanel`)
|
|
181
|
+
run_hook_on_file "src/prefix-extended.tsx" '
|
|
182
|
+
<AppShell layout="primary-header" globalHeader={<GH />}>
|
|
183
|
+
<Sidebar>
|
|
184
|
+
<SidebarFooterPanel>not the DS SidebarFooter</SidebarFooterPanel>
|
|
185
|
+
</Sidebar>
|
|
186
|
+
</AppShell>
|
|
187
|
+
'
|
|
188
|
+
expect_pass_silent "12. prefix-extended <SidebarFooterPanel> → silent(V3 tag-boundary 不誤觸)"
|
|
189
|
+
|
|
146
190
|
echo ""
|
|
147
191
|
echo "=== Summary ==="
|
|
148
192
|
echo "Passed: $PASS / $((PASS + FAIL))"
|
|
@@ -345,6 +345,36 @@ export const P = () => (<div className="px-[var(--layout-space-loose)] border-b
|
|
|
345
345
|
'
|
|
346
346
|
expect_pass_silent "23. R9 skip FileViewer(isOverlay 家)→ 不檢查"
|
|
347
347
|
|
|
348
|
+
# 24. R10 link_canonical: text-primary hover:underline → P1 warn(非 block)
|
|
349
|
+
run_hook "PreToolUse" "Edit" "/foo/my-project/packages/design-system/src/components/Foo/foo.principles.stories.tsx" '
|
|
350
|
+
<span className="text-primary hover:underline font-medium cursor-pointer">查看詳情</span>
|
|
351
|
+
'
|
|
352
|
+
expect_warn "24. R10 text-primary hover:underline → P1 warn" "R10 link_canonical"
|
|
353
|
+
|
|
354
|
+
# 25. R10 canonical(hover:text-primary-hover 換色)→ silent
|
|
355
|
+
run_hook "PreToolUse" "Edit" "/foo/my-project/packages/design-system/src/components/Foo/foo.principles.stories.tsx" '
|
|
356
|
+
<span className="text-primary hover:text-primary-hover font-medium cursor-pointer">查看詳情</span>
|
|
357
|
+
'
|
|
358
|
+
expect_pass_silent "25. R10 canonical hover:text-primary-hover → silent"
|
|
359
|
+
|
|
360
|
+
# 26. R10 escape marker @link-style-allow → silent
|
|
361
|
+
run_hook "PreToolUse" "Edit" "/foo/my-project/packages/design-system/src/components/Foo/foo.principles.stories.tsx" '// @link-style-allow: legacy doc-nav underline
|
|
362
|
+
<span className="text-primary hover:underline">查看詳情</span>
|
|
363
|
+
'
|
|
364
|
+
expect_pass_silent "26. R10 @link-style-allow 豁免 → silent"
|
|
365
|
+
|
|
366
|
+
# 27. R10 broadened: class-separated(cursor-pointer 隔開)text-primary … hover:underline → warn
|
|
367
|
+
run_hook "PreToolUse" "Edit" "/foo/my-project/packages/design-system/src/components/Foo/foo.anatomy.stories.tsx" '
|
|
368
|
+
<button className="text-caption text-primary cursor-pointer hover:underline">重設</button>
|
|
369
|
+
'
|
|
370
|
+
expect_warn "27. R10 class-separated text-primary…hover:underline → warn" "R10 link_canonical"
|
|
371
|
+
|
|
372
|
+
# 28. R10 不誤判描述 label「text-primary · hover:underline」(· 非 class-char,如 LinkInput anatomy 註解)→ silent
|
|
373
|
+
run_hook "PreToolUse" "Edit" "/foo/my-project/packages/design-system/src/components/Foo/foo.anatomy.stories.tsx" '
|
|
374
|
+
<span className="text-fg-muted font-mono">text-primary · hover:underline · 點擊開啟連結</span>
|
|
375
|
+
'
|
|
376
|
+
expect_pass_silent "28. R10 描述 label(· 分隔)→ 不誤判"
|
|
377
|
+
|
|
348
378
|
echo ""
|
|
349
379
|
echo "=== Summary ==="
|
|
350
380
|
echo "Passed: $PASS / $((PASS + FAIL))"
|
|
@@ -173,7 +173,7 @@ User 2026-05-15 verbatim 抓「DS 深度稽核漏 storybook content quality」+
|
|
|
173
173
|
| 53 | **Code-to-spec reverse drift check**(2026-05-17 user 抓 Phase 1 漏抓 FileViewer h-14 spec drift,新加 dim)| 對每 component grep `packages/design-system/src/components/<X>/<X>.tsx` 的 className 硬寫 utility(`h-14` / `w-80` / `px-loose` 類)→ 反向掃對應 `<X>.spec.md` 是否仍寫「固定 h-NN」「寫死」keyword 但 code 已 migrate to token = drift。互補既有 forward Dim 15/20(spec → code)。Hook `check_spec_class_drift.sh` write-time soft P1 warn,本 dim batch verify 既有 60+ 元件 spec.md。錨例:2026-05-17 Phase 1 我 file-viewer.spec.md L103 寫「Known drift:h-14 硬寫不消費 token」但 file-viewer.tsx:333 已 `h-[var(--chrome-header-height)]`,3+ 次 `/design-system-audit --deep` 都沒抓到反向 drift |
|
|
174
174
|
| 54 | **M35 Nearest same-purpose canonical compliance**(2026-05-20 codify per codex Layer B D4)| 對每 `*.stories.tsx` wrap 既有 primitive(Sidebar / DataTable / ChromeHeader / Dialog / Sheet / Popover)的 file 跑:(a) 檔頭含 `@story-baseline:` cite marker?(b) `.claude/references/story-baseline-registry.json` 內 primitive 的 `requiredHelpers` 全 import?(c) `antiPatterns` regex 任一 match → fail?(d) `variantRules` button variant + size + iconOnly + pressed 全 satisfy?Hook `check_story_invariants.sh R8` write-time soft warn,本 dim batch verify。錨例:2026-05-20 AppShell stories 連 5 round drift 後 codex Layer B 抓 root cause = SSOT 消費被當引用儀式 |
|
|
175
175
|
| 55 | **Token cross-namespace mapping integrity**(2026-05-20 codify per user 抓 red→deep-orange bug 100+ audit 沒發現)| `tokens/color/semantic.css` 每 hue interaction token(`--blue-hover` / `--red-hover` / ...)必指向**同名**primitive(`--red-hover: var(--color-red-N)`),**禁**跨 hue 混(`--red-hover: var(--color-deep-orange-N)` 違反)。Primitive 12 hue 全該有對應 interaction(blue/red/deep-orange/orange/amber/yellow/lime/green/turquoise/indigo/purple/magenta)。Status semantic(`--error-hover` 等)直指 primitive,**不**透過 hue layer。錨例:2026-05-20 semantic.css:246 `--red-hover: var(--color-deep-orange-5)` cross-namespace bug,100+ audit 沒發現 = audit 沒檢 token mapping integrity |
|
|
176
|
-
| 56 | **AppShell primary-header consistency**(2026-05-21 codify
|
|
176
|
+
| 56 | **AppShell primary-header consistency**(2026-05-21 codify;2026-06-18 beta.74 擴 V3 + responsive 豁免)| 對每 consumer `.tsx`(stories / app code)grep `layout="primary-header"`(三種 JSX 引號形式 `layout="x"` / `{"x"}` / `{'x'}` 皆偵測,grep -E 字面引號),verify 3 條:(V1) 同 file 含 `globalHeader=` prop(否則邏輯矛盾)/(V2) 不含裸 `<SidebarHeader>`(WorkspaceBrand 該在 globalHeader,不重複;**例外**:同 file 用 `useSidebar`/`isMobile` = mobile-only Sheet 補品牌的 responsive fork → 豁免)/(V3) 不含 `<SidebarFooter>`(帳號入口家在 globalHeader 右、收成 Sheet 鏡像到 Sheet header 右,**不該**用 sidebar footer〔那是 primary-sidebar 慣例〕;**無** isMobile 豁免)。trigger 用 tag-boundary `([^A-Za-z]|$)` 避 prefix-extended 名誤觸。World-class cite:GitHub repo sidebar 無 header + Gmail / Figma brand 在 global top bar + Material modal nav drawer「account switcher 放 drawer header」。Hook `check_app_shell_primary_header_consistency.sh`(V1-V3)write-time exit 2 BLOCKER(via chrome_header_dispatcher,可 escape `// @app-shell-primary-header-allow:`)。對應 `app-shell.spec.md`「WorkspaceBrand 放置 SSOT」+「帳號入口(Account entry)放置 SSOT」段(均含 Responsive 精修子句)|
|
|
177
177
|
| 57 | **M29 DS Anchor Preflight enforcement coverage**(2026-05-26 codify per user verbatim「該程式化的都沒程式化」)| 對每 `*.tsx`(production code,非 stories / test)grep wrap DS primitive(`<Sidebar>` / `<AppShell>` / `<DataTable>` 等)→ verify 過去 30 turns transcript 含 `Grep`/`Read` tool call hit `packages/design-system/src/**/*.spec.md` 或 `*.stories.tsx`,OR 檔頭含 `@story-baseline:` marker 或 inline 3-column owner table。Hook `check_ds_anchor_preflight.sh` write-time soft BLOCKER。對應 meta-patterns.md M29 + self-verify.md Pre-edit phase。錨例:2026-05-26 App.tsx 漏 SidebarTrigger / collapsible / startIcon mock-drift = M29 hook 不存在使 infra 沒攔 |
|
|
178
178
|
| 58 | **Fork-user plugin install enforcement**(2026-05-26 codify per user「我們做那麼多 plugin 不就是要避免這件事?」)| SessionStart hook `check_plugin_fork_health.sh(r1,2026-06-11 merge)` 偵測:(a) cwd 不是 DS repo(無 `packages/design-system/src`)/(b) `package.json` 含 `@qijenchen/design-system` dep /(c) `~/.claude/plugins/design-system/` OR `.claude/plugins/design-system/` 不存在 → 三題 YES 印強制提示。互補 product-workspace `scripts/check-plugin-installed.mjs` npm postinstall layer。**+ 2026-05-30 fork-committed bootstrap 層(補 chicken-egg:plugin 硬 hook 隨 plugin 才裝,沒裝前無 mechanical 防線)**:fork 自帶 `template/ds-product-template/.claude/hooks/check_plugin_bootstrap.sh`(SessionStart 每 session 提醒,fail-open)+ `block_production_edit_without_plugin.sh`(PreToolUse 硬攔 `apps/**` production .tsx/.ts/.css edit,沒裝 plugin → exit 2 BLOCK,escape `CLAUDE_BYPASS_PLUGIN_BOOTSTRAP=1`)+ `.claude/settings.json` hooks 註冊;**不依賴 plugin**(committed in fork),mirror allowlist `.claude` ship 給 published fork。對應 product-workspace/CLAUDE.md「第 −1 步」段 |
|
|
179
179
|
| 59 | **Approval preflight scope coverage**(2026-05-26 extend per user「未來其他人 fork 用其他元件也偏移」)| `check_substantive_edit_approval_preflight.sh` scope 從 `packages/design-system/src/**` 擴大到 `apps/**.{tsx,ts,css}` + `node_modules/@qijenchen/design-system/**`。Audit verify hook regex 涵蓋三 scope + allowlist `*.stories.tsx`/`*.test.*`/`scripts/*`。對應 memory/feedback_ship_then_revert_anti_pattern.md SSOT |
|
|
@@ -192,7 +192,7 @@ User 2026-05-15 verbatim 抓「DS 深度稽核漏 storybook content quality」+
|
|
|
192
192
|
| 72 | **DS API surface tightening**(2026-05-27 — 治標 vs 治本)| Hook 71 偵測 anti-pattern 是 lint 層攔截;治本要 DS API design 強到 misuse 即 fail tsc。Audit:逐 component review API surface — `size?: number` 該改 `'sm'\|'md'\|'lg'` enum / `columns: Column[]` 該加 min length runtime check / `title` + `description` 該有 type-level XOR / Overlay primitive `defaultOpen` 該 require explicit。配套 codify in `tightening-roadmap.md`(若存在;不存在則以 `props-naming.md` + 各 spec API 段為準,對齊 audit-prompts.md dim 72),分 quarter ship。對應 Dim 71 是攔當前 misuse,本 dim 是消除未來 misuse 可能 |
|
|
193
193
|
| 73 | **Full-story visual+interaction sweep enforce**(2026-05-27 codex M31 P0 finding)| Audit report JSON `storyResults.length === manifest.totalStories`(916)。Sample < 916 = reject(per user「不准抽樣」)。Hook `check_full_story_visual_interaction_sweep.sh` PostToolUse audit-report.json BLOCKER。Escape `"_sampling_allowed": "<rationale>"`(極罕見)|
|
|
194
194
|
| 74 | **Overlay open/focus/Escape probe**(2026-05-27 codex M31 P0 finding + user 7-bug 錨點「overlay 沒彈出」)| Consumer story 用 Tooltip / Popover / Dialog / Sheet / DropdownMenu / HoverCard Trigger 必含 `defaultOpen` OR `open={true}` OR `play()` interaction click。Trigger-only catalog = reject(visual snapshot 看不到 content)。Hook `check_overlay_open_focus_escape_probe.sh` BLOCKER。HoverCard exception via `@story-trait-allow: missing-opensnapshot` per codex |
|
|
195
|
-
| 75 | **Plugin freshness session-start prompt**(2026-05-27 chain-C ship + user「主動引導」directive)| Fork user session_start hook `check_plugin_fork_health.sh(r2,2026-06-11 merge)` reads local installed plugin.json version → fetch GitHub raw marketplace.json → diff version → if stale prompt run `npm run sync-all`. Sync-all 1-command
|
|
195
|
+
| 75 | **Plugin freshness session-start prompt**(2026-05-27 chain-C ship + user「主動引導」directive)| Fork user session_start hook `check_plugin_fork_health.sh(r2,2026-06-11 merge)` reads local installed plugin.json version → fetch GitHub raw marketplace.json → diff version → if stale prompt run `npm run sync-all`. Sync-all 1-command(2026-06-17 起 npm-only,不再跑 `claude plugin`):npm update 治理本體 + idempotent 刷新接線骨架 + skills;生效分軌(機械即時 / settings 自動 hot-reload / 指引 `/clear` 或下個 session)|
|
|
196
196
|
| 76 | **Escape marker abuse cap**(2026-05-27 per user「不亂加 escape markers」)| Consumer file 10 escape markers 累計 ≥3 distinct types OR ≥5 total → BLOCK。修法 3 選 1:重構走 DS canonical / 拆 file / env override `CLAUDE_BYPASS_ESCAPE_MARKER_AUDIT`。Hook `check_escape_marker_abuse.sh` enforces escape philosophy「rare per-line documented exception,非 daily tool」|
|
|
197
197
|
| 77 | **Composition-fidelity:conformance-primary,pixel-identity opt-in**(2026-05-27 ship / **2026-06-02 model 修正**)| Consumer 對 DS 用法正確性**主要由靜態 conformance 驗**(dim 71 含 Pattern 8 + `check_layout_space_magic_numbers` + R7/R8),對齊世界級 static lint(Polaris stylelint-polaris / Atlassian eslint-plugin-design-system / Carbon stylelint-plugin-carbon-tokens;WebFetch verified)。`scripts/composition-fidelity-visual-diff.mjs` 的 pixel/DOM identity diff 改**明確 opt-in**:只比標 `@composition-fidelity-mode` 的 mapping(忠實複製 replica / same-story 跨版本回歸,對齊 Chromatic/Storybook same-story baseline);單獨 `@story-baseline` = conformance 不做 identity diff;0 opt-in → exit 0。**禁** 拿產品範本(內容刻意不同)pixel 比 DS showcase(world-class 公認反 pattern)。SSOT `composition-fidelity.md`。CI `.github/workflows/composition-fidelity.yml` |
|
|
198
198
|
| 78 | **Codex brief 禁列檔 invariant**(2026-05-27 codify per codex v1+v2 token-burn 2× anchor)| `check_codex_brief_invariants.sh` 4th invariant check:codex CLI brief 必含「禁列檔 / 禁 rg --files / 只讀 N file / 直接出 verdict」keyword,否則 codex 自動跑 `rg --files` 列 1300+ files 燒光 reasoning,無法產出 Step 5 Verdict(M31 Step 4.5 last-verdict gate fail)。Hook PreToolUse Bash codex exec/review 偵測 → BLOCKER。Escape `// @codex-brief-invariant-skip:` |
|
package/llms-full.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @qijenchen/design-system — 完整設計參考(llms-full)
|
|
2
2
|
|
|
3
|
-
> 全 component / pattern 的 variants / sizes / 禁止事項。build-time 從 spec.md frontmatter 生成,禁手改。v0.1.0-beta.
|
|
3
|
+
> 全 component / pattern 的 variants / sizes / 禁止事項。build-time 從 spec.md frontmatter 生成,禁手改。v0.1.0-beta.75。
|
|
4
4
|
|
|
5
5
|
# Components
|
|
6
6
|
|
package/llms.txt
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @qijenchen/design-system
|
|
2
2
|
|
|
3
3
|
> World-class React design system(Radix/shadcn + Tailwind v4 + 自訂 design token)。
|
|
4
|
-
> 54 components + 4 public patterns + design tokens。v0.1.0-beta.
|
|
4
|
+
> 54 components + 4 public patterns + design tokens。v0.1.0-beta.75。
|
|
5
5
|
|
|
6
6
|
本檔由 source(spec.md frontmatter + Storybook index)build-time 自動生成,**禁手改**(CI --check drift gate 守)。
|
|
7
7
|
每元件 / pattern 的完整 variants / sizes / 禁止事項 全文見 [llms-full.txt](./llms-full.txt)。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qijenchen/design-system",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.75",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "World-class design system — components, patterns, tokens, hooks (single source of truth for team distribution).",
|
|
6
6
|
"type": "module",
|
|
@@ -69,13 +69,13 @@ export const UsageGuidance: Story = {
|
|
|
69
69
|
>
|
|
70
70
|
<ul className="space-y-1">
|
|
71
71
|
<li>
|
|
72
|
-
<LinkTo kind="Design System/Components/Accordion/展示" name="FAQ 常見問題"><span className="text-primary hover:
|
|
72
|
+
<LinkTo kind="Design System/Components/Accordion/展示" name="FAQ 常見問題"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">FAQ 常見問題</span></LinkTo>
|
|
73
73
|
</li>
|
|
74
74
|
<li>
|
|
75
|
-
<LinkTo kind="Design System/Components/Accordion/展示" name="設定分組"><span className="text-primary hover:
|
|
75
|
+
<LinkTo kind="Design System/Components/Accordion/展示" name="設定分組"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">設定分組</span></LinkTo>
|
|
76
76
|
</li>
|
|
77
77
|
<li>
|
|
78
|
-
<LinkTo kind="Design System/Components/Accordion/展示" name="進階選項可隱藏"><span className="text-primary hover:
|
|
78
|
+
<LinkTo kind="Design System/Components/Accordion/展示" name="進階選項可隱藏"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">進階選項可隱藏</span></LinkTo>
|
|
79
79
|
</li>
|
|
80
80
|
</ul>
|
|
81
81
|
</Rule>
|
|
@@ -41,19 +41,19 @@ export const UsageGuidance: Story = {
|
|
|
41
41
|
<p>適合 Alert 的真實業務場景(點擊跳轉「展示」頁範例):</p>
|
|
42
42
|
<ul className="space-y-1">
|
|
43
43
|
<li>
|
|
44
|
-
<LinkTo kind="Design System/Components/Alert/展示" name="低調單行"><span className="text-primary hover:
|
|
44
|
+
<LinkTo kind="Design System/Components/Alert/展示" name="低調單行"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">低調單行</span></LinkTo>
|
|
45
45
|
</li>
|
|
46
46
|
<li>
|
|
47
|
-
<LinkTo kind="Design System/Components/Alert/展示" name="實心單行"><span className="text-primary hover:
|
|
47
|
+
<LinkTo kind="Design System/Components/Alert/展示" name="實心單行"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">實心單行</span></LinkTo>
|
|
48
48
|
</li>
|
|
49
49
|
<li>
|
|
50
|
-
<LinkTo kind="Design System/Components/Alert/展示" name="低調含說明文字"><span className="text-primary hover:
|
|
50
|
+
<LinkTo kind="Design System/Components/Alert/展示" name="低調含說明文字"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">低調含說明文字</span></LinkTo>
|
|
51
51
|
</li>
|
|
52
52
|
<li>
|
|
53
|
-
<LinkTo kind="Design System/Components/Alert/展示" name="實心含說明文字"><span className="text-primary hover:
|
|
53
|
+
<LinkTo kind="Design System/Components/Alert/展示" name="實心含說明文字"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">實心含說明文字</span></LinkTo>
|
|
54
54
|
</li>
|
|
55
55
|
<li>
|
|
56
|
-
<LinkTo kind="Design System/Components/Alert/展示" name="右上角操作群組"><span className="text-primary hover:
|
|
56
|
+
<LinkTo kind="Design System/Components/Alert/展示" name="右上角操作群組"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">右上角操作群組</span></LinkTo>
|
|
57
57
|
</li>
|
|
58
58
|
</ul>
|
|
59
59
|
<p className="text-fg-muted mt-3">判斷不確定時:對照 spec.md「何時用 / 何時不用」段;若仍不符,改用近親元件(見 <code>Vs*Rule</code> stories)。</p>
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
SidebarTrigger,
|
|
29
29
|
useSidebar,
|
|
30
30
|
} from '@/design-system/components/Sidebar/sidebar'
|
|
31
|
+
import { useAppShell } from '@/design-system/components/AppShell/app-shell'
|
|
31
32
|
import { ChromeHeader } from '@/design-system/patterns/header-canonical/chrome-header'
|
|
32
33
|
import {
|
|
33
34
|
ItemAvatar,
|
|
@@ -126,17 +127,31 @@ export function AcmeSidebar({
|
|
|
126
127
|
includeWorkspaceBrand?: boolean
|
|
127
128
|
includeUserFooter?: boolean
|
|
128
129
|
} = {}) {
|
|
129
|
-
// Responsive 品牌/帳號(2026-06-18):小螢幕 sidebar 收成 Sheet(z-50)打開時會「蓋住」globalHeader →
|
|
130
|
-
// primary-header 把品牌+帳號放 globalHeader,Sheet 內就看不到、drawer 變孤兒。故 mobile 時在 sidebar
|
|
131
|
-
//
|
|
132
|
-
// primary-
|
|
133
|
-
//
|
|
130
|
+
// Responsive 品牌/帳號(2026-06-18 v2):小螢幕 sidebar 收成 Sheet(z-50)打開時會「蓋住」globalHeader →
|
|
131
|
+
// primary-header 把品牌+帳號放 globalHeader,Sheet 內就看不到、drawer 變孤兒。故 mobile 時在 sidebar 內補回。
|
|
132
|
+
// **每 mode 鏡像自己桌面的帳號家**(per app-shell.spec.md「帳號入口(Account entry)放置 SSOT」Responsive 精修):
|
|
133
|
+
// - primary-header:桌面帳號在 globalHeader 右(brand 左 / account 右)→ Sheet 內把整條 globalHeader 搬進
|
|
134
|
+
// SidebarHeader(brand + flex-1 + AccountMenu;**SidebarHeader 即 ChromeHeader 基底,與 GlobalHeader 同
|
|
135
|
+
// primitive** = 結構 SSOT,非手刻對齊),**不放 SidebarFooter**(footer 是 primary-sidebar 慣例;
|
|
136
|
+
// 對齊 Material modal navigation drawer「帳號 switcher 放 drawer header,非 footer」)。
|
|
137
|
+
// - primary-sidebar:桌面帳號在 sidebar 底(SidebarFooter)→ Sheet 維持 header=brand / footer=UserFooter(不變)。
|
|
138
|
+
// desktop(globalHeader 可見)維持 headerless/footerless,不重複。「只能出現一次」= 同一時間一次,per breakpoint 判定。
|
|
134
139
|
const { isMobile } = useSidebar()
|
|
140
|
+
const { layout } = useAppShell()
|
|
141
|
+
// primary-header 收成 Sheet:帳號入口鏡像 globalHeader 放 SidebarHeader 右(SidebarHeader = ChromeHeader 基底,
|
|
142
|
+
// 與 GlobalHeader「brand 左 + flex-1 + account 右」完全同結構 → avatar 24px + 右緣距 px-loose 由 construction 保證)。
|
|
143
|
+
const headerHasAccount = layout === 'primary-header' && isMobile
|
|
135
144
|
return (
|
|
136
145
|
<Sidebar collapsible="icon" viewportInsetTop={viewportInsetTop}>
|
|
137
146
|
{(includeWorkspaceBrand || isMobile) && (
|
|
138
147
|
<SidebarHeader>
|
|
139
148
|
<WorkspaceBrand />
|
|
149
|
+
{headerHasAccount && (
|
|
150
|
+
<>
|
|
151
|
+
<div className="flex-1" />
|
|
152
|
+
<AccountMenu />
|
|
153
|
+
</>
|
|
154
|
+
)}
|
|
140
155
|
</SidebarHeader>
|
|
141
156
|
)}
|
|
142
157
|
<SidebarContent>
|
|
@@ -158,7 +173,9 @@ export function AcmeSidebar({
|
|
|
158
173
|
</SidebarGroupContent>
|
|
159
174
|
</SidebarGroup>
|
|
160
175
|
</SidebarContent>
|
|
161
|
-
{(
|
|
176
|
+
{/* Footer 只 primary-sidebar(帳號在 sidebar 底);primary-header 帳號改放 SidebarHeader 右(見上),
|
|
177
|
+
mobile 也不放 footer(誤用他 mode 慣例)。 */}
|
|
178
|
+
{includeUserFooter && (
|
|
162
179
|
<SidebarFooter>
|
|
163
180
|
<UserFooter />
|
|
164
181
|
</SidebarFooter>
|
|
@@ -18,15 +18,15 @@ export const UsageGuidance: Story = {
|
|
|
18
18
|
<ul className="text-body space-y-2">
|
|
19
19
|
<li>
|
|
20
20
|
• 多頁 web service 的主結構——Linear / Notion / Slack / GitHub / Asana 這類「左側導覽 + 中央工作區」產品。完整組合見{' '}
|
|
21
|
-
<LinkTo kind="Design System/Components/AppShell/展示" name="主側欄佈局 — Linear 式議題追蹤"><span className="text-primary hover:
|
|
21
|
+
<LinkTo kind="Design System/Components/AppShell/展示" name="主側欄佈局 — Linear 式議題追蹤"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">展示 → 主側欄佈局 — Linear 式議題追蹤</span></LinkTo>
|
|
22
22
|
</li>
|
|
23
23
|
<li>
|
|
24
24
|
• 需要 sidebar + main 持續共存——在議題列表、看板、報表等頁面間切換時,左側導覽不重渲染、捲動位置不丟失。見{' '}
|
|
25
|
-
<LinkTo kind="Design System/Components/AppShell/展示" name="主側欄佈局 + 頁面分頁"><span className="text-primary hover:
|
|
25
|
+
<LinkTo kind="Design System/Components/AppShell/展示" name="主側欄佈局 + 頁面分頁"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">展示 → 主側欄佈局 + 頁面分頁</span></LinkTo>
|
|
26
26
|
</li>
|
|
27
27
|
<li>
|
|
28
28
|
• 需要右側詳情面板(議題詳情 / inspector / 成員資料)跟 main 並存——如 Linear 點選議題後右側展開詳情。開合行為見{' '}
|
|
29
|
-
<LinkTo kind="Design System/Components/AppShell/設計規格" name="右側面板開合行為(兩種模式)"><span className="text-primary hover:
|
|
29
|
+
<LinkTo kind="Design System/Components/AppShell/設計規格" name="右側面板開合行為(兩種模式)"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">設計規格 → 右側面板開合行為</span></LinkTo>
|
|
30
30
|
</li>
|
|
31
31
|
</ul>
|
|
32
32
|
</section>
|
|
@@ -46,7 +46,7 @@ export const UsageGuidance: Story = {
|
|
|
46
46
|
<p className="text-body">
|
|
47
47
|
兩種佈局模式(primary-sidebar / primary-header)的選型決策樹獨立成「佈局模式怎麼選」story(含
|
|
48
48
|
WorkspaceBrand 放置規則),見本頁側欄或{' '}
|
|
49
|
-
<LinkTo kind="Design System/Components/AppShell/設計原則" name="佈局模式怎麼選"><span className="text-primary hover:
|
|
49
|
+
<LinkTo kind="Design System/Components/AppShell/設計原則" name="佈局模式怎麼選"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">設計原則 → 佈局模式怎麼選</span></LinkTo>
|
|
50
50
|
</p>
|
|
51
51
|
</section>
|
|
52
52
|
|
|
@@ -73,8 +73,9 @@ export const UsageGuidance: Story = {
|
|
|
73
73
|
),
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
// 佈局模式選型 deep-dive — 內容錨定 app-shell.spec.md
|
|
77
|
-
//
|
|
76
|
+
// 佈局模式選型 deep-dive — 內容錨定 app-shell.spec.md 的「Layout mode 兩 mode 差異」+「WorkspaceBrand 放置 SSOT」
|
|
77
|
+
// +「帳號入口(Account entry)放置 SSOT」段(均含 Responsive 精修子句;用段名錨定不寫死行號避免 drift)。
|
|
78
|
+
// category-templates.md component-specific `{Topic}Rule` idiom
|
|
78
79
|
export const LayoutModeRule: Story = {
|
|
79
80
|
name: '佈局模式怎麼選',
|
|
80
81
|
render: () => (
|
|
@@ -97,12 +98,12 @@ export const LayoutModeRule: Story = {
|
|
|
97
98
|
服務整個 app(account / workspace switcher / 跨頁 search / notifications);local toolbar
|
|
98
99
|
<em>仍在</em> main col 頂,只是上面多了 global header。WorkspaceBrand 改放 globalHeader 左側。
|
|
99
100
|
參考 GitHub / Slack / Gmail。完整組合見{' '}
|
|
100
|
-
<LinkTo kind="Design System/Components/AppShell/展示" name="主標頭佈局 — 全域+本地兩層(GitHub/Gmail/Slack 派)"><span className="text-primary hover:
|
|
101
|
+
<LinkTo kind="Design System/Components/AppShell/展示" name="主標頭佈局 — 全域+本地兩層(GitHub/Gmail/Slack 派)"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">展示 → 主標頭佈局 — 全域+本地兩層</span></LinkTo>
|
|
101
102
|
</li>
|
|
102
103
|
</ul>
|
|
103
104
|
<p className="text-caption text-fg-secondary mt-2">
|
|
104
105
|
兩 mode 是 product 角色表態——啟動時固定,不該在 runtime 切換。視覺對照圖見{' '}
|
|
105
|
-
<LinkTo kind="Design System/Components/AppShell/設計規格" name="兩種布局模式對照圖"><span className="text-primary hover:
|
|
106
|
+
<LinkTo kind="Design System/Components/AppShell/設計規格" name="兩種布局模式對照圖"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">設計規格 → 兩種布局模式對照圖</span></LinkTo>
|
|
106
107
|
</p>
|
|
107
108
|
</section>
|
|
108
109
|
|