diff --git a/server/server.js b/server/server.js index eeffb0635..9728c3b15 100644 --- a/server/server.js +++ b/server/server.js @@ -282,6 +282,9 @@ let needSetup = false; const statusPageRouter = require("./routers/status-page-router"); app.use(statusPageRouter); + const { injectDefaultAppearance } = require("./utils/inject-default-appearance"); + app.use(injectDefaultAppearance); + // Universal Route Handler, must be at the end of all express routes. app.get("*", async (_request, response) => { if (_request.originalUrl.startsWith("/upload/")) { diff --git a/server/utils/inject-default-appearance.js b/server/utils/inject-default-appearance.js new file mode 100644 index 000000000..fcf0847ce --- /dev/null +++ b/server/utils/inject-default-appearance.js @@ -0,0 +1,50 @@ +const { Settings } = require("../settings"); +const cheerio = require("cheerio"); +const jsesc = require("jsesc"); +const { log } = require("../../src/util"); + +const injectDefaultAppearance = (req, res, next) => { + + try { + // Intercept send() calls and inject Default Appearance + // https://stackoverflow.com/a/60817116 + const oldSend = res.send; + res.send = async (data) => { + + if (typeof data === "string") { + log.debug("inject-default-appearance", req.method + " " + req.url); + const $ = cheerio.load(data); + + const defaultAppearance = await Settings.get("defaultAppearance"); + if (defaultAppearance) { + const head = $("head"); + + const escapedJSONObject = jsesc(defaultAppearance, { isScriptContext: true }); + + const script = $(` + + `); + + head.append(script); + + data = $.root().html(); + } + } + + res.send = oldSend; // set function back to avoid 'double-send' + return res.send(data); + }; + + next(); + } catch (e) { + + next(e); + } + +}; + +module.exports = { + injectDefaultAppearance +}; diff --git a/src/components/HorizontalTabHeader.vue b/src/components/HorizontalTabHeader.vue new file mode 100644 index 000000000..3857394dc --- /dev/null +++ b/src/components/HorizontalTabHeader.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/src/components/settings/Appearance.vue b/src/components/settings/Appearance.vue index a1391d614..04411960f 100644 --- a/src/components/settings/Appearance.vue +++ b/src/components/settings/Appearance.vue @@ -1,186 +1,97 @@ diff --git a/src/mixins/theme.js b/src/mixins/theme.js index e1486d5af..a8479cfb7 100644 --- a/src/mixins/theme.js +++ b/src/mixins/theme.js @@ -13,6 +13,24 @@ export default { }, mounted() { + if (window.defaultAppearance) { + if (window.defaultAppearance.language) { + localStorage.locale = window.defaultAppearance.language; + } + + if (window.defaultAppearance.theme) { + this.userTheme = window.defaultAppearance.theme; + } + + if (window.defaultAppearance.heartbeatBarTheme) { + this.userHeartbeatBar = window.defaultAppearance.heartbeatBarTheme; + } + + if (window.defaultAppearance.styleElapsedTime) { + this.styleElapsedTime = window.defaultAppearance.styleElapsedTime; + } + } + // Default Light if (! this.userTheme) { this.userTheme = "auto"; diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index 96bb1fee1..40f5304ee 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -183,6 +183,15 @@ export default { this.settings.trustProxy = false; } + if (this.settings.defaultAppearance === undefined) { + this.settings.defaultAppearance = { + theme: null, + language: null, + heartbeatBarTheme: null, + styleElapsedTime: null, + }; + } + this.settingsLoaded = true; }); },