diff --git a/scripts/build-plugins/rollup-plugin-build-themes.js b/scripts/build-plugins/rollup-plugin-build-themes.js index 01969b1a..805590f4 100644 --- a/scripts/build-plugins/rollup-plugin-build-themes.js +++ b/scripts/build-plugins/rollup-plugin-build-themes.js @@ -31,6 +31,17 @@ function appendVariablesToCSS(variables, cssSource) { return cssSource + getRootSectionWithVariables(variables); } +function addThemesToConfig(bundle, themeSummary) { + for (const [fileName, info] of Object.entries(bundle)) { + if (fileName === "assets/config.json") { + const source = new TextDecoder().decode(info.source); + const config = JSON.parse(source); + config["themes"] = themeSummary; + info.source = new TextEncoder().encode(JSON.stringify(config)); + } + } +} + function parseBundle(bundle) { const chunkMap = new Map(); const assetMap = new Map(); @@ -215,6 +226,7 @@ module.exports = function buildThemes(options) { type: "text/css", media: "(prefers-color-scheme: dark)", href: `./${darkThemeLocation}`, + class: "default-theme", } }, { @@ -224,6 +236,7 @@ module.exports = function buildThemes(options) { type: "text/css", media: "(prefers-color-scheme: light)", href: `./${lightThemeLocation}`, + class: "default-theme", } }, ]; @@ -261,6 +274,7 @@ module.exports = function buildThemes(options) { themeSummary[`${name}-${variant}`] = assetHashedFileName; }); } + addThemesToConfig(bundle, themeSummary); this.emitFile({ type: "asset", name: "theme-summary.json", diff --git a/src/domain/session/settings/SettingsViewModel.js b/src/domain/session/settings/SettingsViewModel.js index 7464a659..649983e5 100644 --- a/src/domain/session/settings/SettingsViewModel.js +++ b/src/domain/session/settings/SettingsViewModel.js @@ -127,6 +127,14 @@ export class SettingsViewModel extends ViewModel { return this._formatBytes(this._estimate?.usage); } + get themes() { + return this.platform.themes; + } + + setTheme(name) { + this.platform.setTheme(name); + } + _formatBytes(n) { if (typeof n === "number") { return Math.round(n / (1024 * 1024)).toFixed(1) + " MB"; diff --git a/src/platform/web/Platform.js b/src/platform/web/Platform.js index 7d66301d..6ed4509d 100644 --- a/src/platform/web/Platform.js +++ b/src/platform/web/Platform.js @@ -307,6 +307,33 @@ export class Platform { return DEFINE_VERSION; } + get themes() { + return Object.keys(this.config["themes"]); + } + + setTheme(themeName) { + const themeLocation = this.config["themes"][themeName]; + if (!themeLocation) { + throw new Error(`Cannot find theme location for theme "${themeName}"!`); + } + this._replaceStylesheet(themeLocation); + } + + _replaceStylesheet(newPath) { + // remove default theme + const defaultStylesheets = document.getElementsByClassName("default-theme"); + for (const tag of defaultStylesheets) { + tag.remove(); + } + // add new theme + const head = document.querySelector("head"); + const styleTag = document.createElement("link"); + styleTag.href = `./${newPath}`; + styleTag.rel = "stylesheet"; + styleTag.type = "text/css"; + head.appendChild(styleTag); + } + dispose() { this._disposables.dispose(); } diff --git a/src/platform/web/ui/session/settings/SettingsView.js b/src/platform/web/ui/session/settings/SettingsView.js index 93e44307..b2c78f58 100644 --- a/src/platform/web/ui/session/settings/SettingsView.js +++ b/src/platform/web/ui/session/settings/SettingsView.js @@ -97,6 +97,7 @@ export class SettingsView extends TemplateView { settingNodes.push( t.h3("Preferences"), row(t, vm.i18n`Scale down images when sending`, this._imageCompressionRange(t, vm)), + row(t, vm.i18n`Use the following theme`, this._themeOptions(t, vm)), ); settingNodes.push( t.h3("Application"), @@ -135,4 +136,12 @@ export class SettingsView extends TemplateView { vm.i18n`no resizing`; })]; } + + _themeOptions(t, vm) { + const optionTags = []; + for (const name of vm.themes) { + optionTags.push(t.option({value: name}, name)); + } + return t.select({onChange: (e) => vm.setTheme(e.target.value)}, optionTags); + } }