From 775773e90402bbe1c3b1653e0d5973b052c5db12 Mon Sep 17 00:00:00 2001 From: FredGuiou Date: Wed, 29 Jan 2025 22:17:34 +0100 Subject: [PATCH 1/2] feat: add theme selector --- i18n/english.js | 5 ++++- i18n/french.js | 5 ++++- public/components/views/settings/settings.js | 21 ++++++++++++++++---- public/main.js | 14 ++++++++++--- src/http-server/config.js | 11 ++++++---- views/index.html | 5 +++++ workspaces/vis-network/src/dataset.js | 11 ++++++++-- 7 files changed, 57 insertions(+), 15 deletions(-) diff --git a/i18n/english.js b/i18n/english.js index cbc1218e..ea72d90b 100644 --- a/i18n/english.js +++ b/i18n/english.js @@ -90,7 +90,9 @@ const ui = { dependencies: "scripts & dependencies", warnings: "threats in source code", vulnerabilities: "vulnerabilities (CVE)", - licenses: "licenses conformance (SPDX)" + licenses: "licenses conformance (SPDX)", + dark: "dark", + light: "light" }, title: { maintainers: "maintainers", @@ -170,6 +172,7 @@ const ui = { title: "General", save: "save", defaultPannel: "Default Package Menu", + themePannel: "Theme Panel", warnings: "SAST Warnings to ignore", flags: "Flags (emojis) to ignore", network: "Network", diff --git a/i18n/french.js b/i18n/french.js index ff089a63..7a94eab8 100644 --- a/i18n/french.js +++ b/i18n/french.js @@ -90,7 +90,9 @@ const ui = { dependencies: "scripts & dépendances", warnings: "menaces dans le code", vulnerabilities: "vulnérabilités", - licenses: "conformité des licences (SPDX)" + licenses: "conformité des licences (SPDX)", + dark: "sombre", + light: "clair" }, title: { maintainers: "mainteneurs", @@ -170,6 +172,7 @@ const ui = { title: "Général", save: "sauvegarder", defaultPannel: "Panneau par défaut", + themePannel: "Theme Panel", warnings: "Avertissements à ignorer", flags: "Drapeau (emojis) à ignorer", network: "Réseau", diff --git a/public/components/views/settings/settings.js b/public/components/views/settings/settings.js index 7cbec4b0..3f7ecb30 100644 --- a/public/components/views/settings/settings.js +++ b/public/components/views/settings/settings.js @@ -37,7 +37,8 @@ export class Settings { /** @type {HTMLInputElement} */ shortcutsSection: document.querySelector(".shortcuts"), /** @type {HTMLInputElement} */ - showFriendlyDependenciesCheckbox: document.querySelector("#show-friendly") + showFriendlyDependenciesCheckbox: document.querySelector("#show-friendly"), + themeSelector: document.querySelector("#theme_selector") }; this.saveButton = document.querySelector(".save"); @@ -45,8 +46,14 @@ export class Settings { this.saveButton.classList.add("disabled"); this.dom.defaultPackageMenu.addEventListener("change", () => this.enableSaveButton()); - for (const checkbox of [...this.dom.warningsCheckbox, ...this.dom.flagsCheckbox, this.dom.showFriendlyDependenciesCheckbox]) { - checkbox.addEventListener("change", () => this.enableSaveButton()); + const formFields = [ + ...this.dom.warningsCheckbox, + ...this.dom.flagsCheckbox, + this.dom.showFriendlyDependenciesCheckbox, + this.dom.themeSelector + ]; + for (const formField of formFields) { + formField.addEventListener("change", () => this.enableSaveButton()); } const self = this; @@ -170,6 +177,10 @@ export class Settings { this.flags = new Set(this.config.ignore.flags); this.config.ignore.warnings = this.warnings; this.config.ignore.flags = this.flags; + // this.config.theme = config.theme ?? window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; + if (this.config.theme === void 0) { + this.config.theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"; + } } async fetchUserConfig() { @@ -188,7 +199,8 @@ export class Settings { const newConfig = { defaultPackageMenu: this.dom.defaultPackageMenu.value || Settings.defaultMenuName, ignore: { flags: new Set(), warnings: new Set() }, - showFriendlyDependencies: this.dom.showFriendlyDependenciesCheckbox.checked + showFriendlyDependencies: this.dom.showFriendlyDependenciesCheckbox.checked, + theme: this.dom.themeSelector.value }; for (const checkbox of this.dom.warningsCheckbox) { @@ -221,6 +233,7 @@ export class Settings { updateSettings() { this.dom.defaultPackageMenu.value = this.config.defaultPackageMenu; + this.dom.themeSelector.value = this.config.theme; const warnings = new Set(this.config.ignore.warnings); const flags = new Set(this.config.ignore.flags); diff --git a/public/main.js b/public/main.js index 2f699b6e..ee6d277f 100644 --- a/public/main.js +++ b/public/main.js @@ -97,7 +97,8 @@ async function init(options = {}) { secureDataSet = new NodeSecureDataSet({ flagsToIgnore: window.settings.config.ignore.flags, - warningsToIgnore: window.settings.config.ignore.warnings + warningsToIgnore: window.settings.config.ignore.warnings, + theme: window.settings.config.theme }); await secureDataSet.init(); @@ -118,7 +119,10 @@ async function init(options = {}) { // Initialize vis Network NodeSecureNetwork.networkElementId = "dependency-graph"; - nsn = new NodeSecureNetwork(secureDataSet, { i18n: window.i18n[utils.currentLang()] }); + nsn = new NodeSecureNetwork(secureDataSet, { + i18n: window.i18n[utils.currentLang()], + theme: window.settings.config.theme + }); window.locker = new Locker(nsn); window.legend = new Legend({ show: window.settings.config.showFriendlyDependencies }); new HomeView(secureDataSet, nsn); @@ -205,14 +209,18 @@ function onSettingsSaved() { window.addEventListener("settings-saved", async(event) => { const warningsToIgnore = new Set(event.detail.ignore.warnings); const flagsToIgnore = new Set(event.detail.ignore.flags); + const theme = event.detail.theme; secureDataSet.warningsToIgnore = warningsToIgnore; secureDataSet.flagsToIgnore = flagsToIgnore; + secureDataSet.theme = theme; window.settings.config.ignore.warnings = warningsToIgnore; window.settings.config.ignore.flags = flagsToIgnore; + window.settings.config.theme = theme; await secureDataSet.init( secureDataSet.data, - secureDataSet.FLAGS + secureDataSet.FLAGS, + secureDataSet.theme ); const { nodes } = secureDataSet.build(); nsn.nodes.update(nodes.get()); diff --git a/src/http-server/config.js b/src/http-server/config.js index ae234284..23eb7252 100644 --- a/src/http-server/config.js +++ b/src/http-server/config.js @@ -23,11 +23,14 @@ export async function get() { ignore: { flags, warnings - } = {} + } = {}, + theme } = config; - logger.info(`[config|get](defaultPackageMenu: ${defaultPackageMenu}|ignore-flag: ${flags}|ignore-warnings: ${warnings})`); + logger.info( + `[config|get](defaultPackageMenu: ${defaultPackageMenu}|ignore-flag: ${flags}|ignore-warnings: ${warnings}|theme: ${theme})` + ); - return config; + return { defaultPackageMenu, ignore: { flags, warnings }, theme }; } catch (err) { logger.error(`[config|get](error: ${err.message})`); @@ -41,7 +44,7 @@ export async function get() { } export async function set(newValue) { - logger.info(`[config|set](config: ${newValue})`); + logger.info(`[config|set](config: ${JSON.stringify(newValue)})`); try { await appCache.updateConfig(newValue); diff --git a/views/index.html b/views/index.html index 8e007f52..82571d7d 100644 --- a/views/index.html +++ b/views/index.html @@ -116,6 +116,11 @@

[[=z.token('settings.general.title')]]

+ +

[[=z.token('settings.general.network')]]:

diff --git a/workspaces/vis-network/src/dataset.js b/workspaces/vis-network/src/dataset.js index 92f6eb03..5ae2f936 100644 --- a/workspaces/vis-network/src/dataset.js +++ b/workspaces/vis-network/src/dataset.js @@ -11,13 +11,19 @@ export default class NodeSecureDataSet extends EventTarget { * @param {object} [options] * @param {string[]} [options.flagsToIgnore=[]] * @param {string[]} [options.warningsToIgnore=[]] + * @param {"light"|"dark"} [options.theme] */ constructor(options = {}) { super(); - const { flagsToIgnore = [], warningsToIgnore = [] } = options; + const { + flagsToIgnore = [], + warningsToIgnore = [], + theme = "light" + } = options; this.flagsToIgnore = new Set(flagsToIgnore); this.warningsToIgnore = new Set(warningsToIgnore); + this.theme = theme; this.reset(); } @@ -138,7 +144,8 @@ export default class NodeSecureDataSet extends EventTarget { const color = utils.getNodeColor({ id, hasWarnings, - isFriendly + isFriendly, + theme: this.theme.toUpperCase() }); color.font.multi = "html"; From fd467e2ff9e18127c25fb438fcdd5960759e5164 Mon Sep 17 00:00:00 2001 From: FredGuiou Date: Thu, 27 Feb 2025 14:28:08 +0100 Subject: [PATCH 2/2] feat: start settings css --- i18n/english.js | 2 +- i18n/french.js | 2 +- public/components/gauge/gauge.css | 7 +++ public/components/navigation/navigation.css | 4 ++ public/components/package/package.css | 4 ++ public/components/popup/popup.css | 7 +++ public/components/searchbar/searchbar.css | 12 ++++ public/components/views/home/home.css | 59 +++++++++++++++++++ .../views/home/maintainers/maintainers.css | 37 ++++++++++++ .../components/views/home/report/report.css | 13 ++++ public/components/views/network/network.css | 31 +++++++--- public/components/views/search/search.css | 48 ++++++++++++++- public/components/views/settings/settings.css | 46 +++++++++++++++ public/css/animation.css | 3 + public/css/light.css | 15 +++++ public/main.js | 30 +++++++--- test/config.test.js | 24 ++++++-- test/httpServer.test.js | 13 +++- views/index.html | 15 ++--- workspaces/vis-network/src/constants.js | 16 +++-- 20 files changed, 351 insertions(+), 37 deletions(-) diff --git a/i18n/english.js b/i18n/english.js index ea72d90b..c1bb8acd 100644 --- a/i18n/english.js +++ b/i18n/english.js @@ -172,7 +172,7 @@ const ui = { title: "General", save: "save", defaultPannel: "Default Package Menu", - themePannel: "Theme Panel", + themePannel: "Interface theme", warnings: "SAST Warnings to ignore", flags: "Flags (emojis) to ignore", network: "Network", diff --git a/i18n/french.js b/i18n/french.js index 7a94eab8..39e90126 100644 --- a/i18n/french.js +++ b/i18n/french.js @@ -172,7 +172,7 @@ const ui = { title: "Général", save: "sauvegarder", defaultPannel: "Panneau par défaut", - themePannel: "Theme Panel", + themePannel: "Thème de l'interface", warnings: "Avertissements à ignorer", flags: "Drapeau (emojis) à ignorer", network: "Réseau", diff --git a/public/components/gauge/gauge.css b/public/components/gauge/gauge.css index 100d6cb2..8a169489 100644 --- a/public/components/gauge/gauge.css +++ b/public/components/gauge/gauge.css @@ -10,12 +10,19 @@ padding: 0 10px; border-radius: 4px; } +body.dark .gauge>.line { + color: white; +} .gauge>.line.clickable:hover { background: linear-gradient(to bottom, rgba(255,255,255,1) 0%,rgba(255,255,255,0) 100%); cursor: pointer; } +body.dark .gauge>.line.clickable:hover { + background: var(--dark-theme-primary-color); +} + .gauge>.line+.line { margin-top: 5px; } diff --git a/public/components/navigation/navigation.css b/public/components/navigation/navigation.css index b7213e10..e5e43ca9 100644 --- a/public/components/navigation/navigation.css +++ b/public/components/navigation/navigation.css @@ -9,6 +9,10 @@ nav#aside { z-index: 40; } +body.dark nav#aside { + background: var(--dark-theme-primary-color); +} + nav#aside>.nsecure-logo { margin-top: 20px; } diff --git a/public/components/package/package.css b/public/components/package/package.css index 91333855..9ea497fa 100644 --- a/public/components/package/package.css +++ b/public/components/package/package.css @@ -19,6 +19,10 @@ section#package-info { -webkit-transform: translateX(-100%); } +body.dark section#package-info { + background: var(--dark-theme-primary-lighter); +} + section#package-info .package-container { margin-bottom: 40px; padding: 10px; diff --git a/public/components/popup/popup.css b/public/components/popup/popup.css index 82c20598..642ed0c7 100644 --- a/public/components/popup/popup.css +++ b/public/components/popup/popup.css @@ -32,3 +32,10 @@ section#popup--background>.popup { border-left: 2px solid #ffffff; border-top: 2px solid #FFF; } + +body.dark section#popup--background>.popup { + background: #303263; + box-shadow: 5px 5px 15px var(--dark-theme-primary-color); + border-left: 2px solid var(--dark-theme-secondary-darker); + border-top: 2px solid var(--dark-theme-secondary-darker); +} diff --git a/public/components/searchbar/searchbar.css b/public/components/searchbar/searchbar.css index 37b24a56..e9070b8b 100644 --- a/public/components/searchbar/searchbar.css +++ b/public/components/searchbar/searchbar.css @@ -213,6 +213,10 @@ div.search-result-pannel .package+.package { box-shadow: 2px 1px 10px #26107f7a; } +body.dark #search-nav { + background: var(--dark-theme-primary-color); +} + #search-nav:has(#searchbar[style*="display: none;"]) { display: none; } @@ -246,6 +250,10 @@ div.search-result-pannel .package+.package { color: #def7ff; } +body.dark #search-nav .packages>.package { + background: linear-gradient(to right, rgba(11,3,31,1) 0%, rgba(11,3,31, 0.8) 50%, rgba(11, 3, 31, 0.6) 100%); +} + #search-nav .packages>.package>* { transform: skewX(20deg); } @@ -260,6 +268,10 @@ div.search-result-pannel .package+.package { cursor: pointer; } +body.dark #search-nav .packages>.package:not(.active):hover { + background: linear-gradient(to right, rgba(11, 3, 31, 0.7) 1%, rgba(11, 3, 31, 0.5) 100%); +} + #search-nav .packages>.package.active { background: linear-gradient(to right, rgba(55,34,175,1) 0%,rgba(87,74,173,1) 50%,rgb(59, 110, 205) 100%); } diff --git a/public/components/views/home/home.css b/public/components/views/home/home.css index eb242d01..765ac35d 100644 --- a/public/components/views/home/home.css +++ b/public/components/views/home/home.css @@ -101,6 +101,10 @@ border-bottom: 2px solid #cecec9; } +body.dark .home--header--title .top { + border-bottom: 2px solid var(--dark-theme-secondary-color); +} + .home--header--title .top #project-name { color: var(--primary-lighter); } @@ -112,6 +116,15 @@ margin-top: 5px; } +body.dark .home--header--title .top #project-name { + color: var(--secondary); +} + +body.dark .home--header--title .top #project-version { + color: var(--secondary); + opacity: 0.9; +} + .home--header--title .bottom { display: flex; height: 26px; @@ -125,6 +138,11 @@ font-family: system-ui; } +body.dark .home--header--title .bottom #project-description { + color: var(--secondary); + opacity: 0.9; +} + .home--header--title .bottom>ul { margin-left: auto; height: inherit; @@ -139,6 +157,10 @@ letter-spacing: 0.5px; } +body.dark .home--header--title .bottom>ul li { + color: white; +} + .home--header--title .bottom>ul li:hover { text-decoration: underline; cursor: pointer; @@ -242,6 +264,10 @@ padding: 10px; } +body.dark #home--view .home--body .module>.content>p { + color: #74ace3; +} + /** * WARNINGS BEGIN */ @@ -260,6 +286,11 @@ border-radius: 4px; } +body.dark .home--warnings>p { + background: linear-gradient(to right, rgb(11, 3, 31) 0%, rgba(46, 10, 10, 0.7) 100%); + color: rgb(253, 210, 210); +} + .home--warnings>p+p { margin-top: 5px; } @@ -293,6 +324,10 @@ color: #546884; } +body.dark .home--overview>div { + color: white; +} + .home--overview>div>.title { display: flex; font-size: 20px; @@ -312,6 +347,10 @@ margin-top: 10px; } +body.dark .home--overview>div>span { + color: var(--dark-theme-secondary-color); +} + .home--packages--overview { display: flex; flex-direction: column; @@ -337,17 +376,31 @@ transition: 0.5s linear all; } +body.dark .home--packages--overview>div { + background: linear-gradient(to right, rgb(11, 3, 31) 0%, rgba(46, 10, 10, 0.8) 100%); + color: rgb(253, 210, 210); +} + .home--packages--overview>div:hover { border-color: #da4e44; cursor: pointer; background: linear-gradient(to right, rgb(231, 206, 195) 0%, rgba(255, 255, 255, 0) 100%); } +body.dark .home--packages--overview>div:hover { + border-color: #da4e44; + background: linear-gradient(to right, rgb(11, 3, 31) 0%, rgba(46, 10, 10, 0.8) 100%); +} + .home--packages--overview>div span { color: #6d5703; margin-left: 10px; } +body.dark .home--packages--overview>div span { + color: #ac8a05; +} + .home--packages--overview>div>div.chips { margin-left: auto; display: flex; @@ -365,6 +418,12 @@ color: #611717; } +body.dark .home--packages--overview>div>div.chips>p { + background: linear-gradient(to bottom, rgb(75 22 22) 0%, rgb(26 5 5) 100%); + color: #f5c6c6; + box-shadow: 2px 2px 6px 0px #0e01019e; +} + .home--packages--overview>div>div.chips>p+p { margin-left: 10px; } diff --git a/public/components/views/home/maintainers/maintainers.css b/public/components/views/home/maintainers/maintainers.css index 53a327f1..e3fc66a8 100644 --- a/public/components/views/home/maintainers/maintainers.css +++ b/public/components/views/home/maintainers/maintainers.css @@ -21,6 +21,11 @@ flex-grow: 1; } +body.dark .home--maintainers>.person { + color: white; + background: var(--dark-theme-primary-color); +} + .home--maintainers>.person:hover { border-color: var(--secondary-darker); cursor: pointer; @@ -119,12 +124,21 @@ color: #546884; } +body.dark .maintainers--popup>.header>.informations>p.name { + color: white; +} + .maintainers--popup>.header>.informations>p.email { color: var(--secondary-darker); margin-top: 10px; font-family: monospace; } +body.dark .maintainers--popup>.header>.informations>p.email { + color: var(--dark-theme-secondary-color); + opacity: 0.9; +} + .maintainers--popup>.header>.icons { display: flex; align-items: center; @@ -162,6 +176,10 @@ flex-shrink: 0; } +body.dark .maintainers--popup>.separator { + background: var(--dark-theme-secondary-color); +} + .maintainers--popup>.separator>p { background: #f5f4f4; padding: 0 10px; @@ -171,6 +189,11 @@ color: #255471; } +.maintainers--popup>.separator>p { + background: #303263; + color: #3cbde5; +} + .maintainers--popup>ul { display: flex; flex-direction: column; @@ -196,15 +219,29 @@ font-size: 15px; } +body.dark .maintainers--popup>ul li { + background: linear-gradient(to right, var(--dark-theme-primary-color) 0%, rgba(28, 29, 58, 0.185) 100%); + border: none; + color: white; +} + .maintainers--popup>ul li>p{ color: #234c99; } +body.dark .maintainers--popup>ul li>p{ + color: #9ca6b7; +} + .maintainers--popup>ul li>span{ color: #2470b3; margin-left: 10px; } +body.dark .maintainers--popup>ul li>span{ + color: var(--dark-theme-secondary-color); +} + .maintainers--popup>ul li>i{ margin-left: auto; margin-right: 13px; diff --git a/public/components/views/home/report/report.css b/public/components/views/home/report/report.css index 39d4274f..4cbecb43 100644 --- a/public/components/views/home/report/report.css +++ b/public/components/views/home/report/report.css @@ -15,6 +15,10 @@ flex-shrink: 0; } +body.dark .report--popup>.title { + background: var(--dark-theme-secondary-color); +} + .report--popup>.title>p { background: #f5f4f4; padding: 0 10px; @@ -25,6 +29,11 @@ font-size: 20px; } +body.dark .report--popup>.title>p { + background: #303263; + color: #3cbde5; +} + .report--popup>form { display: flex; flex-direction: column; @@ -39,6 +48,10 @@ font-size: 18px; } +body.dark .report--popup>form label { + color: white; +} + .report--popup>form input { padding: 11px 6px; border: none; diff --git a/public/components/views/network/network.css b/public/components/views/network/network.css index 47301ff1..796404ee 100644 --- a/public/components/views/network/network.css +++ b/public/components/views/network/network.css @@ -7,10 +7,18 @@ box-shadow: -2px -2px 10px #6d29b5b8 inset; } +body.dark #network--view:not(.locked) { + box-shadow: -2px -2px 10px #1d0b30b8 inset; +} + #network--view.locked { box-shadow: -2px -2px 10px #b52929b8 inset; } +body.dark #network--view.locked { + box-shadow: -2px -2px 10px #2b0a0ab8 inset; +} + #network-loader { width: 100%; height: 100%; @@ -23,15 +31,20 @@ align-items: center; flex-direction: column; } - #network-loader>p { - font-size: 18px; - margin-top: 10px; - font-weight: bold; - letter-spacing: 0.5px; - font-family: "mononoki"; - color: var(--primary-darker); - text-shadow: 1px 1px 1px rgba(20, 20, 20, 0.5); - } + +#network-loader>p { + font-size: 18px; + margin-top: 10px; + font-weight: bold; + letter-spacing: 0.5px; + font-family: "mononoki"; + color: var(--primary-darker); + text-shadow: 1px 1px 1px rgba(20, 20, 20, 0.5); +} + +body.dark #network-loader>p { + color: var(--dark-theme-secondary-lighter); +} #dependency-graph { width: 100%; diff --git a/public/components/views/search/search.css b/public/components/views/search/search.css index 034aa4ff..2e860b63 100644 --- a/public/components/views/search/search.css +++ b/public/components/views/search/search.css @@ -74,10 +74,19 @@ padding-left: 5px; } +body.dark .result { + background: var(--dark-theme-primary-lighter); + color: var(--dark-theme-secondary-color); +} + .result.exact { background: #f4fff2 !important; } +body.dark .result.exact { + background: var(--dark-theme-secondary-darker) !important; +} + .result:nth-child(even) { box-shadow: 1px 1px 10px #33333314 inset; } @@ -100,6 +109,10 @@ border-bottom: 2px solid #f7f7f7; } +body.dark .result:not(:last-child) { + border-bottom: 2px solid var(--dark-theme-primary-color); +} + .result span, .result select { font-weight: bold; @@ -132,6 +145,13 @@ box-sizing: border-box; position: relative; } +body.dark .form-group { + background: var(--dark-theme-gray); + border: 1px solid var(--primary-lighter); + /* box-shadow: 2px 2px 20px var(--primary-darker); */ + box-shadow: 2px 2px 20px #5b44da6e; + +} .form-group>input, .form-group>input::placeholder, @@ -155,6 +175,10 @@ margin-top: 10px; } +body.dark .scan-info { + color: white; +} + .spinner { width: 56px; height: 56px; @@ -176,6 +200,16 @@ margin: 0 !important; } +body.dark .spinner { + border: 9px solid var(--dark-theme-accent-lighter); + border-right-color: var(--dark-theme-accent-darker); +} + +body.dark .spinner-small { + border: 4px solid var(--dark-theme-accent-lighter); + border-right-color: var(--dark-theme-accent-darker); +} + @keyframes spinner-d3wgkg { to { transform: rotate(1turn); @@ -229,10 +263,14 @@ input:-webkit-autofill { width: 100%; padding: 5px 0; margin-top: 10px; - background: #54688419; + background: #0b031f71; padding: 5px 10px; } +body.dark .description { + color: var(--dark-theme-secondary-lighter); +} + .package-cache-result button.remove { border: none; position: relative; @@ -265,11 +303,19 @@ input:-webkit-autofill { overflow: auto; } +body.dark .cache-packages, body.dark .recent-packages { + color: var(--secondary-darker); +} + .cache-packages h1, .recent-packages h1 { font-family: "mononoki"; color: #546884; } +body.dark .cache-packages h1, body.dark .recent-packages h1 { + color: white; +} + .cache-packages .package-cache-result:has(span:hover), .recent-packages .package-cache-result:has(span:hover) { color: var(--secondary-darker); background: #5468842a; diff --git a/public/components/views/settings/settings.css b/public/components/views/settings/settings.css index faec7cb8..8bccde74 100644 --- a/public/components/views/settings/settings.css +++ b/public/components/views/settings/settings.css @@ -18,6 +18,11 @@ font-family: 'mononoki'; } +body.dark #settings--view>h1, #settings--view h2 { + color: var(--dark-theme-secondary-color); + border-bottom: 2px solid var(--dark-theme-secondary-color); +} + #settings--view h2 { margin-top: 30px; } @@ -32,6 +37,10 @@ filter: invert(14%) sepia(80%) saturate(5663%) hue-rotate(252deg) brightness(69%) contrast(98%); } +body.dark #settings--view .icon-keyboard { + filter: invert(75%) sepia(81%) saturate(3055%) hue-rotate(178deg) brightness(86%) contrast(88%); +} + #settings--view>h1 i { margin-right: 5px; } @@ -57,6 +66,10 @@ letter-spacing: 0.5px; } +body.dark #settings--view>form .line p, body.dark #settings--view>form .line label { + color: var(--dark-theme-secondary-lighter); +} + #settings--view>form .line>p, #settings--view>form .line>label { margin-bottom: 6px; font-weight: bold; @@ -77,12 +90,22 @@ margin-bottom: 20px; } +body.dark #settings--view .shortcuts .note { + background: var(--dark-theme-accent-darker); + color: white; + +} + #settings--view .shortcuts label { color: #4a5e68; margin-left: 10px; font-weight: 500; } +body.dark #settings--view .shortcuts label { + color: var(--dark-theme-secondary-lighter); +} + #settings--view .shortcuts input:read-only { background: transparent; border-color: rgb(168, 168, 168); @@ -90,6 +113,11 @@ border-style: solid; } +body.dark #settings--view .shortcuts input:read-only { + border-color: var(--dark-theme-secondary-lighter); + color: var(--dark-theme-secondary-lighter); +} + #settings--view .shortcuts input { width: 36px; height: 36px; @@ -109,6 +137,10 @@ margin-left: 10px; } +body.dark #settings--view>form .line>div { + color: var(--dark-theme-secondary-lighter); +} + #settings--view>form .line select { margin-left: 10px; } @@ -167,6 +199,12 @@ select { color: #0c5a9b; } +body.dark select { + color: var(--dark-theme-secondary-lighter); + border: var(--dark-theme-secondary-darker) 1px solid; + background: var(--dark-theme-primary-darker); +} + .settings-line-title { font-size: 15px; color: #4a5e68; @@ -174,3 +212,11 @@ select { margin: 30px 0 6px; font-weight: bold; } + +body.dark .settings-line-title { + color: var(--dark-theme-secondary-color); +} + +.mt-10 { + margin-top: 10px; +} diff --git a/public/css/animation.css b/public/css/animation.css index 0ea12265..1203a550 100644 --- a/public/css/animation.css +++ b/public/css/animation.css @@ -14,6 +14,9 @@ background: var(--primary); animation-timing-function: cubic-bezier(0, 1, 1, 0); } +body.dark .lds-ellipsis div { + background: var(--dark-theme-accent-lighter); +} .lds-ellipsis div:nth-child(1) { left: 8px; animation: lds-ellipsis1 0.6s infinite; diff --git a/public/css/light.css b/public/css/light.css index ed7d98e1..66485e35 100644 --- a/public/css/light.css +++ b/public/css/light.css @@ -5,6 +5,16 @@ --primary-lighter: #5A44DA; --secondary: #00D1FF; --secondary-darker: #1976D2; + --dark-theme-primary-color: #0b031f; + --dark-theme-primary-lighter: #0d1035; + --dark-theme-primary-darker: #0c0d23; + --dark-theme-secondary-lighter: #a7ccdb; + --dark-theme-secondary-darker: #262981; + --dark-theme-secondary-color: #4f9ad1; + --dark-theme-accent-lighter: #7465c5; + --dark-theme-accent-darker: #261c66; + --dark-theme-accent-color: #8d7afc; + --dark-theme-gray: #191a38; } body { color: var(--primary-theme-color); @@ -14,3 +24,8 @@ body { background: radial-gradient(ellipse at center, rgba(255,255,255,1) 15%,rgba(208,220,221,1) 100%); filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#d0dcdd',GradientType=1 ); } + +body.dark { + color: white; + background: var(--dark-theme-gray); +} diff --git a/public/main.js b/public/main.js index ee6d277f..bc183ab8 100644 --- a/public/main.js +++ b/public/main.js @@ -32,7 +32,7 @@ document.addEventListener("DOMContentLoaded", async() => { window.wiki = new Wiki(); await init(); - onSettingsSaved(); + onSettingsSaved(window.settings.config); window.socket = new WebSocket(`ws://${window.location.hostname}:1338`); window.socket.addEventListener("message", async(event) => { @@ -205,11 +205,12 @@ async function updateShowInfoMenu(params) { return void 0; } -function onSettingsSaved() { - window.addEventListener("settings-saved", async(event) => { - const warningsToIgnore = new Set(event.detail.ignore.warnings); - const flagsToIgnore = new Set(event.detail.ignore.flags); - const theme = event.detail.theme; +function onSettingsSaved(defaultConfig = null) { + async function updateSettings(config) { + console.log("[INFO] Settings saved:", config); + const warningsToIgnore = new Set(config.ignore.warnings); + const flagsToIgnore = new Set(config.ignore.flags); + const theme = config.theme; secureDataSet.warningsToIgnore = warningsToIgnore; secureDataSet.flagsToIgnore = flagsToIgnore; secureDataSet.theme = theme; @@ -217,6 +218,13 @@ function onSettingsSaved() { window.settings.config.ignore.flags = flagsToIgnore; window.settings.config.theme = theme; + if (theme === "dark") { + document.body.classList.add("dark"); + } + else { + document.body.classList.remove("dark"); + } + await secureDataSet.init( secureDataSet.data, secureDataSet.FLAGS, @@ -233,11 +241,19 @@ function onSettingsSaved() { updateShowInfoMenu(window.networkNav.currentNodeParams); } - if (event.detail.showFriendlyDependencies) { + if (config.showFriendlyDependencies) { window.legend.show(); } else { window.legend.hide(); } + } + + if (defaultConfig) { + updateSettings(defaultConfig); + } + + window.addEventListener("settings-saved", async(event) => { + updateSettings(event.detail); }); } diff --git a/test/config.test.js b/test/config.test.js index aed1b3b3..022c7a74 100644 --- a/test/config.test.js +++ b/test/config.test.js @@ -37,17 +37,33 @@ describe("config", { concurrency: 1 }, () => { }); it("should get config from cache", async() => { - await cacache.put(CACHE_PATH, kConfigKey, JSON.stringify({ foo: "bar" })); + const expectedConfig = { + defaultPackageMenu: "foo", + ignore: { + flags: ["foo"], + warnings: ["bar"] + }, + theme: "galaxy" + }; + await cacache.put(CACHE_PATH, kConfigKey, JSON.stringify(expectedConfig)); const value = await get(); - assert.deepStrictEqual(value, { foo: "bar" }); + assert.deepStrictEqual(value, expectedConfig); }); it("should set config in cache", async() => { - await set({ foo: "baz" }); + const expectedConfig = { + defaultPackageMenu: "foz", + ignore: { + flags: ["foz"], + warnings: ["baz"] + }, + theme: "galactic" + }; + await set(expectedConfig); const value = await get(); - assert.deepStrictEqual(value, { foo: "baz" }); + assert.deepStrictEqual(value, expectedConfig); }); }); diff --git a/test/httpServer.test.js b/test/httpServer.test.js index fe5397e0..3c6ddba4 100644 --- a/test/httpServer.test.js +++ b/test/httpServer.test.js @@ -212,10 +212,19 @@ describe("httpServer", { concurrency: 1 }, () => { test("GET '/config' should return the config", async() => { const { data: actualConfig } = await get(new URL("/config", kHttpURL)); - await cacache.put(CACHE_PATH, kConfigKey, JSON.stringify({ foo: "bar" })); + const expectedConfig = { + defaultPackageMenu: "foo", + ignore: { + flags: ["foo"], + warnings: ["bar"] + }, + theme: "galaxy" + }; + + await cacache.put(CACHE_PATH, kConfigKey, JSON.stringify(expectedConfig)); const result = await get(new URL("/config", kHttpURL)); - assert.deepEqual(result.data, { foo: "bar" }); + assert.deepEqual(result.data, expectedConfig); await fetch(new URL("/config", kHttpURL), { method: "PUT", diff --git a/views/index.html b/views/index.html index 82571d7d..fa758949 100644 --- a/views/index.html +++ b/views/index.html @@ -32,15 +32,15 @@ - - - + + + - - - + + + @@ -116,7 +116,7 @@

[[=z.token('settings.general.title')]]

- +