From 4ed36e0d3859cc76b6d38104709696831d0c13bd Mon Sep 17 00:00:00 2001 From: Wanjohi Date: Thu, 17 Sep 2026 22:54:00 +0300 Subject: [PATCH] fix(auth): give the sign-in input a text colour, and restore the theme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The email field computed its own background one step lighter than the page and never set `color`. Form controls do not inherit it, so the text someone typed was the UA default — black, over a near-black field. There was no `color-scheme` either, so the browser rendered the control in light appearance to begin with. The theme was a second, separate loss: `issuer()` still takes one and calls `setTheme`, but nothing had passed one since `packages/auth` became a vendored fork, so every sign-in rendered as OpenAuth — its font, its periwinkle, its logo. Restored from the pre-fork config, with the logo and favicon repointed because both URLs it carried now 404 and a broken `logo` renders a broken image rather than falling back. --- apps/auth/src/index.ts | 34 ++++++++++++++++++++++++++++++++++ packages/auth/src/ui/css.ts | 23 +++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/apps/auth/src/index.ts b/apps/auth/src/index.ts index 045be5d0..881def5b 100644 --- a/apps/auth/src/index.ts +++ b/apps/auth/src/index.ts @@ -2,6 +2,7 @@ import type { Hyperdrive } from '@cloudflare/workers-types'; import { issuer } from '@nestri/auth/index'; import { CodeProvider } from '@nestri/auth/provider/code'; import { CodeUI } from '@nestri/auth/ui/code'; +import type { Theme } from '@nestri/auth/ui/theme'; import { isDomainMatch } from '@nestri/auth/util'; import { Actor } from '@nestri/core/actor'; import { PostgresCodeStore } from '@nestri/core/auth/authorization-code'; @@ -169,11 +170,44 @@ export const allowClient = async ( return isDomainMatch(redirect, host); }; +/** + * The sign-in screen's theme. + * + * Restored from the pre-fork issuer config, which carried these exact values + * before the vendored `packages/auth` replaced it and nothing set a theme at + * all — leaving every sign-in on `THEME_OPENAUTH`, which is somebody else's + * brand and, with the input bug this shipped beside, an unreadable one. + * + * `primary` is the one value worth not changing casually: it is the brand + * orange, and the button's own text colour is derived from its lightness + * rather than stated, so a lighter primary silently flips that text to black. + */ +const THEME_NESTRI: Theme = { + title: 'Nestri | Auth', + primary: '#FF4F01', + // Not the URLs the old config carried: `/logo.webp` and `/seo/favicon.ico` + // both 404 today, and `base.tsx` falls back to OpenAuth's own mark only when + // `logo` is absent — a broken URL renders a broken image instead. These two + // are what the site actually serves. + logo: 'https://nestri.io/images/android-chrome-512x512.png', + favicon: 'https://nestri.io/images/favicon.ico', + background: { + light: '#f5f5f5', + dark: '#171717' + }, + radius: 'lg', + font: { + family: 'Geist, sans-serif' + }, + css: `@import url('https://fonts.googleapis.com/css2?family=Geist:wght@100;200;300;400;500;600;700;800;900&display=swap');` +}; + export default { async fetch(request: Request, env: Env, ctx?: ExecutionContext) { Env.init(env as unknown as Record); const inner = issuer({ subjects, + theme: THEME_NESTRI, // One database behind all of it, and nothing that only exists on // one hosting provider. What is left in the generic store is the // rate-limit counters — the only records here that are allowed to diff --git a/packages/auth/src/ui/css.ts b/packages/auth/src/ui/css.ts index 4d88b83a..0c439ee0 100644 --- a/packages/auth/src/ui/css.ts +++ b/packages/auth/src/ui/css.ts @@ -1,4 +1,6 @@ export default `:root { + color-scheme: light dark; + --color-background-dark: #0e0e11; --color-background-light: #ffffff; --color-primary-dark: #6772e5; @@ -133,6 +135,11 @@ export default `:root { h ); background: var(--background); + /* Form controls do not inherit \`color\`, so without this the text someone + types is the UA default — black, over the near-black \`--background\` + computed just above. The page looked fine and the field was unreadable. */ + color: var(--color-high); + caret-color: var(--color-high); border-color: oklch( from var(--color-background) calc(clamp(0.22, l + (-0.12 * clamp(0, calc((l - 0.714) * 1000), 1) + 0.06), 0.88)) c h @@ -141,6 +148,22 @@ export default `:root { font-size: var(--font-size-sm); outline: none; + &::placeholder { + color: var(--color-high); + opacity: 0.5; + } + + /* Chrome paints its own background over autofilled fields and ignores + \`background\`. An inset shadow is the only thing it honours, and + \`-webkit-text-fill-color\` the only thing that moves the glyphs. */ + &:-webkit-autofill, + &:-webkit-autofill:hover, + &:-webkit-autofill:focus { + -webkit-text-fill-color: var(--color-high); + -webkit-box-shadow: 0 0 0 100px var(--background) inset; + caret-color: var(--color-high); + } + &:focus { border-color: oklch( from var(--color-background)