@godxjp/ui 32.5.0 → 32.6.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/DESIGN.md ADDED
@@ -0,0 +1,201 @@
1
+ ---
2
+ version: alpha
3
+ name: godxjp-ui
4
+ description: "Restrained Japanese-enterprise admin UI. Warm off-white canvas, near-black ink, one neutral accent, hairline borders, 14px/1.7 type, dense tables. Hierarchy comes from spacing steps and type, not from boxes, colour or shadow."
5
+
6
+ colors:
7
+ canvas: "#fdfdfc" # --background (= --card, --popover)
8
+ ink: "#24231e" # --foreground
9
+ ink-muted: "#68665e" # --muted-foreground
10
+ ink-tertiary: "#928f87" # --text-tertiary (captions, meta)
11
+ primary: "#18181b" # --primary. Neutral placeholder: set your brand here
12
+ on-primary: "#fdfdfc" # --primary-foreground
13
+ ring: "{colors.primary}" # --ring follows --primary; no separate focus hue
14
+ muted: "#f4f3f0" # --muted / --secondary (quiet fills, zebra, hover)
15
+ accent: "#ebe9e5" # --accent (hover/selected background, NOT a brand colour)
16
+ hairline: "#eeedec" # --border (dividers, card edges, table rules)
17
+ control-edge: "#90877f" # --input (the edge of an input; 3:1 against canvas)
18
+ success: "#68be8d" # --success 若竹
19
+ warning: "#f8b500" # --warning 山吹
20
+ info: "#4c6cb3" # --info 群青
21
+ attention: "#eb6101" # --attention 朱 (non-destructive urgency: late, overdue)
22
+ destructive: "#b7282e" # --destructive 茜 (delete, failed, irreversible)
23
+ text-success: "#09673b" # --text-success (status as text, AA on canvas)
24
+ text-warning: "#8f5600" # --text-warning
25
+ text-info: "#1d48a5" # --text-info
26
+ text-error: "#aa181f" # --text-error
27
+
28
+ typography:
29
+ family: "system stack (--font-sans-base); Noto Sans JP via opt-in @godxjp/ui/styles/fonts"
30
+ base: 14px # --font-size-base; every step derives from it (ratio --font-size-ratio 1.1227)
31
+ page-title: { size: "~20px (--heading-h1)", weight: 500, lineHeight: 1.25 }
32
+ section-title: { size: "~17.6px (--heading-h2)", weight: 500, lineHeight: 1.25 }
33
+ card-title: { size: "14px (--card-title-font-size)", weight: 500, lineHeight: 1.25 }
34
+ body: { size: 14px, weight: 400, lineHeight: 1.7 } # --line-height-body
35
+ caption: { size: "~12.5px (--font-size-xs)", weight: 400, lineHeight: 1.5 }
36
+ weights: [400, 500, 700] # --font-weight-semibold is 500; there is no 600
37
+ numerals: tabular # Text tabular / Badge tabular on every number column
38
+
39
+ rounded:
40
+ base: 6px # --radius (rides --scaling)
41
+ steps: "--radius-sm/md/lg/xl = radius / φ², / φ, ×1, × φ"
42
+ card: "~9.7px (--card-radius = radius × φ)"
43
+ pill: 9999px # --radius-pill: switch, radio, pill badge only
44
+
45
+ spacing:
46
+ scale: "--space-1..24 = 4px steps (4, 8, 12, 16, 20, 24, 32, 40, 48, 80, 96)"
47
+ stack: { xs: 4px, sm: 8px, md: 16px, lg: 24px, xl: 40px } # Flex direction="col" gap
48
+ inline: { xs: 4px, sm: 8px, md: 12px, lg: 16px, xl: 24px } # Flex direction="row" gap
49
+ page: { x: 24px, y: 24px } # --space-page-x / -y
50
+ section: 16px # --space-section
51
+
52
+ density:
53
+ axis: "AppProvider density / PageContainer density / data-density"
54
+ compact: "--scaling 0.92 (data-heavy tables)"
55
+ default: "--scaling 1 (control and row height 32px, --band-height-md)"
56
+ comfortable: "--scaling 1.08 (login, public, touch)"
57
+ touch-floor: 44px # --band-height-xl
58
+
59
+ components:
60
+ button-primary:
61
+ {
62
+ background: "{colors.primary}",
63
+ text: "{colors.on-primary}",
64
+ height: "--control-height",
65
+ radius: "{rounded.base}",
66
+ }
67
+ button-secondary: { variant: outline, edge: "{colors.control-edge}" }
68
+ input:
69
+ {
70
+ background: "{colors.canvas}",
71
+ edge: "{colors.control-edge}",
72
+ focus: "edge recolours to {colors.ring}",
73
+ }
74
+ card:
75
+ {
76
+ background: "{colors.canvas}",
77
+ border: "1px {colors.hairline}",
78
+ shadow: "--shadow-sm",
79
+ radius: "{rounded.card}",
80
+ padding: "--card-space-inset",
81
+ }
82
+ table:
83
+ { rule: "1px {colors.hairline}", rowHeight: "--table-row-height", header: "{colors.ink-muted}" }
84
+ badge: { variant: outline, tone: "status role only" }
85
+ ---
86
+
87
+ ## Overview
88
+
89
+ A calm, dense tool for people who use it all day. The look is restrained Japanese enterprise: 渋み (low chroma), 間 (even breathing room), 簡素 (nothing that does not carry information). Distinctiveness comes from exact spacing, alignment and type, never from decoration.
90
+
91
+ The default `--primary` is a neutral ink (`240 6% 10%`). It is a placeholder, not a brand. Set the brand once with `--primary` in your theme, `tenantTheme('#RRGGBB')` from `@godxjp/ui/app`, a `data-brand` preset (`brand`, `crm`, `logistics`, `partner`, `slate`) or `@godxjp/ui/themes/godx.css`. `--ring` follows `--primary`.
92
+
93
+ ## Colors
94
+
95
+ Colour is scarce. Most of the screen is canvas, ink and hairline.
96
+
97
+ - **Accent (`--primary`)**: the one primary action per view, focus ring, links, the selected nav item. Nothing else: no tinted headers, avatars, icons or section backgrounds.
98
+ - **Status (若竹 success, 山吹 warning, 群青 info, 朱 attention, 茜 destructive)**: only to state a status. Use `Badge status=…` (maps lifecycle keys to a fixed tone and icon) or `tone`. For status as text use the `--text-*` roles. Status colours are never re-themed per tenant.
99
+ - 朱 attention for urgency that is not destructive (late, overdue); 茜 only for loss (delete, failed, irreversible).
100
+ - `--accent` is the hover/selected surface, not a brand colour. `--muted` is for quiet fills.
101
+ - No gradients, glows or tinted page sections on app surfaces.
102
+
103
+ ## Typography
104
+
105
+ - One family. Hierarchy from size steps, weight 400/500/700 and `ink` vs `ink-muted`. Page title ~20px; anything larger belongs on a marketing page.
106
+ - Body 14px / 1.7. Captions and meta 12.5px muted. `Text tabular` on every number, time and money column.
107
+ - Japanese prose: `Text break="phrase"` so lines break between phrases.
108
+ - Copy is quiet and factual: no praise, no alarm, no emoji, no em dash in UI strings. A success message states the fact (「承認しました」).
109
+
110
+ ## Layout & Density
111
+
112
+ - Hierarchy is spacing first: related items `gap="xs"`/`"sm"`, groups `"md"`, sections `"lg"`/`"xl"`. If every gap is the same, nothing is grouped.
113
+ - A section is a `Heading` plus spacing. Add a `Separator` when two sections must not read as one. Use a surface only when it is a real boundary (see Components).
114
+ - Pick one density per page up front: `compact` for review grids, `default` everywhere else, `comfortable` for login and touch.
115
+ - Content measure: forms and settings in `PageContainer measure="narrow"` or `"medium"`; tables use the full width.
116
+ - Spacing comes from component props (`gap`, `pad`) and tokens, never `p-4`/`mt-6` literals.
117
+
118
+ ## Elevation
119
+
120
+ - Flat. A card is canvas with a 1px `--border` hairline and a near-invisible `--shadow-sm`; nothing heavier at rest.
121
+ - `--shadow-md`/`--shadow-lg` belong to things that float: popover, dropdown, dialog, sheet, toast.
122
+ - No hover lift on data cards. Depth never signals importance.
123
+
124
+ ## Components
125
+
126
+ - **PageContainer** is the page shell: `title`, optional `subtitle`, `breadcrumb`, `extra` (page actions, primary last), `toolbar`, `footer`.
127
+ - **Card** only for a real boundary: a table with its own toolbar and pagination, a list of setting rows, a dashboard panel, a danger zone (`accent="destructive"`), a selectable item. Not around every section, never nested. `CardContent flush` for tables and row lists.
128
+ - **Toolbar** (+ `ToolbarGroup`) is the filter strip: search, labelled filters, clear-all, result count. It sits above the table, never in the page header.
129
+ - **DataTable** for lists: sort, selection with `DataTable.BulkActions`, density, empty/loading/error states. Row actions in one kebab `DropdownMenu`.
130
+ - **Descriptions** for record metadata. **ListRow** for setting rows (`trailing` holds the control).
131
+ - **Form + FormField** for every input; actions at the end of the form or in a sticky `PageContainer footer`. Create/edit is a page, not a dialog.
132
+ - **StatCard** only on a dashboard, always with `delta` that compares (vs last week, vs target). **EmptyState**: one sentence and at most one action.
133
+ - **Alert** only for something the user must act on now. **Badge** only for status; one per row at most.
134
+
135
+ ## Admin Screen Anatomy
136
+
137
+ ### List
138
+
139
+ Header: title, then `extra` with the primary create action last. Below it a `Toolbar` with search and filters. Then one Card holding the `DataTable` (`CardContent flush`) and `Pagination`. No KPI row, no subtitle that restates the title, no filter Card separate from the table.
140
+
141
+ ### Detail
142
+
143
+ Header: record name as title, status `Badge` beside it, actions in `extra` (one primary). Body: `Descriptions` for metadata, then sections (Heading + content) for related records and history (`Timeline`). Use `Tabs` only when sections are independent and long. No Card per section; no icon beside every heading.
144
+
145
+ ### Form
146
+
147
+ `Form` in a narrow measure; fields grouped by Heading sections, not Cards. Labels via `FormField`; helper text only when it adds information. One primary submit and a secondary cancel at the end, or in a sticky footer for long forms. Errors inline on the field plus `FormErrors` summary on submit.
148
+
149
+ ### Settings
150
+
151
+ Each section is a Heading (plus one muted line if it adds a fact) over its content: `Descriptions` for read-only values, `ListRow` rows in one `Card` with `CardContent flush` for controls (`trailing` holds the control). Separate sections with spacing or a `Separator`. Changes that apply instantly need no Save button; a page with a Save button applies nothing until saved. Destructive actions last, in one `Card accent="destructive"`, each behind `AlertDialog`.
152
+
153
+ ### Dashboard
154
+
155
+ The only archetype with KPI tiles: at most four `StatCard`s, each with a comparison `delta` (use `inverse` when up is bad). Below, panels in `ResponsiveGrid`, each a Card with a title and one "view all" link: a work queue, a short table, a chart. Every number answers "compared to what".
156
+
157
+ ### Approval queue
158
+
159
+ A list whose rows are decisions. Show requester, target, reason, submitted time; approve and reject reachable from the row (kebab or row buttons); with `DataTable`, also in `BulkActions`. Escalated or overdue rows get one status Badge, not a coloured row.
160
+
161
+ ## Do's and Don'ts
162
+
163
+ ### Do
164
+
165
+ - Lead with the data. The first thing below the header is the table, form or record.
166
+ - Use one `Button` default variant per view; the rest `outline` or `ghost`.
167
+ - Group by spacing, then by heading, then by Separator, and only then by Card.
168
+ - Write the subtitle only when it adds a fact the title does not (date, scope, count).
169
+ - Right-align numbers, `tabular` digits, ISO/`Intl` dates.
170
+
171
+ ### Don't
172
+
173
+ - A subtitle that restates or translates the title.
174
+ - A StatCard row above a list or form.
175
+ - A Card around every section, each with Header + Title + Description.
176
+ - An EmptyState with a large icon inside a Card; an icon in every card header.
177
+ - Alert banners as page decoration; several Alerts stacked.
178
+ - Badge walls: a badge per cell, rainbow tones, badges for non-status labels.
179
+ - Uniform `gap` everywhere; arbitrary px spacing.
180
+ - Coloured avatars, tinted section backgrounds, gradients, hover lift.
181
+
182
+ ## Responsive
183
+
184
+ - Check 390, 768 and 1280 wide. Nothing scrolls horizontally except a wide table inside its own container.
185
+ - `DataTable` hides `hiddenOnMobile` columns and can stack rows (`collapseBelow`); `Table preset="action-collection"` keeps the actions column visible at 390.
186
+ - `ResponsiveGrid` columns follow its container. `AppShell` turns the sidebar into a drawer on narrow screens.
187
+ - Header `extra` wraps under the title; a toolbar wraps its filters. Touch targets 44px at `comfortable`.
188
+
189
+ ## Iteration Guide
190
+
191
+ 1. Pick the archetype, call `get_exemplar` and build from that screen, not from memory.
192
+ 2. Run `node node_modules/@godxjp/ui/scripts/ui-audit.mjs` until it is clean.
193
+ 3. Screenshot at 390, 768 and 1280 next to the exemplar's live preview.
194
+ 4. List the differences, fix the top 3 (structure before styling). Stop after 3 rounds.
195
+
196
+ ## Known Gaps
197
+
198
+ - The default primary is neutral by design; a product without a brand colour looks monochrome until one is set.
199
+ - `ui-audit` checks primitives and tokens, not structure: a page can pass it and still show every Don't above.
200
+ - Exemplar previews deploy on release tags, so they can lag `main`. On GitHub Pages a showcase URL answers HTTP 404 and renders through `404.html`, so open it in a browser; a plain fetch sees the 404.
201
+ - Dark theme (`data-theme="dark"`) is supported; the exemplars are reviewed in light.
package/README.md CHANGED
@@ -51,6 +51,7 @@ static files straight from this public repo — no hosting, no deploy step:
51
51
  | --- | --- | --- |
52
52
  | [`agent/START-HERE.md`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md) | 11 KB | **read first** — self-contained: the four rules, the token override model, a page that passes review |
53
53
  | [`agent/llms.txt`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/llms.txt) | 3 KB | the [llms.txt](https://llmstxt.org/) entry point |
54
+ | [`agent/DESIGN.md`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md) | 12 KB | the visual spec: tokens, colour scarcity, admin screen anatomy, do/don't |
54
55
  | [`agent/index.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json) | 3 KB | manifest: version, counts, every file's URL |
55
56
  | [`agent/components-index.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components-index.json) | 47 KB | all 161 as name + group + tagline — **fetch this first** |
56
57
  | [`agent/components/<Name>.json`](https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/components/Select.json) | 1 KB–37 KB | one file per component, each with its `importPath` — **this is the route to take** |
@@ -0,0 +1,201 @@
1
+ ---
2
+ version: alpha
3
+ name: godxjp-ui
4
+ description: "Restrained Japanese-enterprise admin UI. Warm off-white canvas, near-black ink, one neutral accent, hairline borders, 14px/1.7 type, dense tables. Hierarchy comes from spacing steps and type, not from boxes, colour or shadow."
5
+
6
+ colors:
7
+ canvas: "#fdfdfc" # --background (= --card, --popover)
8
+ ink: "#24231e" # --foreground
9
+ ink-muted: "#68665e" # --muted-foreground
10
+ ink-tertiary: "#928f87" # --text-tertiary (captions, meta)
11
+ primary: "#18181b" # --primary. Neutral placeholder: set your brand here
12
+ on-primary: "#fdfdfc" # --primary-foreground
13
+ ring: "{colors.primary}" # --ring follows --primary; no separate focus hue
14
+ muted: "#f4f3f0" # --muted / --secondary (quiet fills, zebra, hover)
15
+ accent: "#ebe9e5" # --accent (hover/selected background, NOT a brand colour)
16
+ hairline: "#eeedec" # --border (dividers, card edges, table rules)
17
+ control-edge: "#90877f" # --input (the edge of an input; 3:1 against canvas)
18
+ success: "#68be8d" # --success 若竹
19
+ warning: "#f8b500" # --warning 山吹
20
+ info: "#4c6cb3" # --info 群青
21
+ attention: "#eb6101" # --attention 朱 (non-destructive urgency: late, overdue)
22
+ destructive: "#b7282e" # --destructive 茜 (delete, failed, irreversible)
23
+ text-success: "#09673b" # --text-success (status as text, AA on canvas)
24
+ text-warning: "#8f5600" # --text-warning
25
+ text-info: "#1d48a5" # --text-info
26
+ text-error: "#aa181f" # --text-error
27
+
28
+ typography:
29
+ family: "system stack (--font-sans-base); Noto Sans JP via opt-in @godxjp/ui/styles/fonts"
30
+ base: 14px # --font-size-base; every step derives from it (ratio --font-size-ratio 1.1227)
31
+ page-title: { size: "~20px (--heading-h1)", weight: 500, lineHeight: 1.25 }
32
+ section-title: { size: "~17.6px (--heading-h2)", weight: 500, lineHeight: 1.25 }
33
+ card-title: { size: "14px (--card-title-font-size)", weight: 500, lineHeight: 1.25 }
34
+ body: { size: 14px, weight: 400, lineHeight: 1.7 } # --line-height-body
35
+ caption: { size: "~12.5px (--font-size-xs)", weight: 400, lineHeight: 1.5 }
36
+ weights: [400, 500, 700] # --font-weight-semibold is 500; there is no 600
37
+ numerals: tabular # Text tabular / Badge tabular on every number column
38
+
39
+ rounded:
40
+ base: 6px # --radius (rides --scaling)
41
+ steps: "--radius-sm/md/lg/xl = radius / φ², / φ, ×1, × φ"
42
+ card: "~9.7px (--card-radius = radius × φ)"
43
+ pill: 9999px # --radius-pill: switch, radio, pill badge only
44
+
45
+ spacing:
46
+ scale: "--space-1..24 = 4px steps (4, 8, 12, 16, 20, 24, 32, 40, 48, 80, 96)"
47
+ stack: { xs: 4px, sm: 8px, md: 16px, lg: 24px, xl: 40px } # Flex direction="col" gap
48
+ inline: { xs: 4px, sm: 8px, md: 12px, lg: 16px, xl: 24px } # Flex direction="row" gap
49
+ page: { x: 24px, y: 24px } # --space-page-x / -y
50
+ section: 16px # --space-section
51
+
52
+ density:
53
+ axis: "AppProvider density / PageContainer density / data-density"
54
+ compact: "--scaling 0.92 (data-heavy tables)"
55
+ default: "--scaling 1 (control and row height 32px, --band-height-md)"
56
+ comfortable: "--scaling 1.08 (login, public, touch)"
57
+ touch-floor: 44px # --band-height-xl
58
+
59
+ components:
60
+ button-primary:
61
+ {
62
+ background: "{colors.primary}",
63
+ text: "{colors.on-primary}",
64
+ height: "--control-height",
65
+ radius: "{rounded.base}",
66
+ }
67
+ button-secondary: { variant: outline, edge: "{colors.control-edge}" }
68
+ input:
69
+ {
70
+ background: "{colors.canvas}",
71
+ edge: "{colors.control-edge}",
72
+ focus: "edge recolours to {colors.ring}",
73
+ }
74
+ card:
75
+ {
76
+ background: "{colors.canvas}",
77
+ border: "1px {colors.hairline}",
78
+ shadow: "--shadow-sm",
79
+ radius: "{rounded.card}",
80
+ padding: "--card-space-inset",
81
+ }
82
+ table:
83
+ { rule: "1px {colors.hairline}", rowHeight: "--table-row-height", header: "{colors.ink-muted}" }
84
+ badge: { variant: outline, tone: "status role only" }
85
+ ---
86
+
87
+ ## Overview
88
+
89
+ A calm, dense tool for people who use it all day. The look is restrained Japanese enterprise: 渋み (low chroma), 間 (even breathing room), 簡素 (nothing that does not carry information). Distinctiveness comes from exact spacing, alignment and type, never from decoration.
90
+
91
+ The default `--primary` is a neutral ink (`240 6% 10%`). It is a placeholder, not a brand. Set the brand once with `--primary` in your theme, `tenantTheme('#RRGGBB')` from `@godxjp/ui/app`, a `data-brand` preset (`brand`, `crm`, `logistics`, `partner`, `slate`) or `@godxjp/ui/themes/godx.css`. `--ring` follows `--primary`.
92
+
93
+ ## Colors
94
+
95
+ Colour is scarce. Most of the screen is canvas, ink and hairline.
96
+
97
+ - **Accent (`--primary`)**: the one primary action per view, focus ring, links, the selected nav item. Nothing else: no tinted headers, avatars, icons or section backgrounds.
98
+ - **Status (若竹 success, 山吹 warning, 群青 info, 朱 attention, 茜 destructive)**: only to state a status. Use `Badge status=…` (maps lifecycle keys to a fixed tone and icon) or `tone`. For status as text use the `--text-*` roles. Status colours are never re-themed per tenant.
99
+ - 朱 attention for urgency that is not destructive (late, overdue); 茜 only for loss (delete, failed, irreversible).
100
+ - `--accent` is the hover/selected surface, not a brand colour. `--muted` is for quiet fills.
101
+ - No gradients, glows or tinted page sections on app surfaces.
102
+
103
+ ## Typography
104
+
105
+ - One family. Hierarchy from size steps, weight 400/500/700 and `ink` vs `ink-muted`. Page title ~20px; anything larger belongs on a marketing page.
106
+ - Body 14px / 1.7. Captions and meta 12.5px muted. `Text tabular` on every number, time and money column.
107
+ - Japanese prose: `Text break="phrase"` so lines break between phrases.
108
+ - Copy is quiet and factual: no praise, no alarm, no emoji, no em dash in UI strings. A success message states the fact (「承認しました」).
109
+
110
+ ## Layout & Density
111
+
112
+ - Hierarchy is spacing first: related items `gap="xs"`/`"sm"`, groups `"md"`, sections `"lg"`/`"xl"`. If every gap is the same, nothing is grouped.
113
+ - A section is a `Heading` plus spacing. Add a `Separator` when two sections must not read as one. Use a surface only when it is a real boundary (see Components).
114
+ - Pick one density per page up front: `compact` for review grids, `default` everywhere else, `comfortable` for login and touch.
115
+ - Content measure: forms and settings in `PageContainer measure="narrow"` or `"medium"`; tables use the full width.
116
+ - Spacing comes from component props (`gap`, `pad`) and tokens, never `p-4`/`mt-6` literals.
117
+
118
+ ## Elevation
119
+
120
+ - Flat. A card is canvas with a 1px `--border` hairline and a near-invisible `--shadow-sm`; nothing heavier at rest.
121
+ - `--shadow-md`/`--shadow-lg` belong to things that float: popover, dropdown, dialog, sheet, toast.
122
+ - No hover lift on data cards. Depth never signals importance.
123
+
124
+ ## Components
125
+
126
+ - **PageContainer** is the page shell: `title`, optional `subtitle`, `breadcrumb`, `extra` (page actions, primary last), `toolbar`, `footer`.
127
+ - **Card** only for a real boundary: a table with its own toolbar and pagination, a list of setting rows, a dashboard panel, a danger zone (`accent="destructive"`), a selectable item. Not around every section, never nested. `CardContent flush` for tables and row lists.
128
+ - **Toolbar** (+ `ToolbarGroup`) is the filter strip: search, labelled filters, clear-all, result count. It sits above the table, never in the page header.
129
+ - **DataTable** for lists: sort, selection with `DataTable.BulkActions`, density, empty/loading/error states. Row actions in one kebab `DropdownMenu`.
130
+ - **Descriptions** for record metadata. **ListRow** for setting rows (`trailing` holds the control).
131
+ - **Form + FormField** for every input; actions at the end of the form or in a sticky `PageContainer footer`. Create/edit is a page, not a dialog.
132
+ - **StatCard** only on a dashboard, always with `delta` that compares (vs last week, vs target). **EmptyState**: one sentence and at most one action.
133
+ - **Alert** only for something the user must act on now. **Badge** only for status; one per row at most.
134
+
135
+ ## Admin Screen Anatomy
136
+
137
+ ### List
138
+
139
+ Header: title, then `extra` with the primary create action last. Below it a `Toolbar` with search and filters. Then one Card holding the `DataTable` (`CardContent flush`) and `Pagination`. No KPI row, no subtitle that restates the title, no filter Card separate from the table.
140
+
141
+ ### Detail
142
+
143
+ Header: record name as title, status `Badge` beside it, actions in `extra` (one primary). Body: `Descriptions` for metadata, then sections (Heading + content) for related records and history (`Timeline`). Use `Tabs` only when sections are independent and long. No Card per section; no icon beside every heading.
144
+
145
+ ### Form
146
+
147
+ `Form` in a narrow measure; fields grouped by Heading sections, not Cards. Labels via `FormField`; helper text only when it adds information. One primary submit and a secondary cancel at the end, or in a sticky footer for long forms. Errors inline on the field plus `FormErrors` summary on submit.
148
+
149
+ ### Settings
150
+
151
+ Each section is a Heading (plus one muted line if it adds a fact) over its content: `Descriptions` for read-only values, `ListRow` rows in one `Card` with `CardContent flush` for controls (`trailing` holds the control). Separate sections with spacing or a `Separator`. Changes that apply instantly need no Save button; a page with a Save button applies nothing until saved. Destructive actions last, in one `Card accent="destructive"`, each behind `AlertDialog`.
152
+
153
+ ### Dashboard
154
+
155
+ The only archetype with KPI tiles: at most four `StatCard`s, each with a comparison `delta` (use `inverse` when up is bad). Below, panels in `ResponsiveGrid`, each a Card with a title and one "view all" link: a work queue, a short table, a chart. Every number answers "compared to what".
156
+
157
+ ### Approval queue
158
+
159
+ A list whose rows are decisions. Show requester, target, reason, submitted time; approve and reject reachable from the row (kebab or row buttons); with `DataTable`, also in `BulkActions`. Escalated or overdue rows get one status Badge, not a coloured row.
160
+
161
+ ## Do's and Don'ts
162
+
163
+ ### Do
164
+
165
+ - Lead with the data. The first thing below the header is the table, form or record.
166
+ - Use one `Button` default variant per view; the rest `outline` or `ghost`.
167
+ - Group by spacing, then by heading, then by Separator, and only then by Card.
168
+ - Write the subtitle only when it adds a fact the title does not (date, scope, count).
169
+ - Right-align numbers, `tabular` digits, ISO/`Intl` dates.
170
+
171
+ ### Don't
172
+
173
+ - A subtitle that restates or translates the title.
174
+ - A StatCard row above a list or form.
175
+ - A Card around every section, each with Header + Title + Description.
176
+ - An EmptyState with a large icon inside a Card; an icon in every card header.
177
+ - Alert banners as page decoration; several Alerts stacked.
178
+ - Badge walls: a badge per cell, rainbow tones, badges for non-status labels.
179
+ - Uniform `gap` everywhere; arbitrary px spacing.
180
+ - Coloured avatars, tinted section backgrounds, gradients, hover lift.
181
+
182
+ ## Responsive
183
+
184
+ - Check 390, 768 and 1280 wide. Nothing scrolls horizontally except a wide table inside its own container.
185
+ - `DataTable` hides `hiddenOnMobile` columns and can stack rows (`collapseBelow`); `Table preset="action-collection"` keeps the actions column visible at 390.
186
+ - `ResponsiveGrid` columns follow its container. `AppShell` turns the sidebar into a drawer on narrow screens.
187
+ - Header `extra` wraps under the title; a toolbar wraps its filters. Touch targets 44px at `comfortable`.
188
+
189
+ ## Iteration Guide
190
+
191
+ 1. Pick the archetype, call `get_exemplar` and build from that screen, not from memory.
192
+ 2. Run `node node_modules/@godxjp/ui/scripts/ui-audit.mjs` until it is clean.
193
+ 3. Screenshot at 390, 768 and 1280 next to the exemplar's live preview.
194
+ 4. List the differences, fix the top 3 (structure before styling). Stop after 3 rounds.
195
+
196
+ ## Known Gaps
197
+
198
+ - The default primary is neutral by design; a product without a brand colour looks monochrome until one is set.
199
+ - `ui-audit` checks primitives and tokens, not structure: a page can pass it and still show every Don't above.
200
+ - Exemplar previews deploy on release tags, so they can lag `main`. On GitHub Pages a showcase URL answers HTTP 404 and renders through `404.html`, so open it in a browser; a plain fetch sees the 404.
201
+ - Dark theme (`data-theme="dark"`) is supported; the exemplars are reviewed in light.
@@ -3,7 +3,7 @@
3
3
  You are about to write code against a design system you did not author. This file is the whole
4
4
  contract. Read it before you write JSX.
5
5
 
6
- **This catalog describes `@godxjp/ui` 32.5.0.** If the project you are editing has a different
6
+ **This catalog describes `@godxjp/ui` 32.6.0.** If the project you are editing has a different
7
7
  version in its `package.json`, read the pinned catalog for THAT version instead
8
8
  (`…/v<their-version>/agent/…`). A catalog newer than the installed package describes props that do
9
9
  not exist yet; older, and it hides props that do. Neither failure announces itself.
@@ -38,10 +38,13 @@ disk, and costs far fewer tokens than fetching a 1 MB JSON.
38
38
  { "mcpServers": { "godx-ui": { "command": "npx", "args": ["@godxjp/ui-mcp@<installed version>"] } } }
39
39
  ```
40
40
 
41
- Then ask it: `search_components`, `get_component`, `get_tokens`, `get_rule`, `list_anti_ai_tells`.
41
+ Then, before any JSX: `get_design` (the visual target), `route_consumer_task`, `get_exemplar` for
42
+ the closest screen, `search_components` → `get_component`. After building, screenshot at
43
+ 390 / 768 / 1280 beside the exemplar and fix the top 3 differences, at most 3 rounds.
42
44
 
43
45
  **You cannot run a process** (ChatGPT web · Claude.ai · anything fetching URLs)
44
- → These files are for you. Fetch in this order:
46
+ → These files are for you. Read `DESIGN.md` (in this folder) first: tokens, scarcity rules and
47
+ screen anatomy, the visual target the rules below do not give you. Then fetch in this order:
45
48
 
46
49
  0. `patterns-index.json` — 24 whole-task patterns as name + tagline + tags. **If your
47
50
  task is a task** — "build a settings page", "confirm a destructive delete", "a list page with
@@ -61,7 +64,7 @@ Then ask it: `search_components`, `get_component`, `get_tokens`, `get_rule`, `li
61
64
  `--radius`, `--font-size-base` are the handful everything else derives from. The
62
65
  1872 `component` entries are per-part knobs; reach for one only when a role is
63
66
  right everywhere except one component.
64
- 5. `anti-ai-tells.json` — 26 shapes that make generated UI look generated, each with the
67
+ 5. `anti-ai-tells.json` — 35 shapes that make generated UI look generated, each with the
65
68
  fix. Read before you reach for a gradient hero or a wall of coloured chips.
66
69
 
67
70
  **Do not fetch `components.json`.** It is 1.2 MB, and most URL fetchers truncate a
@@ -143,7 +146,7 @@ has stopped following the brand.
143
146
 
144
147
  | `tier` | count | what it is | set it? |
145
148
  |---|---|---|---|
146
- | `foundation` | 211 | the seeds — `--primary`, `--background`, `--foreground`, `--radius`, `--font-size-base`, `--shadow-color`. Everything below is derived from these | **yes — this is the main road.** Handed a brand colour, this is where it goes: `:root { --primary: <H> <S>% <L>%; }` (HSL components, no `hsl()` wrapper) |
149
+ | `foundation` | 211 | the seeds — `--primary`, `--background`, `--foreground`, `--radius`, `--font-size-base`, `--shadow-color`. Everything below is derived from these | **yes — this is the main road.** The default `--primary` is a neutral placeholder: set it (`:root { --primary: <H> <S>% <L>%; }`, HSL components, no `hsl()` wrapper) or import a theme preset such as `@godxjp/ui/themes/godx.css` |
147
150
  | `semantic` | 112 | named roles that follow the seeds — `--ring`, `--text-link`, `--primary-hover`, `--overlay-background` | only when the seed is right and ONE role must differ. That role then stops following a later brand change |
148
151
  | `component` | 1872 | per-part knobs, `--{component}-{part}-{property}` | rarely. Most are declared `initial` with the real default at the call site — deliberate, so a scoped override re-resolves instead of freezing at `:root` |
149
152
 
@@ -160,35 +163,27 @@ theme, every tenant scope and every audit in this package.
160
163
 
161
164
  ```tsx
162
165
  import { PageContainer, Flex } from "@godxjp/ui/layout";
163
- import { Card, CardHeader, CardTitle, CardDescription, CardContent, DataTable } from "@godxjp/ui/data-display";
166
+ import { Card, CardContent, DataTable } from "@godxjp/ui/data-display";
164
167
  import { Button } from "@godxjp/ui/general";
165
- import { Select } from "@godxjp/ui/data-entry";
166
- import { Alert, AlertTitle, AlertDescription } from "@godxjp/ui/feedback";
168
+ import { Select, SearchInput } from "@godxjp/ui/data-entry";
167
169
 
168
170
  export default function InvoicesPage() {
169
171
  return (
170
- <PageContainer title="請求一覧" subtitle="今月の未収を上から">
171
- <Flex direction="col" gap="lg">
172
- <Alert tone="warning">
173
- <AlertTitle>お支払いが確認できていません</AlertTitle>
174
- <AlertDescription>3 件の請求が期限を過ぎています。</AlertDescription>
175
- </Alert>
172
+ <PageContainer title="請求一覧" extra={<Button>請求を作成</Button>}>
173
+ <Flex direction="col" gap="sm">
174
+ {/* filters sit ABOVE the table they filter */}
175
+ <Flex direction="row" gap="sm" wrap>
176
+ <SearchInput aria-label="請求を検索" />
177
+ <Select width="auto" options={statuses} defaultValue="unpaid" aria-label="状態" />
178
+ <Button variant="outline">CSV</Button>
179
+ </Flex>
176
180
 
181
+ {/* `flush` because DataTable draws its own edges — a padded body double-insets it */}
177
182
  <Card>
178
- <CardHeader>
179
- <CardTitle level={2}>未収</CardTitle>
180
- <CardDescription>期限順。金額は税込。</CardDescription>
181
- </CardHeader>
182
- {/* `flush` because DataTable draws its own edges — a padded body double-insets it */}
183
183
  <CardContent flush>
184
- <DataTable data={rows} columns={columns} getRowId={(r) => r.id} striped />
184
+ <DataTable data={rows} columns={columns} getRowId={(r) => r.id} />
185
185
  </CardContent>
186
186
  </Card>
187
-
188
- <Flex direction="row" gap="sm" wrap>
189
- <Select width="auto" options={statuses} defaultValue="unpaid" aria-label="状態" />
190
- <Button variant="outline" size="sm">CSV</Button>
191
- </Flex>
192
187
  </Flex>
193
188
  </PageContainer>
194
189
  );
@@ -196,7 +191,8 @@ export default function InvoicesPage() {
196
191
  ```
197
192
 
198
193
  Note what is absent: no colour, no pixel, no raw control, no `<div className="flex gap-4">` where
199
- `Flex` exists.
194
+ `Flex` exists — and no subtitle restating the title, no KPI row above the list, no banner, no Card
195
+ header repeating the page title. The page answers one question: which invoice next.
200
196
 
201
197
  **Take the import path from the catalog, not from the group.** Every entry in
202
198
  `components/<Name>.json` carries an `importPath`; it is the only one guaranteed to resolve. The
@@ -128,7 +128,7 @@
128
128
  {
129
129
  "body": "Empty state with a chrome / pastel 3D icon (coin, key, shield)\nfloating in the center. Looks like every NFT marketplace from\n2021.",
130
130
  "category": "imagery",
131
- "fix": "Simple lucide-react line icon (`<Inbox size={48} />`) +\ndescriptive title. Or a flat illustration matching the brand\npalette. Skip the 3D entirely unless your brand IS 3D.",
131
+ "fix": "No illustration. In an admin screen an EmptyState is one\nsentence and one action (`<EmptyState title action />`, no `icon`).\nA first-run page outside a Card may take one small line icon via\n`icon={Inbox}`; never a large glyph or a 3D render.",
132
132
  "name": "Floating 3D crypto icon"
133
133
  },
134
134
  {
@@ -137,6 +137,60 @@
137
137
  "fix": "Solid background (`--background`). If you need depth, use a\nsubtle 1px border + `--card` background tint. Reserve high-effort\nbackgrounds for pages where they matter (marketing hero, product\nshowcase) — not every internal screen.",
138
138
  "name": "Decorative gradient mesh background"
139
139
  },
140
+ {
141
+ "body": "Every section of a page wrapped in Card + CardHeader + CardTitle\n+ CardDescription. Boxes everywhere, so no box means anything.",
142
+ "category": "structure",
143
+ "fix": "Mark a section with `<Heading level={2}>` and section spacing\n(PageContainer children). Card only for a real boundary: a table\nsurface, a selectable item. ui-audit: card-per-section.",
144
+ "name": "Card per section"
145
+ },
146
+ {
147
+ "body": "A Card (or StatCard) inside a Card: two borders for one boundary.",
148
+ "category": "structure",
149
+ "fix": "One Card; group inside it with Heading + Flex or Separator.\nui-audit: nested-card.",
150
+ "name": "Nested Card"
151
+ },
152
+ {
153
+ "body": "PageContainer title=\"クーポン管理\" subtitle=\"クーポンの一覧です\".\nThe subtitle repeats the title in more words.",
154
+ "category": "copy",
155
+ "fix": "Omit subtitle. Use it only for a fact the title lacks (scope,\nowner, last sync time).",
156
+ "name": "Subtitle restating the title"
157
+ },
158
+ {
159
+ "body": "3–4 StatCards above a list or detail page: 件数, 公開中, 合計.\nA row count is not a KPI.",
160
+ "category": "structure",
161
+ "fix": "Drop the row; the total is `<Pagination showTotal>`, a record's\nfigures are Descriptions rows. StatCard rows belong on a dashboard\nwith comparison or trend (delta). ui-audit: kpi-row-off-dashboard.",
162
+ "name": "KPI tile row on a non-dashboard page"
163
+ },
164
+ {
165
+ "body": "A large icon + title + description centred inside a Card or\ntable surface.",
166
+ "category": "structure",
167
+ "fix": "One sentence + one action: `<EmptyState title action />`, no\n`icon` (or variant=\"compact\"). ui-audit: empty-state-icon-in-card.",
168
+ "name": "Icon EmptyState inside a Card"
169
+ },
170
+ {
171
+ "body": "An info Alert at the top of each page explaining the page, or\nseveral Alerts repeating the same notice.",
172
+ "category": "structure",
173
+ "fix": "Alert only for a state that blocks or changes the task. Field\nerrors in FormField, results in a toast, standing info in plain\ntext. ui-audit: alert-per-page.",
174
+ "name": "Alert banner on every page"
175
+ },
176
+ {
177
+ "body": "A Badge in every table column, tiers and categories in\ndifferent colours. Colour stops meaning status.",
178
+ "category": "visual",
179
+ "fix": "Badge for status only, one status column per table. Tiers,\ncategories and scopes are plain text (or one neutral tone).\nui-audit: badge-wall.",
180
+ "name": "Badge wall"
181
+ },
182
+ {
183
+ "body": "The same gap everywhere: between sections, between a heading\nand its content, between fields. No hierarchy.",
184
+ "category": "layout",
185
+ "fix": "Two steps: section step (PageContainer children / gap=\"lg\")\nand item step (gap=\"sm\" inside a section).",
186
+ "name": "Uniform spacing"
187
+ },
188
+ {
189
+ "body": "A Lucide icon before each CardTitle, section heading and button\nlabel. Decoration that adds no meaning.",
190
+ "category": "visual",
191
+ "fix": "Text alone. An icon only where it is the affordance (icon-only\nbutton with aria-label) or carries status.",
192
+ "name": "Icon in every heading and button"
193
+ },
140
194
  {
141
195
  "body": "Settings page with 40 form fields in a single scroll. User\nloses their place, can't find the field they came for.",
142
196
  "category": "structure",
@@ -146,7 +200,7 @@
146
200
  {
147
201
  "body": "Click a Button → Dialog opens → click \"Edit\" → another Dialog\nopens → click \"Confirm\" → AlertDialog opens. Triple stack;\nuser loses context.",
148
202
  "category": "structure",
149
- "fix": "Use Sheet for the FIRST level (side panel), Dialog for the\nconfirm. Or, redesign the flow so the edit is INLINE in the\nfirst Dialog (no second Dialog needed). AlertDialog for confirm\nis correct — but ONE deep, not three.",
203
+ "fix": "Use Sheet for the FIRST level (side panel), Dialog for the\nconfirm. Or, redesign the flow so the edit is INLINE in the\nfirst Dialog (no second Dialog needed). A destructive confirm\n(AlertDialog preset, or Dialog variant=\"destructive\") is correct —\nbut ONE deep, not three.",
150
204
  "name": "Modal-in-modal-in-modal"
151
205
  },
152
206
  {
package/agent/index.json CHANGED
@@ -1,13 +1,19 @@
1
1
  {
2
2
  "counts": {
3
- "anti-ai-tells": 26,
3
+ "anti-ai-tells": 35,
4
4
  "components": 161,
5
5
  "patterns": 24,
6
6
  "rules": 43,
7
7
  "tokens": 2195,
8
8
  "vocabulary": 14
9
9
  },
10
+ "design": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md",
10
11
  "files": [
12
+ {
13
+ "file": "DESIGN.md",
14
+ "note": "12 KB — the visual spec: tokens, colour scarcity, admin screen anatomy (list, detail, form, settings, dashboard), do/don't. Read before composing a screen.",
15
+ "url": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/DESIGN.md"
16
+ },
11
17
  {
12
18
  "file": "components-index.json",
13
19
  "note": "47 KB — name + group + tagline for all 161. FETCH THIS FIRST, then fetch only the components you chose.",
@@ -48,7 +54,7 @@
48
54
  "note": "Pin to the tag that matches the @godxjp/ui version you installed. A catalog newer than your package describes props you do not have; older, and it hides props you do.",
49
55
  "read": {
50
56
  "live": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/index.json",
51
- "pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v32.5.0/agent/index.json"
57
+ "pinned": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/v32.6.0/agent/index.json"
52
58
  },
53
59
  "source": "mcp/src/data — the same data @godxjp/ui-mcp serves — plus the foundation and semantic token tiers, read from src/tokens/*.css",
54
60
  "start": "https://raw.githubusercontent.com/godx-jp/godxjp-ui/main/agent/START-HERE.md",
@@ -62,5 +68,5 @@
62
68
  "foundation": "the seeds a consumer is invited to set — --primary, --background, --radius",
63
69
  "semantic": "named roles that follow the seeds — --ring, --text-link, --overlay-background"
64
70
  },
65
- "version": "32.5.0"
71
+ "version": "32.6.0"
66
72
  }