From 451bcab01fd591ec54b63af0fc7084dc9f37928b Mon Sep 17 00:00:00 2001 From: Kuuuube <61125188+Kuuuube@users.noreply.github.com> Date: Tue, 18 Jun 2024 20:18:43 -0400 Subject: Add auto option to body theme (#1086) * Add auto option to body theme * Fix firefox bug where themes do not set correctly in settings due to getOptions failing --- ext/css/popup-preview.css | 6 ++++-- ext/data/schemas/options-schema.json | 4 ++-- ext/js/app/frontend.js | 8 +++++--- ext/js/app/theme-controller.js | 14 ++++++++------ ext/js/display/display.js | 14 +++++++++++++- ext/js/display/query-parser.js | 3 ++- ext/js/language/text-scanner.js | 7 +++++++ ext/js/pages/action-popup-main.js | 2 +- ext/js/pages/info-main.js | 1 + ext/js/pages/quick-start-guide-main.js | 1 + ext/js/pages/settings/popup-preview-frame.js | 2 +- ext/js/pages/settings/settings-display-controller.js | 15 +++++++++------ ext/settings.html | 1 + ext/welcome.html | 1 + types/ext/display.d.ts | 2 ++ types/ext/query-parser.d.ts | 1 + types/ext/text-scanner.d.ts | 1 + 17 files changed, 60 insertions(+), 23 deletions(-) diff --git a/ext/css/popup-preview.css b/ext/css/popup-preview.css index a72edc65..48a1a091 100644 --- a/ext/css/popup-preview.css +++ b/ext/css/popup-preview.css @@ -26,6 +26,7 @@ --animation-duration: 0s; --example-text-color: #333333; + --background-color: #f8f9fa; } :root[data-loaded=true] { --animation-duration: 0.25s; @@ -33,15 +34,16 @@ :root[data-theme=dark] { --example-text-color: #d4d4d4; + --background-color: #1e1e1e; } html { transition: background-color var(--animation-duration) linear 0s, color var(--animation-duration) linear 0s; - background-color: rgba(255, 255, 255, 0); + background-color: var(--background-color); } html.dark { - background-color: #1e1e1e; + background-color: var(--background-color); } html, body { diff --git a/ext/data/schemas/options-schema.json b/ext/data/schemas/options-schema.json index f4748e69..dc230620 100644 --- a/ext/data/schemas/options-schema.json +++ b/ext/data/schemas/options-schema.json @@ -225,8 +225,8 @@ }, "popupTheme": { "type": "string", - "enum": ["light", "dark", "browser"], - "default": "browser" + "enum": ["light", "dark", "browser", "site"], + "default": "site" }, "popupOuterTheme": { "type": "string", diff --git a/ext/js/app/frontend.js b/ext/js/app/frontend.js index 71b8d6ef..8ac27979 100644 --- a/ext/js/app/frontend.js +++ b/ext/js/app/frontend.js @@ -387,14 +387,14 @@ export class Frontend { /** * @param {import('text-scanner').EventArgument<'searchSuccess'>} details */ - _onSearchSuccess({type, dictionaryEntries, sentence, inputInfo: {eventType, detail: inputInfoDetail}, textSource, optionsContext, detail}) { + _onSearchSuccess({type, dictionaryEntries, sentence, inputInfo: {eventType, detail: inputInfoDetail}, textSource, optionsContext, detail, pageTheme}) { this._stopClearSelectionDelayed(); let focus = (eventType === 'mouseMove'); if (typeof inputInfoDetail === 'object' && inputInfoDetail !== null) { const focus2 = inputInfoDetail.focus; if (typeof focus2 === 'boolean') { focus = focus2; } } - this._showContent(textSource, focus, dictionaryEntries, type, sentence, detail !== null ? detail.documentTitle : null, optionsContext); + this._showContent(textSource, focus, dictionaryEntries, type, sentence, detail !== null ? detail.documentTitle : null, optionsContext, pageTheme); } /** */ @@ -716,8 +716,9 @@ export class Frontend { * @param {?import('display').HistoryStateSentence} sentence * @param {?string} documentTitle * @param {import('settings').OptionsContext} optionsContext + * @param {'dark' | 'light'} pageTheme */ - _showContent(textSource, focus, dictionaryEntries, type, sentence, documentTitle, optionsContext) { + _showContent(textSource, focus, dictionaryEntries, type, sentence, documentTitle, optionsContext, pageTheme) { const query = textSource.text(); const {url} = optionsContext; /** @type {import('display').HistoryState} */ @@ -725,6 +726,7 @@ export class Frontend { focusEntry: 0, optionsContext, url, + pageTheme, }; if (sentence !== null) { detailsState.sentence = sentence; } if (documentTitle !== null) { detailsState.documentTitle = documentTitle; } diff --git a/ext/js/app/theme-controller.js b/ext/js/app/theme-controller.js index c12f1113..44ff723b 100644 --- a/ext/js/app/theme-controller.js +++ b/ext/js/app/theme-controller.js @@ -27,14 +27,16 @@ export class ThemeController { constructor(element) { /** @type {?HTMLElement} */ this._element = element; - /** @type {'light'|'dark'|'browser'} */ - this._theme = 'light'; /** @type {'light'|'dark'|'browser'|'site'} */ - this._outerTheme = 'light'; + this._theme = 'site'; + /** @type {'light'|'dark'|'browser'|'site'} */ + this._outerTheme = 'site'; /** @type {?('dark'|'light')} */ this._siteTheme = null; /** @type {'dark'|'light'} */ this._browserTheme = 'light'; + /** @type {boolean} */ + this.siteOverride = false; } /** @@ -55,7 +57,7 @@ export class ThemeController { /** * Gets the main theme for the content. - * @type {'light'|'dark'|'browser'} + * @type {'light'|'dark'|'browser'|'site'} */ get theme() { return this._theme; @@ -63,7 +65,7 @@ export class ThemeController { /** * Sets the main theme for the content. - * @param {'light'|'dark'|'browser'} value The theme value to assign. + * @param {'light'|'dark'|'browser'|'site'} value The theme value to assign. */ set theme(value) { this._theme = value; @@ -171,7 +173,7 @@ export class ThemeController { */ _resolveThemeValue(theme, computedSiteTheme) { switch (theme) { - case 'site': return computedSiteTheme; + case 'site': return this.siteOverride ? this._browserTheme : computedSiteTheme; case 'browser': return this._browserTheme; default: return theme; } diff --git a/ext/js/display/display.js b/ext/js/display/display.js index e9fdfd9f..386f456b 100644 --- a/ext/js/display/display.js +++ b/ext/js/display/display.js @@ -304,7 +304,6 @@ export class Display extends EventDispatcher { /** */ async prepare() { // Theme - this._themeController.siteTheme = 'light'; this._themeController.prepare(); // State setup @@ -488,6 +487,10 @@ export class Display extends EventDispatcher { this._history.pushState(state, content, url); break; } + + if (this._options) { + this._setTheme(this._options); + } } /** @@ -1149,8 +1152,16 @@ export class Display extends EventDispatcher { _setTheme(options) { const {general} = options; const {popupTheme} = general; + try { + // eslint-disable-next-line no-underscore-dangle + const pageTheme = this._history._current.state?.pageTheme; + this._themeController.siteTheme = pageTheme ?? null; + } catch (e) { + log.error(e); + } this._themeController.theme = popupTheme; this._themeController.outerTheme = general.popupOuterTheme; + this._themeController.siteOverride = this._pageType === 'search'; this._themeController.updateTheme(); this.setCustomCss(general.customPopupCss); } @@ -1933,6 +1944,7 @@ export class Display extends EventDispatcher { url, sentence: sentence !== null ? sentence : void 0, documentTitle, + pageTheme: 'light', }, content: { dictionaryEntries: dictionaryEntries !== null ? dictionaryEntries : void 0, diff --git a/ext/js/display/query-parser.js b/ext/js/display/query-parser.js index c53208ca..344383fb 100644 --- a/ext/js/display/query-parser.js +++ b/ext/js/display/query-parser.js @@ -155,7 +155,7 @@ export class QueryParser extends EventDispatcher { /** * @param {import('text-scanner').EventArgument<'searchSuccess'>} details */ - _onSearchSuccess({type, dictionaryEntries, sentence, inputInfo, textSource, optionsContext}) { + _onSearchSuccess({type, dictionaryEntries, sentence, inputInfo, textSource, optionsContext, pageTheme}) { this.trigger('searched', { textScanner: this._textScanner, type, @@ -165,6 +165,7 @@ export class QueryParser extends EventDispatcher { textSource, optionsContext, sentenceOffset: this._getSentenceOffset(textSource), + pageTheme: pageTheme, }); } diff --git a/ext/js/language/text-scanner.js b/ext/js/language/text-scanner.js index fdc33400..249a2eda 100644 --- a/ext/js/language/text-scanner.js +++ b/ext/js/language/text-scanner.js @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import {ThemeController} from '../app/theme-controller.js'; import {EventDispatcher} from '../core/event-dispatcher.js'; import {EventListenerCollection} from '../core/event-listener-collection.js'; import {log} from '../core/log.js'; @@ -478,6 +479,11 @@ export class TextScanner extends EventDispatcher { this.setCurrentTextSource(textSource); this._selectionRestoreInfo = selectionRestoreInfo; + /** @type {ThemeController} */ + this._themeController = new ThemeController(document.documentElement); + this._themeController.prepare(); + const pageTheme = this._themeController.computeSiteTheme(); + this.trigger('searchSuccess', { type, dictionaryEntries, @@ -486,6 +492,7 @@ export class TextScanner extends EventDispatcher { textSource, optionsContext, detail, + pageTheme, }); } else { this._triggerSearchEmpty(inputInfo); diff --git a/ext/js/pages/action-popup-main.js b/ext/js/pages/action-popup-main.js index ce29bcf1..4137d5c3 100644 --- a/ext/js/pages/action-popup-main.js +++ b/ext/js/pages/action-popup-main.js @@ -37,7 +37,6 @@ class DisplayController { /** */ async prepare() { - this._themeController.siteTheme = 'light'; this._themeController.prepare(); const manifest = chrome.runtime.getManifest(); @@ -209,6 +208,7 @@ class DisplayController { void this._updatePermissionsWarnings(options); this._themeController.theme = options.general.popupTheme; + this._themeController.siteOverride = true; this._themeController.updateTheme(); } diff --git a/ext/js/pages/info-main.js b/ext/js/pages/info-main.js index f431239f..079a8c3a 100644 --- a/ext/js/pages/info-main.js +++ b/ext/js/pages/info-main.js @@ -163,6 +163,7 @@ await Application.main(true, async (application) => { const primaryProfile = (profileCurrent >= 0 && profileCurrent < profiles.length) ? profiles[profileCurrent] : null; if (primaryProfile !== null) { themeController.theme = primaryProfile.options.general.popupTheme; + themeController.siteOverride = true; themeController.updateTheme(); } diff --git a/ext/js/pages/quick-start-guide-main.js b/ext/js/pages/quick-start-guide-main.js index 41644f51..6a3cd39b 100644 --- a/ext/js/pages/quick-start-guide-main.js +++ b/ext/js/pages/quick-start-guide-main.js @@ -30,6 +30,7 @@ await Application.main(true, async (application) => { const primaryProfile = (profileCurrent >= 0 && profileCurrent < profiles.length) ? profiles[profileCurrent] : null; if (primaryProfile !== null) { themeController.theme = primaryProfile.options.general.popupTheme; + themeController.siteOverride = true; themeController.updateTheme(); } }); diff --git a/ext/js/pages/settings/popup-preview-frame.js b/ext/js/pages/settings/popup-preview-frame.js index 7abcfe2a..dc00d091 100644 --- a/ext/js/pages/settings/popup-preview-frame.js +++ b/ext/js/pages/settings/popup-preview-frame.js @@ -77,7 +77,6 @@ export class PopupPreviewFrame { async prepare() { window.addEventListener('message', this._onMessage.bind(this), false); - this._themeController.siteTheme = 'light'; this._themeController.prepare(); // Setup events @@ -141,6 +140,7 @@ export class PopupPreviewFrame { options.general.popupVerticalTextPosition = 'before'; options.scanning.selectText = false; this._themeController.theme = options.general.popupTheme; + this._themeController.siteOverride = true; this._themeController.updateTheme(); return options; } diff --git a/ext/js/pages/settings/settings-display-controller.js b/ext/js/pages/settings/settings-display-controller.js index 49f7192c..e179b835 100644 --- a/ext/js/pages/settings/settings-display-controller.js +++ b/ext/js/pages/settings/settings-display-controller.js @@ -42,11 +42,12 @@ export class SettingsDisplayController { this._onMenuButtonClickBind = this._onMenuButtonClick.bind(this); /** @type {ThemeController} */ this._themeController = new ThemeController(document.documentElement); + /** @type {HTMLSelectElement | null}*/ + this._themeDropdown = document.querySelector('[data-setting="general.popupTheme"]'); } /** */ prepare() { - this._themeController.siteTheme = 'light'; this._themeController.prepare(); void this._updateTheme(); @@ -92,16 +93,18 @@ export class SettingsDisplayController { window.addEventListener('popstate', this._onPopState.bind(this), false); this._updateScrollTarget(); - const themeDropdown = document.querySelector('[data-setting="general.popupTheme"]'); - if (themeDropdown) { - themeDropdown.addEventListener('change', this._updateTheme.bind(this), false); + if (this._themeDropdown) { + this._themeDropdown.addEventListener('change', this._updateTheme.bind(this), false); } } /** */ async _updateTheme() { - const options = await this._settingsController.getOptions(); - this._themeController.theme = options.general.popupTheme; + const theme = this._themeDropdown?.value; + if (theme === 'site' || theme === 'light' || theme === 'dark' || theme === 'browser') { + this._themeController.theme = theme; + } + this._themeController.siteOverride = true; this._themeController.updateTheme(); } diff --git a/ext/settings.html b/ext/settings.html index 35545f7a..20472292 100644 --- a/ext/settings.html +++ b/ext/settings.html @@ -680,6 +680,7 @@
Body
+ diff --git a/types/ext/display.d.ts b/types/ext/display.d.ts index 7f4d8966..3aba304e 100644 --- a/types/ext/display.d.ts +++ b/types/ext/display.d.ts @@ -95,6 +95,8 @@ export type HistoryState = { url?: string; /** The originating document title of the content. */ documentTitle?: string; + /** Computed theme of the page */ + pageTheme?: 'dark' | 'light'; }; /** diff --git a/types/ext/query-parser.d.ts b/types/ext/query-parser.d.ts index b1064973..aa90e3a4 100644 --- a/types/ext/query-parser.d.ts +++ b/types/ext/query-parser.d.ts @@ -33,6 +33,7 @@ export type Events = { textSource: TextSource; optionsContext: OptionsContext; sentenceOffset: number | null; + pageTheme: 'dark' | 'light'; }; }; diff --git a/types/ext/text-scanner.d.ts b/types/ext/text-scanner.d.ts index 21ca8f24..4277d49a 100644 --- a/types/ext/text-scanner.d.ts +++ b/types/ext/text-scanner.d.ts @@ -122,6 +122,7 @@ export type Events = { textSource: TextSource.TextSource; optionsContext: Settings.OptionsContext; detail: SearchResultDetail; + pageTheme: 'dark' | 'light'; }; searchEmpty: { inputInfo: InputInfo; -- cgit v1.2.3