I have an HTML page with two CSS files, one for a light theme and one for a dark theme. When I click the respective button, the theme changes to either light.css or dark.css.
However, if I reload the site, it goes back to the light theme, even though it was set to dark, is there any possible way to make this work the way I intended.
function toggleTheme() {
// Obtains an array of all <link>
// elements.
// Select your element using indexing.
var theme = document.getElementsByTagName("link")[0];
// Change the value of href attribute
// to change the css sheet.
if (theme.getAttribute("href") == "light.css") {
theme.setAttribute("href", "dark.css");
} else {
theme.setAttribute("href", "light.css");
}
You could save theme to localstorage like this:
const theme = document.getElementsByTagName('link')[0];
const lightTheme = 'light.css';
const darkTheme = 'dark.css';
const newTheme = theme.getAttribute('href') === lightTheme ? darkTheme : lightTheme;
theme.setAttribute('href', newTheme);
// set new theme as preferred
localStorage.setItem('theme', newTheme);
And after page creation we could check existence of preferred theme:
const theme = document.getElementsByTagName('link')[0];
const themeValue = localStorage.getItem('theme');
if (themeValue) {
theme.setAttribute('href', themeValue);
}
Related
So I have the following code that manages my dark mode (please note I didn't write the original code, I'm just modifying):
if (toggleTheme) {
toggleTheme.click(function () {
darkMode();
});
};
// Theme Switcher
function darkMode() {
const logo = document.getElementById('logo'); // I Added this line
if (html.hasClass('dark-mode')) {
html.removeClass('dark-mode');
localStorage.removeItem("theme");
$(document.documentElement).removeAttr("dark");
logo.src = logo.dataset.logoLight; // I Added this line
} else {
html.addClass('dark-mode');
localStorage.setItem("theme", "dark");
$(document.documentElement).attr("dark", "");
logo.src = logo.dataset.logoDark // I Added this line
}
}
Here's the relative HTML (note, I'm building with Hugo so included is the Go Templating):
{{- $logo := (resources.Get site.Params.logo).Resize "270x webp q100" -}}
{{- $logoDark := (resources.Get "/images/logo-dark.png").Resize "270x webp q100" -}}
<img id="logo" class="logo__image" src="{{- $logo.RelPermalink -}}" data-logo-light="{{- $logo.RelPermalink -}}" data-logo-dark="{{- $logoDark.RelPermalink -}}" alt="{{ .Site.Title }}" height="{{- div $logo.Height 2 -}}" width="{{- div $logo.Width 2 -}}">
I've only added the three lines noted above to the JavaScript.
So that works exactly like I want. When someone toggles the button for dark mode and the logo flips to the darkmode version.
Great.
Except when they click to a new page, the original logo is in place.
Not sure how to store, check for, and retrieve the appropriate logo because I'm not very good with JavaScript (I just kind of hack together what I need).
How would you do this?
There are a couple ways to add the functionality that you're missing, but the most straightforward way given your current implementation is probably to use the theme value from localStorage.
Your code is already using localStorage to store the current theme. The bit you're missing is some JavaScript that checks the theme value in localStorage and then sets the logo path appropriately. You can use that stored value to determine what the theme is when any page loads by putting some JavaScript in the <head> of every page, or by adding it to the JavaScript file where your existing dark mode toggle logic is:
// Define a function that will check localStorage and set the logo path
function checkThemeAndSetLogo() {
const logo = document.getElementById('logo');
const currentTheme = localStorage.getItem("theme"); // get the theme value from localStorage
if (currentTheme === "dark") {
logo.src = logo.dataset.logoDark;
} else {
logo.src = logo.dataset.logoLight;
}
}
// Call the function so that the logo is updated appropriately
checkThemeAndSetLogo();
If you're interested in further reading and additional options for dark mode, I recommend A Complete Guide to Dark Mode on the Web.
i think you can always store a flag var that check if page was toggled to dark-mode, i show you:
// Theme Switcher
function darkMode(){
if (html.hasClass('dark-mode')){
html.removeClass('dark-mode');
localStorage.removeItem("theme");
$(document.documentElement).removeAttr("dark");
localStorage.setItem('dark_mode', 'false');
darkModeLogo();
}else{
html.addClass('dark-mode');
localStorage.setItem("theme", "dark");
$(document.documentElement).attr("dark", "");
localStorage.setItem('dark_mode', 'true');
darkModeLogo();
}
}
//runs everytime the js file is loaded
function darkModeLogo(){
const logo = document.getElementById('logo'); // I Added this line
const DARK_MODE = localStorage.getItem('dark_mode');
if(eval(DARK_MODE)){
logo.src = logo.dataset.logoLight; // I Added this line
}else{
logo.src = logo.dataset.logoDark // I Added this line
}
}
darkModeLogo();
I am trying to make the dark/light mode theme on my site store locally so that it doesnt untoggle every time a new page is opened or the site is refreshed. Where should I put the localStorage.? Or is the whole thing wrong?
const checkbox = document.getElementById('checkbox');
checkbox.addEventListener('change',()=> {
// change theme of website
document.body.classList.toggle('dark');
});
if you're using vanilla javascript i.e on you html you've loaded your script as below
<html>
...
<script src='/to/scripts.js'></script>
</body>
</html>
Then you can add two functions, one which set the them to localStorage and the other which reads it and make it accessible.
on update the update function sets the new value for the theme,
on read the read function reads the stored value even after refresh/reloads
as below
<html>
....
<script>
//for setting
const toggleTheme = () => {
if(localStorage.getItem('theme') === 'dark'){
localStorage.setItem('theme','light')
}else{
localStorage.setItem('theme','dark')
}
}
//for reading
const theme = () => localStorage.getItem('theme') || 'light'
</script>
<script src='/to/scripts.js'></script>
</body>
</html>
Edit (last answer was not solving the problem)
I think you can use DOMContentLoaded event to set the theme from localStorage, when the checkbox changes you set the selected theme on the storage. This way when the page reloads, it will look for the theme and set it, if theme is not set, it will default to light.
Here is a sample:
document.addEventListener("DOMContentLoaded", function(event) {
const theme = localStorage.getItem('theme');
if(theme === undefined) theme = 'light';
document.body.classList.add(theme);
});
const checkbox = document.getElementById('checkbox');
checkbox.addEventListener('change',(e) => {
const theme = e.target.checked ? 'dark' : 'light';
localStorage.setItem(theme);
document.body.classList.add(theme);
});
I have a report that contains a custom toggle visual. The toggle has two possible values, "OFF" (by default) or "ON"
What I would like to do is link that toggle value to a report theme change. So when the value of that toggle value changes, the report theme will update to either light or dark mode.
I'm at a stage where I can get the slicerState of the particular visual and determine it's value as being on or off. However, when trying to apply a report theme update, it appears to loop endlessly ( (see recording here))
My feeling is that it's related to the report.on('rendered'....... function but I'm looking to get a bit of help if possible. With it being a custom visual, I'm unable to listen to a buttonClick or dataSelection (as far as i'm aware), so i guess the only way I can detect that the toggle has been used is to track the slicerState function?
here's is the block of code relating to what i'm trying to do:
// Get a reference to the embedded dashboard HTML element
var $embedContainer = $("#embedContainer");
//define report embed
var report = powerbi.embed($embedContainer.get(0), config);
//when report renders
report.on('rendered', async () => {
//get all pages
const pages = await report.getPages()
//get active page
let activePage = pages.filter(function(page) {
return page.isActive
})[0];
//get visuals on active page
let visuals = await activePage.getVisuals();
//find target visual
const TargetVisual = visuals.filter(function(visual) {
return visual.name === "259fea6751434e7910b4"
})[0];
//get current state of visual
const state = await TargetVisual.getSlicerState();
//get current state value (on or off )
let filteredValue = state.filters[0].values
console.log(filteredValue)
//when the toggle is switched ON, apply the light theme.
if (filteredValue == "ON") {
/*
//when clickon on
report.applyTheme({
themeJson: themes.find(theme => theme.name === "dark")
}); } else {
//when the toggle is switched OFF, apply the dark theme.
//when clickon off
report.applyTheme({
themeJson: themes.find(theme => theme.name === "light")
});
*/
}
........
var themes = [
{
"name": "light",
"dataColors": ["#93A299", "#CF543F", "#B5AE53", "#848058", "#E8B54D", "#786C71", "#93A2A0", "#CF9A3F", "#8CB553", "#728458", "#D0E84D", "#786D6C"],
"background": "#FFFFFF",
"foreground": "#CF543F",
"tableAccent": "#93A299"
},
{
"name": "dark",
"dataColors": ["#31B6FD", "#4584D3", "#5BD078", "#A5D028", "#F5C040", "#05E0DB", "#3153FD", "#4C45D3", "#5BD0B0", "#54D028", "#D0F540", "#057BE0"],
"background": "#000000",
"foreground": "#4584D3",
"tableAccent": "#31B6FD"
}
]
It is not possible to track the slicer state which is applied at the runtime in Power BI embed. getSlicerState will give you an empty array of filters if you change the state of slicer at runtime. If you set the slicer state at compile time using setSlicerState then getslicerState will give you an array of filters and using that you can apply the theme.
if (state.filters.length > 0) {
report.applyTheme({
themeJson: themes.find(theme => theme.name === "dark")
});
Please find the references:
https://community.powerbi.com/t5/Developer/Power-BI-Embedded-Tracking-visual-filters-slicers/m-p/802196
https://learn.microsoft.com/javascript/api/overview/powerbi/control-report-slicers
I am currently working on adding a dark theme toggle to my website and can't seem to figure out the best way to store the data to LocalStorage. All I am using is a button that toggles the class of "dark" on the main document :root. The actual toggle works perfectly fine, I am only struggling with getting that selected option to stay in LocalStorage.
Here is my code with the LocalStorage that I am trying to add (which does save the key of theme to LocalStorage but not the actual class toggle).
document.addEventListener("DOMContentLoaded", function () {
const theme = localStorage.getItem("theme", "dark");
const darkModeToggle = document.getElementById("modeSwitch");
darkModeToggle.addEventListener("click", function () {
document.documentElement.classList.toggle("dark");
if (document.documentElement.classList.contains("dark")) {
localStorage.setItem("theme", "dark");
}
});
});
Here are my CSS variables as well for reference.
:root {
--main-background: #f8fafb;
--app-background: #ffffff;
--app-background-alt: #fcfcfc;
--app-background-hover: #f8fafb;
--dark-background: #141923;
--main-color: #000000;
--secondary-color: #747987;
}
.dark:root {
--main-background: #141923;
--app-background: #171b2c;
--app-background-alt: #1c2031;
--app-background-hover: #1d213d;
--dark-background: #141923;
--main-color: #ffffff;
--secondary-color: #747987;
}
Thank you so much.
Remove second parameter, should be like that:
const theme = localStorage.getItem("theme");
When you get item from LocalStorage need just key
the way you are storing the theme in the localStore is fine, if want to do it in other way, you could store the theme in an object. Here and example:
localStorage.setItem("theme",JSON.stringify({theme: "dark"}));
To be honest, i think that if your application is not too big you can leave it the way is it.
After playing around a bit, I did figure out a way to successfully store the theme into localStorage. What I am doing is checking to see if the toggle was clicked and "dark" was added to the class list. If it was, I store that in localStorage as "theme", "dark" - and if it "dark" was not added to the class list, I store it in localStorage as "theme", "light".
Then, at the top of the function I check to see if the theme contains "dark" - If the theme contains "dark", I add the class "dark" to the :root, and if it does not I remove it.
I am not sure if this is considered the "correct" way, but it does work!
document.addEventListener("DOMContentLoaded", function () {
const theme = localStorage.getItem("theme", "dark");
const darkModeToggle = document.getElementById("modeSwitch");
if (theme === "dark") {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
darkModeToggle.addEventListener("click", function () {
document.documentElement.classList.toggle("dark");
if (document.documentElement.classList.contains("dark")) {
localStorage.setItem("theme", "dark");
} else {
localStorage.setItem("theme", "light");
}
});
});
Currently im working in an app that includes a dark theme, but how it should be, should I toggle the class (the one with dark color) or only change the value of a CSS property?
In other project I used a JS function to toggle some css classes, but the css code grew up much, this time I coded in the other way:
const rootElement = document.getElementById('root');
let theme = "dark";
const callbackThemeF = function () {
if(theme === "dark"){
rootElement.style.setProperty('--elements-background-color', "blue");
theme = "light";
}
else if (theme === "light"){
rootElement.style.setProperty('--elements-background-color', "BLACK");
theme = "dark";
}
}
the CSS var '--elements-background-color' is used in some components, when the function is triggered it works properly but it's correct to do it this way?
I'm working with ReactJS