changeset 2:49ec0da1e698

Replace tab list scroll bar with scroll buttons
author Guido Berhoerster <guido+set-aside@berhoerster.name>
date Wed, 21 Nov 2018 11:39:07 +0100
parents b0827360b8e4
children 48b036902118
files sidebar/images/scroll-arrow.svg sidebar/js/tab-collection-manager.js sidebar/style/tab-collection-manager.css sidebar/tab-collection-manager.html
diffstat 4 files changed, 118 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sidebar/images/scroll-arrow.svg	Wed Nov 21 11:39:07 2018 +0100
@@ -0,0 +1,11 @@
+<!--
+Copyright (C) 2018 Guido Berhoerster <guido+set-aside@berhoerster.name>
+
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, You can obtain one at http://mozilla.org/MPL/2.0/.
+-->
+<svg version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
+  <path fill="none" stroke="#0c0c0d" stroke-width="2" stroke-linecap="round"
+  d="m18 2l-12 10l12 10"/>
+</svg>
--- a/sidebar/js/tab-collection-manager.js	Mon Nov 19 17:26:17 2018 +0100
+++ b/sidebar/js/tab-collection-manager.js	Wed Nov 21 11:39:07 2018 +0100
@@ -38,6 +38,8 @@
 
         document.body.addEventListener('click', this);
 
+        window.addEventListener('optimizedResize', this);
+
         this.isInitialized = true;
     }
 
@@ -104,6 +106,7 @@
                 'to tab collections');
         this.tabCollectionsElement
                 .prepend(this.createTabCollectionNode(tabCollection));
+        this.handleResize();
     }
 
     replaceTabCollection(tabCollection) {
@@ -111,6 +114,7 @@
         this.tabCollectionsElement.querySelector(`[data-tab-collection-uuid=` +
                 `"${tabCollection.uuid}"]`)
                 .replaceWith(this.createTabCollectionNode(tabCollection));
+        this.handleResize();
     }
 
     removeTabCollection(tabCollectionUuid) {
@@ -158,6 +162,31 @@
         this.sortTabCollections();
     }
 
+    handleTabCollectionChanged(tabCollectionContainerElement) {
+        let tabsElement = tabCollectionContainerElement
+                .querySelector('.tab-collection-tabs');
+        let scrollLeftElement = tabCollectionContainerElement
+                .querySelector('.scroll-left');
+        let scrollRightElement = tabCollectionContainerElement
+                .querySelector('.scroll-right');
+        if (tabsElement.scrollWidth > tabsElement.clientWidth) {
+            scrollLeftElement.classList.add('scroll-visible');
+            scrollRightElement.classList.add('scroll-visible');
+        } else {
+            scrollLeftElement.classList.remove('scroll-visible');
+            scrollRightElement.classList.remove('scroll-visible');
+        }
+    }
+
+    handleResize() {
+        let tabCollectionContainerElements =
+                document.querySelectorAll('.tab-collection-tabs-container');
+        for (let tabCollectionContainerElement of
+                tabCollectionContainerElements) {
+            this.handleTabCollectionChanged(tabCollectionContainerElement);
+        }
+    }
+
     handleEvent(ev) {
         console.log('DOM event', ev);
         if (ev.type === 'click') {
@@ -191,6 +220,19 @@
                     tabCollectionUuid,
                     tabUuid
                 });
+            } else if (ev.target.classList.contains('tabs-scroll-button')) {
+                // scroll tab list
+                let tabsElement = ev.target
+                        .closest('.tab-collection-tabs-container')
+                        .querySelector('.tab-collection-tabs');
+                if (ev.target.classList.contains('scroll-left')) {
+                    tabsElement.scrollLeft = Math.max(tabsElement.scrollLeft -
+                            tabsElement.clientWidth * .75, 0);
+                } else {
+                    tabsElement.scrollLeft = Math.min(tabsElement.scrollLeft +
+                            tabsElement.clientWidth * .75,
+                            tabsElement.scrollLeftMax);
+                }
             } else {
                 let tabItemElement = ev.target.closest('.tab-item');
                 if (tabItemElement !== null) {
@@ -207,6 +249,9 @@
                     });
                 }
             }
+        } else if (ev.type === 'optimizedResize') {
+            // window has been resized
+            this.handleResize();
         }
     }
 }
@@ -219,5 +264,23 @@
         return;
     }
 
+    function throttleResize(type, name, obj) {
+        obj = obj || window;
+        var isRunning = false;
+        var func = function() {
+            if (isRunning) {
+                return;
+            }
+
+            isRunning = true;
+            requestAnimationFrame(function() {
+                obj.dispatchEvent(new CustomEvent(name));
+                isRunning = false;
+            });
+        };
+        obj.addEventListener(type, func);
+    };
+    throttleResize('resize', 'optimizedResize');
+
     tabManager = new TabManager();
 });
--- a/sidebar/style/tab-collection-manager.css	Mon Nov 19 17:26:17 2018 +0100
+++ b/sidebar/style/tab-collection-manager.css	Wed Nov 21 11:39:07 2018 +0100
@@ -18,6 +18,14 @@
   --font-size-body-20: 15px;
   --font-size-body-10: 13px;
 
+  --scroll-button-image-width: 24px;
+  --scroll-button-image-height: var(--scroll-button-image-width);
+  --scroll-button-padding: 4px;
+  --scroll-button-width: calc(2 * var(--scroll-button-padding) +
+      var(--scroll-button-image-width));
+  --scroll-button-height: var(--scroll-button-width);
+  --scroll-button-highlight: var(--grey-90-a10);
+
   --thumbnail-width: 224px;
   --thumbnail-height: 128px;
   --thumbnail-shadow: var(--box-shadow-border), 0 1px 4px var(--grey-90-a30);
@@ -112,7 +120,6 @@
   padding-left: 0;
   margin: 0;
   list-style: none;
-  overflow: auto;
 }
 
 .tab-collection-actions {
@@ -146,8 +153,37 @@
   text-decoration: underline;
 }
 
+.tabs-scroll-button {
+  visibility: hidden;
+  position: absolute;
+  margin-top: calc(var(--remove-tab-overlap) + var(--thumbnail-height) / 2 -
+      var(--scroll-button-height) / 2);
+  width: var(--scroll-button-width);
+  height: var(--scroll-button-height);
+  background: url(../images/scroll-arrow.svg)
+      var(--scroll-button-padding)/var(--scroll-button-image-width) no-repeat
+      var(--scroll-button-highlight);
+  border-radius: 4px;
+  z-index: 999;
+  transition: visibility 300ms;
+}
+
+.tab-collection-tabs-container:hover .tabs-scroll-button.scroll-visible {
+  visibility: visible;
+}
+
+.tabs-scroll-button.scroll-left {
+  left: 0;
+}
+
+.tabs-scroll-button.scroll-right {
+  transform: scaleX(-1);
+  right: 0;
+}
+
 .tab-collection-tabs {
-  margin: 4px 0 0 0;
+  overflow: hidden;
+  scroll-behavior: smooth;
 }
 
 .tab-item {
--- a/sidebar/tab-collection-manager.html	Mon Nov 19 17:26:17 2018 +0100
+++ b/sidebar/tab-collection-manager.html	Wed Nov 21 11:39:07 2018 +0100
@@ -23,8 +23,12 @@
           <li><div class="restore-tab-collection" title=""></div></li>
           <li><div class="remove-tab-collection" title=""></div></li>
         </ul>
-        <ul class="tab-collection-tabs">
-        </ul>
+        <div class="tab-collection-tabs-container">
+          <div class="tabs-scroll-button scroll-left scroll-invisible"></div>
+          <div class="tabs-scroll-button scroll-right scroll-invisible"></div>
+          <ul class="tab-collection-tabs">
+          </ul>
+        </div>
       </div>
     </template>
     <template id="tab-item-template">