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…
	
	Add table
		Add a link
		
	
		Reference in a new issue