Fix theme switcher desync and auto-correct unreadable saved colors.
Local Build and Deploy / deploy (push) Successful in 53s
Local Build and Deploy / deploy (push) Successful in 53s
Sync dark-mode state from the DOM after mount so admin text no longer needs a double toggle, and normalize text/button colors against their surfaces on theme save. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
ed56bf0917
commit
0096c55f96
4 files changed
+91
-15
No files matched your search
@@ -174,6 +174,38 @@ describe("deriveAdminPalette", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("ensureReadableThemeColors", () => {
|
||||
it("rewrites saved text colors that fail against their surfaces", async () => {
|
||||
const { ensureReadableThemeColors } = await import("@/lib/theme-contrast");
|
||||
const fixed = ensureReadableThemeColors({
|
||||
color_background: "#0b0f19",
|
||||
color_surface: "#151b27",
|
||||
color_text: "#0b0f19",
|
||||
color_text_muted: "#111827",
|
||||
color_navbar: "#ffffff",
|
||||
color_navbar_text: "#ffffff",
|
||||
button_primary_color: "#f59e0b",
|
||||
button_text_color: "#f59e0b",
|
||||
admin_canvas: "#ffffff",
|
||||
admin_surface: "#f8fafc",
|
||||
admin_text: "#f8fafc",
|
||||
admin_text_muted: "#e2e8f0",
|
||||
});
|
||||
expect(
|
||||
contrastRatio(fixed.color_text, fixed.color_surface),
|
||||
).toBeGreaterThanOrEqual(4.5);
|
||||
expect(
|
||||
contrastRatio(fixed.color_navbar_text, fixed.color_navbar),
|
||||
).toBeGreaterThanOrEqual(4.5);
|
||||
expect(
|
||||
contrastRatio(fixed.button_text_color, fixed.button_primary_color),
|
||||
).toBeGreaterThanOrEqual(4.5);
|
||||
expect(
|
||||
contrastRatio(fixed.admin_text, fixed.admin_canvas),
|
||||
).toBeGreaterThanOrEqual(4.5);
|
||||
});
|
||||
});
|
||||
|
||||
describe("derivePublicForegrounds", () => {
|
||||
it.each(
|
||||
Object.entries(PRESETS),
|
||||
|
||||
@@ -186,6 +186,36 @@ export function readableColor(
|
||||
.sort((a, b) => b.minimum - a.minimum)[0].color;
|
||||
}
|
||||
|
||||
/** Auto-fix foreground hex keys so saved custom themes stay readable. */
|
||||
export function ensureReadableThemeColors(
|
||||
colors: Record<string, string>,
|
||||
): Record<string, string> {
|
||||
const out = { ...colors };
|
||||
const fix = (fgKey: string, bgKeys: readonly string[]) => {
|
||||
const preferred = out[fgKey];
|
||||
if (!preferred) return;
|
||||
const backgrounds = bgKeys
|
||||
.map((key) => out[key])
|
||||
.filter((value): value is string => Boolean(value));
|
||||
if (backgrounds.length === 0) return;
|
||||
out[fgKey] = readableColor(preferred, backgrounds);
|
||||
};
|
||||
|
||||
fix("color_text", ["color_surface", "color_background"]);
|
||||
fix("color_text_muted", ["color_surface", "color_background"]);
|
||||
fix("color_navbar_text", ["color_navbar"]);
|
||||
fix("button_text_color", ["button_primary_color", "color_primary"]);
|
||||
fix("button_secondary_text_color", ["button_secondary_color"]);
|
||||
fix("button_danger_text_color", ["button_danger_color"]);
|
||||
fix("button_outline_text_color", ["color_surface", "color_background"]);
|
||||
fix("link_color", ["color_surface", "color_background"]);
|
||||
fix("link_hover_color", ["color_surface", "color_background"]);
|
||||
fix("admin_text", ["admin_canvas", "admin_surface"]);
|
||||
fix("admin_text_muted", ["admin_canvas", "admin_surface"]);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
function parseHex(value: string): Rgb | null {
|
||||
const trimmed = value.trim();
|
||||
const short = /^#([0-9a-f]{3})$/i.exec(trimmed);
|
||||
|
||||
Reference in new issue
Block a user