mirror of
https://iceshrimp.dev/limepotato/jormungandr-bite.git
synced 2024-11-29 21:37:34 -07:00
Resolve #6500
This commit is contained in:
parent
7812d317a6
commit
860f68a2a2
4 changed files with 90 additions and 12 deletions
|
@ -87,8 +87,9 @@
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<template v-if="isDesktop">
|
<template v-if="isDesktop">
|
||||||
<div class="widgets" :class="{ edit: widgetsEditMode, fixed: $store.state.device.fixedWidgetsPosition }" v-for="place in ['left', 'right']" :key="place">
|
<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">
|
||||||
<template v-if="widgetsEditMode">
|
<div class="spacer"></div>
|
||||||
|
<div class="container" v-if="widgetsEditMode">
|
||||||
<mk-button primary @click="addWidget(place)" class="add"><fa :icon="faPlus"/></mk-button>
|
<mk-button primary @click="addWidget(place)" class="add"><fa :icon="faPlus"/></mk-button>
|
||||||
<x-draggable
|
<x-draggable
|
||||||
:list="widgets[place]"
|
:list="widgets[place]"
|
||||||
|
@ -106,8 +107,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</x-draggable>
|
</x-draggable>
|
||||||
</template>
|
</div>
|
||||||
<component v-else class="_widget" v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget"/>
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
@ -134,6 +137,7 @@ import { ResizeObserver } from '@juggle/resize-observer';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { host, instanceName } from './config';
|
import { host, instanceName } from './config';
|
||||||
import { search } from './scripts/search';
|
import { search } from './scripts/search';
|
||||||
|
import { StickySidebar } from './scripts/sticky-sidebar';
|
||||||
|
|
||||||
const DESKTOP_THRESHOLD = 1100;
|
const DESKTOP_THRESHOLD = 1100;
|
||||||
|
|
||||||
|
@ -232,6 +236,12 @@ export default Vue.extend({
|
||||||
this.showNav = false;
|
this.showNav = false;
|
||||||
this.canBack = (window.history.length > 0 && !['index'].includes(to.name));
|
this.canBack = (window.history.length > 0 && !['index'].includes(to.name));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isDesktop() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.attachSticky();
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
|
@ -277,9 +287,24 @@ export default Vue.extend({
|
||||||
if (window.innerWidth >= DESKTOP_THRESHOLD) this.isDesktop = true;
|
if (window.innerWidth >= DESKTOP_THRESHOLD) this.isDesktop = true;
|
||||||
}, { passive: true });
|
}, { passive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// widget follow
|
||||||
|
this.attachSticky();
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
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() {
|
top() {
|
||||||
window.scroll({ top: 0, behavior: 'smooth' });
|
window.scroll({ top: 0, behavior: 'smooth' });
|
||||||
},
|
},
|
||||||
|
@ -988,15 +1013,14 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
> .widgets {
|
> .widgets {
|
||||||
top: $header-height;
|
|
||||||
min-height: calc(100vh - #{$header-height});
|
|
||||||
padding: 0 var(--margin);
|
padding: 0 var(--margin);
|
||||||
box-shadow: 1px 0 0 0 var(--divider), -1px 0 0 0 var(--divider);
|
box-shadow: 1px 0 0 0 var(--divider), -1px 0 0 0 var(--divider);
|
||||||
|
|
||||||
&.fixed {
|
&.fixed {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
height: calc(100vh - #{$header-height});
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
height: calc(100vh - #{$header-height});
|
||||||
|
top: $header-height;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:first-of-type {
|
&:first-of-type {
|
||||||
|
@ -1007,7 +1031,7 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:empty {
|
&.empty {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1015,9 +1039,16 @@ export default Vue.extend({
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
> * {
|
> .container {
|
||||||
margin: var(--margin) 0;
|
position: sticky;
|
||||||
width: 300px;
|
height: min-content;
|
||||||
|
min-height: calc(100vh - #{$header-height});
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
margin: var(--margin) 0;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .add {
|
> .add {
|
||||||
|
|
|
@ -265,6 +265,10 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
location.reload();
|
location.reload();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
fixedWidgetsPosition() {
|
||||||
|
location.reload()
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
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,
|
showFixedPostForm: false,
|
||||||
disablePagesScript: true,
|
disablePagesScript: true,
|
||||||
enableInfiniteScroll: true,
|
enableInfiniteScroll: true,
|
||||||
fixedWidgetsPosition: true,
|
fixedWidgetsPosition: false,
|
||||||
roomGraphicsQuality: 'medium',
|
roomGraphicsQuality: 'medium',
|
||||||
roomUseOrthographicCamera: true,
|
roomUseOrthographicCamera: true,
|
||||||
sfxVolume: 0.3,
|
sfxVolume: 0.3,
|
||||||
|
|
Loading…
Reference in a new issue