Merge pull request '[PR]: Bring back the scrollable sticky widgets sidebar' (#10294) from Freeplay/calckey:sticky into develop

Reviewed-on: https://codeberg.org/calckey/calckey/pulls/10294
This commit is contained in:
Kainoa Kanter 2023-06-11 12:17:30 +00:00
commit 7034869838
3 changed files with 63 additions and 73 deletions

View file

@ -2,79 +2,56 @@ export class StickySidebar {
private lastScrollTop = 0; private lastScrollTop = 0;
private container: HTMLElement; private container: HTMLElement;
private el: HTMLElement; private el: HTMLElement;
private spacer: HTMLElement;
private marginTop: number;
private isTop = false; private isTop = false;
private isBottom = false; private isBottom = false;
private offsetTop: number; private offsetTop: number;
private globalHeaderHeight = 59;
constructor( constructor(
container: StickySidebar["container"], container: StickySidebar["container"],
marginTop = 0,
globalHeaderHeight = 0,
) { ) {
this.container = container; this.container = container;
this.container.style.display = "flex";
this.el = this.container.children[0] as HTMLElement; this.el = this.container.children[0] as HTMLElement;
this.el.style.position = "sticky"; this.el.style.position = "sticky";
this.spacer = document.createElement("div");
this.container.prepend(this.spacer);
this.marginTop = marginTop;
this.offsetTop = this.container.getBoundingClientRect().top; this.offsetTop = this.container.getBoundingClientRect().top;
this.globalHeaderHeight = globalHeaderHeight;
} }
public calc(scrollTop: number) { public calc(scrollTop: number) {
if (scrollTop > this.lastScrollTop) { if (scrollTop > this.lastScrollTop) {
// downscroll // downscroll
const overflow = Math.max(
0,
this.globalHeaderHeight +
(this.el.clientHeight + this.marginTop) -
window.innerHeight,
);
this.el.style.bottom = null;
this.el.style.top = `${
-overflow + this.marginTop + this.globalHeaderHeight
}px`;
this.isBottom =
scrollTop + window.innerHeight >=
this.el.offsetTop + this.el.clientHeight;
if (this.isTop) {
this.isTop = false; this.isTop = false;
this.spacer.style.marginTop = `${Math.max( this.isBottom =
0, scrollTop + window.innerHeight >
this.globalHeaderHeight + this.el.offsetTop + this.el.clientHeight;
this.lastScrollTop +
this.marginTop -
this.offsetTop,
)}px`;
}
} else { } else {
// upscroll // upscroll
const overflow =
this.globalHeaderHeight +
(this.el.clientHeight + this.marginTop) -
window.innerHeight;
this.el.style.top = null;
this.el.style.bottom = `${-overflow}px`;
this.isTop =
scrollTop + this.marginTop + this.globalHeaderHeight <=
this.el.offsetTop;
if (this.isBottom) {
this.isBottom = false; this.isBottom = false;
this.spacer.style.marginTop = `${ this.isTop = scrollTop < this.el.offsetTop + 1;
this.globalHeaderHeight +
this.lastScrollTop +
this.marginTop -
this.offsetTop -
overflow
}px`;
} }
if (this.isTop) {
if (this.el.style.alignSelf != "flex-start") {
this.el.style.position = "sticky";
this.el.style.bottom = null;
this.el.style.top = "0px";
this.el.style.alignSelf = "flex-start";
console.log("top");
}
this.offsetTop = scrollTop;
} else if (this.isBottom) {
if (this.el.style.alignSelf != "flex-end") {
this.el.style.position = "sticky";
this.el.style.bottom = "0px";
this.el.style.top = null;
this.el.style.alignSelf = "flex-end";
console.log("bottom");
}
this.offsetTop = window.innerHeight + scrollTop - this.el.scrollHeight;
} else {
this.el.style.position = "relative";
this.el.style.top = this.offsetTop + "px";
this.el.style.bottom = null;
this.el.style.alignSelf = null;
} }
this.lastScrollTop = scrollTop <= 0 ? 0 : scrollTop; this.lastScrollTop = scrollTop <= 0 ? 0 : scrollTop;

View file

@ -20,7 +20,7 @@
</MkStickyContainer> </MkStickyContainer>
<div v-if="isDesktop" ref="widgetsEl" class="widgets-container"> <div v-if="isDesktop" ref="widgetsEl" class="widgets-container">
<XWidgets /> <XWidgets @mounted="attachSticky" />
</div> </div>
<button <button
@ -380,6 +380,20 @@ const onContextmenu = (ev: MouseEvent) => {
); );
}; };
const attachSticky = (el: any) => {
let lastScrollTop = 0;
addEventListener(
"scroll",
(ev) => {
requestAnimationFrame(() => {
widgetsEl.scrollTop += window.scrollY - lastScrollTop;
lastScrollTop = window.scrollY <= 0 ? 0 : window.scrollY;
});
},
{ passive: true }
);
};
function top() { function top() {
window.scroll({ top: 0, behavior: "smooth" }); window.scroll({ top: 0, behavior: "smooth" });
} }
@ -440,7 +454,7 @@ console.log(mainRouter.currentRoute.value.name);
$widgets-hide-threshold: 1090px; $widgets-hide-threshold: 1090px;
// 100vh ... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/ // 100vh ... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
height: 100%; min-height: calc(var(--vh, 1vh) * 100);
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
@ -550,13 +564,17 @@ console.log(mainRouter.currentRoute.value.name);
} }
> .widgets-container { > .widgets-container {
margin-right: calc(var(--margin) / 2); position: sticky;
width: calc(300px + (var(--margin) * 1.5)); top: 0;
flex: 0 0 auto; max-height: 100vh;
overflow-y: auto;
padding: 0 var(--margin);
width: 300px;
min-width: max-content;
box-sizing: content-box; box-sizing: content-box;
> :deep(.widgets) { scrollbar-width: none;
padding-left: var(--margin); &::-webkit-scrollbar {
padding-right: calc(var(--margin) / 2); display: none;
} }
@media (max-width: $widgets-hide-threshold) { @media (max-width: $widgets-hide-threshold) {

View file

@ -84,23 +84,18 @@ function updateWidgets(widgets) {
<style lang="scss" scoped> <style lang="scss" scoped>
.widgets { .widgets {
position: sticky;
top: var(--stickyTop, 0px);
height: min-content; height: min-content;
min-height: 100vh; min-height: 100vh;
max-height: 100vh; padding: var(--margin) 0;
box-sizing: content-box; box-sizing: border-box;
overflow: hidden auto;
&:not(:hover):not(:focus-within)::-webkit-scrollbar {
width: 0;
}
> * { > * {
margin: var(--margin) 0; margin: var(--margin) 0;
width: 300px; width: 300px;
&:first-child {
margin-top: 0;
} }
> :first-child {
margin-top: calc(var(--margin) * 2);
} }
> .add { > .add {