Pop-up dictionary browser extension for language learning. Successor to Yomichan. (PERSONAL FORK)

Add full dark mode support (#1079)

* Add full dark mode support

* Fix welcome, permissions, and quick start scrollbars

* Fix action popup dark mode on mobile

* Add theme to info page

* Reduce flashbang

* Move position of settingsDisplayController to not break things

* Fix dictionary import drag drop theming

* Make dark shadow color less bad

* Prepare themeController to avoid not being able to set browser theme

authored by

Kuuuube and committed by
GitHub
ebd91120 129be78c

+197 -65
+44 -19
ext/css/action-popup.css
··· 27 27 28 28 --warning-color: #96751c; 29 29 --warning-color-light: #edc75e; 30 + 31 + --nav-button-background-image: linear-gradient(#f8f8f8, #e0e0e0); 32 + --nav-button-border-color: #cccccc; 33 + --nav-button-background-image-focus: linear-gradient(#e8e8e8, #d0d0d0); 34 + --nav-button-border-color-focus: #aaaaaa; 35 + --nav-button-background-image-active-focus: linear-gradient(#c8c8c8, #e0e0e0); 36 + --nav-button-border-color-active-focus: #808080; 37 + --nav-button-icon-bg: #333333; 38 + --background-color: #f8f9fa; 39 + --text-color: #333333; 40 + --svg-filter: 0; 41 + } 42 + 43 + :root[data-theme=dark] { 44 + --nav-button-background-image: linear-gradient(#464646, #444444); 45 + --nav-button-border-color: #333333; 46 + --nav-button-background-image-focus: linear-gradient(#171717, #2f2f2f); 47 + --nav-button-border-color-focus: #555555; 48 + --nav-button-background-image-active-focus: linear-gradient(#373737, #1f1f1f); 49 + --nav-button-border-color-active-focus: #7f7f7f; 50 + --nav-button-icon-bg: #fbfbfb; 51 + --background-color: #1e1e1e; 52 + --text-color: #cccccc; 53 + --svg-filter: invert(100%); 30 54 } 31 55 32 56 body { ··· 36 60 font-size: var(--font-size); 37 61 width: max-content; 38 62 height: max-content; 63 + background-color: var(--background-color); 39 64 } 40 65 41 66 h3 { ··· 44 69 font-weight: 500; 45 70 line-height: 1.1; 46 71 font-size: 24px; 47 - color: inherit; 72 + color: var(--text-color); 48 73 } 49 74 label { 50 75 font-weight: normal; ··· 98 123 margin: 0 -10px; 99 124 padding: 0.5em 10px; 100 125 cursor: pointer; 101 - color: #333; 126 + color: var(--text-color); 102 127 text-decoration: none; 103 128 background-color: transparent; 104 129 transition: background-color 0.125s linear 0s; ··· 109 134 } 110 135 .link-group:hover, 111 136 .link-group:active { 112 - color: #333; 137 + color: var(--text-color); 113 138 text-decoration: none; 114 139 } 115 140 .link-group:hover>.link-group-label, ··· 136 161 margin: 0; 137 162 padding: 0; 138 163 } 139 - .link-group-icon[data-icon=chevron] { background-image: url(/images/right-chevron.svg); } 140 - .link-group-icon[data-icon=cog] { background-image: url(/images/cog.svg); } 141 - .link-group-icon[data-icon=key] { background-image: url(/images/key.svg); } 142 - .link-group-icon[data-icon=magnifying-glass] { background-image: url(/images/magnifying-glass.svg); } 143 - .link-group-icon[data-icon=question-mark-circle] { background-image: url(/images/question-mark-circle.svg); } 164 + .link-group-icon[data-icon=chevron] { background-image: url(/images/right-chevron.svg); filter: var(--svg-filter); } 165 + .link-group-icon[data-icon=cog] { background-image: url(/images/cog.svg); filter: var(--svg-filter); } 166 + .link-group-icon[data-icon=key] { background-image: url(/images/key.svg); filter: var(--svg-filter); } 167 + .link-group-icon[data-icon=magnifying-glass] { background-image: url(/images/magnifying-glass.svg); filter: var(--svg-filter); } 168 + .link-group-icon[data-icon=question-mark-circle] { background-image: url(/images/question-mark-circle.svg); filter: var(--svg-filter); } 144 169 145 170 .link-group-label { 146 171 vertical-align: middle; ··· 304 329 white-space: nowrap; 305 330 } 306 331 .nav-button { 307 - background-image: linear-gradient(#f8f8f8, #e0e0e0); 308 - border: 1px solid #cccccc; 332 + background-image: var(--nav-button-background-image); 333 + border: 1px solid var(--nav-button-border-color); 309 334 margin: 0; 310 335 padding: 2px 3px; 311 336 cursor: pointer; ··· 317 342 .nav-button:hover, 318 343 .nav-button:focus { 319 344 z-index: 1; 320 - border-color: #aaaaaa; 321 - background-image: linear-gradient(#e8e8e8, #d0d0d0); 345 + border-color: var(--nav-button-border-color-focus); 346 + background-image: var(--nav-button-background-image-focus); 322 347 box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.15); 323 348 outline: none; 324 349 } 325 350 .nav-button:focus:not(:focus-visible) { 326 - background-image: linear-gradient(#f8f8f8, #e0e0e0); 327 - border-color: #cccccc; 351 + background-image: var(--nav-button-background-image); 352 + border-color: var(--nav-button-border-color); 328 353 box-shadow: none; 329 354 } 330 355 .nav-button:focus-visible { 331 356 z-index: 1; 332 - border-color: #aaaaaa; 333 - background-image: linear-gradient(#e8e8e8, #d0d0d0); 357 + border-color: var(--nav-button-border-color-focus); 358 + background-image: var(--nav-button-background-image-focus); 334 359 box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.15); 335 360 } 336 361 .nav-button:active, 337 362 .nav-button:active:focus { 338 363 z-index: 1; 339 - border-color: #808080; 340 - background-image: linear-gradient(#c8c8c8, #e0e0e0); 364 + border-color: var(--nav-button-border-color-active-focus); 365 + background-image: var(--nav-button-background-image-active-focus); 341 366 box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.15); 342 367 } 343 368 .nav-button>.icon { ··· 346 371 width: 16px; 347 372 height: 16px; 348 373 box-sizing: content-box; 349 - background-color: #333333; 374 + background-color: var(--nav-button-icon-bg); 350 375 } 351 376 .nav-button:first-child, 352 377 .nav-button:first-child[hidden]+.nav-button {
+1 -1
ext/css/material.css
··· 136 136 --background-color-light: #0a0a0a; 137 137 --background-color-dark1: #333333; 138 138 139 - --shadow-color: rgba(255, 255, 255, 0.185); 139 + --shadow-color: rgba(105, 105, 105, 0.185); 140 140 --shadow-color-off: rgba(255, 255, 255, 0); 141 141 --shadow-color-light: rgba(255, 255, 255, 0.085); 142 142
+8 -3
ext/css/popup-preview.css
··· 24 24 --line-height: calc(var(--line-height-no-units) / var(--font-size-no-units)); 25 25 26 26 --animation-duration: 0s; 27 + 28 + --example-text-color: #333333; 27 29 } 28 30 :root[data-loaded=true] { 29 31 --animation-duration: 0.25s; 30 32 } 31 33 34 + :root[data-theme=dark] { 35 + --example-text-color: #d4d4d4; 36 + } 37 + 38 + 32 39 html { 33 40 transition: background-color var(--animation-duration) linear 0s, color var(--animation-duration) linear 0s; 34 41 background-color: rgba(255, 255, 255, 0); 35 - color: #333333; 36 42 } 37 43 html.dark { 38 - color: #d4d4d4; 39 44 background-color: #1e1e1e; 40 45 } 41 46 html, ··· 92 97 margin: 0; 93 98 padding: 0; 94 99 outline: none; 95 - color: inherit; 100 + color: var(--example-text-color); 96 101 background-color: transparent; 97 102 white-space: pre; 98 103 transition: background-color var(--animation-duration) linear 0s, border-color var(--animation-duration) linear 0s;
+44 -3
ext/css/settings.css
··· 76 76 --modal-padding-vertical: 0.625em; 77 77 --modal-padding-vertical-half: calc(var(--modal-padding-vertical) * 0.5); 78 78 --modal-button-spacing: 0.625em; 79 + 80 + --scrollbar-thumb-color: #c1c1c1; 81 + --scrollbar-track-color: #f1f1f1; 82 + --scrollbar-inverse-thumb-color: #444444; 83 + --scrollbar-inverse-track-color: #2f2f2f; 84 + 85 + --dictionary-import-border-color: #cccccc; 86 + --dictionary-import-border-color-hover: #bfd1ff; 87 + --dictionary-import-hover-background-color: rgba(28, 116, 233, 0.05); 79 88 } 80 89 :root:not([data-loaded=true]) { 81 90 --animation-duration: 0s; ··· 83 92 :root[data-theme=dark] { 84 93 --separator-color1: #333333; 85 94 --separator-color2: #222222; 95 + 96 + --scrollbar-thumb-color: #444444; 97 + --scrollbar-track-color: #2f2f2f; 98 + --scrollbar-inverse-thumb-color: #c1c1c1; 99 + --scrollbar-inverse-track-color: #f1f1f1; 100 + 101 + --dictionary-import-border-color: #333333; 102 + --dictionary-import-border-color-hover: #1c74e9; 103 + --dictionary-import-hover-background-color: rgba(191, 209, 255, 0.05); 104 + } 105 + 106 + /* Scrollbars */ 107 + :root:not([data-theme=light]) .scrollbar { 108 + scrollbar-color: var(--scrollbar-thumb-color) var(--scrollbar-track-color); 109 + } 110 + :root:not([data-theme=light]) .scrollbar::-webkit-scrollbar { 111 + width: auto; 112 + } 113 + :root:not([data-theme=light]) .scrollbar::-webkit-scrollbar-button { 114 + height: 0; 115 + } 116 + :root:not([data-theme=light]) .scrollbar::-webkit-scrollbar-thumb { 117 + background-color: var(--scrollbar-thumb-color); 118 + } 119 + :root:not([data-theme=light]) .scrollbar::-webkit-scrollbar-track { 120 + background-color: var(--scrollbar-thumb-color); 121 + } 122 + :root:not([data-theme=light]) .scrollbar::-webkit-scrollbar-track-piece { 123 + background-color: var(--scrollbar-track-color); 124 + } 125 + :root:not([data-theme=light]) .scrollbar::-webkit-scrollbar-corner { 126 + background-color: var(--scrollbar-track-color); 86 127 } 87 128 88 129 ··· 2377 2418 2378 2419 #dictionary-drop-file-zone { 2379 2420 transition: background-color var(--animation-duration) ease-in-out, border var(--animation-duration) ease-in-out; 2380 - border: 2px dashed rgb(204, 204, 204); 2421 + border: 2px dashed var(--dictionary-import-border-color); 2381 2422 border-radius: 5px; 2382 2423 flex: auto; 2383 2424 min-height: 20em; ··· 2390 2431 } 2391 2432 2392 2433 #dictionary-drop-file-zone:hover { 2393 - background-color: rgba(28, 116, 233, 0.05); 2434 + background-color: var(--dictionary-import-hover-background-color); 2394 2435 border: 2px dashed var(--accent-color); 2395 2436 } 2396 2437 2397 2438 #dictionary-drop-file-zone.drag-over { 2398 2439 border: 2px solid var(--accent-color); 2399 - background-color: rgb(191, 209, 255); 2440 + background-color: var(--dictionary-import-border-color-hover); 2400 2441 } 2401 2442 2402 2443 #dictionary-drag-drop-text {
+9
ext/js/pages/action-popup-main.js
··· 16 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 17 */ 18 18 19 + import {ThemeController} from '../app/theme-controller.js'; 19 20 import {Application} from '../application.js'; 20 21 import {getAllPermissions, hasRequiredPermissionsForOptions} from '../data/permissions-util.js'; 21 22 import {querySelectorNotNull} from '../dom/query-selector.js'; ··· 30 31 this._api = api; 31 32 /** @type {?import('settings').Options} */ 32 33 this._optionsFull = null; 34 + /** @type {ThemeController} */ 35 + this._themeController = new ThemeController(document.documentElement); 33 36 } 34 37 35 38 /** */ 36 39 async prepare() { 40 + this._themeController.siteTheme = 'light'; 41 + this._themeController.prepare(); 42 + 37 43 const manifest = chrome.runtime.getManifest(); 38 44 39 45 this._showExtensionInfo(manifest); ··· 201 207 } 202 208 void this._updateDictionariesEnabledWarnings(options); 203 209 void this._updatePermissionsWarnings(options); 210 + 211 + this._themeController.theme = options.general.popupTheme; 212 + this._themeController.updateTheme(); 204 213 } 205 214 206 215 /** */
+12
ext/js/pages/info-main.js
··· 16 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 17 */ 18 18 19 + import {ThemeController} from '../app/theme-controller.js'; 19 20 import {Application} from '../application.js'; 20 21 import {promiseTimeout} from '../core/utilities.js'; 21 22 import {DocumentFocusController} from '../dom/document-focus-controller.js'; ··· 153 154 154 155 const settingsController = new SettingsController(application); 155 156 await settingsController.prepare(); 157 + 158 + /** @type {ThemeController} */ 159 + const themeController = new ThemeController(document.documentElement); 160 + themeController.prepare(); 161 + const optionsFull = await application.api.optionsGetFull(); 162 + const {profiles, profileCurrent} = optionsFull; 163 + const primaryProfile = (profileCurrent >= 0 && profileCurrent < profiles.length) ? profiles[profileCurrent] : null; 164 + if (primaryProfile !== null) { 165 + themeController.theme = primaryProfile.options.general.popupTheme; 166 + themeController.updateTheme(); 167 + } 156 168 157 169 const backupController = new BackupController(settingsController, null); 158 170 await backupController.prepare();
+3 -3
ext/js/pages/permissions-main.js
··· 130 130 const persistentStorageController = new PersistentStorageController(application); 131 131 void persistentStorageController.prepare(); 132 132 133 + const settingsDisplayController = new SettingsDisplayController(settingsController, modalController); 134 + settingsDisplayController.prepare(); 135 + 133 136 await promiseTimeout(100); 134 137 135 138 document.documentElement.dataset.loaded = 'true'; 136 - 137 - const settingsDisplayController = new SettingsDisplayController(settingsController, modalController); 138 - settingsDisplayController.prepare(); 139 139 });
+35
ext/js/pages/quick-start-guide-main.js
··· 1 + /* 2 + * Copyright (C) 2024 Yomitan Authors 3 + * 4 + * This program is free software: you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License as published by 6 + * the Free Software Foundation, either version 3 of the License, or 7 + * (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 + */ 17 + 18 + import {ThemeController} from '../app/theme-controller.js'; 19 + import {Application} from '../application.js'; 20 + import {SettingsController} from './settings/settings-controller.js'; 21 + 22 + await Application.main(true, async (application) => { 23 + const settingsController = new SettingsController(application); 24 + await settingsController.prepare(); 25 + /** @type {ThemeController} */ 26 + const themeController = new ThemeController(document.documentElement); 27 + themeController.prepare(); 28 + const optionsFull = await application.api.optionsGetFull(); 29 + const {profiles, profileCurrent} = optionsFull; 30 + const primaryProfile = (profileCurrent >= 0 && profileCurrent < profiles.length) ? profiles[profileCurrent] : null; 31 + if (primaryProfile !== null) { 32 + themeController.theme = primaryProfile.options.general.popupTheme; 33 + themeController.updateTheme(); 34 + } 35 + });
+8 -20
ext/js/pages/settings/popup-preview-frame.js
··· 18 18 19 19 import * as wanakana from '../../../lib/wanakana.js'; 20 20 import {Frontend} from '../../app/frontend.js'; 21 + import {ThemeController} from '../../app/theme-controller.js'; 21 22 import {createApiMap, invokeApiMapHandler} from '../../core/api-map.js'; 22 23 import {querySelectorNotNull} from '../../dom/query-selector.js'; 23 24 import {TextSourceRange} from '../../dom/text-source-range.js'; ··· 57 58 this._languageSummaries = []; 58 59 /** @type {boolean} */ 59 60 this._wanakanaBound = false; 61 + /** @type {ThemeController} */ 62 + this._themeController = new ThemeController(document.documentElement); 60 63 61 64 /* eslint-disable @stylistic/no-multi-spaces */ 62 65 /** @type {import('popup-preview-frame').ApiMap} */ ··· 74 77 async prepare() { 75 78 window.addEventListener('message', this._onMessage.bind(this), false); 76 79 80 + this._themeController.siteTheme = 'light'; 81 + this._themeController.prepare(); 82 + 77 83 // Setup events 78 - /** @type {HTMLInputElement} */ 79 - const darkThemeCheckbox = querySelectorNotNull(document, '#theme-dark-checkbox'); 80 - darkThemeCheckbox.addEventListener('change', this._onThemeDarkCheckboxChanged.bind(this), false); 81 84 this._exampleText.addEventListener('click', this._onExampleTextClick.bind(this), false); 82 85 this._exampleTextInput.addEventListener('blur', this._onExampleTextInputBlur.bind(this), false); 83 86 this._exampleTextInput.addEventListener('input', this._onExampleTextInputInput.bind(this), false); ··· 137 140 options.general.popupHorizontalTextPosition = 'below'; 138 141 options.general.popupVerticalTextPosition = 'before'; 139 142 options.scanning.selectText = false; 143 + this._themeController.theme = options.general.popupTheme; 144 + this._themeController.updateTheme(); 140 145 return options; 141 146 } 142 147 ··· 163 168 const {action, params} = event.data; 164 169 const callback = () => {}; // NOP 165 170 invokeApiMapHandler(this._windowMessageHandlers, action, params, [], callback); 166 - } 167 - 168 - /** 169 - * @param {Event} e 170 - */ 171 - _onThemeDarkCheckboxChanged(e) { 172 - const element = /** @type {HTMLInputElement} */ (e.currentTarget); 173 - document.documentElement.classList.toggle('dark', element.checked); 174 - if (this._themeChangeTimeout !== null) { 175 - clearTimeout(this._themeChangeTimeout); 176 - } 177 - this._themeChangeTimeout = setTimeout(() => { 178 - this._themeChangeTimeout = null; 179 - const popup = /** @type {Frontend} */ (this._frontend).popup; 180 - if (popup === null) { return; } 181 - void popup.updateTheme(); 182 - }, 300); 183 171 } 184 172 185 173 /** */
+19
ext/js/pages/settings/settings-display-controller.js
··· 16 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 17 */ 18 18 19 + import {ThemeController} from '../../app/theme-controller.js'; 19 20 import {isInputElementFocused} from '../../dom/document-util.js'; 20 21 import {PopupMenu} from '../../dom/popup-menu.js'; 21 22 import {querySelectorNotNull} from '../../dom/query-selector.js'; ··· 39 40 this._onMoreToggleClickBind = this._onMoreToggleClick.bind(this); 40 41 /** @type {(event: MouseEvent) => void} */ 41 42 this._onMenuButtonClickBind = this._onMenuButtonClick.bind(this); 43 + /** @type {ThemeController} */ 44 + this._themeController = new ThemeController(document.documentElement); 42 45 } 43 46 44 47 /** */ 45 48 prepare() { 49 + this._themeController.siteTheme = 'light'; 50 + this._themeController.prepare(); 51 + void this._updateTheme(); 52 + 46 53 const onFabButtonClick = this._onFabButtonClick.bind(this); 47 54 for (const fabButton of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('.fab-button'))) { 48 55 fabButton.addEventListener('click', onFabButtonClick, false); ··· 84 91 window.addEventListener('keydown', this._onKeyDown.bind(this), false); 85 92 window.addEventListener('popstate', this._onPopState.bind(this), false); 86 93 this._updateScrollTarget(); 94 + 95 + const themeDropdown = document.querySelector('[data-setting="general.popupTheme"]'); 96 + if (themeDropdown) { 97 + themeDropdown.addEventListener('change', this._updateTheme.bind(this), false); 98 + } 99 + } 100 + 101 + /** */ 102 + async _updateTheme() { 103 + const options = await this._settingsController.getOptions(); 104 + this._themeController.theme = options.general.popupTheme; 105 + this._themeController.updateTheme(); 87 106 } 88 107 89 108 // Private
+3 -3
ext/js/pages/settings/settings-main.js
··· 169 169 const sortFrequencyDictionaryController = new SortFrequencyDictionaryController(settingsController); 170 170 preparePromises.push(sortFrequencyDictionaryController.prepare()); 171 171 172 + const settingsDisplayController = new SettingsDisplayController(settingsController, modalController); 173 + settingsDisplayController.prepare(); 174 + 172 175 await Promise.all(preparePromises); 173 176 174 177 document.documentElement.dataset.loaded = 'true'; 175 - 176 - const settingsDisplayController = new SettingsDisplayController(settingsController, modalController); 177 - settingsDisplayController.prepare(); 178 178 });
+3 -3
ext/js/pages/welcome-main.js
··· 92 92 const languagesController = new LanguagesController(settingsController); 93 93 preparePromises.push(languagesController.prepare()); 94 94 95 + const settingsDisplayController = new SettingsDisplayController(settingsController, modalController); 96 + settingsDisplayController.prepare(); 97 + 95 98 await Promise.all(preparePromises); 96 99 97 100 document.documentElement.dataset.loaded = 'true'; 98 - 99 - const settingsDisplayController = new SettingsDisplayController(settingsController, modalController); 100 - settingsDisplayController.prepare(); 101 101 });
+1 -1
ext/permissions.html
··· 19 19 <body> 20 20 21 21 <!-- Main content --> 22 - <div class="content-outer"><div class="content"> 22 + <div class="content-outer"><div class="content scrollbar"> 23 23 <div class="content-left"></div> 24 24 <div class="content-center"> 25 25
-3
ext/popup-preview.html
··· 25 25 <span class="example-text" id="example-text"></span> 26 26 </div> 27 27 </div> 28 - <div class="top-options-right"> 29 - <label class="theme-button"><input type="checkbox" id="theme-dark-checkbox"><span>dark</span></label> 30 - </div> 31 28 </div> 32 29 <div class="popup-placeholder"><div class="placeholder-info"> 33 30 This page uses the dictionaries you have installed in order to show a preview.
+2 -1
ext/quick-start-guide.html
··· 13 13 <link rel="icon" type="image/png" href="/images/icon128.png" sizes="128x128"> 14 14 <link rel="stylesheet" type="text/css" href="/css/material.css"> 15 15 <link rel="stylesheet" type="text/css" href="/css/settings.css"> 16 + <script src="/js/pages/quick-start-guide-main.js" type="module"></script> 16 17 </head> 17 18 <body> 18 19 19 20 <!-- Main content --> 20 - <div class="content-outer"><div class="content"> 21 + <div class="content-outer"><div class="content scrollbar"> 21 22 <div class="content-left"></div> 22 23 <div class="content-center"> 23 24
+3 -3
ext/settings.html
··· 19 19 <body> 20 20 21 21 <!-- Main content --> 22 - <div class="content-outer"><div class="content"> 22 + <div class="content-outer"><div class="content scrollbar"> 23 23 <div class="content-left"> 24 - <div class="sidebar"><div class="sidebar-inner"> 24 + <div class="sidebar"><div class="sidebar-inner scrollbar"> 25 25 <div class="sidebar-body"> 26 26 <a href="#!profile" class="button outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="profile"></span></span><span class="outline-item-label">Profile</span></a> 27 27 <a href="#!dictionaries" class="button outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="book"></span><span class="outline-item-left-warning-badge no-dictionaries-enabled-warning" hidden><div class="badge warning-badge"><span class="icon" data-icon="exclamation-point-short"></span></div></span></span><span class="outline-item-label">Dictionaries</span></a> ··· 673 673 <div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable"> 674 674 <div class="settings-item-left"> 675 675 <div class="settings-item-label">Theme</div> 676 - <div class="settings-item-description">Adjust the style of the popup.</div> 676 + <div class="settings-item-description">Adjust the style of Yomitan.</div> 677 677 </div> 678 678 <div class="settings-item-right"> 679 679 <div class="settings-item-group">
+2 -2
ext/welcome.html
··· 18 18 <body> 19 19 20 20 <!-- Main content --> 21 - <div class="content-outer"><div class="content"> 21 + <div class="content-outer"><div class="content scrollbar"> 22 22 <div class="content-left"></div> 23 23 <div class="content-center"> 24 24 ··· 128 128 <div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable"> 129 129 <div class="settings-item-left"> 130 130 <div class="settings-item-label">Theme</div> 131 - <div class="settings-item-description">Adjust the style of the popup.</div> 131 + <div class="settings-item-description">Adjust the style of Yomitan.</div> 132 132 </div> 133 133 <div class="settings-item-right"> 134 134 <select data-setting="general.popupTheme" class="short-width">