Componentize modal (#5386)
This commit is contained in:
		
							parent
							
								
									34c82776fc
								
							
						
					
					
						commit
						bf654c6f42
					
				
					 6 changed files with 188 additions and 223 deletions
				
			
		|  | @ -1,6 +1,12 @@ | |||
| <template> | ||||
| <div class="felqjxyj" :class="{ splash }"> | ||||
| 	<div class="bg" ref="bg" @click="onBgClick"></div> | ||||
| <ui-modal | ||||
| 	ref="modal" | ||||
| 	class="modal" | ||||
| 	:class="{ splash }" | ||||
| 	:close-anime-duration="300" | ||||
| 	:close-on-bg-click="false" | ||||
| 	@bg-click="onBgClick" | ||||
| 	@before-close="onBeforeClose"> | ||||
| 	<div class="main" ref="main" :class="{ round: $store.state.device.roundedCorners }"> | ||||
| 		<template v-if="type == 'signin'"> | ||||
| 			<mk-signin/> | ||||
|  | @ -38,7 +44,7 @@ | |||
| 			</ui-horizon-group> | ||||
| 		</template> | ||||
| 	</div> | ||||
| </div> | ||||
| </ui-modal> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
|  | @ -120,14 +126,6 @@ export default Vue.extend({ | |||
| 		if (this.user) this.canOk = false; | ||||
| 
 | ||||
| 		this.$nextTick(() => { | ||||
| 			(this.$refs.bg as any).style.pointerEvents = 'auto'; | ||||
| 			anime({ | ||||
| 				targets: this.$refs.bg, | ||||
| 				opacity: 1, | ||||
| 				duration: 100, | ||||
| 				easing: 'linear' | ||||
| 			}); | ||||
| 
 | ||||
| 			anime({ | ||||
| 				targets: this.$refs.main, | ||||
| 				opacity: 1, | ||||
|  | @ -170,33 +168,27 @@ export default Vue.extend({ | |||
| 			this.close(); | ||||
| 		}, | ||||
| 
 | ||||
| 		onBgClick() { | ||||
| 			if (this.cancelableByBgClick) this.cancel(); | ||||
| 		} | ||||
| 
 | ||||
| 		close() { | ||||
| 			this.$refs.modal.close(); | ||||
| 		}, | ||||
| 
 | ||||
| 		onBeforeClose() { | ||||
| 			this.$el.style.pointerEvents = 'none'; | ||||
| 			(this.$refs.bg as any).style.pointerEvents = 'none'; | ||||
| 			(this.$refs.main as any).style.pointerEvents = 'none'; | ||||
| 
 | ||||
| 			anime({ | ||||
| 				targets: this.$refs.bg, | ||||
| 				opacity: 0, | ||||
| 				duration: 300, | ||||
| 				easing: 'linear' | ||||
| 			}); | ||||
| 			anime({ | ||||
| 				targets: this.$refs.main, | ||||
| 				opacity: 0, | ||||
| 				scale: 0.8, | ||||
| 				duration: 300, | ||||
| 				easing: 'cubicBezier(0, 0.5, 0.5, 1)', | ||||
| 				complete: () => this.destroyDom() | ||||
| 			}); | ||||
| 		}, | ||||
| 
 | ||||
| 		onBgClick() { | ||||
| 			if (this.cancelableByBgClick) { | ||||
| 				this.cancel(); | ||||
| 			} | ||||
| 		}, | ||||
| 
 | ||||
| 		onInputKeydown(e) { | ||||
| 			if (e.which == 13) { // Enter | ||||
| 				e.preventDefault(); | ||||
|  | @ -209,80 +201,63 @@ export default Vue.extend({ | |||
| </script> | ||||
| 
 | ||||
| <style lang="stylus" scoped> | ||||
| .felqjxyj | ||||
| .modal | ||||
| 	display flex | ||||
| 	align-items center | ||||
| 	justify-content center | ||||
| 	position fixed | ||||
| 	z-index 30000 | ||||
| 	top 0 | ||||
| 	left 0 | ||||
| 	width 100% | ||||
| 	height 100% | ||||
| 
 | ||||
| 	&.splash | ||||
| 		> .main | ||||
| 			min-width 0 | ||||
| 			width initial | ||||
| 
 | ||||
| 	> .bg | ||||
| 		display block | ||||
| 		position fixed | ||||
| 		top 0 | ||||
| 		left 0 | ||||
| 		width 100% | ||||
| 		height 100% | ||||
| 		background rgba(#000, 0.7) | ||||
| 		opacity 0 | ||||
| 		pointer-events none | ||||
| .main | ||||
| 	display block | ||||
| 	position fixed | ||||
| 	margin auto | ||||
| 	padding 32px | ||||
| 	min-width 320px | ||||
| 	max-width 480px | ||||
| 	width calc(100% - 32px) | ||||
| 	text-align center | ||||
| 	background var(--face) | ||||
| 	color var(--faceText) | ||||
| 	opacity 0 | ||||
| 
 | ||||
| 	> .main | ||||
| 		display block | ||||
| 		position fixed | ||||
| 		margin auto | ||||
| 		padding 32px | ||||
| 		min-width 320px | ||||
| 		max-width 480px | ||||
| 		width calc(100% - 32px) | ||||
| 		text-align center | ||||
| 		background var(--face) | ||||
| 		color var(--faceText) | ||||
| 		opacity 0 | ||||
| 	&.round | ||||
| 		border-radius 8px | ||||
| 
 | ||||
| 		&.round | ||||
| 			border-radius 8px | ||||
| 	> .icon | ||||
| 		font-size 32px | ||||
| 
 | ||||
| 		> .icon | ||||
| 			font-size 32px | ||||
| 		&.success | ||||
| 			color #85da5a | ||||
| 
 | ||||
| 			&.success | ||||
| 				color #85da5a | ||||
| 		&.error | ||||
| 			color #ec4137 | ||||
| 
 | ||||
| 			&.error | ||||
| 				color #ec4137 | ||||
| 		&.warning | ||||
| 			color #ecb637 | ||||
| 
 | ||||
| 			&.warning | ||||
| 				color #ecb637 | ||||
| 		> * | ||||
| 			display block | ||||
| 			margin 0 auto | ||||
| 
 | ||||
| 			> * | ||||
| 				display block | ||||
| 				margin 0 auto | ||||
| 
 | ||||
| 			& + header | ||||
| 				margin-top 16px | ||||
| 
 | ||||
| 		> header | ||||
| 			margin 0 0 8px 0 | ||||
| 			font-weight bold | ||||
| 			font-size 20px | ||||
| 
 | ||||
| 			& + .body | ||||
| 				margin-top 8px | ||||
| 
 | ||||
| 		> .body | ||||
| 			margin 16px 0 0 0 | ||||
| 
 | ||||
| 		> .buttons | ||||
| 		& + header | ||||
| 			margin-top 16px | ||||
| 
 | ||||
| 	> header | ||||
| 		margin 0 0 8px 0 | ||||
| 		font-weight bold | ||||
| 		font-size 20px | ||||
| 
 | ||||
| 		& + .body | ||||
| 			margin-top 8px | ||||
| 
 | ||||
| 	> .body | ||||
| 		margin 16px 0 0 0 | ||||
| 
 | ||||
| 	> .buttons | ||||
| 		margin-top 16px | ||||
| 
 | ||||
| </style> | ||||
|  |  | |||
|  | @ -1,24 +1,14 @@ | |||
| <template> | ||||
| <div class="dkjvrdxtkvqrwmhfickhndpmnncsgacq" v-hotkey.global="keymap"> | ||||
| 	<div class="bg" @click="close"></div> | ||||
| 	<img :src="image.url" :alt="image.name" :title="image.name" @click="close"/> | ||||
| </div> | ||||
| <ui-modal ref="modal" v-hotkey.global="keymap"> | ||||
| 	<img :src="image.url" :alt="image.name" :title="image.name" @click="close" /> | ||||
| </ui-modal> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import anime from 'animejs'; | ||||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	props: ['image'], | ||||
| 	mounted() { | ||||
| 		anime({ | ||||
| 			targets: this.$el, | ||||
| 			opacity: 1, | ||||
| 			duration: 100, | ||||
| 			easing: 'linear' | ||||
| 		}); | ||||
| 	}, | ||||
| 	computed: { | ||||
| 		keymap(): any { | ||||
| 			return { | ||||
|  | @ -28,50 +18,24 @@ export default Vue.extend({ | |||
| 	}, | ||||
| 	methods: { | ||||
| 		close() { | ||||
| 			anime({ | ||||
| 				targets: this.$el, | ||||
| 				opacity: 0, | ||||
| 				duration: 100, | ||||
| 				easing: 'linear', | ||||
| 				complete: () => this.destroyDom() | ||||
| 			}); | ||||
| 			(this.$refs.modal as any).close(); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="stylus" scoped> | ||||
| .dkjvrdxtkvqrwmhfickhndpmnncsgacq | ||||
| 	display block | ||||
| img | ||||
| 	position fixed | ||||
| 	z-index 2048 | ||||
| 	z-index 2 | ||||
| 	top 0 | ||||
| 	right 0 | ||||
| 	bottom 0 | ||||
| 	left 0 | ||||
| 	width 100% | ||||
| 	height 100% | ||||
| 	opacity 0 | ||||
| 
 | ||||
| 	> .bg | ||||
| 		display block | ||||
| 		position fixed | ||||
| 		z-index 1 | ||||
| 		top 0 | ||||
| 		left 0 | ||||
| 		width 100% | ||||
| 		height 100% | ||||
| 		background rgba(#000, 0.7) | ||||
| 
 | ||||
| 	> img | ||||
| 		position fixed | ||||
| 		z-index 2 | ||||
| 		top 0 | ||||
| 		right 0 | ||||
| 		bottom 0 | ||||
| 		left 0 | ||||
| 		max-width 100% | ||||
| 		max-height 100% | ||||
| 		margin auto | ||||
| 		cursor zoom-out | ||||
| 		image-orientation from-image | ||||
| 	max-width 100% | ||||
| 	max-height 100% | ||||
| 	margin auto | ||||
| 	cursor zoom-out | ||||
| 	image-orientation from-image | ||||
| 
 | ||||
| </style> | ||||
|  |  | |||
|  | @ -47,6 +47,7 @@ import uiInfo from './ui/info.vue'; | |||
| import uiMargin from './ui/margin.vue'; | ||||
| import uiHr from './ui/hr.vue'; | ||||
| import uiPagination from './ui/pagination.vue'; | ||||
| import uiModal from './ui/modal.vue'; | ||||
| import formButton from './ui/form/button.vue'; | ||||
| import formRadio from './ui/form/radio.vue'; | ||||
| 
 | ||||
|  | @ -97,5 +98,6 @@ Vue.component('ui-info', uiInfo); | |||
| Vue.component('ui-margin', uiMargin); | ||||
| Vue.component('ui-hr', uiHr); | ||||
| Vue.component('ui-pagination', uiPagination); | ||||
| Vue.component('ui-modal', uiModal); | ||||
| Vue.component('form-button', formButton); | ||||
| Vue.component('form-radio', formRadio); | ||||
|  |  | |||
							
								
								
									
										80
									
								
								src/client/app/common/views/components/ui/modal.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/client/app/common/views/components/ui/modal.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,80 @@ | |||
| <template> | ||||
| <div class="modal"> | ||||
| 	<div class="bg" ref="bg" @click="onBgClick" /> | ||||
| 	<slot class="main" /> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import anime from 'animejs'; | ||||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	props: { | ||||
| 		closeOnBgClick: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: true | ||||
| 		}, | ||||
| 		openAnimeDuration: { | ||||
| 			type: Number, | ||||
| 			required: false, | ||||
| 			default: 100 | ||||
| 		}, | ||||
| 		closeAnimeDuration: { | ||||
| 			type: Number, | ||||
| 			required: false, | ||||
| 			default: 100 | ||||
| 		} | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		anime({ | ||||
| 			targets: this.$refs.bg, | ||||
| 			opacity: 1, | ||||
| 			duration: this.openAnimeDuration, | ||||
| 			easing: 'linear' | ||||
| 		}); | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		onBgClick() { | ||||
| 			this.$emit('bg-click'); | ||||
| 			if (this.closeOnBgClick) this.close(); | ||||
| 		}, | ||||
| 		close() { | ||||
| 			this.$emit('before-close'); | ||||
| 
 | ||||
| 			anime({ | ||||
| 				targets: this.$refs.bg, | ||||
| 				opacity: 0, | ||||
| 				duration: this.closeAnimeDuration, | ||||
| 				easing: 'linear', | ||||
| 				complete: () => (this as any).destroyDom() | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="stylus" scoped> | ||||
| .modal | ||||
| 	position fixed | ||||
| 	z-index 2048 | ||||
| 	top 0 | ||||
| 	left 0 | ||||
| 	width 100% | ||||
| 	height 100% | ||||
| 
 | ||||
| .bg | ||||
| 	display block | ||||
| 	position fixed | ||||
| 	z-index 1 | ||||
| 	top 0 | ||||
| 	left 0 | ||||
| 	width 100% | ||||
| 	height 100% | ||||
| 	background rgba(#000, 0.7) | ||||
| 	opacity 0 | ||||
| 
 | ||||
| .main | ||||
| 	z-index 1 | ||||
| </style> | ||||
|  | @ -1,23 +1,15 @@ | |||
| <template> | ||||
| <div class="mk-media-video-dialog" v-hotkey.global="keymap"> | ||||
| 	<div class="bg" @click="close"></div> | ||||
| 	<video :src="video.url" :title="video.name" controls autoplay ref="video" @volumechange="volumechange"/> | ||||
| </div> | ||||
| <ui-modal v-hotkey.global="keymap"> | ||||
| 	<video :src="video.url" :title="video.name" controls autoplay ref="video" @volumechange="volumechange" /> | ||||
| </ui-modal> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import anime from 'animejs'; | ||||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	props: ['video', 'start'], | ||||
| 	mounted() { | ||||
| 		anime({ | ||||
| 			targets: this.$el, | ||||
| 			opacity: 1, | ||||
| 			duration: 100, | ||||
| 			easing: 'linear' | ||||
| 		}); | ||||
| 		const videoTag = this.$refs.video as HTMLVideoElement; | ||||
| 		if (this.start) videoTag.currentTime = this.start | ||||
| 		videoTag.volume = this.$store.state.device.mediaVolume; | ||||
|  | @ -31,13 +23,6 @@ export default Vue.extend({ | |||
| 	}, | ||||
| 	methods: { | ||||
| 		close() { | ||||
| 			anime({ | ||||
| 				targets: this.$el, | ||||
| 				opacity: 0, | ||||
| 				duration: 100, | ||||
| 				easing: 'linear', | ||||
| 				complete: () => this.destroyDom() | ||||
| 			}); | ||||
| 		}, | ||||
| 		volumechange() { | ||||
| 			const videoTag = this.$refs.video as HTMLVideoElement; | ||||
|  | @ -48,35 +33,15 @@ export default Vue.extend({ | |||
| </script> | ||||
| 
 | ||||
| <style lang="stylus" scoped> | ||||
| .mk-media-video-dialog | ||||
| 	display block | ||||
| video | ||||
| 	position fixed | ||||
| 	z-index 2048 | ||||
| 	z-index 2 | ||||
| 	top 0 | ||||
| 	right 0 | ||||
| 	bottom 0 | ||||
| 	left 0 | ||||
| 	width 100% | ||||
| 	height 100% | ||||
| 	opacity 0 | ||||
| 
 | ||||
| 	> .bg | ||||
| 		display block | ||||
| 		position fixed | ||||
| 		z-index 1 | ||||
| 		top 0 | ||||
| 		left 0 | ||||
| 		width 100% | ||||
| 		height 100% | ||||
| 		background rgba(#000, 0.7) | ||||
| 
 | ||||
| 	> video | ||||
| 		position fixed | ||||
| 		z-index 2 | ||||
| 		top 0 | ||||
| 		right 0 | ||||
| 		bottom 0 | ||||
| 		left 0 | ||||
| 		max-width 80vw | ||||
| 		max-height 80vh | ||||
| 		margin auto | ||||
| 	max-width 80vw | ||||
| 	max-height 80vh | ||||
| 	margin auto | ||||
| 
 | ||||
| </style> | ||||
|  |  | |||
|  | @ -1,6 +1,9 @@ | |||
| <template> | ||||
| <div class="ulveipglmagnxfgvitaxyszerjwiqmwl"> | ||||
| 	<div class="bg" ref="bg"></div> | ||||
| <ui-modal | ||||
| 	ref="modal" | ||||
| 	:close-on-bg-click="false" | ||||
| 	:close-anime-duration="300" | ||||
| 	@before-close="onBeforeClose"> | ||||
| 	<div class="main" ref="main"> | ||||
| 		<x-post-form ref="form" | ||||
| 			:reply="reply" | ||||
|  | @ -12,7 +15,7 @@ | |||
| 			@posted="onPosted" | ||||
| 			@cancel="onCanceled"/> | ||||
| 	</div> | ||||
| </div> | ||||
| </ui-modal> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
|  | @ -55,14 +58,6 @@ export default Vue.extend({ | |||
| 
 | ||||
| 	mounted() { | ||||
| 		this.$nextTick(() => { | ||||
| 			(this.$refs.bg as any).style.pointerEvents = 'auto'; | ||||
| 			anime({ | ||||
| 				targets: this.$refs.bg, | ||||
| 				opacity: 1, | ||||
| 				duration: 100, | ||||
| 				easing: 'linear' | ||||
| 			}); | ||||
| 
 | ||||
| 			anime({ | ||||
| 				targets: this.$refs.main, | ||||
| 				opacity: 1, | ||||
|  | @ -78,26 +73,22 @@ export default Vue.extend({ | |||
| 			this.$refs.form.focus(); | ||||
| 		}, | ||||
| 
 | ||||
| 		close() { | ||||
| 			(this.$refs.bg as any).style.pointerEvents = 'none'; | ||||
| 			anime({ | ||||
| 				targets: this.$refs.bg, | ||||
| 				opacity: 0, | ||||
| 				duration: 300, | ||||
| 				easing: 'linear' | ||||
| 			}); | ||||
| 
 | ||||
| 		onBeforeClose() { | ||||
| 			(this.$refs.main as any).style.pointerEvents = 'none'; | ||||
| 
 | ||||
| 			anime({ | ||||
| 				targets: this.$refs.main, | ||||
| 				opacity: 0, | ||||
| 				translateY: 16, | ||||
| 				duration: 300, | ||||
| 				easing: 'easeOutQuad', | ||||
| 				complete: () => this.destroyDom() | ||||
| 				easing: 'easeOutQuad' | ||||
| 			}); | ||||
| 		}, | ||||
| 
 | ||||
| 		close() { | ||||
| 			(this.$refs.modal as any).close(); | ||||
| 		}, | ||||
| 
 | ||||
| 		onPosted() { | ||||
| 			this.$emit('posted'); | ||||
| 			this.close(); | ||||
|  | @ -112,30 +103,18 @@ export default Vue.extend({ | |||
| </script> | ||||
| 
 | ||||
| <style lang="stylus" scoped> | ||||
| .ulveipglmagnxfgvitaxyszerjwiqmwl | ||||
| 	> .bg | ||||
| 		display block | ||||
| 		position fixed | ||||
| 		z-index 10000 | ||||
| 		top 0 | ||||
| 		left 0 | ||||
| 		width 100% | ||||
| 		height 100% | ||||
| 		background rgba(#000, 0.7) | ||||
| 		opacity 0 | ||||
| 		pointer-events none | ||||
| 
 | ||||
| 	> .main | ||||
| 		display block | ||||
| 		position fixed | ||||
| 		z-index 10000 | ||||
| 		top 0 | ||||
| 		left 0 | ||||
| 		right 0 | ||||
| 		height 100% | ||||
| 		overflow auto | ||||
| 		margin 0 auto 0 auto | ||||
| 		opacity 0 | ||||
| 		transform translateY(-16px) | ||||
| .main | ||||
| 	display block | ||||
| 	position fixed | ||||
| 	z-index 10000 | ||||
| 	top 0 | ||||
| 	left 0 | ||||
| 	right 0 | ||||
| 	height 100% | ||||
| 	overflow auto | ||||
| 	margin 0 auto 0 auto | ||||
| 	opacity 0 | ||||
| 	transform translateY(-16px) | ||||
| 
 | ||||
| </style> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue