pigment-mcp 0.8.0 → 0.11.0
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/cli.js +36 -14
- package/content/registry.json +25 -1
- package/content/shots.json +46 -0
- package/content/templates/graphite-blueprint/1.0.0/CHANGELOG.md +77 -0
- package/content/templates/graphite-blueprint/1.0.0/agent/instructions.md +38 -0
- package/content/templates/graphite-blueprint/1.0.0/components/badge.md +16 -0
- package/content/templates/graphite-blueprint/1.0.0/components/button.md +18 -0
- package/content/templates/graphite-blueprint/1.0.0/components/card.md +13 -0
- package/content/templates/graphite-blueprint/1.0.0/components/checkbox.md +13 -0
- package/content/templates/graphite-blueprint/1.0.0/components/dialog.md +11 -0
- package/content/templates/graphite-blueprint/1.0.0/components/empty-state.md +9 -0
- package/content/templates/graphite-blueprint/1.0.0/components/index.json +17 -0
- package/content/templates/graphite-blueprint/1.0.0/components/navigation.md +17 -0
- package/content/templates/graphite-blueprint/1.0.0/components/select.md +12 -0
- package/content/templates/graphite-blueprint/1.0.0/components/switch.md +11 -0
- package/content/templates/graphite-blueprint/1.0.0/components/table.md +28 -0
- package/content/templates/graphite-blueprint/1.0.0/components/tabs.md +10 -0
- package/content/templates/graphite-blueprint/1.0.0/components/text-field.md +17 -0
- package/content/templates/graphite-blueprint/1.0.0/components/toast.md +11 -0
- package/content/templates/graphite-blueprint/1.0.0/dist/agent.md +976 -0
- package/content/templates/graphite-blueprint/1.0.0/dist/tokens.css +349 -0
- package/content/templates/graphite-blueprint/1.0.0/dist/tokens.json +540 -0
- package/content/templates/graphite-blueprint/1.0.0/manifest.json +77 -0
- package/content/templates/graphite-blueprint/1.0.0/principles/visual-language.md +475 -0
- package/content/templates/graphite-blueprint/1.0.0/tokens/primitives.json +714 -0
- package/content/templates/graphite-blueprint/1.0.0/tokens/semantic.dark.json +245 -0
- package/content/templates/graphite-blueprint/1.0.0/tokens/semantic.light.json +245 -0
- package/content/templates/graphite-blueprint/1.1.0/CHANGELOG.md +280 -0
- package/content/templates/graphite-blueprint/1.1.0/agent/instructions.md +41 -0
- package/content/templates/graphite-blueprint/1.1.0/components/badge.md +15 -0
- package/content/templates/graphite-blueprint/1.1.0/components/button.md +18 -0
- package/content/templates/graphite-blueprint/1.1.0/components/card.md +12 -0
- package/content/templates/graphite-blueprint/1.1.0/components/checkbox.md +11 -0
- package/content/templates/graphite-blueprint/1.1.0/components/dialog.md +11 -0
- package/content/templates/graphite-blueprint/1.1.0/components/empty-state.md +9 -0
- package/content/templates/graphite-blueprint/1.1.0/components/index.json +17 -0
- package/content/templates/graphite-blueprint/1.1.0/components/navigation.md +21 -0
- package/content/templates/graphite-blueprint/1.1.0/components/select.md +11 -0
- package/content/templates/graphite-blueprint/1.1.0/components/switch.md +11 -0
- package/content/templates/graphite-blueprint/1.1.0/components/table.md +52 -0
- package/content/templates/graphite-blueprint/1.1.0/components/tabs.md +12 -0
- package/content/templates/graphite-blueprint/1.1.0/components/text-field.md +17 -0
- package/content/templates/graphite-blueprint/1.1.0/components/toast.md +12 -0
- package/content/templates/graphite-blueprint/1.1.0/dist/agent.md +1016 -0
- package/content/templates/graphite-blueprint/1.1.0/dist/tokens.css +349 -0
- package/content/templates/graphite-blueprint/1.1.0/dist/tokens.json +540 -0
- package/content/templates/graphite-blueprint/1.1.0/manifest.json +77 -0
- package/content/templates/graphite-blueprint/1.1.0/principles/visual-language.md +486 -0
- package/content/templates/graphite-blueprint/1.1.0/tokens/primitives.json +714 -0
- package/content/templates/graphite-blueprint/1.1.0/tokens/semantic.dark.json +245 -0
- package/content/templates/graphite-blueprint/1.1.0/tokens/semantic.light.json +245 -0
- package/content/templates/night-cartridge/1.2.0/CHANGELOG.md +438 -0
- package/content/templates/night-cartridge/1.2.0/agent/instructions.md +40 -0
- package/content/templates/night-cartridge/1.2.0/components/badge.md +5 -0
- package/content/templates/night-cartridge/1.2.0/components/button.md +13 -0
- package/content/templates/night-cartridge/1.2.0/components/card.md +7 -0
- package/content/templates/night-cartridge/1.2.0/components/checkbox.md +7 -0
- package/content/templates/night-cartridge/1.2.0/components/dialog.md +7 -0
- package/content/templates/night-cartridge/1.2.0/components/empty-state.md +5 -0
- package/content/templates/night-cartridge/1.2.0/components/index.json +17 -0
- package/content/templates/night-cartridge/1.2.0/components/navigation.md +18 -0
- package/content/templates/night-cartridge/1.2.0/components/select.md +7 -0
- package/content/templates/night-cartridge/1.2.0/components/switch.md +7 -0
- package/content/templates/night-cartridge/1.2.0/components/table.md +17 -0
- package/content/templates/night-cartridge/1.2.0/components/tabs.md +7 -0
- package/content/templates/night-cartridge/1.2.0/components/text-field.md +7 -0
- package/content/templates/night-cartridge/1.2.0/components/toast.md +7 -0
- package/content/templates/night-cartridge/1.2.0/dist/agent.md +713 -0
- package/content/templates/night-cartridge/1.2.0/dist/tokens.css +196 -0
- package/content/templates/night-cartridge/1.2.0/dist/tokens.json +226 -0
- package/content/templates/night-cartridge/1.2.0/manifest.json +99 -0
- package/content/templates/night-cartridge/1.2.0/principles/visual-language.md +363 -0
- package/content/templates/night-cartridge/1.2.0/tokens/primitives.json +520 -0
- package/content/templates/night-cartridge/1.2.0/tokens/semantic.dark.json +220 -0
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -34493,7 +34493,7 @@ function resolveTokens(primitives, semantic) {
|
|
|
34493
34493
|
for (const [path, token] of all) resolved.set(path, { value: resolveValue(token.value, /* @__PURE__ */ new Set([path])), type: token.type });
|
|
34494
34494
|
return resolved;
|
|
34495
34495
|
}
|
|
34496
|
-
var TemplateId, SemVer, Hex, AppId, Scenario, TemplateStatus, Manifest, DtcgType, DtcgToken, ComponentCategory, ComponentEntry, ComponentIndex, AUDIT_AREAS, AuditArea, Evidence, Signature, Analysis, RunRecord, GateResult, CriticScores, EvalReport, Registry;
|
|
34496
|
+
var TemplateId, SemVer, Hex, AppId, HoldoutAppId, RunAppId, Scenario, TemplateStatus, Manifest, DtcgType, DtcgToken, ComponentCategory, ComponentEntry, ComponentIndex, AUDIT_AREAS, AuditArea, Evidence, Signature, Analysis, RunRecord, GateResult, CriticFinding, score, CriticScores, EvalReport, Registry;
|
|
34497
34497
|
var init_src = __esm({
|
|
34498
34498
|
"../schema/src/index.ts"() {
|
|
34499
34499
|
"use strict";
|
|
@@ -34502,6 +34502,8 @@ var init_src = __esm({
|
|
|
34502
34502
|
SemVer = external_exports.string().regex(/^\d+\.\d+\.\d+(-[0-9a-z.-]+)?$/, "semantic version, e.g. 1.0.0 or 0.1.0-rc.1");
|
|
34503
34503
|
Hex = external_exports.string().regex(/^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/, "6 or 8 digit hex");
|
|
34504
34504
|
AppId = external_exports.enum(["dashboard", "commerce", "blog", "settings"]);
|
|
34505
|
+
HoldoutAppId = external_exports.enum(["landing", "docs"]);
|
|
34506
|
+
RunAppId = external_exports.union([AppId, HoldoutAppId]);
|
|
34505
34507
|
Scenario = external_exports.enum(["new", "existing", "ongoing"]);
|
|
34506
34508
|
TemplateStatus = external_exports.enum(["draft", "candidate", "published", "deprecated"]);
|
|
34507
34509
|
Manifest = external_exports.object({
|
|
@@ -34682,7 +34684,7 @@ var init_src = __esm({
|
|
|
34682
34684
|
runId: external_exports.string(),
|
|
34683
34685
|
template: TemplateId,
|
|
34684
34686
|
version: SemVer,
|
|
34685
|
-
app:
|
|
34687
|
+
app: RunAppId,
|
|
34686
34688
|
scenario: Scenario,
|
|
34687
34689
|
agent: external_exports.enum(["claude", "codex"]),
|
|
34688
34690
|
model: external_exports.string().optional(),
|
|
@@ -34700,17 +34702,33 @@ var init_src = __esm({
|
|
|
34700
34702
|
threshold: external_exports.union([external_exports.number(), external_exports.string()]).optional(),
|
|
34701
34703
|
detail: external_exports.string().optional()
|
|
34702
34704
|
});
|
|
34705
|
+
CriticFinding = external_exports.object({
|
|
34706
|
+
severity: external_exports.enum(["blocker", "major", "minor"]),
|
|
34707
|
+
/** Rubric area: referenceFidelity, crossAppConsistency, hierarchy, spacingRhythm, componentStates, polish, signature. */
|
|
34708
|
+
area: external_exports.string(),
|
|
34709
|
+
summary: external_exports.string(),
|
|
34710
|
+
/** In how many of the evaluated samples it appears, and how many there were. */
|
|
34711
|
+
samples: external_exports.number().int().min(0),
|
|
34712
|
+
of: external_exports.number().int().min(1),
|
|
34713
|
+
/** The spec's own wording or recipe causes it (a missing, ambiguous or contradictory rule). */
|
|
34714
|
+
specCaused: external_exports.boolean().default(false),
|
|
34715
|
+
evidence: external_exports.array(external_exports.string()).default([]),
|
|
34716
|
+
/** A general rule that would prevent it in any product — never a fix tied to one demo app's screen or data. */
|
|
34717
|
+
promptFix: external_exports.string().optional()
|
|
34718
|
+
});
|
|
34719
|
+
score = external_exports.number().min(0).max(5);
|
|
34703
34720
|
CriticScores = external_exports.object({
|
|
34704
|
-
|
|
34705
|
-
|
|
34706
|
-
|
|
34707
|
-
|
|
34708
|
-
|
|
34709
|
-
|
|
34710
|
-
|
|
34711
|
-
signature:
|
|
34712
|
-
|
|
34713
|
-
|
|
34721
|
+
/** Descriptive only (the verdict comes from findings). Older critic files gate on them. */
|
|
34722
|
+
referenceFidelity: score.nullable().optional(),
|
|
34723
|
+
crossAppConsistency: score.optional(),
|
|
34724
|
+
hierarchy: score.optional(),
|
|
34725
|
+
spacingRhythm: score.optional(),
|
|
34726
|
+
componentStates: score.optional(),
|
|
34727
|
+
polish: score.optional(),
|
|
34728
|
+
signature: score.nullable().optional(),
|
|
34729
|
+
findings: external_exports.array(CriticFinding).optional(),
|
|
34730
|
+
notes: external_exports.array(external_exports.string()).default([]),
|
|
34731
|
+
promptFixes: external_exports.array(external_exports.string()).default([]).describe("Concrete spec changes that would fix the observed problems")
|
|
34714
34732
|
});
|
|
34715
34733
|
EvalReport = external_exports.object({
|
|
34716
34734
|
template: TemplateId,
|
|
@@ -34720,13 +34738,17 @@ var init_src = __esm({
|
|
|
34720
34738
|
runs: external_exports.array(
|
|
34721
34739
|
external_exports.object({
|
|
34722
34740
|
runId: external_exports.string(),
|
|
34723
|
-
app:
|
|
34741
|
+
app: RunAppId,
|
|
34724
34742
|
gates: external_exports.array(GateResult),
|
|
34725
34743
|
metrics: external_exports.record(external_exports.string(), external_exports.number())
|
|
34726
34744
|
})
|
|
34727
34745
|
),
|
|
34728
34746
|
crossApp: external_exports.array(GateResult).default([]),
|
|
34747
|
+
/** Measured layout defects (clipped or overlapping text, near-miss alignment, doubled rules, repeated drawings). */
|
|
34748
|
+
layout: external_exports.array(external_exports.object({ app: RunAppId, runId: external_exports.string(), route: external_exports.string(), viewport: external_exports.string(), kind: external_exports.string(), where: external_exports.string(), detail: external_exports.string() })).optional(),
|
|
34729
34749
|
critic: CriticScores.optional(),
|
|
34750
|
+
/** Agent spend of this version and of its whole family (all candidates), for the record. */
|
|
34751
|
+
cost: external_exports.object({ versionUsd: external_exports.number(), familyUsd: external_exports.number(), familyRuns: external_exports.number() }).optional(),
|
|
34730
34752
|
verdict: external_exports.enum(["pass", "fail", "pending-review"]),
|
|
34731
34753
|
reasons: external_exports.array(external_exports.string())
|
|
34732
34754
|
});
|
|
@@ -34971,7 +34993,7 @@ var init_package = __esm({
|
|
|
34971
34993
|
"package.json"() {
|
|
34972
34994
|
package_default = {
|
|
34973
34995
|
name: "@pigment/mcp",
|
|
34974
|
-
version: "0.
|
|
34996
|
+
version: "0.11.0",
|
|
34975
34997
|
private: true,
|
|
34976
34998
|
type: "module",
|
|
34977
34999
|
description: "MCP server for Pigment design systems: tokens, rules, component specs and installation guides for your coding agent.",
|
package/content/registry.json
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"id": "night-cartridge",
|
|
35
|
-
"latest": "1.
|
|
35
|
+
"latest": "1.2.0",
|
|
36
36
|
"versions": [
|
|
37
37
|
{
|
|
38
38
|
"version": "1.0.0",
|
|
@@ -45,6 +45,30 @@
|
|
|
45
45
|
"status": "published",
|
|
46
46
|
"publishedAt": "2026-10-15T04:49:09.540Z",
|
|
47
47
|
"sha256": "a4e943cb722c1506dac7af6ab80341f3c28bbe1aef3184038d4a9cb863a06e30"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"version": "1.2.0",
|
|
51
|
+
"status": "published",
|
|
52
|
+
"publishedAt": "2026-10-18T13:46:07.189Z",
|
|
53
|
+
"sha256": "82dcfe93ef26940ddbb6a3d6bf15c4ab4539638de605ee9b206512e42a98ad63"
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "graphite-blueprint",
|
|
59
|
+
"latest": "1.1.0",
|
|
60
|
+
"versions": [
|
|
61
|
+
{
|
|
62
|
+
"version": "1.0.0",
|
|
63
|
+
"status": "published",
|
|
64
|
+
"publishedAt": "2026-10-17T10:38:28.909Z",
|
|
65
|
+
"sha256": "0a34e9d7f81627182cd5fba1eb0c1aa758350479c5bed36adf2e5962386e49df"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"version": "1.1.0",
|
|
69
|
+
"status": "published",
|
|
70
|
+
"publishedAt": "2026-10-18T11:26:12.349Z",
|
|
71
|
+
"sha256": "f15b112756c795d50a806d53754f2946f3436bbb81a841154c6220da93139063"
|
|
48
72
|
}
|
|
49
73
|
]
|
|
50
74
|
}
|
package/content/shots.json
CHANGED
|
@@ -80,5 +80,51 @@
|
|
|
80
80
|
"dashboard.mobileDark": "/showcase/night-cartridge/1.1.0/dashboard/home-mobile-dark.png",
|
|
81
81
|
"settings.desktopDark": "/showcase/night-cartridge/1.1.0/settings/settings-profile-desktop-dark.png",
|
|
82
82
|
"settings.mobileDark": "/showcase/night-cartridge/1.1.0/settings/settings-profile-mobile-dark.png"
|
|
83
|
+
},
|
|
84
|
+
"night-cartridge@1.2.0": {
|
|
85
|
+
"blog.desktopDark": "/showcase/night-cartridge/1.2.0/blog/home-desktop-dark.png",
|
|
86
|
+
"blog.mobileDark": "/showcase/night-cartridge/1.2.0/blog/home-mobile-dark.png",
|
|
87
|
+
"commerce.desktopDark": "/showcase/night-cartridge/1.2.0/commerce/home-desktop-dark.png",
|
|
88
|
+
"commerce.mobileDark": "/showcase/night-cartridge/1.2.0/commerce/home-mobile-dark.png",
|
|
89
|
+
"dashboard.desktopDark": "/showcase/night-cartridge/1.2.0/dashboard/home-desktop-dark.png",
|
|
90
|
+
"dashboard.mobileDark": "/showcase/night-cartridge/1.2.0/dashboard/home-mobile-dark.png",
|
|
91
|
+
"settings.desktopDark": "/showcase/night-cartridge/1.2.0/settings/settings-profile-desktop-dark.png",
|
|
92
|
+
"settings.mobileDark": "/showcase/night-cartridge/1.2.0/settings/settings-profile-mobile-dark.png"
|
|
93
|
+
},
|
|
94
|
+
"graphite-blueprint@1.0.0": {
|
|
95
|
+
"blog.desktopLight": "/showcase/graphite-blueprint/1.0.0/blog/home-desktop-light.png",
|
|
96
|
+
"blog.desktopDark": "/showcase/graphite-blueprint/1.0.0/blog/home-desktop-dark.png",
|
|
97
|
+
"blog.mobileLight": "/showcase/graphite-blueprint/1.0.0/blog/home-mobile-light.png",
|
|
98
|
+
"blog.mobileDark": "/showcase/graphite-blueprint/1.0.0/blog/home-mobile-dark.png",
|
|
99
|
+
"commerce.desktopLight": "/showcase/graphite-blueprint/1.0.0/commerce/home-desktop-light.png",
|
|
100
|
+
"commerce.desktopDark": "/showcase/graphite-blueprint/1.0.0/commerce/home-desktop-dark.png",
|
|
101
|
+
"commerce.mobileLight": "/showcase/graphite-blueprint/1.0.0/commerce/home-mobile-light.png",
|
|
102
|
+
"commerce.mobileDark": "/showcase/graphite-blueprint/1.0.0/commerce/home-mobile-dark.png",
|
|
103
|
+
"dashboard.desktopLight": "/showcase/graphite-blueprint/1.0.0/dashboard/home-desktop-light.png",
|
|
104
|
+
"dashboard.desktopDark": "/showcase/graphite-blueprint/1.0.0/dashboard/home-desktop-dark.png",
|
|
105
|
+
"dashboard.mobileLight": "/showcase/graphite-blueprint/1.0.0/dashboard/home-mobile-light.png",
|
|
106
|
+
"dashboard.mobileDark": "/showcase/graphite-blueprint/1.0.0/dashboard/home-mobile-dark.png",
|
|
107
|
+
"settings.desktopLight": "/showcase/graphite-blueprint/1.0.0/settings/settings-profile-desktop-light.png",
|
|
108
|
+
"settings.desktopDark": "/showcase/graphite-blueprint/1.0.0/settings/settings-profile-desktop-dark.png",
|
|
109
|
+
"settings.mobileLight": "/showcase/graphite-blueprint/1.0.0/settings/settings-profile-mobile-light.png",
|
|
110
|
+
"settings.mobileDark": "/showcase/graphite-blueprint/1.0.0/settings/settings-profile-mobile-dark.png"
|
|
111
|
+
},
|
|
112
|
+
"graphite-blueprint@1.1.0": {
|
|
113
|
+
"blog.desktopLight": "/showcase/graphite-blueprint/1.1.0/blog/home-desktop-light.png",
|
|
114
|
+
"blog.desktopDark": "/showcase/graphite-blueprint/1.1.0/blog/home-desktop-dark.png",
|
|
115
|
+
"blog.mobileLight": "/showcase/graphite-blueprint/1.1.0/blog/home-mobile-light.png",
|
|
116
|
+
"blog.mobileDark": "/showcase/graphite-blueprint/1.1.0/blog/home-mobile-dark.png",
|
|
117
|
+
"commerce.desktopLight": "/showcase/graphite-blueprint/1.1.0/commerce/home-desktop-light.png",
|
|
118
|
+
"commerce.desktopDark": "/showcase/graphite-blueprint/1.1.0/commerce/home-desktop-dark.png",
|
|
119
|
+
"commerce.mobileLight": "/showcase/graphite-blueprint/1.1.0/commerce/home-mobile-light.png",
|
|
120
|
+
"commerce.mobileDark": "/showcase/graphite-blueprint/1.1.0/commerce/home-mobile-dark.png",
|
|
121
|
+
"dashboard.desktopLight": "/showcase/graphite-blueprint/1.1.0/dashboard/home-desktop-light.png",
|
|
122
|
+
"dashboard.desktopDark": "/showcase/graphite-blueprint/1.1.0/dashboard/home-desktop-dark.png",
|
|
123
|
+
"dashboard.mobileLight": "/showcase/graphite-blueprint/1.1.0/dashboard/home-mobile-light.png",
|
|
124
|
+
"dashboard.mobileDark": "/showcase/graphite-blueprint/1.1.0/dashboard/home-mobile-dark.png",
|
|
125
|
+
"settings.desktopLight": "/showcase/graphite-blueprint/1.1.0/settings/settings-profile-desktop-light.png",
|
|
126
|
+
"settings.desktopDark": "/showcase/graphite-blueprint/1.1.0/settings/settings-profile-desktop-dark.png",
|
|
127
|
+
"settings.mobileLight": "/showcase/graphite-blueprint/1.1.0/settings/settings-profile-mobile-light.png",
|
|
128
|
+
"settings.mobileDark": "/showcase/graphite-blueprint/1.1.0/settings/settings-profile-mobile-dark.png"
|
|
83
129
|
}
|
|
84
130
|
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.0
|
|
4
|
+
|
|
5
|
+
First release of Graphite Blueprint: a near-black instrument panel. Graphite greys stacked in five steps,
|
|
6
|
+
1px hairlines, pill controls and one indigo kept for focus and selection. The product's own interface is the
|
|
7
|
+
main image, set on a softly lit stage; work in progress speaks in a 5x5 dot matrix and a passing shimmer, and
|
|
8
|
+
explanations are drawn as isometric hairline blueprints with mono figure captions. Dark is the default, with a
|
|
9
|
+
light mode in cool neutral greys.
|
|
10
|
+
|
|
11
|
+
- Ten defining rules and a Never list: the ground covers most of every screen, text in four steps of grey,
|
|
12
|
+
indigo at most three times a screen, hairlines instead of shadows, pills and 8px panels.
|
|
13
|
+
- Six signature recipes: the spotlit stage, the dot-matrix status glyph, isometric blueprints with marching
|
|
14
|
+
connectors, spec plates for items without a picture, the working shimmer, and the split section opener.
|
|
15
|
+
- Motion in two speeds: state changes in 100 to 160ms, slow stepped loops only for work in progress, and every
|
|
16
|
+
loop frozen on a readable frame under reduced motion.
|
|
17
|
+
- Layout rules for dense screens: side-by-side panels end together, tables keep a pinned first column on small
|
|
18
|
+
screens, and frames never nest more than two deep.
|
|
19
|
+
- 13 specified components with designed states, Inter and Geist Mono (both openly licensed).
|
|
20
|
+
|
|
21
|
+
## 0.1.0-rc.3
|
|
22
|
+
|
|
23
|
+
Panels side by side now end on one line, pinned table columns on phones no longer cut the text beside them, and
|
|
24
|
+
stores close with a statement over the dot field again. Spec plates have twice as many figures, so neighbouring cards
|
|
25
|
+
no longer look alike.
|
|
26
|
+
|
|
27
|
+
- Spotlit stage: "panels in one row align to their content" is replaced by "panels in one row end together": the chart
|
|
28
|
+
stage stretches to the row height (at least `size.stageMini`) or the list beside it is capped with "View all →";
|
|
29
|
+
no empty band inside a panel, no column ending more than `space.48` above its neighbour.
|
|
30
|
+
- Applying the concept, dashboard: the chart and the activity list end on one line, otherwise the chart takes the full
|
|
31
|
+
row and activity goes below.
|
|
32
|
+
- Table, small screens: the pinned column is opaque (`color.surface.default`, or `card` inside a card), with a 1px
|
|
33
|
+
`color.border.subtle` edge and a 16px fade over the scrolling cells; under `breakpoint.sm` secondary columns are
|
|
34
|
+
hidden instead of half-visible.
|
|
35
|
+
- Applying the concept, closing: was "newsletter" only; now newsletter, store and blog list pages end with a two-tone
|
|
36
|
+
statement over the dot field (a store: its shipping or returns promise).
|
|
37
|
+
- Spec plate: figure kinds 4 → 8 (bars, perspective grid, ringed sphere, square lattice added); neighbours in a grid
|
|
38
|
+
never share a kind (`specKinds`).
|
|
39
|
+
- Blueprint: slab half-widths are rendered pixels, at least 40; slabs side by side get `size.blueprintMd` each, and a
|
|
40
|
+
narrow column shows one slab and the connector instead of four shrunk ones.
|
|
41
|
+
- Text field: a failed submit shows the danger banner (hairline box, `color.status.dangerTint` wash, danger dot) on
|
|
42
|
+
every form, checkout included; never bare red text.
|
|
43
|
+
- Verification: rows at 1440px end within 48px of each other; no table cell cut mid-letter at 390px.
|
|
44
|
+
|
|
45
|
+
## 0.1.0-rc.2
|
|
46
|
+
|
|
47
|
+
Rows and controls stay clickable, count badges are readable, captions describe the item, and frames no longer stack
|
|
48
|
+
inside each other. Slab drawings have tighter corners, plate figures sit centred and connectors move.
|
|
49
|
+
|
|
50
|
+
- Checkbox and radio: the row's hit area now comes from wrapping input and text in the `<label>` (or padding the
|
|
51
|
+
label), never from an overlay; controls inside a row or card with a stretched link get `position:relative;z-index:1`.
|
|
52
|
+
- Never: nothing stacked above a native control; no stage inside a bordered card or frames nested more than two deep;
|
|
53
|
+
no copy that explains the system or how a drawing was made.
|
|
54
|
+
- Badge: the count badge is its own `.count` class (16px, `color.action.primary` fill, `color.text.onAction`
|
|
55
|
+
numeral), never combined with the generic badge.
|
|
56
|
+
- Spotlit stage: sits on the ground or in one hairline cell; a panel whose content is a quiet stage drops its border
|
|
57
|
+
and fill; panels in a row align to their content. The blog featured post is a wide plate, not a stage.
|
|
58
|
+
- Blueprint: vertex rounding `r` 14% → 8% and `s` 7% → 5% of the half-width; every connector marches except a
|
|
59
|
+
stopped connection.
|
|
60
|
+
- Spec plate: the fan figure is centred (origin at the tile's centre line, length 66 to 78); every figure stays inside
|
|
61
|
+
the central 78%; captions name the item.
|
|
62
|
+
- Table: under `breakpoint.md` the first column keeps `white-space:nowrap` and `min-width:160px`, cells wrap to at
|
|
63
|
+
most 2 lines.
|
|
64
|
+
- Verification: click each checkbox, radio and switch on the box itself, run the project's end-to-end tests (or say
|
|
65
|
+
they were not run), and check badge and count legibility in both modes.
|
|
66
|
+
- Unused primitives `space.64`, `motion.easing.inOut` and `motion.distance.flow` removed.
|
|
67
|
+
|
|
68
|
+
## 0.1.0-rc.1
|
|
69
|
+
|
|
70
|
+
First candidate of Graphite Blueprint, derived from the reference study. Dark is canonical; light comes from the
|
|
71
|
+
reference's documentation theme, with derived light versions of the stage, blueprint, spec plate and glyph.
|
|
72
|
+
|
|
73
|
+
- Tokens: graphite ladder, four text steps, white-alpha hairlines, one indigo, light and dark semantics; tertiary text
|
|
74
|
+
and control outlines lifted for contrast.
|
|
75
|
+
- Signature elements: spotlit stage (lit and quiet), dot-matrix glyph with dot field and meter, isometric hairline
|
|
76
|
+
blueprint, spec plate, working shimmer and live edges, split opener with two-tone voice and mono figures.
|
|
77
|
+
- Thirteen components specified, empty state included.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
## New project
|
|
2
|
+
|
|
3
|
+
1. Inspect the stack; propose an installation plan and wait for approval. Ask which appearances the product supports. Both: tokens.css follows the device setting; a theme switch sets `data-theme` on `html` only if the product has or asks for one. One: dark (`<html data-theme="dark">`, `color-scheme: dark`) unless the user asks for light.
|
|
4
|
+
2. Copy `dist/tokens.css` into global styles (or map `dist/tokens.json` into the theme); never retype values.
|
|
5
|
+
3. Load Inter (variable, weights 400, 510 and 590) and Geist Mono 400 with `font-display:swap`. Root: body `color.surface.default`, `color.text.body`, sans `font.size.body`, `font.lineHeight.body`, `font.tracking.body`; headings primary; `pre, code, kbd, samp` mono; global `:focus-visible`; the reduced-motion block; `html, body{overflow-x:clip}`.
|
|
6
|
+
4. Build the six signature elements first, as reusable pieces: `Stage` (lit and quiet), `DotGlyph` (with its pattern data), dot field and dot meter, `Blueprint` (`slab`, `link`), `SpecPlate` (with `specKinds`), shimmer, live edge, pulse and caret classes, `Opener`, `ScreenHead` and `.mono-label`. Review them (Verification) before any screen.
|
|
7
|
+
5. Build the components with every state; place the signature elements per Applying the concept.
|
|
8
|
+
6. Create `design-system/` with `VERSION` (system id and the spec's update date, e.g. `graphite-blueprint, updated 2026-01-31`), the tokens, and `components.md`: conventions, where each signature element is used, each blueprint's subject by screen.
|
|
9
|
+
7. Add to `AGENTS.md` and `CLAUDE.md` (create if missing): "UI work follows design-system/ — read it before building screens."
|
|
10
|
+
|
|
11
|
+
## Existing project
|
|
12
|
+
|
|
13
|
+
1. Audit styling, components, routes and tests; propose a migration plan (what changes, what stays) and wait for approval. Ask about appearances as in New project.
|
|
14
|
+
2. Map the tokens onto the existing variables (alias old names so nothing breaks mid-migration). A brand action color becomes `color.action.primary` (the inverse pill), never the accent.
|
|
15
|
+
3. Build the signature elements, restyle one representative screen with them in place as a sample, and wait for review.
|
|
16
|
+
4. Continue screen by screen, one commit each. Spinners become dot glyphs; missing images become spec plates. Never add delays, fake loading or working states, or a second `role="status"` region.
|
|
17
|
+
5. Preserve routes, logic, API contracts, form fields and validation, test ids, text used by tests and accessibility attributes. Restyle existing markup; keep native inputs.
|
|
18
|
+
6. Finish with `design-system/` and the pointer lines from New project.
|
|
19
|
+
|
|
20
|
+
## Ongoing development
|
|
21
|
+
|
|
22
|
+
- Read `design-system/` first; use semantic tokens and existing components; no hard-coded colors, sizes, radii, shadows or durations.
|
|
23
|
+
- Every new screen gets the signature elements its context calls for in Applying the concept; a screen without them is unfinished.
|
|
24
|
+
- Uncovered needs: compose from tokens and note it in `components.md`. Conflicting requests (colored primary, spinner, bold headings): present options.
|
|
25
|
+
|
|
26
|
+
## Verification
|
|
27
|
+
|
|
28
|
+
- Build and tests pass; no raw colors, sizes or radii outside the token files.
|
|
29
|
+
- Review loop, two rounds or more: render each signature piece alone at 2x in dark and light (on a temporary route, removed before you finish, never committed); compare with its recipe: stage light peaking at the top edge and gone by 62%; 0.5px slab strokes, tight vertices (about 8%), faces hiding what is behind; distinct lit and unlit dots on a 3-unit pitch; plate figures centered, caption bottom-left. Note at least three differences, fix, render again.
|
|
30
|
+
- Then each screen at 1440px and 390px, dark and light: no sideways scroll; at most 3 indigo uses; status and row actions visible; no bare `serif` or `monospace` text; frames at most two deep; captions name the item; every badge, chip and count (cart count too) legible at 2x; columns of a row end within 48px of each other (1440px); no table cell cut mid-letter at rest (390px).
|
|
31
|
+
- Reduced motion (emulate the media feature): nothing loops, every glyph shows its rest frame, every block is final.
|
|
32
|
+
- Tab through every screen: the indigo outline is always visible. Click each checkbox, radio and switch on the box itself, not its label. Run the project's end-to-end tests if the command exists; otherwise report they were not run.
|
|
33
|
+
- Walk the ten rules and the Never list. Report files changed, what you could not apply, and your decisions.
|
|
34
|
+
|
|
35
|
+
## Rollback
|
|
36
|
+
|
|
37
|
+
- Each screen is its own commit and can be reverted alone.
|
|
38
|
+
- Tokens, fonts, root setup and the signature pieces are separate commits, reverted last.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
### Badge
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Height 20px, `radius.full`, padding 0 `space.8`, 1px `color.border.default`, transparent fill,
|
|
4
|
+
`font.size.caption` sans 510 `color.text.body`; a leading 6px dot in the status hue (or a 12px status icon), gap
|
|
5
|
+
`space.6`. Count badge: its own class, never combined with `.badge`; the numeral reads at 4.5:1 in both modes; on an
|
|
6
|
+
icon button it sits inside the button (`position:absolute`, `pointer-events:none`):
|
|
7
|
+
|
|
8
|
+
```css
|
|
9
|
+
.count{display:inline-grid;place-items:center;min-width:16px;height:16px;padding:0 var(--space-4);border:0;
|
|
10
|
+
border-radius:var(--radius-full);background:var(--color-action-primary);color:var(--color-text-on-action);
|
|
11
|
+
font:var(--font-weight-semibold) var(--font-size-micro)/1 var(--font-family-sans);font-variant-numeric:tabular-nums;}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**States.** Static by default. Interactive chips follow Interaction (filter chip). A running item gets the live edge
|
|
15
|
+
on its badge only. Current: border `color.border.strong`.
|
|
16
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
### Button
|
|
2
|
+
|
|
3
|
+
**Use.** One inverse pill per region (form, dialog, header); secondary for the rest; ghost in toolbars and nav.
|
|
4
|
+
|
|
5
|
+
**Anatomy.** Pill (`radius.full`), label `font.size.small` 510, sentence case, verb first, 1 to 3 words; optional
|
|
6
|
+
trailing arrow or 16px icon, gap `space.6`. Sizes: `size.control` (padding 0 `space.12`), `size.controlLg` (0
|
|
7
|
+
`space.16`; forms and content actions), `size.touch` (0 `space.20`, `font.size.body`; landing hero only). Icon
|
|
8
|
+
button: square `size.controlSm`, `radius.full`, `aria-label`. Full width: `display:flex;width:100%`, centered.
|
|
9
|
+
|
|
10
|
+
**Variants.** Inverse: `color.action.primary`, `color.text.onAction`. Secondary: `color.action.secondary`,
|
|
11
|
+
`color.text.body`. Bordered: transparent, `color.text.secondary`, 1px `color.border.default`. Ghost: transparent,
|
|
12
|
+
`color.text.secondary`. Danger: `color.action.danger`, `color.text.onDanger`. Send (message composers only): a
|
|
13
|
+
`color.accent.default` circle with a `color.text.onAccent` icon.
|
|
14
|
+
|
|
15
|
+
**States.** Hover, press, focus-visible: Interaction. Disabled: Interaction. Loading, only
|
|
16
|
+
while a real request runs: a 12px scan glyph replaces the trailing icon, the label becomes a gerund ("Saving"), width
|
|
17
|
+
held, `aria-busy="true"`. Done: the label returns; the result is announced in the status region.
|
|
18
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
### Card
|
|
2
|
+
|
|
3
|
+
**Anatomy.** `color.surface.card`, 1px `color.border.default`, `radius.md`, padding `space.20` (app) or `space.24`
|
|
4
|
+
(content). Mono caption meta above the title; title `font.size.body` (590 app, 510 content) `color.text.primary`; body
|
|
5
|
+
`color.text.secondary`. Media on top: a spec plate or photo, flush, the card padding below. KPI card: mono label, value
|
|
6
|
+
`font.size.h3` 510 tabular, change in `font.size.small` with a 6px status dot (never a colored number). Plan card:
|
|
7
|
+
tier slabs, name, price `font.size.h3`, 16px checks.
|
|
8
|
+
|
|
9
|
+
**States.** Linked card: hover and focus per Interaction; the whole card is one link (the title link stretched with
|
|
10
|
+
`::after`); controls inside get `position:relative;z-index:1`.
|
|
11
|
+
Current or selected: border `color.border.strong` plus a "Current" badge. Loading: static bars on
|
|
12
|
+
`color.surface.hover`. Error: a danger banner inside with Retry.
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
### Checkbox and radio
|
|
2
|
+
|
|
3
|
+
**Anatomy.** 14px box, `radius.xs` (radio: circle), 1px `color.border.check`, transparent fill; label
|
|
4
|
+
`font.size.small` `color.text.body`, gap `space.8`; row height `size.rowDense`. Group label:
|
|
5
|
+
mono caption tertiary, or a 590 `font.size.body` title.
|
|
6
|
+
|
|
7
|
+
**States.** Hover: Interaction. Focus-visible: outline on the box. Checked: fill and border
|
|
8
|
+
`color.accent.default`, 1.5px `color.text.onAccent` check (radio: 6px inner dot).
|
|
9
|
+
Indeterminate: a 6px bar. Disabled: `opacity.disabled`. Error: outline `color.status.danger` plus the field message.
|
|
10
|
+
|
|
11
|
+
**Implementation.** Native input (`appearance:none`); `checked`, `name`, `value` and test ids unchanged. The row is the
|
|
12
|
+
hit area by wrapping input and text in the `<label>` or padding the label, never an overlay over the input (no
|
|
13
|
+
`label::after{position:absolute;inset:0}`). Controls in a row with a stretched link get `position:relative;z-index:1`.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
### Dialog
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Native `<dialog>` where it exists. Panel max `size.dialog`, `color.surface.subtle`, `radius.lg`,
|
|
4
|
+
`elevation.popover`, padding `space.24`: mono caption label (the object or step), title `font.size.title` 590, body
|
|
5
|
+
`font.size.body` `color.text.body`; footer right-aligned, gap `space.8`: bordered Cancel, then the inverse pill
|
|
6
|
+
(danger for destructive confirms). Scrim `color.surface.overlay` with `backdrop-filter:blur(4px)`. Under
|
|
7
|
+
`breakpoint.sm`: full width at the bottom, top corners `radius.lg`, actions stacked, primary first.
|
|
8
|
+
|
|
9
|
+
**States.** Open and close: Motion; the scrim fades.
|
|
10
|
+
Focus moves to the first control; Escape and Cancel close it and focus returns to the trigger. Submitting: button
|
|
11
|
+
loading state. Error: a danger banner above the footer. `aria-labelledby` the title.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
### Empty state
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Centered in its container, max 360px wide, padding `space.48` `space.24`: a drawing (the 48px empty
|
|
4
|
+
glyph in panels and tables; a `size.blueprintMd` dimmed slab stack on full screens), `space.16`, a mono caption
|
|
5
|
+
("NO RESULTS"), `space.8`, a two-tone sentence in `font.size.body` (what is empty, then what to do), `space.20`, one
|
|
6
|
+
secondary pill (inverse when it is the screen's only action). Error variant: the error glyph or the broken-connector
|
|
7
|
+
blueprint on a quiet stage, a mono code ("ERR 404"), a 590 heading and two pills.
|
|
8
|
+
|
|
9
|
+
**States.** Static. Existing actions keep their labels and test ids.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"components": [
|
|
3
|
+
{"name": "button", "category": "action", "status": "specified", "file": "button.md", "states": ["default", "hover", "focus-visible", "active", "disabled", "loading"]},
|
|
4
|
+
{"name": "text-field", "category": "form", "status": "specified", "file": "text-field.md", "states": ["default", "hover", "focus-visible", "disabled", "loading", "error"]},
|
|
5
|
+
{"name": "select", "category": "form", "status": "specified", "file": "select.md", "states": ["default", "hover", "focus-visible", "selected", "disabled", "error"]},
|
|
6
|
+
{"name": "checkbox", "category": "form", "status": "specified", "file": "checkbox.md", "states": ["default", "hover", "focus-visible", "selected", "disabled", "error"]},
|
|
7
|
+
{"name": "switch", "category": "form", "status": "specified", "file": "switch.md", "states": ["default", "hover", "focus-visible", "selected", "disabled", "loading"]},
|
|
8
|
+
{"name": "tabs", "category": "navigation", "status": "specified", "file": "tabs.md", "states": ["default", "hover", "focus-visible", "selected", "disabled"]},
|
|
9
|
+
{"name": "navigation", "category": "navigation", "status": "specified", "file": "navigation.md", "states": ["default", "hover", "focus-visible", "selected"]},
|
|
10
|
+
{"name": "card", "category": "surface", "status": "specified", "file": "card.md", "states": ["default", "hover", "focus-visible", "selected", "loading", "error"]},
|
|
11
|
+
{"name": "table", "category": "data-display", "status": "specified", "file": "table.md", "states": ["default", "hover", "focus-visible", "selected", "loading", "error"]},
|
|
12
|
+
{"name": "badge", "category": "data-display", "status": "specified", "file": "badge.md", "states": ["default", "hover", "selected"]},
|
|
13
|
+
{"name": "dialog", "category": "overlay", "status": "specified", "file": "dialog.md", "states": ["default", "focus-visible", "loading", "error"]},
|
|
14
|
+
{"name": "toast", "category": "feedback", "status": "specified", "file": "toast.md", "states": ["default", "loading", "error"]},
|
|
15
|
+
{"name": "empty-state", "category": "feedback", "status": "specified", "file": "empty-state.md", "states": ["default", "error"]}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
### Navigation
|
|
2
|
+
|
|
3
|
+
**Header.** `size.header`, sticky (Shape and depth). Left: the product
|
|
4
|
+
name as text (`font.size.body` 590); ghost nav pills (`size.control`, `font.size.small` 510, gap `space.4`); right:
|
|
5
|
+
secondary links, a 1px 16px-tall `color.border.default` divider, one inverse pill. Cart or inbox: icon button with a
|
|
6
|
+
count badge (Badge) at its top right. Under `breakpoint.md`: name, inverse pill and a menu icon button opening a sheet
|
|
7
|
+
(`color.surface.subtle`, rows `size.row`, hairlines).
|
|
8
|
+
|
|
9
|
+
**Sidebar.** `size.sidebar`, `color.surface.subtle`, hairline right edge, padding `space.12` `space.8`; group labels
|
|
10
|
+
mono caption tertiary, `space.16` above; rows `size.rowDense`, `radius.sm`, 16px icon `color.icon.idle`,
|
|
11
|
+
`font.size.dense` `color.text.secondary`. Current row: `color.surface.tint`, text and icon primary,
|
|
12
|
+
`aria-current="page"`. Under `breakpoint.lg`: a pill row that scrolls inside itself.
|
|
13
|
+
|
|
14
|
+
**Contents list.** `font.size.small` secondary links; the current one primary with a 2px `color.text.primary` bar
|
|
15
|
+
on a hairline track at its left. Breadcrumbs: " / " separators.
|
|
16
|
+
|
|
17
|
+
**Footer.** Hairline top; `font.size.small` secondary link columns under 510 primary titles.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
### Select
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Trigger like the text field (`size.field`, `radius.sm`, `color.surface.card`, 1px
|
|
4
|
+
`color.border.default`), value `color.text.primary`, 16px chevron `color.icon.idle` at the right. Prefer the native
|
|
5
|
+
`<select>` styled this way (`appearance:none`). Custom menus: `color.surface.raised`, `radius.md`,
|
|
6
|
+
`elevation.popover`, padding `space.4`, rows `size.rowDense` with `radius.sm`, section labels mono caption tertiary,
|
|
7
|
+
a 16px check at the right of the selected row.
|
|
8
|
+
|
|
9
|
+
**States.** Hover, focus-visible: as Text field. Open: chevron and menu per Motion,
|
|
10
|
+
the current option highlighted. Option hover or active: `color.surface.hover`. Disabled: `opacity.disabled`. Error: as Text field.
|
|
11
|
+
|
|
12
|
+
**Keyboard and screen readers.** Custom menus: `role="listbox"`, arrows move, Enter selects, Escape closes and returns focus.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
### Switch
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Track 28x16 `radius.full`; off: `color.surface.press` with 1px `color.border.check`, 12px thumb
|
|
4
|
+
`color.text.secondary` inset 2px. On: track `color.accent.default`, thumb `color.text.onAccent` at the right. Label
|
|
5
|
+
left in `font.size.small` `color.text.primary`, description below in `color.text.secondary`; the switch right-aligned
|
|
6
|
+
in settings rows (`size.row`, hairline between rows). Group counts in mono caption ("4 / 6 ON").
|
|
7
|
+
|
|
8
|
+
**States.** Hover: Interaction. Focus-visible: outline on the track. Toggle: thumb and track over
|
|
9
|
+
`motion.duration.hover`, `motion.easing.standard`. Disabled: `opacity.disabled`.
|
|
10
|
+
|
|
11
|
+
**Implementation.** `<input type="checkbox" role="switch">` stays native; its checked state drives the visuals.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
### Table
|
|
2
|
+
|
|
3
|
+
**Anatomy.** No outer box: a hairline above the head and under each row (`color.border.subtle`), no zebra, no
|
|
4
|
+
vertical rules. Head: mono caption uppercase `color.text.tertiary`, height `size.rowDense`. Rows `size.row`
|
|
5
|
+
(`size.rowDense` from 20 rows), cells `font.size.small` `color.text.body`, padding 0 `space.12`; first column
|
|
6
|
+
`color.text.primary` 510; IDs, timestamps and codes mono caption; numbers right-aligned tabular. Status: 14px status
|
|
7
|
+
icon plus word. Row actions: ghost pills or icon buttons at the right. Sort: a 12px chevron after the head label.
|
|
8
|
+
|
|
9
|
+
**States.** Hover, focus-visible (interactive rows) and selected (`aria-selected`): Interaction. Sorted head
|
|
10
|
+
`color.text.secondary`, `aria-sort`. Syncing row: a 12px rise glyph in its status cell. Loading: 5 static rows of
|
|
11
|
+
`color.surface.card` bars. Empty: the empty state in one full-width cell. Error: a danger banner above with Retry.
|
|
12
|
+
|
|
13
|
+
**Small screens.** Under `breakpoint.md` the first column keeps `white-space:nowrap` and `min-width:160px`, and the
|
|
14
|
+
table scrolls inside its wrapper; no cell wraps past 2 lines. The pinned column (status or actions) is opaque, with a
|
|
15
|
+
1px edge and a 16px fade over the cells scrolling under it. Under `breakpoint.sm` hide
|
|
16
|
+
secondary columns (location, last active, owner); to keep a value, show it as the first cell's second line via
|
|
17
|
+
`content:attr(data-sub)`, never duplicated in the DOM.
|
|
18
|
+
|
|
19
|
+
```css
|
|
20
|
+
.pin{position:sticky;right:0;z-index:1;background:var(--pin-bg,var(--color-surface-default));box-shadow:inset 1px 0 0 var(--color-border-subtle);}
|
|
21
|
+
.pin::before{content:"";position:absolute;inset-block:0;right:100%;width:var(--space-16);pointer-events:none;
|
|
22
|
+
background:linear-gradient(90deg,transparent,var(--pin-bg,var(--color-surface-default)));}
|
|
23
|
+
tr:hover .pin{background:linear-gradient(var(--color-surface-tint),var(--color-surface-tint)),var(--pin-bg,var(--color-surface-default));}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Inside a card set `--pin-bg:var(--color-surface-card)`.
|
|
27
|
+
|
|
28
|
+
**Accessibility.** Real `<table>`, `<th scope>`, sort buttons inside head cells.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
### Tabs
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Text tabs: `font.size.small` 510 `color.text.secondary`, height `size.control`, gap `space.24`, a
|
|
4
|
+
`color.border.subtle` hairline under the row; the selected tab `color.text.primary` with a 2px `color.text.primary`
|
|
5
|
+
indicator on the hairline that slides (Motion). Segmented pills (inside panels,
|
|
6
|
+
option pickers): track `color.surface.card`, `radius.full`, padding `space.2`; items `size.controlSm`; the selected
|
|
7
|
+
item `color.surface.press` with `elevation.ring`.
|
|
8
|
+
|
|
9
|
+
**States.** Hover: `color.text.body`. Focus-visible: outline. Selected: as above, `aria-selected="true"`. Disabled:
|
|
10
|
+
`opacity.disabled`. The panel swap does not animate. Keyboard: arrows, Home, End.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
### Text field
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Label above (`font.size.small` 510, `color.text.body`); control `size.field` high,
|
|
4
|
+
`radius.sm`, `color.surface.card`, 1px `color.border.default`, padding 0 `space.12`, text `font.size.dense`
|
|
5
|
+
`color.text.primary`, placeholder `color.text.tertiary`; helper (Spacing) in `font.size.caption` sans,
|
|
6
|
+
`color.text.secondary`. Textarea: min 3 rows, padding `space.8` `space.12`; a counter right of the helper in mono
|
|
7
|
+
caption ("120 / 160"). Search: pill (`radius.full`), `size.control`, 16px icon at `space.12`, text from 36px.
|
|
8
|
+
|
|
9
|
+
**States.** Hover and focus-visible: Interaction.
|
|
10
|
+
Disabled: `opacity.disabled` on `color.surface.subtle`. Error: border `color.status.danger`; the message replaces the
|
|
11
|
+
helper in `color.status.danger`, `aria-invalid="true"`, `aria-describedby`; never a red fill. A failed submit, on
|
|
12
|
+
every form (checkout too), shows a banner `space.32` above the actions (hairline box, `color.status.dangerTint` wash,
|
|
13
|
+
6px danger dot, "2 fields need attention" in `color.text.body`, `role="alert"`), never bare red text, and focuses the
|
|
14
|
+
first invalid field.
|
|
15
|
+
Checking (async only): the helper becomes a shimmer line ("Checking").
|
|
16
|
+
|
|
17
|
+
**Keyboard and screen readers.** Native input; the visible label is its `<label for>`.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
### Toast
|
|
2
|
+
|
|
3
|
+
**Anatomy.** Bottom right, `space.24` from the edges (full width minus `space.16` under `breakpoint.sm`), width
|
|
4
|
+
`size.toast`, `color.surface.raised`, `radius.md`, `elevation.popover`, padding `space.12` `space.16`: a 16px leading
|
|
5
|
+
status icon (the core glyph while running), text `font.size.small` `color.text.primary`, optional ghost
|
|
6
|
+
action and close icon button. Up to 3 stacked, `space.8` apart.
|
|
7
|
+
|
|
8
|
+
**States.** Enter and leave: opacity (Motion; leave `motion.duration.ui`). Running: live edge, title shimmer, core glyph; done: the done frame, then the check icon.
|
|
9
|
+
Error: error icon, message, Retry. Auto-dismiss after 5s unless it has an action or focus.
|
|
10
|
+
|
|
11
|
+
**Accessibility.** Text goes through the screen's one `role="status"` region (errors `role="alert"`); never steals focus.
|