summaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2020-07-06 16:08:30 +0900
committersyuilo <syuilotan@yahoo.co.jp>2020-07-06 16:08:30 +0900
commitc25cf7f89a1d3d7e55331396bbc3f44920a38de5 (patch)
tree3633b7e2a2718cc91cad8d2ff22e544b76a2cdcc /src/client
parent:art: (diff)
downloadsharkey-c25cf7f89a1d3d7e55331396bbc3f44920a38de5.tar.gz
sharkey-c25cf7f89a1d3d7e55331396bbc3f44920a38de5.tar.bz2
sharkey-c25cf7f89a1d3d7e55331396bbc3f44920a38de5.zip
Resolve #6500
Diffstat (limited to 'src/client')
-rw-r--r--src/client/app.vue53
-rw-r--r--src/client/pages/preferences/index.vue4
-rw-r--r--src/client/scripts/sticky-sidebar.ts43
-rw-r--r--src/client/store.ts2
4 files changed, 90 insertions, 12 deletions
diff --git a/src/client/app.vue b/src/client/app.vue
index 673949ce12..34c7543ace 100644
--- a/src/client/app.vue
+++ b/src/client/app.vue
@@ -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 {
diff --git a/src/client/pages/preferences/index.vue b/src/client/pages/preferences/index.vue
index f3a6f1db29..3dba0a7438 100644
--- a/src/client/pages/preferences/index.vue
+++ b/src/client/pages/preferences/index.vue
@@ -265,6 +265,10 @@ export default Vue.extend({
}
location.reload();
},
+
+ fixedWidgetsPosition() {
+ location.reload()
+ },
},
methods: {
diff --git a/src/client/scripts/sticky-sidebar.ts b/src/client/scripts/sticky-sidebar.ts
new file mode 100644
index 0000000000..872e162d2b
--- /dev/null
+++ b/src/client/scripts/sticky-sidebar.ts
@@ -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;
+ }
+}
diff --git a/src/client/store.ts b/src/client/store.ts
index bf1bdf1a84..eee3f59618 100644
--- a/src/client/store.ts
+++ b/src/client/store.ts
@@ -57,7 +57,7 @@ export const defaultDeviceSettings = {
showFixedPostForm: false,
disablePagesScript: true,
enableInfiniteScroll: true,
- fixedWidgetsPosition: true,
+ fixedWidgetsPosition: false,
roomGraphicsQuality: 'medium',
roomUseOrthographicCamera: true,
sfxVolume: 0.3,