mirror of
https://github.com/zadam/trilium.git
synced 2025-12-12 18:34:24 +01:00
feat(ribbon): basic implementation for scroll pinning
This commit is contained in:
parent
6b059a9a75
commit
0805e077a1
18
apps/client/src/widgets/containers/content_header.css
Normal file
18
apps/client/src/widgets/containers/content_header.css
Normal file
@ -0,0 +1,18 @@
|
||||
.content-header-widget {
|
||||
position: relative;
|
||||
transition: position 0.3s ease, box-shadow 0.3s ease, z-index 0.3s ease;
|
||||
z-index: 8;
|
||||
}
|
||||
|
||||
.content-header-widget.floating {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 11;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
background-color: var(--main-background-color, #fff);
|
||||
}
|
||||
|
||||
/* Ensure content inside doesn't get affected by the floating state */
|
||||
.content-header-widget > * {
|
||||
transition: inherit;
|
||||
}
|
||||
@ -2,6 +2,7 @@ import { EventData } from "../../components/app_context";
|
||||
import BasicWidget from "../basic_widget";
|
||||
import Container from "./container";
|
||||
import NoteContext from "../../components/note_context";
|
||||
import "./content_header.css";
|
||||
|
||||
export default class ContentHeader extends Container<BasicWidget> {
|
||||
|
||||
@ -11,6 +12,9 @@ export default class ContentHeader extends Container<BasicWidget> {
|
||||
resizeObserver: ResizeObserver;
|
||||
currentHeight: number = 0;
|
||||
currentSafeMargin: number = NaN;
|
||||
previousScrollTop: number = 0;
|
||||
isFloating: boolean = false;
|
||||
scrollThreshold: number = 10; // pixels before triggering float
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@ -35,7 +39,36 @@ export default class ContentHeader extends Container<BasicWidget> {
|
||||
this.thisElement = this.$widget.get(0)!;
|
||||
|
||||
this.resizeObserver.observe(this.thisElement);
|
||||
this.parentElement.addEventListener("scroll", this.updateSafeMargin.bind(this));
|
||||
this.parentElement.addEventListener("scroll", this.updateScrollState.bind(this), { passive: true });
|
||||
}
|
||||
|
||||
updateScrollState() {
|
||||
const currentScrollTop = this.parentElement!.scrollTop;
|
||||
const isScrollingUp = currentScrollTop < this.previousScrollTop;
|
||||
const hasMovedEnough = Math.abs(currentScrollTop - this.previousScrollTop) > this.scrollThreshold;
|
||||
|
||||
if (hasMovedEnough) {
|
||||
this.setFloating(isScrollingUp);
|
||||
this.previousScrollTop = currentScrollTop;
|
||||
}
|
||||
|
||||
this.updateSafeMargin();
|
||||
}
|
||||
|
||||
setFloating(shouldFloat: boolean) {
|
||||
if (shouldFloat !== this.isFloating) {
|
||||
this.isFloating = shouldFloat;
|
||||
|
||||
if (shouldFloat) {
|
||||
this.$widget.addClass("floating");
|
||||
// Set CSS variable so ribbon can position itself below the floating header
|
||||
this.parentElement!.style.setProperty("--content-header-height", `${this.currentHeight}px`);
|
||||
} else {
|
||||
this.$widget.removeClass("floating");
|
||||
// Reset CSS variable when header is not floating
|
||||
this.parentElement!.style.removeProperty("--content-header-height");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateSafeMargin() {
|
||||
|
||||
@ -1,5 +1,15 @@
|
||||
.ribbon-container {
|
||||
margin-bottom: 5px;
|
||||
position: relative;
|
||||
transition: position 0.3s ease, z-index 0.3s ease, top 0.3s ease;
|
||||
z-index: 8;
|
||||
}
|
||||
|
||||
/* When content header is floating, ribbon sticks below it */
|
||||
.scrolling-container:has(.content-header-widget.floating) .ribbon-container {
|
||||
position: sticky;
|
||||
top: var(--content-header-height, 100px);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.ribbon-top-row {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user