mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-12-24 05:33:08 +02:00
Resolve #6500
This commit is contained in:
parent
ade11aa447
commit
c25cf7f89a
4 changed files with 90 additions and 12 deletions
|
@ -87,8 +87,9 @@
|
|||
</main>
|
||||
|
||||
<template v-if="isDesktop">
|
||||
<div class="widgets" :class="{ edit: widgetsEditMode, fixed: $store.state.device.fixedWidgetsPosition }" v-for="place in ['left', 'right']" :key="place">
|
||||
<template v-if="widgetsEditMode">
|
||||
<div v-for="place in ['left', 'right']" ref="widgets" class="widgets" :class="{ edit: widgetsEditMode, fixed: $store.state.device.fixedWidgetsPosition, empty: widgets[place].length === 0 && !widgetsEditMode }" :key="place">
|
||||
<div class="spacer"></div>
|
||||
<div class="container" v-if="widgetsEditMode">
|
||||
<mk-button primary @click="addWidget(place)" class="add"><fa :icon="faPlus"/></mk-button>
|
||||
<x-draggable
|
||||
:list="widgets[place]"
|
||||
|
@ -106,8 +107,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</x-draggable>
|
||||
</template>
|
||||
<component v-else class="_widget" v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget"/>
|
||||
</div>
|
||||
<div class="container" v-else>
|
||||
<component class="_widget" v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
@ -134,6 +137,7 @@ import { ResizeObserver } from '@juggle/resize-observer';
|
|||
import { v4 as uuid } from 'uuid';
|
||||
import { host, instanceName } from './config';
|
||||
import { search } from './scripts/search';
|
||||
import { StickySidebar } from './scripts/sticky-sidebar';
|
||||
|
||||
const DESKTOP_THRESHOLD = 1100;
|
||||
|
||||
|
@ -232,6 +236,12 @@ export default Vue.extend({
|
|||
this.showNav = false;
|
||||
this.canBack = (window.history.length > 0 && !['index'].includes(to.name));
|
||||
},
|
||||
|
||||
isDesktop() {
|
||||
this.$nextTick(() => {
|
||||
this.attachSticky();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
|
@ -277,9 +287,24 @@ export default Vue.extend({
|
|||
if (window.innerWidth >= DESKTOP_THRESHOLD) this.isDesktop = true;
|
||||
}, { passive: true });
|
||||
}
|
||||
|
||||
// widget follow
|
||||
this.attachSticky();
|
||||
},
|
||||
|
||||
methods: {
|
||||
attachSticky() {
|
||||
if (!this.isDesktop) return;
|
||||
if (this.$store.state.device.fixedWidgetsPosition) return;
|
||||
|
||||
const stickyWidgetColumns = this.$refs.widgets.map(w => new StickySidebar(w.children[1], w.children[0], w.offsetTop));
|
||||
window.addEventListener('scroll', () => {
|
||||
for (const stickyWidgetColumn of stickyWidgetColumns) {
|
||||
stickyWidgetColumn.calc(window.scrollY);
|
||||
}
|
||||
}, { passive: true });
|
||||
},
|
||||
|
||||
top() {
|
||||
window.scroll({ top: 0, behavior: 'smooth' });
|
||||
},
|
||||
|
@ -988,15 +1013,14 @@ export default Vue.extend({
|
|||
}
|
||||
|
||||
> .widgets {
|
||||
top: $header-height;
|
||||
min-height: calc(100vh - #{$header-height});
|
||||
padding: 0 var(--margin);
|
||||
box-shadow: 1px 0 0 0 var(--divider), -1px 0 0 0 var(--divider);
|
||||
|
||||
&.fixed {
|
||||
position: sticky;
|
||||
height: calc(100vh - #{$header-height});
|
||||
overflow: auto;
|
||||
height: calc(100vh - #{$header-height});
|
||||
top: $header-height;
|
||||
}
|
||||
|
||||
&:first-of-type {
|
||||
|
@ -1007,7 +1031,7 @@ export default Vue.extend({
|
|||
}
|
||||
}
|
||||
|
||||
&:empty {
|
||||
&.empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -1015,9 +1039,16 @@ export default Vue.extend({
|
|||
display: none;
|
||||
}
|
||||
|
||||
> * {
|
||||
margin: var(--margin) 0;
|
||||
width: 300px;
|
||||
> .container {
|
||||
position: sticky;
|
||||
height: min-content;
|
||||
min-height: calc(100vh - #{$header-height});
|
||||
overflow: hidden;
|
||||
|
||||
> * {
|
||||
margin: var(--margin) 0;
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
> .add {
|
||||
|
|
|
@ -265,6 +265,10 @@ export default Vue.extend({
|
|||
}
|
||||
location.reload();
|
||||
},
|
||||
|
||||
fixedWidgetsPosition() {
|
||||
location.reload()
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
|
43
src/client/scripts/sticky-sidebar.ts
Normal file
43
src/client/scripts/sticky-sidebar.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
export class StickySidebar {
|
||||
private lastScrollTop = 0;
|
||||
private el: HTMLElement;
|
||||
private spacer: HTMLElement;
|
||||
private marginTop: number;
|
||||
private isTop = false;
|
||||
private isBottom = false;
|
||||
|
||||
constructor(el: StickySidebar['el'], spacer: StickySidebar['spacer'], marginTop = 0) {
|
||||
this.el = el;
|
||||
this.spacer = spacer;
|
||||
this.marginTop = marginTop;
|
||||
}
|
||||
|
||||
public calc(scrollTop: number) {
|
||||
if (scrollTop > this.lastScrollTop) { // downscroll
|
||||
const overflow = this.el.clientHeight - window.innerHeight;
|
||||
this.el.style.bottom = null;
|
||||
this.el.style.top = `${-overflow}px`;
|
||||
|
||||
this.isBottom = (scrollTop + window.innerHeight) >= (this.el.offsetTop + this.el.clientHeight);
|
||||
|
||||
if (this.isTop) {
|
||||
this.isTop = false;
|
||||
this.spacer.style.marginTop = `${scrollTop}px`;
|
||||
}
|
||||
} else { // upscroll
|
||||
const overflow = this.el.clientHeight - window.innerHeight;
|
||||
this.el.style.top = null;
|
||||
this.el.style.bottom = `${-overflow - this.marginTop}px`;
|
||||
|
||||
this.isTop = scrollTop <= this.el.offsetTop;
|
||||
|
||||
if (this.isBottom) {
|
||||
this.isBottom = false;
|
||||
const overflow = this.el.clientHeight - window.innerHeight;
|
||||
this.spacer.style.marginTop = `${scrollTop - (overflow + this.marginTop)}px`;
|
||||
}
|
||||
}
|
||||
|
||||
this.lastScrollTop = scrollTop <= 0 ? 0 : scrollTop;
|
||||
}
|
||||
}
|
|
@ -57,7 +57,7 @@ export const defaultDeviceSettings = {
|
|||
showFixedPostForm: false,
|
||||
disablePagesScript: true,
|
||||
enableInfiniteScroll: true,
|
||||
fixedWidgetsPosition: true,
|
||||
fixedWidgetsPosition: false,
|
||||
roomGraphicsQuality: 'medium',
|
||||
roomUseOrthographicCamera: true,
|
||||
sfxVolume: 0.3,
|
||||
|
|
Loading…
Reference in a new issue