FIX: Issues with FOUC and dark mode when switching palettes (#99)

Followup 6a4b979514

In this commit I changed how we load the selected palette
stylesheet so the system specs would know when the CSS is actually
loaded, however this introduced an issue where the user would see
a FOUC when switching palettes. I also introduced a bug where
if you chose to force dark mode then switched the palette, you would
see light mode instead.

This commit fixes both issues, by swapping the CSS link with a preloaded
one then waiting for the preload before switching the href of the
existing link, and removes `mode` shenanigans causing the light mode
issue.
This commit is contained in:
Martin Brennan
2025-04-01 13:07:26 +10:00
committed by GitHub
parent 878da19552
commit 96da1d3439
@@ -3,6 +3,7 @@ import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { service } from "@ember/service"; import { service } from "@ember/service";
import { isEmpty } from "@ember/utils"; import { isEmpty } from "@ember/utils";
import { Promise } from "rsvp";
import concatClass from "discourse/helpers/concat-class"; import concatClass from "discourse/helpers/concat-class";
import icon from "discourse/helpers/d-icon"; import icon from "discourse/helpers/d-icon";
import { reload } from "discourse/helpers/page-reloader"; import { reload } from "discourse/helpers/page-reloader";
@@ -127,7 +128,6 @@ export default class UserColorPaletteSelector extends Component {
const lightPaletteId = colorPalette.id; const lightPaletteId = colorPalette.id;
const darkPaletteId = colorPalette.correspondingDarkModeId; const darkPaletteId = colorPalette.correspondingDarkModeId;
const lightTag = document.querySelector("link.light-scheme");
const darkTag = document.querySelector("link.dark-scheme"); const darkTag = document.querySelector("link.dark-scheme");
// TODO(osama) once we have built-in light/dark modes for each palette, we // TODO(osama) once we have built-in light/dark modes for each palette, we
@@ -146,35 +146,32 @@ export default class UserColorPaletteSelector extends Component {
`/color-scheme-stylesheet/${darkPaletteId}/${colorPalette.theme_id}.json` `/color-scheme-stylesheet/${darkPaletteId}/${colorPalette.theme_id}.json`
); );
const replaceLinkTag = (oldTag, newHref, className, mode, paletteId) => { Promise.all([
const newTag = document.createElement("link"); this.#preloadAndSwapCSS(lightPaletteInfo.new_href, "light-scheme"),
newTag.rel = "stylesheet"; this.#preloadAndSwapCSS(darkPaletteInfo.new_href, "dark-scheme"),
newTag.href = newHref; ]).then(() => {
newTag.className = className; this.cssLoaded = true;
newTag.dataset.schemeId = paletteId; });
newTag.media = `(prefers-color-scheme: ${mode})`; }
#preloadAndSwapCSS(newHref, existingLinkClass) {
return new Promise((resolve) => {
const existingLink = document.querySelector(
`link[rel='stylesheet'].${existingLinkClass}`
);
const newTag = document.createElement("link");
newTag.rel = "preload";
newTag.href = newHref;
newTag.as = "style";
newTag.onload = () => { newTag.onload = () => {
this.cssLoaded = true; existingLink.href = newHref;
newTag.remove();
resolve();
}; };
oldTag.parentNode.replaceChild(newTag, oldTag); document.head.appendChild(newTag);
}; });
replaceLinkTag(
lightTag,
lightPaletteInfo.new_href,
"light-scheme",
"light",
lightPaletteId
);
replaceLinkTag(
darkTag,
darkPaletteInfo.new_href,
"dark-scheme",
"dark",
darkPaletteId
);
} }
<template> <template>