mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
A reader who had never chosen a theme got dark whatever the device said: the
head's boot script was seeded with `dark`. The install's default is now
`system` (lib/appearance.ts), painted before the first frame, and the client
applies it once mounted, which is what installs the listener that follows the
device when it changes.
/zen's generations, the timeline marks and the Train/Attest/Evaluate/Release
underlines set `borderStyle` with one side's width, so the other three sides
drew at the browser's medium width: every generation was a 3px box with its
text against the edge. Each now sets `borderWidth={0}` before its side.
Gate e2e/gates/scheme.spec.ts: a first visit under a light and a dark device
paints that scheme and follows a change, and /zen's generations read
1px 0 0 0. The look gate still passes.
Claude-Session: https://claude.ai/code/session_01SCPMGSQsLNF2YtHFL4bwyp
53 lines
2.2 KiB
TypeScript
53 lines
2.2 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
|
import { serveExport } from './export'
|
|
|
|
/**
|
|
* A READER WHO HAS NEVER CHOSEN A THEME GETS THEIR DEVICE'S.
|
|
*
|
|
* The boot script paints `light`/`t_light` or `dark`/`t_dark` before the first
|
|
* frame from the stored choice, else from `prefers-color-scheme` (the install's
|
|
* default is `system`, app/layout.tsx). Read off the class gui's colours hang
|
|
* on, on a fresh profile, for both schemes, and again after the device changes
|
|
* its mind: `system` keeps following it.
|
|
*
|
|
* And /zen's generations are divided by a rule above each, not boxed: a side
|
|
* given a width beside an explicit `borderStyle` draws the other three sides at
|
|
* the browser's medium width, which is what boxed them.
|
|
*/
|
|
|
|
test.describe('scheme', () => {
|
|
let site: Awaited<ReturnType<typeof serveExport>>
|
|
test.beforeAll(async () => {
|
|
site = await serveExport()
|
|
})
|
|
test.afterAll(async () => {
|
|
await site.close()
|
|
})
|
|
|
|
for (const scheme of ['light', 'dark'] as const) {
|
|
const other = scheme === 'light' ? 'dark' : 'light'
|
|
test(`a first visit under a ${scheme} device paints ${scheme}, and follows it`, async ({ page }) => {
|
|
await page.emulateMedia({ colorScheme: scheme })
|
|
for (const path of ['/', '/zen']) {
|
|
await page.goto(`${site.url}${path}`)
|
|
await expect.poll(() => page.evaluate(() => document.documentElement.className)).toContain(`t_${scheme}`)
|
|
expect(await page.evaluate(() => getComputedStyle(document.documentElement).colorScheme)).toBe(scheme)
|
|
}
|
|
await page.emulateMedia({ colorScheme: other })
|
|
await expect.poll(() => page.evaluate(() => document.documentElement.className)).toContain(`t_${other}`)
|
|
})
|
|
}
|
|
|
|
test('/zen divides its generations with a rule, not a box', async ({ page }) => {
|
|
await page.goto(`${site.url}/zen`)
|
|
const sides = await page.locator('[data-gen]').evaluateAll((els) =>
|
|
els.map((el) => {
|
|
const c = getComputedStyle(el)
|
|
return [c.borderTopWidth, c.borderRightWidth, c.borderBottomWidth, c.borderLeftWidth].join(' ')
|
|
}),
|
|
)
|
|
expect(sides.length).toBeGreaterThan(5)
|
|
for (const s of sides) expect(s).toBe('1px 0px 0px 0px')
|
|
})
|
|
})
|