From 96da1d3439de4b1055aed0aefc74f1c6b27cf82c Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Tue, 1 Apr 2025 13:07:26 +1000 Subject: [PATCH] FIX: Issues with FOUC and dark mode when switching palettes (#99) Followup 6a4b979514c19bca33ef4759adb52d990dfdc56f 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. --- .../user-color-palette-selector.gjs | 49 +++++++++---------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/javascripts/discourse/components/user-color-palette-selector.gjs b/javascripts/discourse/components/user-color-palette-selector.gjs index 82e845f..7a85774 100644 --- a/javascripts/discourse/components/user-color-palette-selector.gjs +++ b/javascripts/discourse/components/user-color-palette-selector.gjs @@ -3,6 +3,7 @@ import { tracked } from "@glimmer/tracking"; import { action } from "@ember/object"; import { service } from "@ember/service"; import { isEmpty } from "@ember/utils"; +import { Promise } from "rsvp"; import concatClass from "discourse/helpers/concat-class"; import icon from "discourse/helpers/d-icon"; import { reload } from "discourse/helpers/page-reloader"; @@ -127,7 +128,6 @@ export default class UserColorPaletteSelector extends Component { const lightPaletteId = colorPalette.id; const darkPaletteId = colorPalette.correspondingDarkModeId; - const lightTag = document.querySelector("link.light-scheme"); const darkTag = document.querySelector("link.dark-scheme"); // 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` ); - const replaceLinkTag = (oldTag, newHref, className, mode, paletteId) => { - const newTag = document.createElement("link"); - newTag.rel = "stylesheet"; - newTag.href = newHref; - newTag.className = className; - newTag.dataset.schemeId = paletteId; - newTag.media = `(prefers-color-scheme: ${mode})`; + Promise.all([ + this.#preloadAndSwapCSS(lightPaletteInfo.new_href, "light-scheme"), + this.#preloadAndSwapCSS(darkPaletteInfo.new_href, "dark-scheme"), + ]).then(() => { + this.cssLoaded = true; + }); + } + #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 = () => { - this.cssLoaded = true; + existingLink.href = newHref; + newTag.remove(); + resolve(); }; - oldTag.parentNode.replaceChild(newTag, oldTag); - }; - - replaceLinkTag( - lightTag, - lightPaletteInfo.new_href, - "light-scheme", - "light", - lightPaletteId - ); - replaceLinkTag( - darkTag, - darkPaletteInfo.new_href, - "dark-scheme", - "dark", - darkPaletteId - ); + document.head.appendChild(newTag); + }); }