diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-12-18 09:43:54 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-12-18 09:43:54 -0500 | 
| commit | bf349050123eaaa7b58f82b7e3a84e2857fdea8c (patch) | |
| tree | acebf6669a642d4c6f0e0f8bf5fc07ff9e194a4f | |
| parent | c3e772fadc8d0cba975284af774fc2266de44723 (diff) | |
Improve display tags (#1117)
* Update tag style
* Add styles/HTML for notifications
* Add DisplayNotification class
* Add support for tag notifications
* Simplify notification content
| -rw-r--r-- | ext/bg/search.html | 2 | ||||
| -rw-r--r-- | ext/fg/float.html | 2 | ||||
| -rw-r--r-- | ext/mixed/css/display.css | 88 | ||||
| -rw-r--r-- | ext/mixed/display-templates.html | 6 | ||||
| -rw-r--r-- | ext/mixed/js/display-generator.js | 7 | ||||
| -rw-r--r-- | ext/mixed/js/display-notification.js | 90 | ||||
| -rw-r--r-- | ext/mixed/js/display.js | 26 | 
7 files changed, 221 insertions, 0 deletions
| diff --git a/ext/bg/search.html b/ext/bg/search.html index c0f98d8c..34d36478 100644 --- a/ext/bg/search.html +++ b/ext/bg/search.html @@ -65,6 +65,7 @@                  </div>              </div>          </div> +        <div class="content-footer-container1"><div class="content-footer-container2"><div class="content-footer" id="content-footer"></div><div class="scrollbar-spacer scrollbar"></div></div></div>      </div>  </div> @@ -87,6 +88,7 @@  <script src="/mixed/js/display.js"></script>  <script src="/mixed/js/display-generator.js"></script>  <script src="/mixed/js/display-history.js"></script> +<script src="/mixed/js/display-notification.js"></script>  <script src="/mixed/js/dynamic-loader.js"></script>  <script src="/mixed/js/media-loader.js"></script>  <script src="/mixed/js/scroll.js"></script> diff --git a/ext/fg/float.html b/ext/fg/float.html index 50c3b691..41e73a7e 100644 --- a/ext/fg/float.html +++ b/ext/fg/float.html @@ -52,6 +52,7 @@                  </div>              </div>          </div> +        <div class="content-footer-container1"><div class="content-footer-container2"><div class="content-footer" id="content-footer"></div><div class="scrollbar-spacer scrollbar"></div></div></div>      </div>      <div class="content-sidebar scrollbar" id="content-sidebar" hidden>          <div class="content-sidebar-inner"> @@ -91,6 +92,7 @@  <script src="/mixed/js/display.js"></script>  <script src="/mixed/js/display-generator.js"></script>  <script src="/mixed/js/display-history.js"></script> +<script src="/mixed/js/display-notification.js"></script>  <script src="/mixed/js/dynamic-loader.js"></script>  <script src="/mixed/js/frame-endpoint.js"></script>  <script src="/mixed/js/media-loader.js"></script> diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css index 0a676a8f..d95aee2f 100644 --- a/ext/mixed/css/display.css +++ b/ext/mixed/css/display.css @@ -126,6 +126,10 @@      --progress-bar-track-color: #cccccc;      --progress-bar-indicator-color: var(--accent-color);      --entry-current-indicator-color: var(--accent-color); + +    --notification-text-color: #ffffff; +    --notification-background-color: #333333; +    --notification-shadow-color: rgba(0, 0, 0, 0.5);  }  :root[data-theme=dark] {      /* Colors */ @@ -182,6 +186,10 @@      --progress-bar-track-color: #3a3a3a;      --progress-bar-indicator-color: var(--accent-color);      --entry-current-indicator-color: var(--accent-color); + +    --notification-text-color: #2f2f2f; +    --notification-background-color: #e1e1e1; +    --notification-shadow-color: rgba(255, 255, 255, 0.25);  } @@ -252,6 +260,13 @@ a {  :root:not([data-theme=default]) .scrollbar::-webkit-scrollbar-corner {      background-color: var(--scrollbar-track-color);  } +.scrollbar-spacer { +    display: inline-block; +    overflow-x: hidden; +    overflow-y: scroll; +    visibility: hidden; +    flex: 0 1 auto; +}  /* Main layout */ @@ -284,6 +299,27 @@ a {      width: 100%;      padding: var(--main-content-vertical-padding) var(--main-content-horizontal-padding);  } +.content-footer-container1 { +    display: flex; +    flex-flow: row nowrap; +    position: absolute; +    left: 0; +    right: 0; +    bottom: 0; +    max-height: 100%; +    pointer-events: none; +    z-index: 5; +} +.content-footer-container2 { +    display: flex; +    flex-flow: row nowrap; +    justify-content: center; +    flex: 1 1 auto; +} +.content-footer { +    max-width: var(--main-content-size); +    width: 100%; +}  /* Sidebar layout */ @@ -519,6 +555,7 @@ button.action-button {      background-color: var(--tag-default-background-color);      border: var(--tag-border-size) var(--tag-border-style) var(--tag-border-color);      margin-right: 0.375em; +    cursor: pointer;  }  .tag[data-category=name] {      background-color: var(--tag-name-background-color); @@ -1165,6 +1202,57 @@ button.action-button {  } +/* Footer notifications */ +.footer-notification { +    display: flex; +    flex-flow: row nowrap; +    align-items: center; +    pointer-events: auto; +    border-radius: 0.25em; +    background-color: var(--notification-background-color); +    box-shadow: 0 0.125em 0.25em 0 var(--notification-shadow-color); +    color: var(--notification-text-color); +    margin: 0.5em; +    padding: 0.5em 0.75em; +    transition: opacity var(--animation-duration) ease-out; +} +.footer-notification[hidden] { +    display: flex; +    opacity: 0; +    transition: opacity var(--animation-duration) ease-in; +} +.footer-notification-body { +    flex: 1 1 auto; +    padding-right: 0.5em; +} +.footer-notification-close-button { +    flex: 0 0 auto; +    background-color: transparent; +    margin: -0.25em; +    padding: 0.5em; +    border: none; +    outline: none; +    cursor: pointer; +    font-size: inherit; +} +.footer-notification-close-button-icon { +    display: block; +    width: calc(12em / var(--font-size-no-units)); +    height: calc(12em / var(--font-size-no-units)); +    mask-repeat: no-repeat; +    mask-position: center center; +    mask-mode: alpha; +    mask-size: var(--sidebar-button-icon-size) var(--sidebar-button-icon-size); +    mask-image: url(/mixed/img/cross.svg); +    -webkit-mask-repeat: no-repeat; +    -webkit-mask-position: center center; +    -webkit-mask-mode: alpha; +    -webkit-mask-size: var(--sidebar-button-icon-size) var(--sidebar-button-icon-size); +    -webkit-mask-image: url(/mixed/img/cross.svg); +    background-color: var(--notification-text-color); +} + +  /* Conditional styles */  :root:not([data-enable-search-tags=true]) .tag[data-category=search] {      display: none; diff --git a/ext/mixed/display-templates.html b/ext/mixed/display-templates.html index 3953098d..40d11d7a 100644 --- a/ext/mixed/display-templates.html +++ b/ext/mixed/display-templates.html @@ -117,4 +117,10 @@      </span>  </span></template> +<!-- Extra --> +<template id="footer-notification-template"><div class="footer-notification"> +    <div class="footer-notification-body"></div> +    <button class="footer-notification-close-button"><span class="footer-notification-close-button-icon"></span></button> +</div></template> +  </body></html> diff --git a/ext/mixed/js/display-generator.js b/ext/mixed/js/display-generator.js index 1810000b..1ccd5941 100644 --- a/ext/mixed/js/display-generator.js +++ b/ext/mixed/js/display-generator.js @@ -117,6 +117,10 @@ class DisplayGenerator {          return node;      } +    createEmptyFooterNotification() { +        return this._templates.instantiate('footer-notification'); +    } +      // Private      _createTermExpression(details) { @@ -310,6 +314,7 @@ class DisplayGenerator {          node.title = details.notes;          inner.textContent = details.name; +        node.dataset.details = details.notes || details.name;          node.dataset.category = details.category;          if (details.redundant) { node.dataset.redundant = 'true'; } @@ -472,6 +477,7 @@ class DisplayGenerator {          node.dataset.readingIsSame = `${reading === expression}`;          node.dataset.dictionary = dictionary;          node.dataset.frequency = frequency; +        node.dataset.details = `${dictionary}: ${frequency}`;          return node;      } @@ -486,6 +492,7 @@ class DisplayGenerator {          node.dataset.character = character;          node.dataset.dictionary = dictionary;          node.dataset.frequency = frequency; +        node.dataset.details = `${dictionary}: ${frequency}`;          return node;      } diff --git a/ext/mixed/js/display-notification.js b/ext/mixed/js/display-notification.js new file mode 100644 index 00000000..2d3c50bb --- /dev/null +++ b/ext/mixed/js/display-notification.js @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2017-2020  Yomichan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <https://www.gnu.org/licenses/>. + */ + +class DisplayNotification { +    constructor(container, node) { +        this._container = container; +        this._node = node; +        this._body = node.querySelector('.footer-notification-body'); +        this._closeButton = node.querySelector('.footer-notification-close-button'); +        this._eventListeners = new EventListenerCollection(); +        this._closeTimer = null; +    } + +    open() { +        if (!this.isClosed()) { return; } + +        this._clearTimer(); + +        const node = this._node; +        this._container.appendChild(node); +        const style = getComputedStyle(node); +        node.hidden = true; +        style.getPropertyValue('opacity'); // Force CSS update, allowing animation +        node.hidden = false; +        this._eventListeners.addEventListener(this._closeButton, 'click', this._onCloseButtonClick.bind(this), false); +    } + +    close(animate=false) { +        if (this.isClosed()) { return; } + +        if (animate) { +            if (this._closeTimer !== null) { return; } + +            this._node.hidden = true; +            this._closeTimer = setTimeout(this._onDelayClose.bind(this), 200); +        } else { +            this._clearTimer(); + +            this._eventListeners.removeAllEventListeners(); +            const parent = this._node.parentNode; +            if (parent !== null) { +                parent.removeChild(this._node); +            } +        } +    } + +    setContent(text) { +        this._body.textContent = text; +    } + +    isClosing() { +        return this._closeTimer !== null; +    } + +    isClosed() { +        return this._node.parentNode === null; +    } + +    // Private + +    _onCloseButtonClick() { +        this.close(true); +    } + +    _onDelayClose() { +        this._closeTimer = null; +        this.close(false); +    } + +    _clearTimer() { +        if (this._closeTimer !== null) { +            clearTimeout(this._closeTimer); +            this._closeTimer = null; +        } +    } +} diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index 26a05abd..77bf9649 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -20,6 +20,7 @@   * AudioSystem   * DisplayGenerator   * DisplayHistory + * DisplayNotification   * DocumentUtil   * FrameEndpoint   * Frontend @@ -114,6 +115,8 @@ class Display extends EventDispatcher {          this._frameResizeStartSize = null;          this._frameResizeStartOffset = null;          this._frameResizeEventListeners = new EventListenerCollection(); +        this._tagNotification = null; +        this._tagNotificationContainer = document.querySelector('#content-footer');          this.registerActions([              ['close',             () => { this.onEscape(); }], @@ -543,6 +546,7 @@ class Display extends EventDispatcher {              this._closePopups();              this._eventListeners.removeAllEventListeners();              this._mediaLoader.unloadAll(); +            this._hideTagNotification(false);              // Prepare              const urlSearchParams = new URLSearchParams(location.search); @@ -799,6 +803,27 @@ class Display extends EventDispatcher {          this._entrySetCurrent(index);      } +    _onTagClick(e) { +        const node = e.currentTarget; +        const {dataset: {details}} = node; +        this._showTagNotification(details); +    } + +    _showTagNotification(content) { +        if (this._tagNotification === null) { +            const node = this._displayGenerator.createEmptyFooterNotification(); +            this._tagNotification = new DisplayNotification(this._tagNotificationContainer, node); +        } + +        this._tagNotification.setContent(content); +        this._tagNotification.open(); +    } + +    _hideTagNotification(animate) { +        if (this._tagNotification === null) { return; } +        this._tagNotification.close(animate); +    } +      _updateDocumentOptions(options) {          const data = document.documentElement.dataset;          data.ankiEnabled = `${options.anki.enable}`; @@ -1720,6 +1745,7 @@ class Display extends EventDispatcher {          this._addMultipleEventListeners(entry, '.action-play-audio', 'click', this._onAudioPlay.bind(this));          this._addMultipleEventListeners(entry, '.kanji-link', 'click', this._onKanjiLookup.bind(this));          this._addMultipleEventListeners(entry, '.debug-log-link', 'click', this._onDebugLogClick.bind(this)); +        this._addMultipleEventListeners(entry, '.tag', 'click', this._onTagClick.bind(this));      }      _updateDefinitionTextScanner(options) { |