@micha.bigler/ui-core-micha 3.11.2 → 3.13.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/CHANGELOG.md +10 -0
- package/README.md +6 -0
- package/WORK_ORDERS.md +5 -1
- package/dist/pages/AccountPage.js +2 -2
- package/dist/theme/createAppTheme.js +18 -3
- package/dist/theme/tokens.js +11 -7
- package/docs/TYPE-SCALE.md +111 -0
- package/package.json +1 -1
- package/src/pages/AccountPage.jsx +2 -0
- package/src/theme/createAppTheme.js +7 -0
- package/src/theme/tokens.js +12 -7
- package/tests/AccountPage.profileStatements.test.jsx +162 -0
- package/tests/createAppThemeTypography.test.js +53 -0
- package/tests/fixtures/light-theme-baseline.json +18 -12
- package/work-orders/UCM-AUTH-12.md +98 -0
- package/work-orders/UCM-THEME-17.md +111 -0
- package/work-orders/UCM-THEME-18.md +184 -0
- package/work-orders/assets/UCM-THEME-17-type-scale.html +391 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { assertThemeComplete, createAppTheme } from '../src/theme';
|
|
4
|
+
import { breakpointDownQuery } from '../src/theme/tokens';
|
|
5
|
+
|
|
6
|
+
const themes = [
|
|
7
|
+
['light', createAppTheme({ palette: { primary: { main: '#0F62FE' } } })],
|
|
8
|
+
['dark', createAppTheme({ palette: { mode: 'dark', primary: { main: '#468AB2' } } })],
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
const decidedSizes = {
|
|
12
|
+
h1: '36px',
|
|
13
|
+
h2: '32px',
|
|
14
|
+
h3: '28px',
|
|
15
|
+
h4: '24px',
|
|
16
|
+
h5: '20px',
|
|
17
|
+
subtitle1: '13px',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
describe('createAppTheme frozen typography scale', () => {
|
|
21
|
+
it.each(themes)('uses the decided type sizes in %s mode', (_mode, theme) => {
|
|
22
|
+
for (const [variant, fontSize] of Object.entries(decidedSizes)) {
|
|
23
|
+
expect(theme.typography[variant].fontSize).toBe(fontSize);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it.each(themes)('steps h4 down below the theme sm breakpoint in %s mode', (_mode, theme) => {
|
|
28
|
+
const query = breakpointDownQuery(theme.breakpoints.values.sm);
|
|
29
|
+
|
|
30
|
+
expect(Object.keys(theme.typography.h4)).toContain(query);
|
|
31
|
+
expect(theme.typography.h4[query]).toEqual({ fontSize: '23px' });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('reports no typography finding for the baseline theme', () => {
|
|
35
|
+
const theme = createAppTheme({ palette: { primary: { main: '#0F62FE' } } });
|
|
36
|
+
|
|
37
|
+
expect(Object.keys(theme.typography.h4)).toContain(breakpointDownQuery(theme.breakpoints.values.sm));
|
|
38
|
+
expect(assertThemeComplete(theme).findings.filter(({ surface }) =>
|
|
39
|
+
surface.startsWith('typography.'),
|
|
40
|
+
)).toEqual([]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('moves the h4 step with an app-overridden sm breakpoint', () => {
|
|
44
|
+
const theme = createAppTheme({
|
|
45
|
+
palette: { primary: { main: '#0F62FE' } },
|
|
46
|
+
breakpoints: { values: { sm: 480 } },
|
|
47
|
+
});
|
|
48
|
+
const keys = Object.keys(theme.typography.h4).filter((key) => key.startsWith('@media'));
|
|
49
|
+
|
|
50
|
+
expect(keys).toEqual([breakpointDownQuery(480)]);
|
|
51
|
+
expect(theme.typography.h4[keys[0]]).toEqual({ fontSize: '23px' });
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -754,35 +754,38 @@
|
|
|
754
754
|
"fontWeightRegular": 400,
|
|
755
755
|
"h1": {
|
|
756
756
|
"fontFamily": "'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
757
|
-
"fontSize": "
|
|
757
|
+
"fontSize": "36px",
|
|
758
758
|
"fontWeight": 600,
|
|
759
759
|
"letterSpacing": 0,
|
|
760
760
|
"lineHeight": 1.2
|
|
761
761
|
},
|
|
762
762
|
"h2": {
|
|
763
763
|
"fontFamily": "'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
764
|
-
"fontSize": "
|
|
764
|
+
"fontSize": "32px",
|
|
765
765
|
"fontWeight": 600,
|
|
766
766
|
"letterSpacing": 0,
|
|
767
767
|
"lineHeight": 1.22
|
|
768
768
|
},
|
|
769
769
|
"h3": {
|
|
770
770
|
"fontFamily": "'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
771
|
-
"fontSize": "
|
|
771
|
+
"fontSize": "28px",
|
|
772
772
|
"fontWeight": 600,
|
|
773
773
|
"letterSpacing": 0,
|
|
774
774
|
"lineHeight": 1.25
|
|
775
775
|
},
|
|
776
776
|
"h4": {
|
|
777
|
+
"@media (max-width:599.95px)": {
|
|
778
|
+
"fontSize": "23px"
|
|
779
|
+
},
|
|
777
780
|
"fontFamily": "'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
778
|
-
"fontSize": "
|
|
781
|
+
"fontSize": "24px",
|
|
779
782
|
"fontWeight": 600,
|
|
780
783
|
"letterSpacing": 0,
|
|
781
784
|
"lineHeight": 1.3
|
|
782
785
|
},
|
|
783
786
|
"h5": {
|
|
784
787
|
"fontFamily": "'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
785
|
-
"fontSize": "
|
|
788
|
+
"fontSize": "20px",
|
|
786
789
|
"fontWeight": 600,
|
|
787
790
|
"letterSpacing": 0,
|
|
788
791
|
"lineHeight": 1.3
|
|
@@ -813,7 +816,7 @@
|
|
|
813
816
|
"pxToRem": "size => `${size / htmlFontSize * coef}rem`",
|
|
814
817
|
"subtitle1": {
|
|
815
818
|
"fontFamily": "'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
816
|
-
"fontSize": "
|
|
819
|
+
"fontSize": "13px",
|
|
817
820
|
"fontWeight": 600,
|
|
818
821
|
"letterSpacing": 0,
|
|
819
822
|
"lineHeight": 1.4
|
|
@@ -1867,35 +1870,38 @@
|
|
|
1867
1870
|
"fontWeightRegular": 400,
|
|
1868
1871
|
"h1": {
|
|
1869
1872
|
"fontFamily": "Fixture Sans",
|
|
1870
|
-
"fontSize": "
|
|
1873
|
+
"fontSize": "36px",
|
|
1871
1874
|
"fontWeight": 600,
|
|
1872
1875
|
"letterSpacing": 0,
|
|
1873
1876
|
"lineHeight": 1.2
|
|
1874
1877
|
},
|
|
1875
1878
|
"h2": {
|
|
1876
1879
|
"fontFamily": "Fixture Sans",
|
|
1877
|
-
"fontSize": "
|
|
1880
|
+
"fontSize": "32px",
|
|
1878
1881
|
"fontWeight": 600,
|
|
1879
1882
|
"letterSpacing": 0,
|
|
1880
1883
|
"lineHeight": 1.22
|
|
1881
1884
|
},
|
|
1882
1885
|
"h3": {
|
|
1883
1886
|
"fontFamily": "Fixture Sans",
|
|
1884
|
-
"fontSize": "
|
|
1887
|
+
"fontSize": "28px",
|
|
1885
1888
|
"fontWeight": 600,
|
|
1886
1889
|
"letterSpacing": 0,
|
|
1887
1890
|
"lineHeight": 1.25
|
|
1888
1891
|
},
|
|
1889
1892
|
"h4": {
|
|
1893
|
+
"@media (max-width:599.95px)": {
|
|
1894
|
+
"fontSize": "23px"
|
|
1895
|
+
},
|
|
1890
1896
|
"fontFamily": "Fixture Sans",
|
|
1891
|
-
"fontSize": "
|
|
1897
|
+
"fontSize": "24px",
|
|
1892
1898
|
"fontWeight": 600,
|
|
1893
1899
|
"letterSpacing": 0,
|
|
1894
1900
|
"lineHeight": 1.3
|
|
1895
1901
|
},
|
|
1896
1902
|
"h5": {
|
|
1897
1903
|
"fontFamily": "Fixture Sans",
|
|
1898
|
-
"fontSize": "
|
|
1904
|
+
"fontSize": "20px",
|
|
1899
1905
|
"fontWeight": 600,
|
|
1900
1906
|
"letterSpacing": 0,
|
|
1901
1907
|
"lineHeight": 1.3
|
|
@@ -1926,7 +1932,7 @@
|
|
|
1926
1932
|
"pxToRem": "size => `${size / htmlFontSize * coef}rem`",
|
|
1927
1933
|
"subtitle1": {
|
|
1928
1934
|
"fontFamily": "Fixture Sans",
|
|
1929
|
-
"fontSize": "
|
|
1935
|
+
"fontSize": "13px",
|
|
1930
1936
|
"fontWeight": 600,
|
|
1931
1937
|
"letterSpacing": 0,
|
|
1932
1938
|
"lineHeight": 1.4
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# UCM-AUTH-12: Optional profile statement text on the account page
|
|
2
|
+
|
|
3
|
+
# A. Envelope — operator-approved scope
|
|
4
|
+
|
|
5
|
+
## Goal and expected outcome
|
|
6
|
+
|
|
7
|
+
Expose `AccountPage.showProfileStatements` so an app without privacy/cookie statement
|
|
8
|
+
endpoints can suppress the explanatory statement panels and their requests. The default
|
|
9
|
+
is `true`, preserving every existing consumer's behavior. With `false`, the account profile
|
|
10
|
+
still renders and submits both existing consent fields.
|
|
11
|
+
|
|
12
|
+
The operator explicitly approved this switch, its release and the innoservice pin bump on
|
|
13
|
+
2026-10-13. innoservice CI38387014900 records privacy/cookie 404s; auth policy returns 200.
|
|
14
|
+
|
|
15
|
+
## Scope and non-goals
|
|
16
|
+
|
|
17
|
+
- Add the optional prop and pass it to the existing ProfileComponent statement switch.
|
|
18
|
+
- Publish a minor release 3.13.0; innoservice consumes it under INNO-FIX-13.
|
|
19
|
+
- Do not change consent defaults, payloads, validation, permissions, authentication,
|
|
20
|
+
account navigation, statement fetching implementation, theme tokens or other consumers.
|
|
21
|
+
- Do not fix UCM-SHELL-8 or invent statement endpoints/content.
|
|
22
|
+
- No new visual design or prototype; this config uses the existing ProfileComponent surface.
|
|
23
|
+
|
|
24
|
+
## Tier, risk and required tests
|
|
25
|
+
|
|
26
|
+
Tier 3: source inside shared-core on an account surface. Compatibility rests on default true.
|
|
27
|
+
Tests to write: render the real AccountPage and ProfileComponent; omission of the new prop
|
|
28
|
+
fetches both statements and presents the existing panels; false performs neither request and
|
|
29
|
+
hides the panels, while both consent controls remain editable and their values reach the
|
|
30
|
+
existing updateUserProfile submission. Keep the existing account-navigation tests.
|
|
31
|
+
|
|
32
|
+
# B. Implementation map — ADDRESSED TO THE IMPLEMENTER
|
|
33
|
+
|
|
34
|
+
## Target and ownership
|
|
35
|
+
|
|
36
|
+
Target: `C:/Users/Micha Bigler/Documents/webapps/ui-core-micha`.
|
|
37
|
+
Native bootstrap retains workspace-root cwd; use explicit absolute paths and workdirs.
|
|
38
|
+
You are not alone in the workspace. Own only:
|
|
39
|
+
- `src/pages/AccountPage.jsx`
|
|
40
|
+
- new `tests/AccountPage.profileStatements.test.jsx`
|
|
41
|
+
|
|
42
|
+
## Context package
|
|
43
|
+
|
|
44
|
+
`src/pages/AccountPage.jsx:39` exports named AccountPage with destructured optional props.
|
|
45
|
+
Its profile branch near line228 renders ProfileComponent with showName/showPrivacy/showCookies.
|
|
46
|
+
Its existing handleProfileSubmit calls updateUserProfile(payload), then AuthContext.login(updated).
|
|
47
|
+
`src/components/ProfileComponent.jsx:23` exports named ProfileComponent; showStatements defaults
|
|
48
|
+
true, independently of showPrivacy/showCookies. Its statement-loading effect at83 returns before
|
|
49
|
+
either fetch when showStatements is false. Panels at255 are also controlled by showStatements.
|
|
50
|
+
Consent controls at230/242 and payload at130/133 depend only on showPrivacy/showCookies.
|
|
51
|
+
Use that established switch; leave this component untouched.
|
|
52
|
+
|
|
53
|
+
Read only these targets plus `tests/AccountPage.test.jsx` for theme/router/AuthContext setup,
|
|
54
|
+
and `src/auth/authApi.jsx` for the four API export names if necessary. Do not explore broadly.
|
|
55
|
+
The existing navigation test mocks ProfileComponent, so it cannot prove the no-request and
|
|
56
|
+
consent invariant: write a separate test file rendering both real components. Stub network API
|
|
57
|
+
functions and unrelated account children only. Relevant real accessible labels are translation
|
|
58
|
+
keys Profile.ACCEPT_PRIVACY_LABEL, Profile.ACCEPT_COOKIES_LABEL, Profile.PRIVACY_STATEMENT_TITLE,
|
|
59
|
+
Profile.COOKIES_STATEMENT_TITLE and Profile.SAVE_BUTTON.
|
|
60
|
+
Use the suite's established translation seam; never mock AccountPage/ProfileComponent under test.
|
|
61
|
+
|
|
62
|
+
## Preamble
|
|
63
|
+
|
|
64
|
+
> This committed WO is the COMPLETE spec. You are the initial implementer, not the reviewer.
|
|
65
|
+
> Preserve other edits. Edit only the two owned source/test paths using explicit UTF-8 I/O.
|
|
66
|
+
> Do not edit dependencies, lockfiles, package/version/changelog/register/README/governance,
|
|
67
|
+
> settings, environment, other repos or memory. Never read .env or dump settings/environment.
|
|
68
|
+
> No installs, package-manager commands, containers, git operations, self-review or subagents.
|
|
69
|
+
> Write the required tests and run your own new file ONCE with the existing Node/Vitest runtime,
|
|
70
|
+
> maxWorkers=2; no affected/full suite, build or app startup. If unavailable, report the obstacle.
|
|
71
|
+
> The orchestrator's tests and separate reviews are the acceptance gate. Leave uncommitted.
|
|
72
|
+
> Start PLAN, emit PROGRESS before relevant actions without silence over two minutes, then
|
|
73
|
+
> exactly one final RESULT: DONE or RESULT: BLOCKED.
|
|
74
|
+
|
|
75
|
+
# C. Orchestrator only — NOT ADDRESSED TO THE IMPLEMENTER
|
|
76
|
+
|
|
77
|
+
> IMPLEMENTER STOP HERE. You ARE the initial implementation instance. No steps below belong to you.
|
|
78
|
+
|
|
79
|
+
Gate #1: operator explicitly approved the exact API/default, retained consents, release and pin
|
|
80
|
+
bump in the innoservice orchestration chat on 2026-10-13. Native plain worker requested
|
|
81
|
+
codex/gpt-6-luna, fresh context, full committed WO inline. Record accepted ID and actual metadata;
|
|
82
|
+
effective provider/model stays unverified when the API does not expose it. No protection-parity claim.
|
|
83
|
+
|
|
84
|
+
Parent owns version/changelog/README/register and pnpm state. Independent four lenses plus UI
|
|
85
|
+
and security concurrently, full scoped context, CLI read-only without bypass. Parent fixes findings.
|
|
86
|
+
Scoped gate: new real-component tests, existing AccountPage navigation and affected auth tests.
|
|
87
|
+
Publish workflow on main already runs build/full tests; shared-core ripple justifies that existing
|
|
88
|
+
release suite. Do not dispatch publish manually; normal reviewed main push triggers it. Check
|
|
89
|
+
publish job success before app pin. Minor 3.13.0 is additive; read exact release diff before app bump.
|
|
90
|
+
Final core row includes deduplicated review totals and test results; second register commit before
|
|
91
|
+
one main push. innoservice AccountPage/WelcomePage statements false and capture evidence remain
|
|
92
|
+
INNO-FIX-13; keep existing consents, request diagnostics and capture checks intact.
|
|
93
|
+
|
|
94
|
+
Accepted native implementer: `/root/kit_account_statements`, explicit requested gpt-6-luna,
|
|
95
|
+
high reasoning, fresh context, complete WO inline. Effective native provider/model metadata
|
|
96
|
+
was not exposed and remains unverified. Source/test edits only; the one permitted author test
|
|
97
|
+
attempt failed before collection with temporary-file EPERM (zero tests). Parent runs the
|
|
98
|
+
authoritative scoped gate through the normal runtime approval path. No author review or git.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# UCM-THEME-17: Decide a less compressed baseline type scale
|
|
2
|
+
|
|
3
|
+
# A. Envelope, authored by the Expertenchat
|
|
4
|
+
|
|
5
|
+
## Goal & expected outcome
|
|
6
|
+
|
|
7
|
+
The baseline's heading steps are too small to carry a hierarchy. Page title, card title and section label
|
|
8
|
+
differ by 1 to 3 px, so screens rely on weight alone, and where every level is bold the levels merge. This
|
|
9
|
+
order produces the **decided** type scale as a committed reference sheet that the operator freezes. A
|
|
10
|
+
later implementation order puts it into `src/theme/tokens.js`. The output here is a document, no code.
|
|
11
|
+
|
|
12
|
+
Operator decision (2026-10-04): treat this as a baseline finding, the way dark mode was treated
|
|
13
|
+
(`UCM-THEME-13`), not as per-app overrides.
|
|
14
|
+
|
|
15
|
+
## Context the operator established
|
|
16
|
+
|
|
17
|
+
- **The baseline scale today** (`src/theme/tokens.js:157-168`): h1 32, h2 28, h3 24, h4 20, h5 18, h6 16,
|
|
18
|
+
subtitle1 15/600, subtitle2 13/500, body1 14, body2 13, button 14/500, caption 12, overline 11 (px).
|
|
19
|
+
- **Measured on rendered screens, 2026-10-04** (computed styles in the browser):
|
|
20
|
+
|
|
21
|
+
| Screen | Page title | Card title | Section | Text |
|
|
22
|
+
|---|---|---|---|---|
|
|
23
|
+
| hram, Research | h4 20/500 | h5 18/500 | subtitle1 15/600 | 14 |
|
|
24
|
+
| jg-ferien, Dashboard | h5 18/600 | h6 16/600 | – | 14, partly 600 |
|
|
25
|
+
| kerzenziehen, Admin | h5 18/600 | – | – | 14 |
|
|
26
|
+
| survey_app site (operator screenshots) | h4 20/800 | h6 16/800 | – | – |
|
|
27
|
+
| for comparison, the MUI scale (spesix, stale local build) | h4 34 | h5 24 | – | 16 |
|
|
28
|
+
|
|
29
|
+
- **Operator feedback:** survey_app editor and sites read "more harmonious" at the old MUI sizes, and on the
|
|
30
|
+
sites the section title and the question labels became indistinguishable. jg-ferien already restored its
|
|
31
|
+
own sizes (`jg-ferien` `JG-DL-7`). Six other apps accepted the baseline scale without comment.
|
|
32
|
+
- **The MUI scale is the other extreme**: 34/24 px titles read heavy in a dense tool.
|
|
33
|
+
|
|
34
|
+
## Inventory (stage 1, 2026-10-04)
|
|
35
|
+
|
|
36
|
+
From 88 prototypes in `*/work-orders/assets/` (screen selectors hand-checked in nine: KZ-UI-1, RES-14,
|
|
37
|
+
INNO-PLAN-1, JG-MEM-1, UX-10, PRIM-1, FM-8, OBS-10, KIRA-CRUD-6), the app theme overrides and the
|
|
38
|
+
measurements above:
|
|
39
|
+
|
|
40
|
+
| Role | Baseline today | Approved prototypes (typical) | MUI |
|
|
41
|
+
|---|---|---|---|
|
|
42
|
+
| Screen title | h4 20/600, fixed | 24 at 1280, 17-21 at 375 (KZ 24->17, jg 25.6->20, survey 24->21) | 34 |
|
|
43
|
+
| Panel / dialog | h5 18 | 18-20 | 24 |
|
|
44
|
+
| Card title | h6 16 | 15-18 | 20/500 |
|
|
45
|
+
| Section label | subtitle1 15/600 | 12-13 at 600-700 | - |
|
|
46
|
+
| Body | 14 | 14 (20 sheets), 15 (13 sheets) | 16 |
|
|
47
|
+
|
|
48
|
+
- The approved designs had the larger title step (screen title about 1.7x body; baseline 1.43x), and step
|
|
49
|
+
the title down on mobile. Both were lost between prototype and baseline.
|
|
50
|
+
- The section label sits on the wrong side of body: 15 px, one pixel under the card title.
|
|
51
|
+
- jg-ferien rejected larger **body** text (`JG-DL-7`); survey_app misses **heading** steps. The two are
|
|
52
|
+
compatible.
|
|
53
|
+
- Weight no longer carries hierarchy: every heading is 600 and apps override it per level (survey_app 800,
|
|
54
|
+
hram 500).
|
|
55
|
+
|
|
56
|
+
## Structural decisions (operator, 2026-10-04)
|
|
57
|
+
|
|
58
|
+
1. **One scale** for every app and page type; no separate reading register. Body stays the tool density.
|
|
59
|
+
2. **The screen title steps down one size on narrow screens.**
|
|
60
|
+
3. **Size carries the hierarchy, weight is fixed**: headings share one weight; the section label is small
|
|
61
|
+
and strong. App overrides are for font family, not for per-level weight.
|
|
62
|
+
4. **The section label (subtitle1) moves below body size**, set apart by weight.
|
|
63
|
+
|
|
64
|
+
The role mapping of the `THEME-1` sheet stands: h4 screen title, h5 panel/dialog, h6 card title.
|
|
65
|
+
|
|
66
|
+
## Outcome
|
|
67
|
+
|
|
68
|
+
**Frozen 2026-10-04** after two value rounds: candidate B, mobile screen title 23, h1 to h3 36 / 32 / 28. The
|
|
69
|
+
frozen sheet is [`docs/TYPE-SCALE.md`](../docs/TYPE-SCALE.md); the implementation order is `UCM-THEME-18`.
|
|
70
|
+
|
|
71
|
+
## Scope + non-goals
|
|
72
|
+
|
|
73
|
+
In scope: an inventory of the type sizes the estate actually uses (app overrides, prototypes, the
|
|
74
|
+
`THEME-1` reference sheet's own reasoning); an instrument showing two to three candidate scales next to
|
|
75
|
+
today's baseline and the MUI default, on real screens (hram Research, a survey site, the jg-ferien dashboard,
|
|
76
|
+
a kerzenziehen admin view), at 375 px and 1280 px; value rounds; a frozen sheet with provenance and the
|
|
77
|
+
rejected candidates.
|
|
78
|
+
|
|
79
|
+
Non-goals:
|
|
80
|
+
- No code, no tests (the implementation is a separate order).
|
|
81
|
+
- No change to font families. Apps keep their identity fonts.
|
|
82
|
+
- No per-app decisions. App overrides that exist only to escape the compressed scale (survey_app's planned
|
|
83
|
+
revert, `JG-DL-7`) are reviewed after the freeze, not here.
|
|
84
|
+
|
|
85
|
+
## Tier · precondition / gate
|
|
86
|
+
|
|
87
|
+
- **Tier 2 · tests: none (document only).** It decides future shared-core content but changes none.
|
|
88
|
+
- Precondition: none.
|
|
89
|
+
- Gate: **the operator freezes the sheet**, with a dated section in it.
|
|
90
|
+
|
|
91
|
+
## Risks
|
|
92
|
+
|
|
93
|
+
- **Every adopted app moves with the baseline.** A new scale changes the look of ten-plus apps at once; the
|
|
94
|
+
instrument has to show the dense tool screens, not only reading screens.
|
|
95
|
+
- **Bigger steps cost vertical space** on dense screens (hram, cockpit). The candidates must be judged
|
|
96
|
+
there, not only on the survey sites.
|
|
97
|
+
- **Weight and size interact.** The fix may be partly a weight rule (fewer bold levels), not only sizes.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
# B. Implementation map
|
|
102
|
+
|
|
103
|
+
*Not applicable. This is an Expertenchat document order, authored in-session with the operator.*
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
# C. Orchestrator only, NOT ADDRESSED TO THE IMPLEMENTER
|
|
108
|
+
|
|
109
|
+
> **If you are the implementer reading this: STOP.** There is no implementer for this order.
|
|
110
|
+
|
|
111
|
+
Register: row -> `done` with the commit of the frozen sheet. Then the implementation order is written.
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# UCM-THEME-18: Ship the frozen baseline type scale
|
|
2
|
+
|
|
3
|
+
# A. Envelope, authored by the Expertenchat
|
|
4
|
+
|
|
5
|
+
## Goal & expected outcome
|
|
6
|
+
|
|
7
|
+
`createAppTheme` produces the type scale frozen in [`docs/TYPE-SCALE.md`](../docs/TYPE-SCALE.md) (`UCM-THEME-17`,
|
|
8
|
+
frozen 2026-10-04), in light and dark. The screen title (h4) steps down one size below the baseline's `sm`
|
|
9
|
+
breakpoint. Released as a **minor** version (`3.12.0`), because every adopted app looks different after the bump.
|
|
10
|
+
|
|
11
|
+
## Decided values (from `docs/TYPE-SCALE.md`, by variant)
|
|
12
|
+
|
|
13
|
+
| Variant | Before | After |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| h1 / h2 / h3 | 32 / 28 / 24 | **36 / 32 / 28** |
|
|
16
|
+
| h4 | 20 | **24**, and **23 below `sm`** |
|
|
17
|
+
| h5 | 18 | **20** |
|
|
18
|
+
| subtitle1 | 15 | **13** |
|
|
19
|
+
|
|
20
|
+
Unchanged: h6, subtitle2, body1, body2, button, caption, overline; every weight (headings 600, subtitle1 600);
|
|
21
|
+
every line height; `letterSpacing`. If this table and `docs/TYPE-SCALE.md` disagree, the sheet wins.
|
|
22
|
+
|
|
23
|
+
## Context the operator established
|
|
24
|
+
|
|
25
|
+
- **Typography lives in one block**: `src/theme/tokens.js:223-241`, built with `typeVariant` (`tokens.js:45`).
|
|
26
|
+
`createAppTheme` (`src/theme/createAppTheme.js:379-387`) spreads it unchanged and takes only `fontFamily`
|
|
27
|
+
from the app, so light and dark get the same scale from the same place.
|
|
28
|
+
- **Breakpoints**: `tokens.js:250-252`, `sm: 600`. The mobile step means "below `sm`", the same line MUI's
|
|
29
|
+
`breakpoints.down('sm')` draws.
|
|
30
|
+
- **`assertThemeComplete`** reads `fontSize`, `fontWeight`, `lineHeight` and `letterSpacing` per variant
|
|
31
|
+
(`src/theme/themeCompleteness.js:38`). A nested media-query key inside h4 is new to it.
|
|
32
|
+
- **The light regression fixture** `tests/fixtures/light-theme-baseline.json`, checked by
|
|
33
|
+
`tests/createAppThemeLightGuard.test.js`, contains the typography and changes with this order.
|
|
34
|
+
- **The kit's own screens use the variants too** (h6 about 24 times, h4 twice, h5 once in `src/`), so kit
|
|
35
|
+
screens such as the account pages change with the scale. That is intended.
|
|
36
|
+
|
|
37
|
+
## Scope + non-goals
|
|
38
|
+
|
|
39
|
+
In scope: the typography values above; the h4 step below `sm`; the fixture's typography entries;
|
|
40
|
+
`CHANGELOG.md` naming the visible change for every adopted app; the minor release.
|
|
41
|
+
|
|
42
|
+
Non-goals:
|
|
43
|
+
- No app repo changes. The per-app follow-up (listed below) is written after the release, one order per app.
|
|
44
|
+
- No font family, weight or line-height change; no new variant; no change to `breakpoints`.
|
|
45
|
+
- No responsive step for any variant other than h4.
|
|
46
|
+
|
|
47
|
+
## Tier · precondition / gate
|
|
48
|
+
|
|
49
|
+
- **Tier 3 · tests: the typography values per variant and the h4 step, in light and dark; the light
|
|
50
|
+
regression fixture updated in its typography entries only; the existing `createAppTheme` and completeness
|
|
51
|
+
tests.** A change inside shared-core (`AGENTS.md` -> Tiering).
|
|
52
|
+
- Precondition: `UCM-THEME-17` `done` (frozen sheet committed).
|
|
53
|
+
- No prototype gate: the instrument is a decision sheet, not a screen to match.
|
|
54
|
+
|
|
55
|
+
## Risks
|
|
56
|
+
|
|
57
|
+
- **Every adopted app moves on its next bump.** Intended; the changelog says so in one line an app session can
|
|
58
|
+
act on.
|
|
59
|
+
- **An app that overrides h4's size keeps the baseline's 23 px below `sm`**, because a theme merge keeps the
|
|
60
|
+
nested media key. survey_app sets h4 to `2.125rem` today; on mobile it would fall to 23. The per-app
|
|
61
|
+
follow-up handles it; the changelog names it.
|
|
62
|
+
- **`assertThemeComplete` may misread the nested key** (as a missing or extra surface). It must neither raise
|
|
63
|
+
a finding for the baseline's own media key nor let an app's h4 override go unnoticed.
|
|
64
|
+
|
|
65
|
+
## Required tests to WRITE (you write them and run YOUR OWN new ones; the Orchestrator's run is the gate)
|
|
66
|
+
|
|
67
|
+
1. For a light and a dark theme from `createAppTheme`: each variant in the table resolves to its decided
|
|
68
|
+
`fontSize`, read from the theme, compared with the value in the table.
|
|
69
|
+
2. h4 carries a media-query entry for "below `sm`" with `fontSize` 23px, and that query is derived from
|
|
70
|
+
`breakpoints.values.sm`, not typed a second time. Show the test fails if `sm` changes and the query does not.
|
|
71
|
+
3. `assertThemeComplete` on the baseline returns no typography finding.
|
|
72
|
+
|
|
73
|
+
Run, do not write: `tests/createAppTheme.test.js`, `tests/createAppThemeLightGuard.test.js` (with the fixture's
|
|
74
|
+
typography entries updated, and only those), the completeness tests.
|
|
75
|
+
|
|
76
|
+
## Parity guardrail
|
|
77
|
+
|
|
78
|
+
No behaviour change; type sizes only. Palette, spacing, components and exports unchanged.
|
|
79
|
+
|
|
80
|
+
## Downstream (not this order; one order per app after the release)
|
|
81
|
+
|
|
82
|
+
Measured 2026-10-04 (see `docs/TYPE-SCALE.md` -> "Known consequences"):
|
|
83
|
+
|
|
84
|
+
| App | What the follow-up does |
|
|
85
|
+
|---|---|
|
|
86
|
+
| hram | screen titles on 5 pages from h5 to h4; drop the per-level weight 500 |
|
|
87
|
+
| jg-ferien | screen titles on 3 pages from h5 to h4 (`DashboardPage.jsx:187`) |
|
|
88
|
+
| kerzenziehen | admin screen title from h5 to h4 |
|
|
89
|
+
| spesix | 1 page title from h5 to h4; drop per-level weight overrides |
|
|
90
|
+
| fitness-monitor | 1 page title from h5 to h4 |
|
|
91
|
+
| survey_app | drop the 800/700 weights and the h4 `2.125rem`/400 override; decide the h3 page titles (24 -> 28); closes the held `SVA-THEME-1` typography revert |
|
|
92
|
+
| all other adopted apps | bump only |
|
|
93
|
+
|
|
94
|
+
webshop-guenter (own handoff scale), Kira, Cinevia and Gustav (no MUI heading variants) are unaffected.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
# B. Implementation map, filled by the Orchestrator and ADDRESSED TO THE IMPLEMENTER
|
|
99
|
+
|
|
100
|
+
Work from this package; open only the named files. A value the sheet lacks is `RESULT: BLOCKED <value>`.
|
|
101
|
+
|
|
102
|
+
## Target working directory (absolute)
|
|
103
|
+
|
|
104
|
+
`C:\Users\biglmi\Documents\webapps\ui-core-micha` (branch `main`). Never the workspace root.
|
|
105
|
+
|
|
106
|
+
## Context package
|
|
107
|
+
|
|
108
|
+
- **`src/theme/tokens.js`**: `BASELINE_STATIC.typography` (l.~222-241) uses `typeVariant(size, weight, lineHeight, extra)`
|
|
109
|
+
(l.45). Change h1/h2/h3/h4/h5/subtitle1 to the table in Part A; nothing else in that block moves.
|
|
110
|
+
h4 gets the mobile step as a nested media-query key inside the variant (`extra`), `fontSize: '23px'`.
|
|
111
|
+
The query must be **derived from the breakpoint value**, not typed a second time: introduce one
|
|
112
|
+
constant for `sm` (600) in `tokens.js`, use it in `breakpoints.values.sm` (l.~251) and build the key
|
|
113
|
+
from it, in the form MUI's `breakpoints.down('sm')` produces (`@media (max-width:599.95px)`, that is
|
|
114
|
+
`sm - 0.05`). Export the constant or the key builder so the test can reference it.
|
|
115
|
+
- **`src/theme/createAppTheme.js`** (l.~379-387) spreads `BASELINE_STATIC.typography` and takes only
|
|
116
|
+
`fontFamily` from the app; no change expected. Verify the nested media key survives `createTheme`
|
|
117
|
+
into `theme.typography.h4` in both light and dark (read the resolved theme, do not assume).
|
|
118
|
+
- **`src/theme/themeCompleteness.js`** (`TYPOGRAPHY_SURFACES`, l.~38) reads fontSize/fontWeight/lineHeight/
|
|
119
|
+
letterSpacing per variant. Verify the baseline h4 with its media key raises no finding; change this file
|
|
120
|
+
only if it does.
|
|
121
|
+
- **Light regression fixture** `tests/fixtures/light-theme-baseline.json` (checked by
|
|
122
|
+
`tests/createAppThemeLightGuard.test.js`): update ONLY the typography entries that this order changes
|
|
123
|
+
(h1-h5 and subtitle1 `fontSize`, and h4's new media key), in both of its snapshots (`baseline`, `override`).
|
|
124
|
+
Regenerate carefully: the diff of the fixture must contain nothing but those typography lines. Do not
|
|
125
|
+
re-capture the whole file blindly; check `git diff` of the fixture afterwards (use `git diff` to read it,
|
|
126
|
+
do not stage).
|
|
127
|
+
- **Docs / release**: `CHANGELOG.md` entry `3.12.0 - UCM-THEME-18` (newest first, same style as the
|
|
128
|
+
existing entries): the new scale in one table-free sentence; the visible change for every adopted app;
|
|
129
|
+
that an app overriding h4's `fontSize` keeps the baseline's 23px below `sm` (survey_app sets h4
|
|
130
|
+
`2.125rem`); that headings are fixed at weight 600 and apps should not override per level.
|
|
131
|
+
`package.json` version `3.11.2` -> `3.12.0` (no lockfile in this repo).
|
|
132
|
+
- Kit components: no edit expected (they use the variants).
|
|
133
|
+
|
|
134
|
+
**Existing tests to follow** (style): `tests/createAppTheme.test.js`, `tests/createAppThemeDark.test.js`.
|
|
135
|
+
New tests go in `tests/createAppThemeTypography.test.js`.
|
|
136
|
+
|
|
137
|
+
**Pitfalls**: weights, line heights, letterSpacing, h6, subtitle2, body1/2, button, caption, overline are
|
|
138
|
+
unchanged and must stay byte-identical. Do not touch `breakpoints` values or add a second source for `sm`.
|
|
139
|
+
|
|
140
|
+
## Required tests, restated
|
|
141
|
+
|
|
142
|
+
The three tests of Part A. Test 2 must show it can fail: derive the expected query from
|
|
143
|
+
`breakpoints.values.sm` of the resolved theme (not a literal), and include an assertion that would break if
|
|
144
|
+
the baseline's key were typed independently of that value (for example by building a theme with a different
|
|
145
|
+
`sm` through the same constant, if the constant is the single source, or by asserting the key string equals
|
|
146
|
+
the builder applied to the theme's own `sm`).
|
|
147
|
+
|
|
148
|
+
## Preamble
|
|
149
|
+
|
|
150
|
+
The text above is the COMPLETE spec: the committed WO file's content, not a plan to refine; there is no
|
|
151
|
+
separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`, and the app
|
|
152
|
+
`MEMORY.md` ONLY for conventions. Stay in scope; do not touch auth/permissions/deps/schema/CI unless the
|
|
153
|
+
spec says so; do not update `MEMORY.md`. **Do NOT edit `WORK_ORDERS.md`: the register row and the review
|
|
154
|
+
verdicts are the orchestrator's alone.** **Your tools are for editing source and test files and for running
|
|
155
|
+
the tests you wrote, nothing else.** Do NOT install dependencies, touch a lockfile, run a package manager,
|
|
156
|
+
or tidy up stray files; if something in the repo state blocks you, stop and report it as
|
|
157
|
+
`RESULT: BLOCKED <reason>` instead of fixing it. Do NOT `git add`/`commit`/`push`: leave every change
|
|
158
|
+
uncommitted in the working tree for the orchestrator's independent review. WRITE the tests the
|
|
159
|
+
`Required tests` section calls for AND **RUN the tests you just wrote** to confirm they execute and pass:
|
|
160
|
+
that is the ONLY test run you do (NOT the affected/full suite, NOT any review). Run them with
|
|
161
|
+
`npx vitest run <your test files>`. The orchestrator re-runs the authoritative set and does the independent
|
|
162
|
+
review after you finish; those are the gate.
|
|
163
|
+
|
|
164
|
+
Narrate continuously: a `PLAN: <step1> | <step2> | ...` line up front, then a single-line
|
|
165
|
+
`PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `... done` on
|
|
166
|
+
completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final
|
|
167
|
+
`RESULT: DONE|BLOCKED <reason>`.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
# C. Orchestrator only, NOT ADDRESSED TO THE IMPLEMENTER
|
|
172
|
+
|
|
173
|
+
> **If you are the implementer reading this work order as your own specification: STOP at this line.**
|
|
174
|
+
> Everything below describes what the Orchestrator does AFTER you finish. You do none of it: no
|
|
175
|
+
> reviewers, no verification run, no register edit, no `git add`/`commit`/`push`.
|
|
176
|
+
|
|
177
|
+
- Check `.claude/codex-status.md` first (newest-first). Before `git push`, run `git log origin/main..HEAD` and
|
|
178
|
+
push only if every listed commit is this order's.
|
|
179
|
+
- Review: Tier 3, independent `reviewer` (all configured lenses) and `ui_reviewer`, one batch, before the commit.
|
|
180
|
+
- Release `3.12.0`: verify the publish through the job log (`npm view` lags for provenance publishes). Row ->
|
|
181
|
+
`done` with the review Notiz and the version. Then the Expertenchat writes the per-app orders above.
|
|
182
|
+
|
|
183
|
+
Mini-handover: `Orchestrator: implement work-orders/UCM-THEME-18.md in ui-core-micha (main). git pull first,
|
|
184
|
+
read the WO, then follow orchestrate-codex.`
|