also looking at this
Promote main to production: signed-out chrome and the subscriber tables
#17
54 files
+4252
-1353
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -101,7 +101,22 @@ export default { | ||
| 101 | 101 | 'fg': 'var(--text)', |
| 102 | 102 | 'fg-strong': 'var(--text)', |
| 103 | 103 | 'fg-muted': 'var(--text-2)', |
| 104 | 'fg-soft': 'var(--text-2)', | |
| 104 | /* | |
| 105 | * The library's quiet text scale is four steps - fg, fg-muted, fg-soft, | |
| 106 | * fg-subtle - and this palette has three, so two roles share a value. | |
| 107 | * They used to share at the WRONG end: fg-soft was byte-identical to | |
| 108 | * fg-muted, which makes "quieter than muted" exactly as loud as muted. | |
| 109 | * | |
| 110 | * Nothing renders it today, which is why it was invisible: of the 53 | |
| 111 | * <EmptyState> sites in the estate none passes an `icon` (the only | |
| 112 | * thing there that reads fg-soft) and there is no <Badge dot>. But | |
| 113 | * <Breadcrumb> paints separators with fg-soft and links with fg-muted, | |
| 114 | * so the two being equal is a divider as loud as the labels it divides. | |
| 115 | * | |
| 116 | * Doubling up at the quiet end keeps the scale monotonic, so a | |
| 117 | * component asking for a quieter grey gets one. | |
| 118 | */ | |
| 119 | 'fg-soft': 'var(--text-3)', | |
| 105 | 120 | 'fg-subtle': 'var(--text-3)', |
| 106 | 121 | 'line-strong': 'color-mix(in srgb, var(--text-3) 55%, var(--border))', |
| 107 | 122 | 'line-hover': 'color-mix(in srgb, var(--text-2) 70%, var(--border))', |
| @@ -5,6 +5,8 @@ import { loadCssEngine } from '../../node_modules/@stacksjs/stx/dist/dev-server/ | ||
| 5 | 5 | import { SEMANTIC_TOKENS, SHAPE_TOKENS } from '../../node_modules/@stacksjs/stx/dist/theme-tokens.js' |
| 6 | 6 | import { mergeCssConfig } from '../../node_modules/@stacksjs/stx/dist/ts-css-config.js' |
| 7 | 7 | |
| 8 | const colors: Record<string, string> = theme.theme.extend.colors | |
| 9 | ||
| 8 | 10 | describe('component palette contract', () => { |
| 9 | 11 | test('every component color and radius emits an app-owned utility', async () => { |
| 10 | 12 | const engine = await loadCssEngine() |
| @@ -21,4 +23,31 @@ describe('component palette contract', () => { | ||
| 21 | 23 | expect(css).toContain('.rounded-control {\n border-radius: 10px;') |
| 22 | 24 | expect(css).toContain('.rounded-panel {\n border-radius: 0.75rem;') |
| 23 | 25 | }) |
| 26 | ||
| 27 | test('the quiet text scale stays monotonic, so a separator cannot shout', () => { | |
| 28 | /* | |
| 29 | * The library asks for four steps of quiet text and this palette has three, | |
| 30 | * so two roles share a value. Which two is the whole point. | |
| 31 | * | |
| 32 | * fg-soft used to equal fg-muted. Nothing rendered it -- none of the 53 | |
| 33 | * <EmptyState> sites passes an `icon` and there is no <Badge dot> -- so it | |
| 34 | * was invisible, and the contract test above could not see it either: that | |
| 35 | * one asserts every role is MAPPED, not that the mapping means anything. | |
| 36 | * <Breadcrumb> paints separators with fg-soft and its links with fg-muted, | |
| 37 | * so the two being equal is a divider as loud as the labels it divides. | |
| 38 | * | |
| 39 | * Asserted as an ordering rather than as literal values so re-theming the | |
| 40 | * palette cannot quietly reintroduce it. | |
| 41 | */ | |
| 42 | const steps = ['fg', 'fg-muted', 'fg-soft', 'fg-subtle'] as const | |
| 43 | const rank: Record<string, number> = { 'var(--text)': 0, 'var(--text-2)': 1, 'var(--text-3)': 2 } | |
| 44 | const ordered = steps.map((role) => { | |
| 45 | const value = colors[role] ?? colors['fg-strong'] | |
| 46 | expect(rank[value]).toBeDefined() | |
| 47 | return rank[value] | |
| 48 | }) | |
| 49 | for (let i = 1; i < ordered.length; i++) | |
| 50 | expect(ordered[i]).toBeGreaterThanOrEqual(ordered[i - 1]) | |
| 51 | expect(colors['fg-soft']).not.toBe(colors['fg-muted']) | |
| 52 | }) | |
| 24 | 53 | }) |