]> BookStack Code Mirror - bookstack/commitdiff
Layout: Added scroll fade to the sidebars
authorDan Brown <redacted>
Mon, 30 Jun 2025 13:10:48 +0000 (14:10 +0100)
committerDan Brown <redacted>
Mon, 30 Jun 2025 13:10:48 +0000 (14:10 +0100)
resources/js/components/tri-layout.js
resources/sass/_layout.scss
resources/views/layouts/tri.blade.php

index be9388e8d4615f5919a81068ff57915bc9d52ae9..85533da5eeddf89838dc0001678046322a1237d4 100644 (file)
@@ -5,6 +5,7 @@ export class TriLayout extends Component {
     setup() {
         this.container = this.$refs.container;
         this.tabs = this.$manyRefs.tab;
+        this.sidebarScrollContainers = this.$manyRefs.sidebarScrollContainer;
 
         this.lastLayoutType = 'none';
         this.onDestroy = null;
@@ -22,6 +23,8 @@ export class TriLayout extends Component {
         window.addEventListener('resize', () => {
             this.updateLayout();
         }, {passive: true});
+
+        this.setupSidebarScrollHandlers();
     }
 
     updateLayout() {
@@ -108,4 +111,28 @@ export class TriLayout extends Component {
         this.lastTabShown = tabName;
     }
 
+    setupSidebarScrollHandlers() {
+        for (const sidebar of this.sidebarScrollContainers) {
+            sidebar.addEventListener('scroll', () => this.handleSidebarScroll(sidebar), {
+                passive: true,
+            });
+            this.handleSidebarScroll(sidebar);
+        }
+
+        window.addEventListener('resize', () => {
+            for (const sidebar of this.sidebarScrollContainers) {
+                this.handleSidebarScroll(sidebar);
+            }
+        });
+    }
+
+    handleSidebarScroll(sidebar) {
+        const scrollable = sidebar.clientHeight !== sidebar.scrollHeight;
+        const atTop = sidebar.scrollTop === 0;
+        const atBottom = (sidebar.scrollTop + sidebar.clientHeight) === sidebar.scrollHeight;
+
+        sidebar.parentElement.classList.toggle('scroll-away-from-top', !atTop && scrollable);
+        sidebar.parentElement.classList.toggle('scroll-away-from-bottom', !atBottom && scrollable);
+    }
+
 }
index 58c06f4ac99fa276a56129ae262a8be1293901da..48b4b0ca22ef5d28430140049b817c6fbba2e217 100644 (file)
@@ -389,10 +389,12 @@ body.flexbox {
 .tri-layout-right {
   grid-area: c;
   min-width: 0;
+  position: relative;
 }
 .tri-layout-left {
   grid-area: a;
   min-width: 0;
+  position: relative;
 }
 
 @include mixins.larger-than(vars.$bp-xxl) {
@@ -523,4 +525,26 @@ body.flexbox {
     margin-inline-start: 0;
     margin-inline-end: 0;
   }
+}
+
+/**
+ * Scroll Indicators
+ */
+.scroll-away-from-top:before,
+.scroll-away-from-bottom:after {
+  content: '';
+  display: block;
+  position: absolute;
+  @include mixins.lightDark(color, #F2F2F2, #111);
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 50px;
+  background: linear-gradient(to bottom, currentColor, transparent);
+  z-index: 2;
+}
+.scroll-away-from-bottom:after {
+  top: auto;
+  bottom: 0;
+  background: linear-gradient(to top, currentColor, transparent);
 }
\ No newline at end of file
index c3cedf0fbc2a2106c91f954b3a8142cb16db53c2..061cc69945c3dcace59ea8bed5401a21f3ed3773 100644 (file)
     <div refs="tri-layout@container" class="tri-layout-container" @yield('container-attrs') >
 
         <div class="tri-layout-sides print-hidden">
-            <div class="tri-layout-sides-content">
+            <div refs="tri-layout@sidebar-scroll-container" class="tri-layout-sides-content">
                 <div class="tri-layout-right print-hidden">
-                    <aside class="tri-layout-right-contents">
+                    <aside refs="tri-layout@sidebar-scroll-container" class="tri-layout-right-contents">
                         @yield('right')
                     </aside>
                 </div>
 
                 <div class="tri-layout-left print-hidden" id="sidebar">
-                    <aside class="tri-layout-left-contents">
+                    <aside refs="tri-layout@sidebar-scroll-container" class="tri-layout-left-contents">
                         @yield('left')
                     </aside>
                 </div>