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.
| @@ -87,6 +87,50 @@ | ||
| 87 | 87 | "warning": "#f59e0b", |
| 88 | 88 | "info": "#b3bccb" |
| 89 | 89 | } |
| 90 | }, | |
| 91 | "marketing": { | |
| 92 | "light": { | |
| 93 | "fg": "#0b0f19", | |
| 94 | "fg-strong": "#0b0f19", | |
| 95 | "fg-muted": "#4b5565", | |
| 96 | "fg-soft": "#6b7280", | |
| 97 | "fg-subtle": "#6b7280", | |
| 98 | "page": "#fbfbfd", | |
| 99 | "panel": "#ffffff", | |
| 100 | "field": "#ffffff", | |
| 101 | "surface": "#ffffff", | |
| 102 | "surface-sunken": "#fbfbfd", | |
| 103 | "line": "rgba(15, 23, 42, 0.09)", | |
| 104 | "line-strong": "color-mix(in srgb, #6b7280 55%, rgba(15, 23, 42, 0.09))", | |
| 105 | "accent": "#047857", | |
| 106 | "accent-solid": "#047857", | |
| 107 | "accent-ink": "#ffffff", | |
| 108 | "danger": "#b91c1c", | |
| 109 | "success": "color-mix(in srgb, #16a34a 75%, #0b0f19)", | |
| 110 | "warning": "#b45309", | |
| 111 | "info": "#4b5565" | |
| 112 | }, | |
| 113 | "dark": { | |
| 114 | "fg": "#f3f5f9", | |
| 115 | "fg-strong": "#f3f5f9", | |
| 116 | "fg-muted": "#b3bccb", | |
| 117 | "fg-soft": "#79839a", | |
| 118 | "fg-subtle": "#79839a", | |
| 119 | "page": "#090b11", | |
| 120 | "panel": "#10131c", | |
| 121 | "field": "#10131c", | |
| 122 | "surface": "#10131c", | |
| 123 | "surface-sunken": "#090b11", | |
| 124 | "line": "rgba(148, 163, 184, 0.12)", | |
| 125 | "line-strong": "color-mix(in srgb, #79839a 55%, rgba(148, 163, 184, 0.12))", | |
| 126 | "accent": "#34d399", | |
| 127 | "accent-solid": "#34d399", | |
| 128 | "accent-ink": "#04140d", | |
| 129 | "danger": "#f87171", | |
| 130 | "success": "color-mix(in srgb, #4ade80 75%, #f3f5f9)", | |
| 131 | "warning": "#f59e0b", | |
| 132 | "info": "#b3bccb" | |
| 133 | } | |
| 90 | 134 | } |
| 91 | 135 | }, |
| 92 | 136 | "lost": [ |
| @@ -77,6 +77,7 @@ const source = readFileSync(resolve(ROOT, 'config/crosswind.ts'), 'utf8') | ||
| 77 | 77 | const SURFACES: Record<string, RegExp | null> = { |
| 78 | 78 | base: null, |
| 79 | 79 | dashboard: /\.page-dashboard/, |
| 80 | marketing: /stx-layout-group/, | |
| 80 | 81 | } |
| 81 | 82 | |
| 82 | 83 | /** |
| @@ -89,7 +90,15 @@ const SURFACES: Record<string, RegExp | null> = { | ||
| 89 | 90 | * `.page-dashboard` overrides -- so the naive version attributed the dashboard's |
| 90 | 91 | * indigo to the base surface and reported an accent no base page renders. |
| 91 | 92 | */ |
| 92 | function* declarationsInContext(css: string): Generator<[string, string, string]> { | |
| 93 | function* declarationsInContext(raw: string): Generator<[string, string, string]> { | |
| 94 | /* | |
| 95 | * Comments out first. The scan below treats whatever precedes a `{` as a | |
| 96 | * selector, so a comment is not inert here -- prose containing a brace, a | |
| 97 | * semicolon or the words `data-theme="dark"` lands in the selector stack and | |
| 98 | * can reclassify a whole block. Found while pointing this at the other five | |
| 99 | * apps, where sentences from comment blocks turned up as selector names. | |
| 100 | */ | |
| 101 | const css = raw.replace(/\/\*[\s\S]*?\*\//g, ' ').replace(/^[ \t]*\/\/.*$/gm, ' ') | |
| 93 | 102 | const stack: string[] = [] |
| 94 | 103 | let i = 0 |
| 95 | 104 | let pending = '' |
| @@ -28,7 +28,7 @@ const config = readFileSync(join(ROOT, 'config/crosswind.ts'), 'utf8') | ||
| 28 | 28 | |
| 29 | 29 | describe('token manifest', () => { |
| 30 | 30 | test('covers both surfaces in both modes', () => { |
| 31 | expect(Object.keys(manifest.roles).sort()).toEqual(['base', 'dashboard']) | |
| 31 | expect(Object.keys(manifest.roles).sort()).toEqual(['base', 'dashboard', 'marketing']) | |
| 32 | 32 | for (const surface of Object.keys(manifest.roles)) |
| 33 | 33 | expect(Object.keys(manifest.roles[surface]).sort(), surface).toEqual(['dark', 'light']) |
| 34 | 34 | }) |
| @@ -76,6 +76,23 @@ describe('token manifest', () => { | ||
| 76 | 76 | * value as `fg` and `bg-panel`. That is a real limit on what a shared |
| 77 | 77 | * component can express here; the list exists so a NEW collapse is visible. |
| 78 | 78 | */ |
| 79 | /* | |
| 80 | * Marketing declares its own block but overrides nothing any component role | |
| 81 | * reads, so it resolves identically to base. Asserted rather than left | |
| 82 | * implicit: if marketing ever moves off the base palette, this is where it | |
| 83 | * shows up, instead of the manifest quietly carrying a surface nobody checks. | |
| 84 | */ | |
| 85 | test('marketing resolves identically to base, and dashboard differs only in the accent', () => { | |
| 86 | for (const mode of ['light', 'dark'] as const) | |
| 87 | expect(manifest.roles.marketing[mode], mode).toEqual(manifest.roles.base[mode]) | |
| 88 | ||
| 89 | for (const mode of ['light', 'dark'] as const) { | |
| 90 | const differing = Object.keys(manifest.roles.base[mode]) | |
| 91 | .filter(role => manifest.roles.base[mode][role] !== manifest.roles.dashboard[mode][role]) | |
| 92 | expect(differing.sort(), mode).toEqual(['accent', 'accent-solid']) | |
| 93 | } | |
| 94 | }) | |
| 95 | ||
| 79 | 96 | test('the known lost distinctions are exactly these two', () => { |
| 80 | 97 | expect(manifest.lost.sort()).toEqual(['fg = fg-strong', 'panel = field']) |
| 81 | 98 | }) |