diff --git a/ext/fg/float.html b/ext/fg/float.html
index dc3e159a..818bee32 100644
--- a/ext/fg/float.html
+++ b/ext/fg/float.html
@@ -15,17 +15,13 @@
+
diff --git a/ext/fg/js/float.js b/ext/fg/js/float.js
index 9f58439f..bc555ffd 100644
--- a/ext/fg/js/float.js
+++ b/ext/fg/js/float.js
@@ -63,7 +63,7 @@ class DisplayFloat extends Display {
}
onEscape() {
- this._invokeOwner('closePopup');
+ this.close();
}
async getDocumentTitle() {
@@ -83,6 +83,10 @@ class DisplayFloat extends Display {
return data.data;
}
+ close() {
+ this._invokeOwner('closePopup');
+ }
+
// Message handling
_onWindowMessage(e) {
diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css
index f6317d54..5a8c0212 100644
--- a/ext/mixed/css/display.css
+++ b/ext/mixed/css/display.css
@@ -38,6 +38,13 @@
--entry-padding: 0.72em;
+ --sidebar-width-no-units: 40;
+ --sidebar-width: calc(1em * (var(--sidebar-width-no-units) / var(--font-size-no-units)));
+ --sidebar-button-height-no-units: 30;
+ --sidebar-button-height: calc(1em * (var(--sidebar-button-height-no-units) / var(--font-size-no-units)));
+ --sidebar-button-icon-size-no-units: 16;
+ --sidebar-button-icon-size: calc(1em * (var(--sidebar-button-icon-size-no-units) / var(--font-size-no-units)));
+
/* Colors */
--background-color: #ffffff;
--glossary-image-background-color: #eeeeee;
@@ -66,6 +73,18 @@
--tag-part-of-speech-background-color: #565656;
--tag-search-background-color: #8a8a91;
--tag-pitch-accent-dictionary-background-color: #6640be;
+
+ --sidebar-background-color: #f8f9fa;
+
+ --sidebar-button-background-color: transparent;
+ --sidebar-button-background-color-hover: #cccccc;
+ --sidebar-button-background-color-active: #aaaaaa;
+ --sidebar-button-danger-background-color: transparent;
+ --sidebar-button-danger-background-color-hover: #dd2222;
+ --sidebar-button-danger-background-color-active: #bb2222;
+ --sidebar-button-icon-color: #333333;
+ --sidebar-button-disabled-icon-color: #888888;
+ --sidebar-button-danger-icon-color: #ffffff;
}
:root[data-yomichan-theme=dark] {
/* Colors */
@@ -96,6 +115,18 @@
--tag-part-of-speech-background-color: #565656;
--tag-search-background-color: #69696e;
--tag-pitch-accent-dictionary-background-color: #6640be;
+
+ --sidebar-background-color: #282828;
+
+ --sidebar-button-background-color: transparent;
+ --sidebar-button-background-color-hover: #3a3a3a;
+ --sidebar-button-background-color-active: #5a5a5a;
+ --sidebar-button-danger-background-color: transparent;
+ --sidebar-button-danger-background-color-hover: #dd2222;
+ --sidebar-button-danger-background-color-active: #bb2222;
+ --sidebar-button-icon-color: #cccccc;
+ --sidebar-button-disabled-icon-color: #777777;
+ --sidebar-button-danger-icon-color: #ffffff;
}
@@ -172,39 +203,125 @@ a {
}
-/* Navigation */
-.navigation-header {
- top: 0;
- left: 0;
+/* Sidebar layout */
+.content-outer {
width: 100%;
- height: 2.1em;
- box-sizing: border-box;
- padding: 0.25em 0.5em;
- border-bottom: var(--thin-border-size) solid var(--light-border-color);
- background-color: var(--background-color);
- z-index: 10;
-}
-.navigation-header-actions {
+ height: 100%;
display: flex;
+ flex-flow: row nowrap;
+ overflow: hidden;
+ align-items: stretch;
+ justify-content: center;
}
-.navigation-header:not([data-has-previous=true]) .navigation-header-actions .action-button.action-previous::before,
-.navigation-header:not([data-has-next=true]) .navigation-header-actions .action-button.action-next::before {
- opacity: 0.25;
- -webkit-filter: grayscale(100%);
- filter: grayscale(100%);
+.content-sidebar {
+ flex: 0 0 auto;
+ height: 100%;
+ overflow-x: hidden;
+ overflow-y: auto;
+ background-color: var(--sidebar-background-color);
+ z-index: 1;
+ position: relative;
+ display: block;
}
-.action-button.action-next::before {
- transform: scaleX(-1);
+.content-sidebar[hidden] {
+ display: none;
+}
+.content-sidebar[hidden][data-has-navigation-previous=true],
+.content-sidebar[hidden][data-has-navigation-next=true] {
+ display: block;
+}
+.content-sidebar-inner {
+ display: flex;
+ flex-flow: column nowrap;
+ width: var(--sidebar-width);
+ height: 100%;
+}
+.content-sidebar-top {
+ flex: 1 1 auto;
+ display: flex;
+ flex-flow: column nowrap;
+}
+.content-sidebar-bottom {
+ position: sticky;
+ bottom: 0;
+ background-color: var(--sidebar-background-color);
+ display: flex;
+ flex-flow: column nowrap;
}
-:root[data-yomichan-page=search] .navigation-header {
- position: sticky;
+
+/* Sidebar buttons */
+button.sidebar-button {
+ width: 100%;
+ height: var(--sidebar-button-height);
+ background-color: var(--sidebar-button-background-color);
+ margin: 0;
+ padding: 0;
+ border: 0;
+ cursor: pointer;
+ display: block;
+ transition: background-color 0.125s ease-in-out;
+ outline: none;
+ font-size: inherit;
}
-:root[data-yomichan-page=float] .navigation-header {
- position: fixed;
+button.sidebar-button:disabled {
+ cursor: default;
}
-:root[data-yomichan-page=float] .navigation-header:not([hidden])~.navigation-header-spacer {
- height: 2.1em;
+button.sidebar-button:hover:not(:disabled) {
+ background-color: var(--sidebar-button-background-color-hover);
+}
+button.sidebar-button:active:not(:disabled) {
+ background-color: var(--sidebar-button-background-color-active);
+}
+button.sidebar-button.danger {
+ background-color: var(--sidebar-button-danger-background-color);
+}
+button.sidebar-button.danger:hover:not(:disabled) {
+ background-color: var(--sidebar-button-danger-background-color-hover);
+}
+button.sidebar-button.danger:active:not(:disabled) {
+ background-color: var(--sidebar-button-danger-background-color-active);
+}
+.sidebar-button-icon {
+ display: block;
+ width: 100%;
+ height: 100%;
+ mask-repeat: no-repeat;
+ mask-position: center center;
+ mask-mode: alpha;
+ mask-size: var(--sidebar-button-icon-size) var(--sidebar-button-icon-size);
+ -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);
+ background-color: var(--sidebar-button-icon-color);
+ transition: background-color 0.125s ease-in-out;
+}
+button.sidebar-button:disabled .sidebar-button-icon {
+ background-color: var(--sidebar-button-disabled-icon-color);
+}
+button.sidebar-button.danger:hover .sidebar-button-icon {
+ background-color: var(--sidebar-button-danger-icon-color);
+}
+.sidebar-button-icon[data-icon=cross] {
+ mask-image: url(/mixed/img/cross.svg);
+ -webkit-mask-image: url(/mixed/img/cross.svg);
+}
+.sidebar-button-icon[data-icon=left-chevron] {
+ mask-image: url(/mixed/img/left-chevron.svg);
+ -webkit-mask-image: url(/mixed/img/left-chevron.svg);
+}
+.sidebar-button-icon[data-icon=right-chevron] {
+ mask-image: url(/mixed/img/right-chevron.svg);
+ -webkit-mask-image: url(/mixed/img/right-chevron.svg);
+}
+.sidebar-button-icon[data-icon=kebab-menu] {
+ mask-image: url(/mixed/img/kebab-menu.svg);
+ -webkit-mask-image: url(/mixed/img/kebab-menu.svg);
+}
+.sidebar-button-icon[data-icon=profile] {
+ mask-image: url(/mixed/img/profile.svg);
+ -webkit-mask-image: url(/mixed/img/profile.svg);
}
diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js
index f79ba303..2ee5b608 100644
--- a/ext/mixed/js/display.js
+++ b/ext/mixed/js/display.js
@@ -90,6 +90,10 @@ class Display extends EventDispatcher {
this._contentScrollBodyElement = document.querySelector('#content-body');
this._contentScrollFocusElement = document.querySelector('#content-scroll-focus');
this._windowScroll = new WindowScroll(this._contentScrollElement);
+ this._contentSidebar = document.querySelector('#content-sidebar');
+ this._closeButton = document.querySelector('#close-button');
+ this._navigationPreviousButton = document.querySelector('#navigate-previous-button');
+ this._navigationNextButton = document.querySelector('#navigate-next-button');
this.registerActions([
['close', () => { this.onEscape(); }],
@@ -406,6 +410,10 @@ class Display extends EventDispatcher {
return query;
}
+ close() {
+ // NOP
+ }
+
// Message handlers
_onMessage({action, params}, sender, callback) {
@@ -543,6 +551,11 @@ class Display extends EventDispatcher {
this.setContent(details);
}
+ _onCloseButtonClick(e) {
+ e.preventDefault();
+ this.close();
+ }
+
_onSourceTermView(e) {
e.preventDefault();
this._sourceTermView();
@@ -769,16 +782,16 @@ class Display extends EventDispatcher {
this._interactive = interactive;
if (interactive) {
- const actionPrevious = document.querySelector('.action-previous');
- const actionNext = document.querySelector('.action-next');
-
this._persistentEventListeners.addEventListener(document, 'keydown', this.onKeyDown.bind(this), false);
this._persistentEventListeners.addEventListener(document, 'wheel', this._onWheel.bind(this), {passive: false});
- if (actionPrevious !== null) {
- this._persistentEventListeners.addEventListener(actionPrevious, 'click', this._onSourceTermView.bind(this));
+ if (this._closeButton !== null) {
+ this._persistentEventListeners.addEventListener(this._closeButton, 'click', this._onCloseButtonClick.bind(this));
}
- if (actionNext !== null) {
- this._persistentEventListeners.addEventListener(actionNext, 'click', this._onNextTermView.bind(this));
+ if (this._navigationPreviousButton !== null) {
+ this._persistentEventListeners.addEventListener(this._navigationPreviousButton, 'click', this._onSourceTermView.bind(this));
+ }
+ if (this._navigationNextButton !== null) {
+ this._persistentEventListeners.addEventListener(this._navigationNextButton, 'click', this._onNextTermView.bind(this));
}
} else {
this._persistentEventListeners.removeAllEventListeners();
@@ -943,7 +956,7 @@ class Display extends EventDispatcher {
errorExtensionUnloaded.hidden = false;
}
- this._updateNavigation(null, null);
+ this._updateNavigation(false, false);
this._setNoContentVisible(false);
this._setTitleText('');
}
@@ -984,10 +997,16 @@ class Display extends EventDispatcher {
}
_updateNavigation(previous, next) {
- if (this._navigationHeader === null) { return; }
- this._navigationHeader.hidden = !(previous || next);
- this._navigationHeader.dataset.hasPrevious = `${!!previous}`;
- this._navigationHeader.dataset.hasNext = `${!!next}`;
+ if (this._contentSidebar !== null) {
+ this._contentSidebar.dataset.hasNavigationPrevious = `${previous}`;
+ this._contentSidebar.dataset.hasNavigationNext = `${next}`;
+ }
+ if (this._navigationPreviousButton !== null) {
+ this._navigationPreviousButton.disabled = !previous;
+ }
+ if (this._navigationNextButton !== null) {
+ this._navigationNextButton.disabled = !next;
+ }
}
async _updateAdderButtons(token, isTerms, definitions) {