This commit is contained in:
syuilo 2020-07-06 16:08:30 +09:00
parent ade11aa447
commit c25cf7f89a
4 changed files with 90 additions and 12 deletions

View file

@ -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,10 +1039,17 @@ export default Vue.extend({
display: none; display: none;
} }
> .container {
position: sticky;
height: min-content;
min-height: calc(100vh - #{$header-height});
overflow: hidden;
> * { > * {
margin: var(--margin) 0; margin: var(--margin) 0;
width: 300px; width: 300px;
} }
}
> .add { > .add {
margin: 0 auto; margin: 0 auto;

View file

@ -265,6 +265,10 @@ export default Vue.extend({
} }
location.reload(); location.reload();
}, },
fixedWidgetsPosition() {
location.reload()
},
}, },
methods: { methods: {

View 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;
}
}

View file

@ -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,