diff --git a/.eslintignore b/.eslintignore index 572c354a4e..5358ca71f5 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ node_modules/ -builds/ \ No newline at end of file +builds/ +manifest-variants.v2.json diff --git a/docs/anki-integration.md b/docs/anki-integration.md index 150e422031..28da41c881 100644 --- a/docs/anki-integration.md +++ b/docs/anki-integration.md @@ -33,7 +33,7 @@ Flashcard fields can be configured with the following steps: | `{audio}` | Audio of the term's pronunciation from one of the audio sources (if available). | | `{clipboard-image}` | An image which is stored in the system clipboard, if present. | | `{clipboard-text}` | Text which is stored in the system clipboard, if present. | - | `{cloze-body}` | Raw, inflected term as it appeared before being reduced to dictionary form by Rikaitan. | + | `{cloze-body}` | Raw, inflected term as it appeared before being reduced to dictionary form by Rikaitan. | | `{cloze-body-kana}` | Kana reading for `{cloze-body}`. | | `{cloze-prefix}` | Fragment of the containing `{sentence}` starting at the beginning of `{sentence}` until the beginning of `{cloze-body}`. | | `{cloze-suffix}` | Fragment of the containing `{sentence}` starting at the end of `{cloze-body}` until the end of `{sentence}`. | @@ -80,7 +80,7 @@ Flashcard fields can be configured with the following steps: | `{character}` | Unicode glyph representing the current kanji. | | `{clipboard-image}` | An image which is stored in the system clipboard, if present. | | `{clipboard-text}` | Text which is stored in the system clipboard, if present. | - | `{cloze-body}` | Raw, inflected parent term as it appeared before being reduced to dictionary form by Rikaitan. | + | `{cloze-body}` | Raw, inflected parent term as it appeared before being reduced to dictionary form by Rikaitan. | | `{cloze-prefix}` | Fragment of the containing `{sentence}` starting at the beginning of `{sentence}` until the beginning of `{cloze-body}`. | | `{cloze-suffix}` | Fragment of the containing `{sentence}` starting at the end of `{cloze-body}` until the end of `{sentence}`. | | `{dictionary}` | Name of the dictionary from which the card is being created. | diff --git a/docs/audio.md b/docs/audio.md index a137caa5bb..c419d455e0 100644 --- a/docs/audio.md +++ b/docs/audio.md @@ -30,7 +30,7 @@ To enable this, just add a new playback source with the `Text-to-speech` type an - TTS voices vary between browsers and so might not support all languages. For instance, [Microsoft Edge](https://www.microsoft.com/en-us/edge) offers a wide selection of free Azure natural voices for a variety of languages. Edge provides over 300 voices, compared to around 25 in Google Chrome (see [here](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=stt) for a list of supported languages). - TTS audio can be inaccurate for languages with complex pronunciation such as Japanese, where words can have multiple possible readings and pitch accents. -- ⚠️ Note that the TTS voices cannot be sent to Anki; this is a [limitation of the browser SpeechSynthesis API](https://github.com/Ajatt-Tools/rikaitan/issues/864). +- ⚠️ Note that the TTS voices cannot be sent to Anki; this is a limitation of the browser SpeechSynthesis API. ### Custom URL diff --git a/docs/dictionaries.md b/docs/dictionaries.md index d1dacc5813..dbb331d100 100644 --- a/docs/dictionaries.md +++ b/docs/dictionaries.md @@ -12,8 +12,8 @@ you may consider also importing the English version for better coverage. ### Recommended Dictionaries -* [Our recommended dictionaries](https://tatsumoto.neocities.org/blog/yomichan-and-epwing-dictionaries#rikaitan) -* [Other dictionaries](https://github.com/Ajatt-Tools/rikaitan/tree/dictionaries) +- [Our recommended dictionaries](https://tatsumoto.neocities.org/blog/yomichan-and-epwing-dictionaries#rikaitan) +- [Other dictionaries](https://github.com/Ajatt-Tools/rikaitan/tree/dictionaries) ### Japanese beginner dictionaries diff --git a/ext/css/action-popup.css b/ext/css/action-popup.css index 389270d158..78f678af19 100644 --- a/ext/css/action-popup.css +++ b/ext/css/action-popup.css @@ -503,7 +503,7 @@ select.profile-select { /* Small text inside the popup that reports the current version */ .popup-version { font-size: 10px; - color: gray; + color: #616161; } /* Mobile overrides */ diff --git a/ext/css/display.css b/ext/css/display.css index 4eef597a10..288bb26f03 100644 --- a/ext/css/display.css +++ b/ext/css/display.css @@ -577,6 +577,7 @@ button.sidebar-button.sidebar-button-highlight { /* Search page */ .search-header-wrapper { + background-color: var(--background-color); width: 100%; display: flex; justify-content: center; @@ -595,7 +596,6 @@ button.sidebar-button.sidebar-button-highlight { padding: var(--main-content-vertical-padding) var(--main-content-horizontal-padding); } #query-parser-container { - overflow-y: auto; padding-left: var(--entry-horizontal-padding); padding-right: var(--entry-horizontal-padding); padding-bottom: 0.25em; @@ -605,12 +605,19 @@ button.sidebar-button.sidebar-button-highlight { margin-top: 0.5em; font-size: var(--query-parser-font-size); white-space: pre-wrap; - max-height: calc(var(--query-parser-font-size) * 2); } #query-parser-content[data-term-spacing=true] .query-parser-term { margin-right: 0.2em; } +.sticky-header { + #query-parser-container { + overflow-y: auto; + } + #query-parser-content { + max-height: calc(var(--query-parser-font-size) * 2); + } +} /* Action buttons */ .actions { diff --git a/ext/data/schemas/options-schema.json b/ext/data/schemas/options-schema.json index 8873b935c1..efff88f89b 100644 --- a/ext/data/schemas/options-schema.json +++ b/ext/data/schemas/options-schema.json @@ -319,7 +319,8 @@ "useLeft", "useTop", "windowType", - "windowState" + "windowState", + "searchStickyHeader" ], "properties": { "width": { @@ -357,6 +358,10 @@ "type": "string", "enum": ["normal", "maximized", "fullscreen"], "default": "normal" + }, + "searchStickyHeader": { + "type": "boolean", + "default": true } } }, diff --git a/ext/js/data/options-util.js b/ext/js/data/options-util.js index e43b43cf6c..80cc1f49f6 100644 --- a/ext/js/data/options-util.js +++ b/ext/js/data/options-util.js @@ -835,6 +835,7 @@ export class OptionsUtil { useTop: false, windowType: 'popup', windowState: 'normal', + searchStickyHeader: true, }; profile.options.audio.customSourceType = 'audio'; profile.options.clipboard = { diff --git a/ext/js/display/display.js b/ext/js/display/display.js index b54eea2f86..d58db7277d 100644 --- a/ext/js/display/display.js +++ b/ext/js/display/display.js @@ -426,6 +426,18 @@ export class Display extends EventDispatcher { await this.updateOptions(); } + /** + * @throws {Error} + * @returns {boolean} + */ + isSearchStickyHeaderEnabled() { + if (this._options) { + return Boolean(this._options.popupWindow.searchStickyHeader); + } else { + throw new Error('options should be initialized.'); + } + } + /** */ async updateOptions() { const options = await this._application.api.optionsGet(this.getOptionsContext()); diff --git a/ext/js/display/search-display-controller.js b/ext/js/display/search-display-controller.js index a25b90347a..83b74fc133 100644 --- a/ext/js/display/search-display-controller.js +++ b/ext/js/display/search-display-controller.js @@ -20,6 +20,7 @@ import * as wanakana from '../../lib/wanakana.js'; import {ClipboardMonitor} from '../comm/clipboard-monitor.js'; import {createApiMap, invokeApiMapHandler} from '../core/api-map.js'; import {EventListenerCollection} from '../core/event-listener-collection.js'; +import {log} from '../core/log.js'; import {querySelectorNotNull} from '../dom/query-selector.js'; export class SearchDisplayController { @@ -113,6 +114,19 @@ export class SearchDisplayController { if (displayOptions !== null) { await this._onDisplayOptionsUpdated({options: displayOptions}); } + + this.setStickyHeaderState(); + } + + /** + * + */ + setStickyHeaderState() { + try { + querySelectorNotNull(document, '#sticky_header').classList.toggle('sticky-header', this._display.isSearchStickyHeaderEnabled()); + } catch (e) { + log.error(e); + } } /** @@ -174,6 +188,7 @@ export class SearchDisplayController { if (query) { this._display.searchLast(false); } + this.setStickyHeaderState(); } /** diff --git a/ext/js/pages/action-popup-main.js b/ext/js/pages/action-popup-main.js index 6965da3ad7..9f9bb2d9bb 100644 --- a/ext/js/pages/action-popup-main.js +++ b/ext/js/pages/action-popup-main.js @@ -19,6 +19,7 @@ import {ThemeController} from '../app/theme-controller.js'; import {Application} from '../application.js'; import {getAllPermissions, hasRequiredPermissionsForOptions} from '../data/permissions-util.js'; +import {querySelectorNotNull} from '../dom/query-selector.js'; import {HotkeyHelpController} from '../input/hotkey-help-controller.js'; class DisplayController { @@ -74,7 +75,7 @@ class DisplayController { // Show Rikaitan version. // replace version number () - document.querySelector('#version').textContent = `v${manifest.version}`; + querySelectorNotNull(document, '#version').textContent = `v${manifest.version}`; this._updateProfileSelect(profiles, profileCurrent); diff --git a/ext/search.html b/ext/search.html index 071f2f9031..b47d68467a 100644 --- a/ext/search.html +++ b/ext/search.html @@ -55,7 +55,7 @@