Reputation: 31
I'd like to handle the light/dark theme, but the code does not run on browser the first time
useTask$(({ track }) => {
track(() => themeAppearance.value);
if (isBrowser) {
const savedTheme = localStorage.getItem("themeApp");
console.log("from local storage", savedTheme);
if (savedTheme) {
themeAppearance.value =
savedTheme === "dark" ? ThemeTypes.Dark : ThemeTypes.Ligth;
return;
}
}
});
only if i change the themeAppearance with the button with this function from useThemeHook
const toggleAppearance$ = $(() => {
console.log(themeAppearance.value);
if (themeAppearance.value === ThemeTypes.Dark) {
themeAppearance.value = ThemeTypes.Ligth;
backGroundPrimaryColor.value = BackdrounColor.Ligth;
backGroundSecondaryColor.value = BackdrounColor.Ligth;
textColorPrimary.value = TextColor.HardTextLigthBackground;
textColorSecondary.value = TextColor.LigthTextLigthBackground;
localStorage.setItem("themeApp", ThemeTypes.Ligth);
return;
}
if (
themeAppearance.value === ThemeTypes.Ligth &&
panelBackground === "solid"
) {
themeAppearance.value = ThemeTypes.Dark;
backGroundPrimaryColor.value = BackdrounColor.DarkPrimarySolid;
backGroundSecondaryColor.value = BackdrounColor.DarkSecondarySolid;
textColorPrimary.value = TextColor.HardTextDarkBackground;
textColorSecondary.value = TextColor.LigthTextDarkBackground;
localStorage.setItem("themeApp", ThemeTypes.Dark);
return;
}
if (
themeAppearance.value === ThemeTypes.Ligth &&
panelBackground === "translucent"
) {
themeAppearance.value = ThemeTypes.Dark;
backGroundPrimaryColor.value = BackdrounColor.DarkPrimaryTranslucent;
backGroundSecondaryColor.value = BackdrounColor.DarkSecondaryTranslucent;
textColorPrimary.value = TextColor.HardTextDarkBackground;
textColorSecondary.value = TextColor.LigthTextDarkBackground;
localStorage.setItem("themeApp", ThemeTypes.Dark);
return;
}
});
I tried using useVisibleTask$()
but it doesn't work for me because it runs after the first render so it's going to be a bad user experience its first render with default theme dark and then change to light saved theme
Upvotes: 0
Views: 355
Reputation: 11
I've been experimenting with this myself. There is a hint in the Qwik docs Cookbook section. However, it leaves something to be desired in terms of detail and flexibility.
I am using Tailwind, as in the example, but the idea should at least be a starting point for your case. In short, to avoid the flash of un-themed content, you have to add the startup code to a script
tag in the document head, in root.tsx
. To do this, you'll have to add a string representing the code with dangerouslySetInnerHTML
.
<script dangerouslySetInnerHTML={code-string-here}></script>
In the Qwik docs example, they just copy and paste all the code, unformatted, in a string. This should work, but is pretty ugly, and just feels bad.
But since Qwik uses Vite as a build tool, there is a better way!
In your case, create a file like ./utils/setInitialTheme.js
and add your code:
const savedTheme = localStorage.getItem("themeApp");
console.log("from local storage", savedTheme);
if (savedTheme) {
themeAppearance.value =
savedTheme === "dark" ? ThemeTypes.Dark : ThemeTypes.Ligth;
return;
}
However, you'd have to come up with a different strategy than using signals initially. You couldn't use themeAppearance.value
here. And you'd have to import ThemeTypes
.
Then in root.tsx
:
// ?raw imports the file as a raw string
...
import setInitialThemeAsString from "./utils/setInitialTheme.js?raw"
...
...
<head>
<meta charSet="utf-8" />
<link rel="manifest" href="/manifest.json" />
<RouterHead />
<script dangerouslySetInnerHTML={setInitialThemeAsString}></script>
</head>
...
That is all I had to do to get this working without any flash.
For the sake of completeness, I'll add for anyone coming to this problem using Tailwind: Simply use the code they have in the Tailwind docs:
if (localStorage.theme === 'dark' ||
(!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
Then you can use whatever makes sense for your app to react to users changing the theme.
=== EDIT ===
After working on my project more I did uncover an issue with the solution above using the Vite ?raw
technique. This worked fine in development, but I encountered build errors running a production build. They had something to do with Rollup and I couldn't quite figure out how to solve it. So, if you want this to work in prod, you may have to move the code out of a separate file and into a string constant in the root.tsx file. That will work as expected in prod as well.
If interested in an in-depth tutorial, and a working example, feel free to check out my personal website/blog: https://eldss.dev/blog/build-a-theme-toggle-in-qwik-pt-one/
Upvotes: 1
Reputation: 1378
Did you try enabling eagerness?
useVisibleTask$(
() => {
const savedTheme = localStorage.getItem("themeApp");
console.log("from local storage", savedTheme);
if (savedTheme) {
themeAppearance.value =
savedTheme === "dark" ? ThemeTypes.Dark : ThemeTypes.Ligth;
return;
}
},
{ strategy: 'document-ready' }
);
Upvotes: 0