diff --git a/src/popup/index.html b/src/popup/index.html index 2c62210..34d6997 100644 --- a/src/popup/index.html +++ b/src/popup/index.html @@ -824,7 +824,7 @@

Display

+
+ + +
diff --git a/src/popup/index.js b/src/popup/index.js index f343d6f..5c98a60 100644 --- a/src/popup/index.js +++ b/src/popup/index.js @@ -6,6 +6,7 @@ const { state, saveState, loadState } = require("../shared/state"); const { refreshPrices } = require("../shared/prices"); const { refreshBalances } = require("../shared/balances"); const { $, showView } = require("./views/helpers"); +const { applyTheme } = require("./theme"); const home = require("./views/home"); const welcome = require("./views/welcome"); @@ -176,6 +177,7 @@ async function init() { } await loadState(); + applyTheme(state.theme); // Auto-default active address if ( diff --git a/src/popup/styles/main.css b/src/popup/styles/main.css index f7f86a5..37cc00b 100644 --- a/src/popup/styles/main.css +++ b/src/popup/styles/main.css @@ -15,6 +15,18 @@ --color-section: #dddddd; } +html.dark { + --color-bg: #000000; + --color-fg: #ffffff; + --color-muted: #999999; + --color-border: #ffffff; + --color-border-light: #333333; + --color-hover: #111111; + --color-well: #0a0a0a; + --color-danger-well: #1a0000; + --color-section: #222222; +} + body { width: 396px; overflow-x: hidden; diff --git a/src/popup/theme.js b/src/popup/theme.js new file mode 100644 index 0000000..0032a3c --- /dev/null +++ b/src/popup/theme.js @@ -0,0 +1,33 @@ +// Theme management: applies light/dark class to based on preference. + +let mediaQuery = null; +let mediaHandler = null; + +function applyTheme(theme) { + // Clean up previous system listener + if (mediaQuery && mediaHandler) { + mediaQuery.removeEventListener("change", mediaHandler); + mediaHandler = null; + } + + if (theme === "dark") { + document.documentElement.classList.add("dark"); + } else if (theme === "light") { + document.documentElement.classList.remove("dark"); + } else { + // system + mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); + const update = () => { + if (mediaQuery.matches) { + document.documentElement.classList.add("dark"); + } else { + document.documentElement.classList.remove("dark"); + } + }; + mediaHandler = update; + mediaQuery.addEventListener("change", update); + update(); + } +} + +module.exports = { applyTheme }; diff --git a/src/popup/views/settings.js b/src/popup/views/settings.js index ea67337..b1b91b8 100644 --- a/src/popup/views/settings.js +++ b/src/popup/views/settings.js @@ -1,4 +1,5 @@ const { $, showView, showFlash, escapeHtml } = require("./helpers"); +const { applyTheme } = require("../theme"); const { state, saveState } = require("../../shared/state"); const { ETHEREUM_MAINNET_CHAIN_ID } = require("../../shared/constants"); const { log, debugFetch } = require("../../shared/log"); @@ -214,6 +215,13 @@ function init(ctx) { await saveState(); }); + $("settings-theme").value = state.theme; + $("settings-theme").addEventListener("change", async () => { + state.theme = $("settings-theme").value; + await saveState(); + applyTheme(state.theme); + }); + $("settings-hide-low-holders").checked = state.hideLowHolderTokens; $("settings-hide-low-holders").addEventListener("change", async () => { state.hideLowHolderTokens = $("settings-hide-low-holders").checked; diff --git a/src/shared/state.js b/src/shared/state.js index a98d84c..0331439 100644 --- a/src/shared/state.js +++ b/src/shared/state.js @@ -25,6 +25,7 @@ const DEFAULT_STATE = { dustThresholdGwei: 100000, fraudContracts: [], tokenHolderCache: {}, + theme: "system", }; const state = { @@ -55,6 +56,7 @@ async function saveState() { dustThresholdGwei: state.dustThresholdGwei, fraudContracts: state.fraudContracts, tokenHolderCache: state.tokenHolderCache, + theme: state.theme, currentView: state.currentView, selectedWallet: state.selectedWallet, selectedAddress: state.selectedAddress, @@ -110,6 +112,7 @@ async function loadState() { : 100000; state.fraudContracts = saved.fraudContracts || []; state.tokenHolderCache = saved.tokenHolderCache || {}; + state.theme = saved.theme || "system"; state.currentView = saved.currentView || null; state.selectedWallet = saved.selectedWallet !== undefined ? saved.selectedWallet : null;