diff options
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/css/settings.css | 187 | ||||
| -rw-r--r-- | ext/js/pages/settings/dictionary-controller.js | 293 | ||||
| -rw-r--r-- | ext/settings.html | 142 | ||||
| -rw-r--r-- | ext/welcome.html | 95 | 
4 files changed, 460 insertions, 257 deletions
| diff --git a/ext/css/settings.css b/ext/css/settings.css index 6bc377c2..f0070a1f 100644 --- a/ext/css/settings.css +++ b/ext/css/settings.css @@ -1313,65 +1313,6 @@ body.preview-sidebar-visible .fab-container-item.fab-container-item-popup-previe      display: none;  } -.dictionary-info { -    display: flex; -    flex-flow: row nowrap; -    align-items: center; -} -.dictionary-info-label { -    margin-left: 1em; -} - -.dictionary-title { -    color: inherit; -    transition: color var(--animation-duration) ease-in-out; -} -.dictionary-item[data-enabled=false] .dictionary-title { -    color: var(--text-color-light2); -} - -.dictionary-list { -    display: flex; -    flex-flow: column nowrap; -    width: 100%; -} -.dictionary-list>.settings-item, -.dictionary-list>.settings-item+.settings-item { -    margin-left: calc(var(--modal-padding-horizontal) * -1); -    margin-right: calc(var(--modal-padding-horizontal) * -1); -    border-top: var(--thin-border-size) solid var(--separator-color2); -} -.dictionary-details-table { -    display: table; -    width: 100%; -} -.dictionary-details-entry { -    display: table-row; -} -.dictionary-details-entry+.dictionary-details-entry>* { -    padding-top: 0.25em; -} -.dictionary-details-entry-label { -    display: table-cell; -    font-weight: bold; -    white-space: nowrap; -    padding-right: 0.5em; -} -.dictionary-details-entry-info { -    display: table-cell; -    white-space: pre-line; -} -.dictionary-counts { -    width: 100%; -    box-sizing: border-box; -    font-size: inherit; -    max-height: 10em; -    line-height: 1.25; -    font-family: 'Courier New', Courier, monospace; -    white-space: pre; -    overflow: auto; -} -  .profile-add-button-container {      display: flex;      flex-flow: row nowrap; @@ -2096,28 +2037,47 @@ button.hotkey-list-item-enabled-button[data-scope-count='0'] {      top: calc(1em * (3 / var(--font-size-no-units)));  } -.warning-badge { +.badge {      position: relative;      width: var(--badge-size);      height: var(--badge-size);      margin: 0;      padding: 0; -    background-color: var(--warning-color-light);      border-radius: 50%;      box-shadow: var(--shadow-vertical);  } -.warning-badge:not([hidden]) { +.badge:not([hidden]) {      display: block;  } -.warning-badge>.icon { +.badge>.icon {      display: block;      position: absolute;      left: 0;      top: 0;      right: 0;      bottom: 0; +} +.badge.badge-small-icon>.icon { +    margin: calc(1em / var(--font-size-no-units)); +} +.badge.info-badge { +    background-color: var(--accent-color-lighter); +} +.badge.info-badge>.icon { +    background-color: var(--accent-color); +} +.badge.warning-badge { +    background-color: var(--warning-color-light); +} +.badge.warning-badge>.icon {      background-color: var(--warning-color);  } +.badge.danger-badge { +    background-color: var(--danger-color-lighter); +} +.badge.danger-badge>.icon { +    background-color: var(--danger-color); +}  .collapsible-dictionary-list {      width: 100%; @@ -2160,6 +2120,107 @@ button.hotkey-list-item-enabled-button[data-scope-count='0'] {  } +/* Dictionary settings */ +.dictionary-list { +    width: 100%; +    display: grid; +    grid-template-columns: auto 1fr auto auto; +    grid-template-rows: auto; +    place-items: center start; +    margin-top: 0.5em; +} +.dictionary-list[data-count='0']>.dictionary-item-top { +    display: none; +} +.dictionary-item-button-height { +    height: var(--icon-button-size); +} +.dictionary-item { +    display: flex; +    flex-flow: row nowrap; +    align-items: center; +    border-top: var(--thin-border-size) solid var(--separator-color2); +} +.dictionary-item-enabled-toggle-container { +    margin-right: 0.5em; +} +.dictionary-item-title-container { +    flex: 1 1 auto; +    display: flex; +    flex-flow: row nowrap; +    align-items: center; +    margin-right: 0.5em; +} +.dictionary-title { +    color: inherit; +    transition: color var(--animation-duration) ease-in-out; +} +.dictionary-item[data-enabled=false] .dictionary-title { +    color: var(--text-color-light2); +} +input[type=number].dictionary-priority { +    margin-top: 0; +    margin-right: 0.5em; +} +.dictionary-outdated-button, +.dictionary-integrity-button { +    --button-content-color: transparent; +    --button-border-color: transparent; +    --button-background-color: transparent; +    --button-shadow: none; + +    --button-hover-content-color: transparent; +    --button-hover-border-color: transparent; +    --button-hover-background-color: transparent; +    --button-hover-shadow: none; + +    --button-active-content-color: transparent; +    --button-active-border-color: transparent; +    --button-active-background-color: transparent; +    --button-active-shadow: none; + +    --button-disabled-content-color: transparent; +    --button-disabled-border-color: transparent; +    --button-disabled-background-color: transparent; +    --button-disabled-shadow: none; + +    --button-padding-vertical: 0; +    --button-padding-horizontal: 0; + +    margin-left: 0.375em; +} +.dictionary-details-table { +    display: table; +    width: 100%; +} +.dictionary-details-entry { +    display: table-row; +} +.dictionary-details-entry+.dictionary-details-entry>* { +    padding-top: 0.25em; +} +.dictionary-details-entry-label { +    display: table-cell; +    font-weight: bold; +    white-space: nowrap; +    padding-right: 0.5em; +} +.dictionary-details-entry-info { +    display: table-cell; +    white-space: pre-line; +} +.dictionary-counts { +    width: 100%; +    box-sizing: border-box; +    font-size: inherit; +    max-height: 10em; +    line-height: 1.25; +    font-family: 'Courier New', Courier, monospace; +    white-space: pre; +    overflow: auto; +} + +  /* Generic layouts */  .margin-above {      margin-top: 0.85em; diff --git a/ext/js/pages/settings/dictionary-controller.js b/ext/js/pages/settings/dictionary-controller.js index f000aa62..6d358f25 100644 --- a/ext/js/pages/settings/dictionary-controller.js +++ b/ext/js/pages/settings/dictionary-controller.js @@ -20,19 +20,21 @@   */  class DictionaryEntry { -    constructor(dictionaryController, node, index, dictionaryInfo) { +    constructor(dictionaryController, fragment, index, dictionaryInfo) {          this._dictionaryController = dictionaryController; -        this._node = node;          this._index = index;          this._dictionaryInfo = dictionaryInfo;          this._eventListeners = new EventListenerCollection(); -        this._detailsContainer = null; -        this._hasDetails = false; -        this._hasCounts = false; -    } - -    get node() { -        return this._node; +        this._counts = null; +        this._nodes = [...fragment.childNodes]; +        this._enabledCheckbox = fragment.querySelector('.dictionary-enabled'); +        this._priorityInput = fragment.querySelector('.dictionary-priority'); +        this._menuButton = fragment.querySelector('.dictionary-menu-button'); +        this._outdatedButton = fragment.querySelector('.dictionary-outdated-button'); +        this._integrityButton = fragment.querySelector('.dictionary-integrity-button'); +        this._titleNode = fragment.querySelector('.dictionary-title'); +        this._versionNode = fragment.querySelector('.dictionary-version'); +        this._titleContainer = fragment.querySelector('.dictionary-item-title-container');      }      get dictionaryTitle() { @@ -40,98 +42,80 @@ class DictionaryEntry {      }      prepare() { -        const node = this._node;          const index = this._index; -        const {title, revision, prefixWildcardsSupported, version} = this._dictionaryInfo; - -        this._detailsContainer = node.querySelector('.dictionary-details'); - -        const enabledCheckbox = node.querySelector('.dictionary-enabled'); -        const priorityInput = node.querySelector('.dictionary-priority'); -        const menuButton = node.querySelector('.dictionary-menu-button'); -        const detailsTable = node.querySelector('.dictionary-details-table'); -        const outdatedContainer = node.querySelector('.dictionary-outdated-notification'); -        const titleNode = node.querySelector('.dictionary-title'); -        const versionNode = node.querySelector('.dictionary-version'); -        const wildcardSupportedCheckbox = node.querySelector('.dictionary-prefix-wildcard-searches-supported'); - -        const hasDetails = (detailsTable !== null && this._setupDetails(detailsTable)); -        this._hasDetails = hasDetails; - -        titleNode.textContent = title; -        versionNode.textContent = `rev.${revision}`; -        if (wildcardSupportedCheckbox !== null) { -            wildcardSupportedCheckbox.checked = !!prefixWildcardsSupported; -        } -        if (outdatedContainer !== null) { -            outdatedContainer.hidden = (version >= 3); -        } -        if (enabledCheckbox !== null) { -            enabledCheckbox.dataset.setting = `dictionaries[${index}].enabled`; -            this._eventListeners.addEventListener(enabledCheckbox, 'settingChanged', this._onEnabledChanged.bind(this), false); -        } -        if (priorityInput !== null) { -            priorityInput.dataset.setting = `dictionaries[${index}].priority`; -        } -        if (menuButton !== null) { -            this._eventListeners.addEventListener(menuButton, 'menuOpen', this._onMenuOpen.bind(this), false); -            this._eventListeners.addEventListener(menuButton, 'menuClose', this._onMenuClose.bind(this), false); -        } +        const {title, revision, version} = this._dictionaryInfo; + +        this._titleNode.textContent = title; +        this._versionNode.textContent = `rev.${revision}`; +        this._outdatedButton.hidden = (version >= 3); +        this._priorityInput.dataset.setting = `dictionaries[${index}].priority`; +        this._enabledCheckbox.dataset.setting = `dictionaries[${index}].enabled`; +        this._eventListeners.addEventListener(this._enabledCheckbox, 'settingChanged', this._onEnabledChanged.bind(this), false); +        this._eventListeners.addEventListener(this._menuButton, 'menuClose', this._onMenuClose.bind(this), false); +        this._eventListeners.addEventListener(this._outdatedButton, 'click', this._onOutdatedButtonClick.bind(this), false); +        this._eventListeners.addEventListener(this._integrityButton, 'click', this._onIntegrityButtonClick.bind(this), false);      }      cleanup() {          this._eventListeners.removeAllEventListeners(); -        const node = this._node; -        if (node.parentNode !== null) { -            node.parentNode.removeChild(node); +        for (const node of this._nodes) { +            if (node.parentNode !== null) { +                node.parentNode.removeChild(node); +            }          } +        this._nodes = [];      }      setCounts(counts) { -        const node = this._node.querySelector('.dictionary-counts'); -        node.textContent = JSON.stringify({info: this._dictionaryInfo, counts}, null, 4); -        node.hidden = false; -        this._hasCounts = true; +        this._counts = counts; +        this._integrityButton.hidden = false;      } -    // Private - -    _onMenuOpen(e) { -        const bodyNode = e.detail.menu.bodyNode; -        const showDetails = bodyNode.querySelector('.popup-menu-item[data-menu-action="showDetails"]'); -        const hideDetails = bodyNode.querySelector('.popup-menu-item[data-menu-action="hideDetails"]'); -        const hasDetails = (this._detailsContainer !== null); -        const detailsVisible = (hasDetails && !this._detailsContainer.hidden); -        if (showDetails !== null) { -            showDetails.hidden = detailsVisible; -            showDetails.disabled = !hasDetails; -        } -        if (hideDetails !== null) { -            hideDetails.hidden = !detailsVisible; -            hideDetails.disabled = !hasDetails; -        } +    setEnabled(value) { +        this._enabledCheckbox.checked = value;      } +    // Private +      _onMenuClose(e) {          switch (e.detail.action) {              case 'delete':                  this._delete();                  break;              case 'showDetails': -                if (this._detailsContainer !== null) { this._detailsContainer.hidden = false; } -                break; -            case 'hideDetails': -                if (this._detailsContainer !== null) { this._detailsContainer.hidden = true; } +                this._showDetails();                  break;          }      }      _onEnabledChanged(e) {          const {detail: {value}} = e; -        this._node.dataset.enabled = `${value}`; +        this._titleContainer.dataset.enabled = `${value}`;          this._dictionaryController.updateDictionariesEnabled();      } +    _onOutdatedButtonClick() { +        this._showDetails(); +    } + +    _onIntegrityButtonClick() { +        this._showDetails(); +    } + +    _showDetails() { +        const {title, revision, version} = this._dictionaryInfo; + +        const modal = this._dictionaryController.modalController.getModal('dictionary-details'); + +        modal.node.querySelector('.dictionary-title').textContent = title; +        modal.node.querySelector('.dictionary-version').textContent = `rev.${revision}`; +        modal.node.querySelector('.dictionary-outdated-notification').hidden = (version >= 3); +        modal.node.querySelector('.dictionary-counts').textContent = this._counts !== null ? JSON.stringify(this._counts, null, 4) : ''; +        this._setupDetails(modal.node.querySelector('.dictionary-details-table')); + +        modal.setVisible(true); +    } +      _setupDetails(detailsTable) {          const targets = [              ['Author', 'author'], @@ -156,6 +140,7 @@ class DictionaryEntry {              any = true;          } +        detailsTable.textContent = '';          detailsTable.appendChild(fragment);          return any;      } @@ -165,6 +150,57 @@ class DictionaryEntry {      }  } +class DictionaryExtraInfo { +    constructor(parent, totalCounts, remainders, totalRemainder) { +        this._parent = parent; +        this._totalCounts = totalCounts; +        this._remainders = remainders; +        this._totalRemainder = totalRemainder; +        this._eventListeners = new EventListenerCollection(); +        this._nodes = null; +    } + +    prepare(container) { +        const fragment = this._parent.instantiateTemplateFragment('dictionary-extra'); +        this._nodes = [...fragment.childNodes]; + +        this._setTitle(fragment.querySelector('.dictionary-total-count')); +        this._eventListeners.addEventListener(fragment.querySelector('.dictionary-integrity-button'), 'click', this._onIntegrityButtonClick.bind(this), false); + +        container.appendChild(fragment); +    } + +    cleanup() { +        this._eventListeners.removeAllEventListeners(); +        for (const node of this._nodes) { +            if (node.parentNode !== null) { +                node.parentNode.removeChild(node); +            } +        } +        this._nodes = []; +    } + +    // Private + +    _onIntegrityButtonClick() { +        this._showDetails(); +    } + +    _showDetails() { +        const modal = this._parent.modalController.getModal('dictionary-extra-data'); + +        const info = {counts: this._totalCounts, remainders: this._remainders}; +        modal.node.querySelector('.dictionary-counts').textContent = JSON.stringify(info, null, 4); +        this._setTitle(modal.node.querySelector('.dictionary-total-count')); + +        modal.setVisible(true); +    } + +    _setTitle(node) { +        node.textContent = `${this._totalRemainder} item${this._totalRemainder !== 1 ? 's' : ''}`; +    } +} +  class DictionaryController {      constructor(settingsController, modalController, statusFooter) {          this._settingsController = settingsController; @@ -176,34 +212,40 @@ class DictionaryController {          this._checkingIntegrity = false;          this._checkIntegrityButton = null;          this._dictionaryEntryContainer = null; -        this._integrityExtraInfoContainer = null;          this._dictionaryInstallCountNode = null;          this._dictionaryEnabledCountNode = null;          this._noDictionariesInstalledWarnings = null;          this._noDictionariesEnabledWarnings = null;          this._deleteDictionaryModal = null; -        this._integrityExtraInfoNode = null; +        this._allCheckbox = null; +        this._extraInfo = null;          this._isDeleting = false;      } +    get modalController() { +        return this._modalController; +    } +      async prepare() {          this._checkIntegrityButton = document.querySelector('#dictionary-check-integrity');          this._dictionaryEntryContainer = document.querySelector('#dictionary-list'); -        this._integrityExtraInfoContainer = document.querySelector('#dictionary-list-extra');          this._dictionaryInstallCountNode = document.querySelector('#dictionary-install-count');          this._dictionaryEnabledCountNode = document.querySelector('#dictionary-enabled-count');          this._noDictionariesInstalledWarnings = document.querySelectorAll('.no-dictionaries-installed-warning');          this._noDictionariesEnabledWarnings = document.querySelectorAll('.no-dictionaries-enabled-warning');          this._deleteDictionaryModal = this._modalController.getModal('dictionary-confirm-delete'); +        this._allCheckbox = document.querySelector('#all-dictionaries-enabled');          yomichan.on('databaseUpdated', this._onDatabaseUpdated.bind(this));          this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); - +        this._allCheckbox.addEventListener('change', this._onAllCheckboxChange.bind(this), false);          document.querySelector('#dictionary-confirm-delete-button').addEventListener('click', this._onDictionaryConfirmDelete.bind(this), false);          if (this._checkIntegrityButton !== null) {              this._checkIntegrityButton.addEventListener('click', this._onCheckIntegrityButtonClick.bind(this), false);          } +        this._updateDictionaryEntryCount(); +          await this._onDatabaseUpdated();      } @@ -219,6 +261,10 @@ class DictionaryController {          return this._settingsController.instantiateTemplate(name);      } +    instantiateTemplateFragment(name) { +        return this._settingsController.instantiateTemplateFragment(name); +    } +      async updateDictionariesEnabled() {          const options = await this._settingsController.getOptions();          this._updateDictionariesEnabledWarnings(options); @@ -303,6 +349,12 @@ class DictionaryController {          await this._updateEntries();      } +    _onAllCheckboxChange() { +        const value = this._allCheckbox.checked; +        this._allCheckbox.checked = !value; +        this._setAllDictionariesEnabled(value); +    } +      async _updateEntries() {          const dictionaries = this._dictionaries;          this._updateMainDictionarySelectOptions(dictionaries); @@ -311,6 +363,7 @@ class DictionaryController {              entry.cleanup();          }          this._dictionaryEntries = []; +        this._updateDictionaryEntryCount();          if (this._dictionaryInstallCountNode !== null) {              this._dictionaryInstallCountNode.textContent = `${dictionaries.length}`; @@ -341,29 +394,40 @@ class DictionaryController {      }      _updateDictionariesEnabledWarnings(options) { -        let enabledCount = 0; +        const {dictionaries} = options; +        let enabledDictionaryCountValid = 0; +        let enabledDictionaryCount = 0; +        const dictionaryCount = dictionaries.length;          if (this._dictionaries !== null) {              const enabledDictionaries = new Set(); -            for (const {name, enabled} of options.dictionaries) { +            for (const {name, enabled} of dictionaries) {                  if (enabled) { +                    ++enabledDictionaryCount;                      enabledDictionaries.add(name);                  }              }              for (const {title} of this._dictionaries) {                  if (enabledDictionaries.has(title)) { -                    ++enabledCount; +                    ++enabledDictionaryCountValid;                  }              }          } -        const hasEnabledDictionary = (enabledCount > 0); +        const hasEnabledDictionary = (enabledDictionaryCountValid > 0);          for (const node of this._noDictionariesEnabledWarnings) {              node.hidden = hasEnabledDictionary;          }          if (this._dictionaryEnabledCountNode !== null) { -            this._dictionaryEnabledCountNode.textContent = `${enabledCount}`; +            this._dictionaryEnabledCountNode.textContent = `${enabledDictionaryCountValid}`; +        } + +        this._allCheckbox.checked = (enabledDictionaryCount >= dictionaryCount); + +        const entries = this._dictionaryEntries; +        for (let i = 0, ii = Math.min(entries.length, dictionaryCount); i < ii; ++i) { +            entries[i].setEnabled(dictionaries[i].enabled);          }      } @@ -447,43 +511,29 @@ class DictionaryController {              totalRemainder += remainders[key];          } -        this._cleanupExtra(); -        if (totalRemainder > 0) { -            this.extra = this._createExtra(totalCounts, remainders, totalRemainder); +        if (this._extraInfo !== null) { +            this._extraInfo.cleanup(); +            this._extraInfo = null;          } -    } - -    _createExtra(totalCounts, remainders, totalRemainder) { -        const node = this.instantiateTemplate('dictionary-extra'); -        this._integrityExtraInfoNode = node; - -        node.querySelector('.dictionary-total-count').textContent = `${totalRemainder} item${totalRemainder !== 1 ? 's' : ''}`; - -        const n = node.querySelector('.dictionary-counts'); -        n.textContent = JSON.stringify({counts: totalCounts, remainders}, null, 4); -        n.hidden = false; - -        this._integrityExtraInfoContainer.appendChild(node); -    } -    _cleanupExtra() { -        const node = this._integrityExtraInfoNode; -        if (node === null) { return; } -        this._integrityExtraInfoNode = null; - -        const parent = node.parentNode; -        if (parent === null) { return; } - -        parent.removeChild(node); +        if (totalRemainder > 0) { +            this._extraInfo = new DictionaryExtraInfo(this, totalCounts, remainders, totalRemainder); +            this._extraInfo.prepare(this._dictionaryEntryContainer); +        }      }      _createDictionaryEntry(index, dictionaryInfo) { -        const node = this.instantiateTemplate('dictionary'); -        this._dictionaryEntryContainer.appendChild(node); +        const fragment = this.instantiateTemplateFragment('dictionary'); -        const entry = new DictionaryEntry(this, node, index, dictionaryInfo); +        const entry = new DictionaryEntry(this, fragment, index, dictionaryInfo);          this._dictionaryEntries.push(entry);          entry.prepare(); + +        const container = this._dictionaryEntryContainer; +        const relative = container.querySelector('.dictionary-item-bottom'); +        container.insertBefore(fragment, relative); + +        this._updateDictionaryEntryCount();      }      async _deleteDictionary(dictionaryTitle) { @@ -589,4 +639,25 @@ class DictionaryController {      _triggerStorageChanged() {          yomichan.trigger('storageChanged');      } + +    _updateDictionaryEntryCount() { +        this._dictionaryEntryContainer.dataset.count = `${this._dictionaryEntries.length}`; +    } + +    async _setAllDictionariesEnabled(value) { +        const options = await this._settingsController.getOptions(); +        const {dictionaries} = options; + +        const targets = []; +        for (let i = 0, ii = dictionaries.length; i < ii; ++i) { +            targets.push({ +                action: 'set', +                path: `dictionaries[${i}].enabled`, +                value +            }); +        } +        await this._settingsController.modifyProfileSettings(targets); + +        await this.updateDictionariesEnabled(); +    }  } diff --git a/ext/settings.html b/ext/settings.html index 872dac4d..eee06a60 100644 --- a/ext/settings.html +++ b/ext/settings.html @@ -22,7 +22,7 @@      <div class="sidebar"><div class="sidebar-inner">          <div class="sidebar-body">              <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> -            <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="warning-badge"><span class="icon" data-icon="exclamation-point-short"></span></div></span></span><span class="outline-item-label">Dictionaries</span></a> +            <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>              <a href="#!general"          class="button outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="cog"></span></span><span class="outline-item-label">General</span></a>              <a href="#!scanning"         class="button outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="scanning"></span></span><span class="outline-item-label">Scanning</span></a>              <a href="#!popup"            class="button outline-item"><span class="outline-item-left"><span class="outline-item-icon icon" data-icon="popup"></span></span><span class="outline-item-label">Popup</span></a> @@ -121,7 +121,7 @@                  <div class="settings-item-label">                      <div class="flex-row-nowrap">                          <div>Configure installed and enabled dictionaries…</div> -                        <div class="flex-margin-left warning-badge no-dictionaries-enabled-warning" hidden><span class="icon" data-icon="exclamation-point-short"></span></div> +                        <div class="flex-margin-left badge warning-badge no-dictionaries-enabled-warning" hidden><span class="icon" data-icon="exclamation-point-short"></span></div>                      </div>                  </div>              </div> @@ -2080,8 +2080,12 @@              for a list free dictionaries or click the <em>Import</em> button below to select a dictionary file to import.          </div>          <div id="dictionary-error" class="danger-text margin-above" hidden></div> -        <div id="dictionary-list" class="dictionary-list"></div> -        <div id="dictionary-list-extra" class="dictionary-list"></div> +        <div id="dictionary-list" class="dictionary-list" data-count="0"> +            <label class="dictionary-item-top toggle dictionary-item-enabled-toggle-container"><input type="checkbox" id="all-dictionaries-enabled"><span class="toggle-body"><span class="toggle-track"></span><span class="toggle-knob"></span></span></label> +            <div class="dictionary-item-top dictionary-item-title-container">All</div> +            <div class="dictionary-item-top">Priority</div> +            <div class="dictionary-item-top dictionary-item-button-height"></div> +        </div>          <div hidden><input type="file" id="dictionary-import-file-input" accept=".zip,application/zip" multiple></div>      </div> @@ -2166,86 +2170,102 @@      </div>  </div></div> - -<!-- Dictionary templates --> -<template id="dictionary-template"><div class="settings-item dictionary-item"> -    <div class="settings-item-inner"> -        <div class="settings-item-left"> -            <div class="settings-item-label dictionary-info"> -                <label class="toggle"><input type="checkbox" class="dictionary-enabled"><span class="toggle-body"><span class="toggle-track"></span><span class="toggle-knob"></span></span></label> -                <span class="dictionary-info-label"><strong class="dictionary-title"></strong> <span class="light dictionary-version"></span></span> -            </div> -        </div> -        <div class="settings-item-right"> -            <button class="icon-button dictionary-menu-button" data-menu="dictionary-menu" data-menu-position="below left"><span class="icon-button-inner"><span class="icon" data-icon="kebab-menu"></span></span></button> -        </div> +<div id="dictionary-details-modal" class="modal" tabindex="-1" role="dialog" hidden><div class="modal-content"> +    <div class="modal-header"> +        <div class="modal-title"><strong class="dictionary-title"></strong> <span class="light dictionary-version"></span></div>      </div> -    <div class="settings-item-children"> - +    <div class="modal-body">          <div class="settings-item dictionary-outdated-notification" hidden><div class="settings-item-children danger-text">              This dictionary is outdated and may not support new extension features.              Re-import the dictionary to enable support for the latest features.          </div></div> -        <div class="settings-item"><div class="settings-item-inner settings-item-inner-wrappable"> -            <div class="settings-item-left"> -                <div class="settings-item-label">Priority</div> -            </div> -            <div class="settings-item-right"> -                <input type="number" step="1" class="short-height dictionary-priority"> -            </div> -        </div></div> -        <div class="dictionary-details" hidden> -            <div class="settings-item"> -                <div class="settings-item-inner"> -                    <div class="settings-item-left"> -                        <div class="settings-item-label"> -                            Prefix wildcard searches supported -                            <a class="more-toggle more-only" data-parent-distance="4">(?)</a> -                        </div> -                    </div> -                    <div class="settings-item-right"> -                        <label class="toggle"><input type="checkbox" class="dictionary-prefix-wildcard-searches-supported" disabled readonly><span class="toggle-body"><span class="toggle-track"></span><span class="toggle-knob"></span></span></label> +        <div class="settings-item"> +            <div class="settings-item-inner"> +                <div class="settings-item-left"> +                    <div class="settings-item-label"> +                        Prefix wildcard searches supported +                        <a class="more-toggle more-only" data-parent-distance="4">(?)</a>                      </div>                  </div> -                <div class="settings-item-children more" hidden> -                    <p class="warning-text"> -                        Changing this value requires the dictionary to be re-imported. -                    </p> -                    <p><a class="more-toggle" data-parent-distance="3">Hide…</a></p> +                <div class="settings-item-right"> +                    <label class="toggle"><input type="checkbox" class="dictionary-prefix-wildcard-searches-supported" disabled readonly><span class="toggle-body"><span class="toggle-track"></span><span class="toggle-knob"></span></span></label>                  </div>              </div> -            <div class="settings-item"><div class="settings-item-children"> -                <div class="dictionary-details-table"></div> -                <div class="dictionary-counts"></div> -            </div></div> +            <div class="settings-item-children more" hidden> +                <p class="warning-text"> +                    Changing this value requires the dictionary to be re-imported. +                </p> +                <p><a class="more-toggle" data-parent-distance="3">Hide…</a></p> +            </div>          </div> - +        <div class="settings-item"><div class="settings-item-children"> +            <div class="dictionary-details-table"></div> +            <div class="dictionary-counts"></div> +        </div></div>      </div> -</div></template> - -<template id="dictionary-details-entry-template"><div class="dictionary-details-entry"> -    <span class="dictionary-details-entry-label"></span> -    <span class="dictionary-details-entry-info"></span> -</div></template> +    <div class="modal-footer"> +        <button data-modal-action="hide">Close</button> +    </div> +</div></div> -<template id="dictionary-extra-template"><div class="settings-item"> -    <div class="settings-item-inner"> -        <div class="settings-item-left"> -            <div class="settings-item-label"><strong class="dictionary-title">Unassociated Data</strong> <span class="light dictionary-total-count"></span></div> +<div id="dictionary-extra-data-modal" class="modal" tabindex="-1" role="dialog" hidden><div class="modal-content"> +    <div class="modal-header"> +        <div class="modal-title"> +            <strong class="dictionary-title">Unassociated Data</strong> <span class="light dictionary-total-count"></span>          </div>      </div> -    <div class="settings-item-children"> +    <div class="modal-body">          <p class="warning-text">              The database contains extra data which is not associated with any installed dictionary.              Purging the database can fix this issue.          </p>          <div class="dictionary-counts"></div>      </div> +    <div class="modal-footer"> +        <button data-modal-action="hide">Close</button> +    </div> +</div></div> + + +<!-- Dictionary templates --> +<template id="dictionary-template"> +    <label class="toggle dictionary-item-enabled-toggle-container"><input type="checkbox" class="dictionary-enabled"><span class="toggle-body"><span class="toggle-track"></span><span class="toggle-knob"></span></span></label> +    <div class="dictionary-item-title-container"> +        <span> +            <strong class="dictionary-title"></strong> <span class="light dictionary-version"></span> +        </span> +        <button class="dictionary-outdated-button" hidden> +            <div class="badge warning-badge"><span class="icon" data-icon="exclamation-point-short"></span></div> +        </button> +        <button class="dictionary-integrity-button" hidden> +            <div class="badge info-badge badge-small-icon"><span class="icon" data-icon="checkmark"></span></div> +        </button> +    </div> +    <input type="number" step="1" class="short-height dictionary-priority"> +    <button class="icon-button dictionary-menu-button" data-menu="dictionary-menu" data-menu-position="below left"><span class="icon-button-inner"><span class="icon" data-icon="kebab-menu"></span></span></button> +</template> + +<template id="dictionary-details-entry-template"><div class="dictionary-details-entry"> +    <span class="dictionary-details-entry-label"></span> +    <span class="dictionary-details-entry-info"></span>  </div></template> +<template id="dictionary-extra-template"> +    <div class="dictionary-item-bottom"></div> +    <div class="dictionary-item-bottom dictionary-item-title-container"> +        <span> +            <strong class="dictionary-title">Unassociated Data</strong> <span class="light dictionary-total-count"></span> +        </span> +        <button class="dictionary-integrity-button"> +            <div class="badge warning-badge"><span class="icon" data-icon="exclamation-point-short"></span></div> +        </button> +    </div> +    <div class="dictionary-item-bottom"></div> +    <div class="dictionary-item-bottom dictionary-item-button-height"></div> +</template> +  <template id="dictionary-menu-template"><div class="popup-menu-container" tabindex="-1" role="dialog"><div class="popup-menu"><div class="popup-menu-body"> -    <button class="popup-menu-item" data-menu-action="showDetails">Show details</button> -    <button class="popup-menu-item" data-menu-action="hideDetails" hidden>Hide details</button> +    <button class="popup-menu-item" data-menu-action="showDetails">Details…</button>      <button class="popup-menu-item" data-menu-action="delete">Delete</button>  </div></div></div></template> diff --git a/ext/welcome.html b/ext/welcome.html index 5876ad4c..fc7c203f 100644 --- a/ext/welcome.html +++ b/ext/welcome.html @@ -201,7 +201,15 @@  <!-- Dictionary modals -->  <div id="dictionaries-modal" class="modal" tabindex="-1" role="dialog" hidden><div class="modal-content"> -    <div class="modal-header"><div class="modal-title">Dictionaries</div></div> +    <div class="modal-header"> +        <div class="modal-title">Dictionaries</div> +        <div class="modal-header-button-container"> +            <div class="modal-header-button-group"> +                <button class="icon-button modal-header-button" data-modal-action="expand"><span class="icon-button-inner"><span class="icon" data-icon="expand"></span></span></button> +                <button class="icon-button modal-header-button" data-modal-action="collapse"><span class="icon-button-inner"><span class="icon" data-icon="collapse"></span></span></button> +            </div> +        </div> +    </div>      <div class="modal-body">          <div class="settings-item">              <div class="settings-item-inner"> @@ -231,22 +239,18 @@              </div>          </div> -        <div class="settings-item"><div class="settings-item-inner"> -            <div class="settings-item-left"> -                <div class="settings-item-label"> -                    More dictionary settings are available on the <a href="/settings.html" rel="noopener">Settings</a> page -                </div> -            </div> -        </div></div> -          <div class="warning-text margin-above no-dictionaries-installed-warning" hidden>              No dictionaries have been installed yet.              Visit the <a href="https://foosoft.net/projects/yomichan/#dictionaries" target="_blank" rel="noopener noreferrer">Yomichan homepage</a>              for a list free dictionaries or click the <em>Import</em> button below to select a dictionary file to import.          </div>          <div id="dictionary-error" class="danger-text margin-above" hidden></div> -        <div id="dictionary-list" class="dictionary-list"></div> -        <div id="dictionary-list-extra" class="dictionary-list"></div> +        <div id="dictionary-list" class="dictionary-list" data-count="0"> +            <label class="dictionary-item-top toggle dictionary-item-enabled-toggle-container"><input type="checkbox" id="all-dictionaries-enabled"><span class="toggle-body"><span class="toggle-track"></span><span class="toggle-knob"></span></span></label> +            <div class="dictionary-item-top dictionary-item-title-container">All</div> +            <div class="dictionary-item-top">Priority</div> +            <div class="dictionary-item-top dictionary-item-button-height"></div> +        </div>          <div hidden><input type="file" id="dictionary-import-file-input" accept=".zip,application/zip" multiple></div>      </div> @@ -290,23 +294,70 @@      </div>  </div></div> - -<!-- Dictionary templates --> -<template id="dictionary-template"><div class="settings-item dictionary-item"> -    <div class="settings-item-inner"> -        <div class="settings-item-left"> -            <div class="settings-item-label dictionary-info"> -                <label class="toggle"><input type="checkbox" class="dictionary-enabled"><span class="toggle-body"><span class="toggle-track"></span><span class="toggle-knob"></span></span></label> -                <span class="dictionary-info-label"><strong class="dictionary-title"></strong> <span class="light dictionary-version"></span></span> +<div id="dictionary-details-modal" class="modal" tabindex="-1" role="dialog" hidden><div class="modal-content"> +    <div class="modal-header"> +        <div class="modal-title"><strong class="dictionary-title"></strong> <span class="light dictionary-version"></span></div> +    </div> +    <div class="modal-body"> +        <div class="settings-item dictionary-outdated-notification" hidden><div class="settings-item-children danger-text"> +            This dictionary is outdated and may not support new extension features. +            Re-import the dictionary to enable support for the latest features. +        </div></div> +        <div class="settings-item"> +            <div class="settings-item-inner"> +                <div class="settings-item-left"> +                    <div class="settings-item-label"> +                        Prefix wildcard searches supported +                        <a class="more-toggle more-only" data-parent-distance="4">(?)</a> +                    </div> +                </div> +                <div class="settings-item-right"> +                    <label class="toggle"><input type="checkbox" class="dictionary-prefix-wildcard-searches-supported" disabled readonly><span class="toggle-body"><span class="toggle-track"></span><span class="toggle-knob"></span></span></label> +                </div> +            </div> +            <div class="settings-item-children more" hidden> +                <p class="warning-text"> +                    Changing this value requires the dictionary to be re-imported. +                </p> +                <p><a class="more-toggle" data-parent-distance="3">Hide…</a></p>              </div>          </div> -        <div class="settings-item-right"> -            <button class="icon-button dictionary-menu-button" data-menu="dictionary-menu" data-menu-position="below left"><span class="icon-button-inner"><span class="icon" data-icon="kebab-menu"></span></span></button> -        </div> +        <div class="settings-item"><div class="settings-item-children"> +            <div class="dictionary-details-table"></div> +            <div class="dictionary-counts"></div> +        </div></div>      </div> +    <div class="modal-footer"> +        <button data-modal-action="hide">Close</button> +    </div> +</div></div> + + +<!-- Dictionary templates --> +<template id="dictionary-template"> +    <label class="toggle dictionary-item-enabled-toggle-container"><input type="checkbox" class="dictionary-enabled"><span class="toggle-body"><span class="toggle-track"></span><span class="toggle-knob"></span></span></label> +    <div class="dictionary-item-title-container"> +        <span> +            <strong class="dictionary-title"></strong> <span class="light dictionary-version"></span> +        </span> +        <button class="dictionary-outdated-button" hidden> +            <div class="badge warning-badge"><span class="icon" data-icon="exclamation-point-short"></span></div> +        </button> +        <button class="dictionary-integrity-button" hidden> +            <div class="badge info-badge badge-small-icon"><span class="icon" data-icon="checkmark"></span></div> +        </button> +    </div> +    <input type="number" step="1" class="short-height dictionary-priority"> +    <button class="icon-button dictionary-menu-button" data-menu="dictionary-menu" data-menu-position="below left"><span class="icon-button-inner"><span class="icon" data-icon="kebab-menu"></span></span></button> +</template> + +<template id="dictionary-details-entry-template"><div class="dictionary-details-entry"> +    <span class="dictionary-details-entry-label"></span> +    <span class="dictionary-details-entry-info"></span>  </div></template>  <template id="dictionary-menu-template"><div class="popup-menu-container" tabindex="-1" role="dialog"><div class="popup-menu"><div class="popup-menu-body"> +    <button class="popup-menu-item" data-menu-action="showDetails">Details…</button>      <button class="popup-menu-item" data-menu-action="delete">Delete</button>  </div></div></div></template> |