ReviewOS

also looking at this

loghqorg/loghq

Promote main to production: signed-out chrome and the subscriber tables

#17
Merged glennmichael123 wants to merge main into production
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.

config/tokens.jsonmodified+44-0
Changes to config/tokens.json
@@ -87,6 +87,50 @@
8787 "warning": "#f59e0b",
8888 "info": "#b3bccb"
8989 }
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 }
90134 }
91135 },
92136 "lost": [
scripts/tokens.tsmodified+10-1
Changes to scripts/tokens.ts
@@ -77,6 +77,7 @@ const source = readFileSync(resolve(ROOT, 'config/crosswind.ts'), 'utf8')
7777const SURFACES: Record<string, RegExp | null> = {
7878 base: null,
7979 dashboard: /\.page-dashboard/,
80 marketing: /stx-layout-group/,
8081}
8182
8283/**
@@ -89,7 +90,15 @@ const SURFACES: Record<string, RegExp | null> = {
8990 * `.page-dashboard` overrides -- so the naive version attributed the dashboard's
9091 * indigo to the base surface and reported an accent no base page renders.
9192 */
92function* declarationsInContext(css: string): Generator<[string, string, string]> {
93function* 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, ' ')
93102 const stack: string[] = []
94103 let i = 0
95104 let pending = ''
tests/unit/tokens.test.tsmodified+18-1
Changes to tests/unit/tokens.test.ts
@@ -28,7 +28,7 @@ const config = readFileSync(join(ROOT, 'config/crosswind.ts'), 'utf8')
2828
2929describe('token manifest', () => {
3030 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'])
3232 for (const surface of Object.keys(manifest.roles))
3333 expect(Object.keys(manifest.roles[surface]).sort(), surface).toEqual(['dark', 'light'])
3434 })
@@ -76,6 +76,23 @@ describe('token manifest', () => {
7676 * value as `fg` and `bg-panel`. That is a real limit on what a shared
7777 * component can express here; the list exists so a NEW collapse is visible.
7878 */
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
7996 test('the known lost distinctions are exactly these two', () => {
8097 expect(manifest.lost.sort()).toEqual(['fg = fg-strong', 'panel = field'])
8198 })