Make admin light/dark mode follow real palettes end-to-end.
Local Build and Deploy / deploy (push) Successful in 55s

Light admin derives from the public light theme; dark keeps HK overrides. Remap inputs, cards, muted text, and kill the public wallpaper on admin so fonts and boxes stay readable in both modes.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-07-15 21:37:25 +02:00
1 parent 94904f2ddb
commit 7b6c02c07d
7 files changed
+154 -19

No files matched your search

+42
View File
@@ -131,6 +131,48 @@ describe("deriveAdminPalette", () => {
expect(admin.surface).not.toBe("#00ff00");
});
it("in light mode mirrors readable public surfaces", () => {
const admin = deriveAdminPalette(
{
color_background: "#f8fafc",
color_surface: "#ffffff",
color_dropdown: "#f1f5f9",
color_text: "#0f172a",
color_text_muted: "#64748b",
color_primary: "#f59e0b",
color_navbar: "#ffffff",
color_navbar_text: "#1e293b",
},
{
canvas: "#0b0f19",
surface: "#151b27",
text: "#f8fafc",
},
"light",
);
expect(admin.canvas).toBe("#f8fafc");
expect(admin.surface).toBe("#ffffff");
expect(contrastRatio(admin.text, admin.canvas)).toBeGreaterThanOrEqual(4.5);
expect(contrastRatio(admin.sidebarText, admin.sidebar)).toBeGreaterThanOrEqual(
4.5,
);
});
it("ignores dark admin overrides while in light mode", () => {
const admin = deriveAdminPalette(
{
color_background: "#ffffff",
color_surface: "#ffffff",
color_text: "#0f172a",
color_primary: "#f59e0b",
},
{ canvas: "#0b0f19", text: "#f8fafc" },
"light",
);
expect(admin.canvas).toBe("#ffffff");
expect(admin.text.toLowerCase()).not.toBe("#f8fafc");
});
it("repairs default light text when admin canvas is forced light", () => {
const admin = deriveAdminPalette(
{ color_primary: "#f59e0b" },
+32 -3
View File
@@ -30,9 +30,31 @@ export interface AdminPalette {
export function deriveAdminPalette(
colors: PublicThemeColors,
overrides?: Partial<AdminPalette>,
mode: "light" | "dark" = "dark",
): AdminPalette {
const accent = overrides?.accent ?? colors.color_primary ?? "#f59e0b";
const defaults: AdminPalette = {
const lightDefaults: AdminPalette = {
canvas: colors.color_background ?? "#f8fafc",
surface: colors.color_surface ?? "#ffffff",
surfaceElevated: colors.color_dropdown ?? "#f1f5f9",
text: colors.color_text ?? "#0f172a",
muted: colors.color_text_muted ?? "#64748b",
border: "#e2e8f0",
accent,
accentText: accent,
accentForeground: "#ffffff",
success: colors.color_success ?? "#16a34a",
warning: colors.color_warning ?? "#eab308",
error: colors.color_error ?? "#ef4444",
info: colors.color_info ?? "#0ea5e9",
sidebar: colors.color_navbar ?? colors.color_surface ?? "#ffffff",
sidebarText: colors.color_navbar_text ?? colors.color_text ?? "#0f172a",
overlay: "rgba(15, 23, 42, 0.45)",
focusRing: accent,
};
const darkDefaults: AdminPalette = {
canvas: "#0b0f19",
surface: "#151b27",
surfaceElevated: "#1e2635",
@@ -52,11 +74,18 @@ export function deriveAdminPalette(
focusRing: accent,
};
const defaults = mode === "light" ? lightDefaults : darkDefaults;
// Staff admin_* overrides are the dark-HK palette — apply only in dark mode
// so light mode stays readable and tracks the public light theme.
const merged: AdminPalette = {
...defaults,
...overrides,
...(mode === "dark" ? overrides : {}),
accent,
overlay: overrides?.overlay ?? defaults.overlay,
overlay:
mode === "dark"
? (overrides?.overlay ?? defaults.overlay)
: defaults.overlay,
focusRing: accent,
};
+6 -1
View File
@@ -74,8 +74,13 @@ export function themePaletteCss(
palette: ThemePalette,
adminOverrides?: Partial<AdminPalette>,
): string {
const mode: "light" | "dark" = selector.includes("dark") ? "dark" : "light";
const semantic = derivePublicForegrounds(palette);
const admin = deriveAdminPalette(palette, adminOverrides);
const admin = deriveAdminPalette(
palette,
mode === "dark" ? adminOverrides : undefined,
mode,
);
const declarations = Object.entries(CSS_VARIABLES).map(
([key, cssName]) => `--${cssName}:${palette[key as keyof ThemePalette]};`,
);