diff --git a/src/popup/App.scss b/src/popup/App.scss index 3e690c7..8b68274 100644 --- a/src/popup/App.scss +++ b/src/popup/App.scss @@ -1,262 +1,299 @@ -@import './App-color.scss'; -@import './App-scrollbar.scss'; -@import '~bootstrap/scss/bootstrap.scss'; -@import '~bootstrap-vue/src/index.scss'; -@import '~tippy.js/dist/tippy.css'; - -body { - box-sizing: content-box !important; - width: 470px; -} - -.header { - height: 45px; - width: 460px; - position: absolute; - top: 0; - left: 0; - z-index: 10; -} - -.header .back { - cursor: pointer; -} - -.overlay { - position: fixed; - top: 0; - left: 0; - z-index: 20; - height: 100vh; - width: 100vw; - min-height: 350px; - background-color: rgba(255, 255, 255, 0.8); -} - -.overlay-content { - position: fixed; - z-index: 21; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - text-align: center; -} - -.app { - width: 470px; - box-sizing: content-box !important; - overflow-y: hidden; -} - -.app .content { - box-sizing: border-box; - margin-top: 45px; - padding-top: 15px; - padding-bottom: 40px; - max-height: 500px; - overflow-y: auto; -} - -.splash .logo { - width: 200px; -} - -.splash .loading { - width: 30px; - padding-top: 20px; -} - -.splash.overlay { - background-color: white; -} - -em { - font-style: normal; - background-color: #ffff00; -} - -.small-text { - font-size: 12px; - font-weight: lighter; -} - -.tooltip-inner { - max-width: 400px; -} - -.card-rating { - border-radius: 8px; - border: 1px solid #b02a8f; -} - -/* list aliases */ -.vue-js-switch { - margin-bottom: 0; -} - -.list-item-alias .disabled { - opacity: 0.7; -} - -.list-item-email { - margin-right: 30px !important; - position: relative; - overflow: hidden; - cursor: pointer; -} - -.list-item-email > a { - white-space: nowrap; -} - -.list-item-email .email-sub { - font-size: 12px; -} - -.list-item-email-fade { - right: 0; - width: 30px; - height: 100%; - background: linear-gradient(to right, transparent, white); - top: 0; - position: absolute; -} - -.list-item-alias .alias-note-preview { - font-size: 12px; - max-height: calc(12px * 1.5 * 3); /* font-size * line-height */ - overflow-y: hidden; -} - -.header { - .actions-container { - position: absolute; - right: 0.5rem; - } - - .header-button { - height: 20px; - margin-top: 2px; - margin-left: 10px; - margin-right: 7px; - color: #b02a8f; - cursor: pointer; - } -} - -.app-header-menu { - left: auto !important; - float: right !important; - right: 10px; - margin-top: 5px !important; -} - -/* toasted: white close button */ -.toasted.toasted-primary > .action.ripple { - color: white !important; -} - -/* button img */ -.btn-svg { - cursor: pointer; - padding: 5px; - display: inline; -} - -/* send btn*/ -.btn-send { - width: 14px; - height: 14px; - color: #b02a8f; -} - -/* more options */ -.btn-delete:hover, .btn-svg:hover { - background-color: rgba(0, 0, 0, 0.1); -} - -.btn-delete { - float: right; -} - -.btn-delete > img { - vertical-align: unset; - height: 14px; -} - -.more-options { - margin-top: 10px; -} - -.cursor { - cursor: pointer; -} - -span.link { - color: #b02a8f; -} - -.more-options > .action { - margin-top: 10px; - min-height: 25px; -} - -.more-options > label { - margin-bottom: 0; - font-size: 12px; -} - -/* BETA badge */ -.beta-badge { - padding: 0.1em 0.4em; - font-size: 0.65em; - margin-left: 1em; - border: 0.7px solid #b02a8f; - display: inline-block; - color: #b02a8f; -} - -/* App Settings */ -table.settings-list > tr { - border-bottom: 1px solid #bbb; -} - -table.settings-list > tr > td { - vertical-align: top; - padding: 6px; -} - -table.settings-list { - margin-bottom: 3em; - - tr.disabled { - opacity: 0.7; - pointer-events: none; - } -} - -/* Quick fix for Firefox Overflow Menu */ -.app.ff-overflow-menu { - width: auto; - font-size: 88%; - - .content { - max-height: 500px; - overflow-y: auto; - scrollbar-width: thin; - } - - textarea, input { - font-size: 88%; - } - - .header { - width: 100%; - - .dashboard-btn { - height: 20px; - margin-top: 2px; - padding: 0 0.5rem !important; - } - } -} +@import "./App-color.scss"; +@import "./App-scrollbar.scss"; +@import "./Theme.scss"; +@import "~bootstrap/scss/bootstrap.scss"; +@import "~bootstrap-vue/src/index.scss"; +@import "~tippy.js/dist/tippy.css"; + +body { + box-sizing: content-box !important; + width: 470px; + background-color: var(--bg-color); + color: var(--text-color); +} + +input.form-control, +select.form-control, +textarea.form-control, +.dropdown-menu.show { + color: var(--text-color); + background-color: var(--input-bg-color); + border-color: var(--input-border-color); +} + +input.form-control:disabled, +select.form-control:disabled, +textarea.form-control:disabled { + color: var(--text-color); + background-color: var(--bg-color); + border-color: var(--input-border-color); +} + +input.form-control:focus, +select.form-control:focus, +textarea.form-control:focus { + color: var(--text-color); + background-color: var(--input-bg-focus); + border-color: var(--input-border-color); +} + +.v--modal-box.v--modal.vue-dialog div, +.v--modal-box.v--modal.vue-dialog button { + color: var(--text-color); + background-color: var(--input-bg-color); + border-color: var(--delimiter-color); +} + +.header { + height: 45px; + width: 460px; + position: absolute; + top: 0; + left: 0; + z-index: 10; +} + +.header .back { + cursor: pointer; +} + +.overlay { + position: fixed; + top: 0; + left: 0; + z-index: 20; + height: 100vh; + width: 100vw; + min-height: 350px; + background-color: var(--overlay-background-color); +} + +.overlay-content { + position: fixed; + z-index: 21; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + text-align: center; +} + +.app { + width: 470px; + box-sizing: content-box !important; + overflow-y: hidden; +} + +.app .content { + box-sizing: border-box; + margin-top: 45px; + padding-top: 15px; + padding-bottom: 40px; + max-height: 500px; + overflow-y: auto; +} + +.splash .logo { + width: 200px; +} + +.splash .loading { + width: 30px; + padding-top: 20px; +} + +.splash.overlay { + background-color: var(--background-color); +} + +em { + font-style: normal; + background-color: #ffff00; +} + +.small-text { + font-size: 12px; + font-weight: lighter; +} + +.tooltip-inner { + max-width: 400px; +} + +.card-rating { + border-radius: 8px; + border: 1px solid var(--brand-color); +} + +/* list aliases */ +.vue-js-switch { + margin-bottom: 0; +} + +.list-item-alias .disabled { + opacity: 0.7; +} + +.list-item-email { + margin-right: 30px !important; + position: relative; + overflow: hidden; + cursor: pointer; +} + +.list-item-email > a { + white-space: nowrap; +} + +.list-item-email .email-sub { + font-size: 12px; +} + +.list-item-email-fade { + right: 0; + width: 30px; + height: 100%; + background: linear-gradient(to right, transparent, var(--bg-color)); + top: 0; + position: absolute; +} + +.list-item-alias .alias-note-preview { + font-size: 12px; + max-height: calc(12px * 1.5 * 3); /* font-size * line-height */ + overflow-y: hidden; +} + +.header { + .actions-container { + position: absolute; + right: 0.5rem; + } + + .header-button { + height: 20px; + margin-top: 2px; + margin-left: 10px; + margin-right: 7px; + color: var(--brand-color); + cursor: pointer; + } +} + +.app-header-menu { + left: auto !important; + float: right !important; + right: 10px; + margin-top: 5px !important; +} + +/* toasted: white close button */ +.toasted.toasted-primary > .action.ripple { + color: white !important; +} + +/* button img */ +.btn-svg { + cursor: pointer; + padding: 5px; + display: inline; +} + +/* send btn*/ +.btn-send { + width: 14px; + height: 14px; + color: var(--brand-color); +} + +/* more options */ +.btn-delete:hover, +.btn-svg:hover { + background-color: var(--delete-button-hover-color); +} + +.btn-delete { + float: right; +} + +.btn-delete > img { + vertical-align: unset; + height: 14px; +} + +.more-options { + margin-top: 10px; +} + +.cursor { + cursor: pointer; +} + +span.link { + color: var(--brand-color); +} + +.more-options > .action { + margin-top: 10px; + min-height: 25px; +} + +.more-options > label { + margin-bottom: 0; + font-size: 12px; +} + +/* BETA badge */ +.beta-badge { + padding: 0.1em 0.4em; + font-size: 0.65em; + margin-left: 1em; + border: 0.7px solid var(--brand-color); + display: inline-block; + color: var(--brand-color); +} + +/* App Settings */ +table.settings-list > tr { + border-bottom: 1px solid var(--delimiter-color); +} + +table.settings-list > tr > td { + vertical-align: top; + padding: 6px; +} + +table.settings-list { + margin-bottom: 3em; + + tr.disabled { + opacity: 0.7; + pointer-events: none; + } +} + +/* Quick fix for Firefox Overflow Menu */ +.app.ff-overflow-menu { + width: auto; + font-size: 88%; + + .content { + max-height: 500px; + overflow-y: auto; + scrollbar-width: thin; + } + + textarea, + input { + font-size: 88%; + } + + .header { + width: 100%; + + .dashboard-btn { + height: 20px; + margin-top: 2px; + padding: 0 0.5rem !important; + } + } +} diff --git a/src/popup/App.vue b/src/popup/App.vue index 7716489..6fb0bf5 100644 --- a/src/popup/App.vue +++ b/src/popup/App.vue @@ -20,8 +20,10 @@ import Main from "./components/Main"; import NewAliasResult from "./components/NewAliasResult"; import ReverseAlias from "./components/ReverseAlias"; import AppSettings from "./components/AppSettings"; +import SLStorage from "./SLStorage"; import Utils from "./Utils"; import APIService from "./APIService"; +import { getSavedTheme, setThemeClass } from "./theme"; const components = { "sl-header": Header, @@ -53,6 +55,7 @@ export default { }, async mounted() { await APIService.initService(); + await setThemeClass(await getSavedTheme()); Utils.setToasted(this.$toasted); Navigation.setRouter(this.$router); Navigation.navigateTo(Navigation.PATH.ROOT); diff --git a/src/popup/SLStorage.js b/src/popup/SLStorage.js index 3161fba..e30ca82 100644 --- a/src/popup/SLStorage.js +++ b/src/popup/SLStorage.js @@ -1,5 +1,6 @@ import Utils from "./Utils"; import browser from "webextension-polyfill"; +import { THEME_SYSTEM } from "./theme"; const TEMP = {}; @@ -10,6 +11,7 @@ class SLStorage { NOT_ASKING_RATE: "notAskingRate", SHOW_SL_BUTTON: "showSLButton", SL_BUTTON_POSITION: "SLButtonPosition", + THEME: "SLTheme", EXTRA_ALLOWED_DOMAINS: [], }; @@ -21,6 +23,7 @@ class SLStorage { [SLStorage.SETTINGS.NOT_ASKING_RATE]: false, [SLStorage.SETTINGS.SHOW_SL_BUTTON]: true, [SLStorage.SETTINGS.SL_BUTTON_POSITION]: "right-inside", + [SLStorage.SETTINGS.THEME]: THEME_SYSTEM, [SLStorage.SETTINGS.EXTRA_ALLOWED_DOMAINS]: devConfig ? devConfig.EXTRA_ALLOWED_DOMAINS : [], diff --git a/src/popup/Theme.js b/src/popup/Theme.js new file mode 100644 index 0000000..f163e13 --- /dev/null +++ b/src/popup/Theme.js @@ -0,0 +1,27 @@ +import SLStorage from './SLStorage'; + +export const THEME_LIGHT = "theme-light"; +export const THEME_DARK = "theme-dark"; +export const THEME_SYSTEM = "theme-system"; + +export const THEMES = [THEME_LIGHT, THEME_DARK, THEME_SYSTEM]; + +export const THEME_LABELS = { + [THEME_LIGHT]: "Light", + [THEME_DARK]: "Dark", + [THEME_SYSTEM]: "System", +}; + +export async function getSavedTheme() { + return (await SLStorage.get(SLStorage.SETTINGS.THEME)) ?? THEME_SYSTEM; +} + +export async function setThemeClass(nextTheme, prevTheme) { + await SLStorage.set(SLStorage.SETTINGS.THEME, nextTheme); + + if (prevTheme === undefined) { + return document.body.classList.add(nextTheme); + } + + document.body.classList.replace(prevTheme, nextTheme); +} diff --git a/src/popup/Theme.scss b/src/popup/Theme.scss new file mode 100644 index 0000000..d6cad06 --- /dev/null +++ b/src/popup/Theme.scss @@ -0,0 +1,68 @@ +:root { + --brand-color: #b02a8f; + --muted-brand-color: rgba(176, 42, 143, 0.7); +} + +.theme-light { + --bg-color: white; + --input-bg-color: white; + --overlay-bg-color: rgba(255, 255, 255, 0.8); + --text-color: black; + --delimiter-color: #bbb; + --delete-button-hover-color: rgba(0, 0, 0, 0.1); +} + +.theme-dark { + --bg-color: #222; + --input-bg-color: #333; + --input-bg-focus: #444; + --input-border-color: black; + --overlay-bg-color: rgba(0, 0, 0, 0.8); + --text-color: #ddd; + --delimiter-color: #555; + --delete-button-hover-color: rgba(255, 255, 255, 0.1); + + // For switching colors of monochrome images + .invertable, .btn.dropdown-toggle { + filter: invert(0.8); + } + + .btn-primary.btn-primary-muted { + background-color: var(--muted-brand-color); + } +} + +@media (prefers-color-scheme: light) { + // copy of .theme-light + .theme-system { + --bg-color: white; + --input-bg-color: white; + --overlay-bg-color: rgba(255, 255, 255, 0.8); + --text-color: black; + --delimiter-color: #bbb; + --delete-button-hover-color: rgba(0, 0, 0, 0.1); + } +} + +@media (prefers-color-scheme: dark) { + // copy of .theme-dark + .theme-system { + --bg-color: #222; + --input-bg-color: #333; + --input-bg-focus: #444; + --input-border-color: black; + --overlay-bg-color: rgba(0, 0, 0, 0.8); + --text-color: #ddd; + --delimiter-color: #555; + --delete-button-hover-color: rgba(255, 255, 255, 0.1); + + // For switching colors of monochrome images + .invertable, .btn.dropdown-toggle { + filter: invert(0.8); + } + + .btn-primary.btn-primary-muted { + background-color: var(--muted-brand-color); + } + } +} diff --git a/src/popup/components/AppSettings.vue b/src/popup/components/AppSettings.vue index 5043b9a..858ac4d 100644 --- a/src/popup/components/AppSettings.vue +++ b/src/popup/components/AppSettings.vue @@ -53,6 +53,31 @@ + +