Merge pull request #1304 from rinsuki/features/implement-media-video
Implement mk-media-video
This commit is contained in:
		
						commit
						4189ffd5e4
					
				|  | @ -1,7 +1,8 @@ | |||
| <template> | ||||
| <div class="mk-media-list" :data-count="mediaList.length"> | ||||
| 	<template v-for="media in mediaList"> | ||||
| 		<mk-media-image :image="media" :key="media.id"/> | ||||
| 		<mk-media-video :video="media" :key="media.id" v-if="media.type.startsWith('video')" :inline-playable="mediaList.length === 1"/> | ||||
| 		<mk-media-image :image="media" :key="media.id" v-else /> | ||||
| 	</template> | ||||
| </div> | ||||
| </template> | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ import analogClock from './analog-clock.vue'; | |||
| import ellipsisIcon from './ellipsis-icon.vue'; | ||||
| import mediaImage from './media-image.vue'; | ||||
| import mediaImageDialog from './media-image-dialog.vue'; | ||||
| import mediaVideo from './media-video.vue'; | ||||
| import notifications from './notifications.vue'; | ||||
| import postForm from './post-form.vue'; | ||||
| import repostForm from './repost-form.vue'; | ||||
|  | @ -42,6 +43,7 @@ Vue.component('mk-analog-clock', analogClock); | |||
| Vue.component('mk-ellipsis-icon', ellipsisIcon); | ||||
| Vue.component('mk-media-image', mediaImage); | ||||
| Vue.component('mk-media-image-dialog', mediaImageDialog); | ||||
| Vue.component('mk-media-video', mediaVideo); | ||||
| Vue.component('mk-notifications', notifications); | ||||
| Vue.component('mk-post-form', postForm); | ||||
| Vue.component('mk-repost-form', repostForm); | ||||
|  |  | |||
|  | @ -0,0 +1,70 @@ | |||
| <template> | ||||
| <div class="mk-media-video-dialog"> | ||||
| 	<div class="bg" @click="close"></div> | ||||
| 	<video :src="video.url" :title="video.name" controls autoplay ref="video"/> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import * as 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 | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		close() { | ||||
| 			anime({ | ||||
| 				targets: this.$el, | ||||
| 				opacity: 0, | ||||
| 				duration: 100, | ||||
| 				easing: 'linear', | ||||
| 				complete: () => this.$destroy() | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="stylus" scoped> | ||||
| .mk-media-video-dialog | ||||
| 	display block | ||||
| 	position fixed | ||||
| 	z-index 2048 | ||||
| 	top 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(0, 0, 0, 0.7) | ||||
| 
 | ||||
| 	> video | ||||
| 		position fixed | ||||
| 		z-index 2 | ||||
| 		top 0 | ||||
| 		right 0 | ||||
| 		bottom 0 | ||||
| 		left 0 | ||||
| 		max-width 80vw | ||||
| 		max-height 80vh | ||||
| 		margin auto | ||||
| 
 | ||||
| </style> | ||||
|  | @ -0,0 +1,67 @@ | |||
| <template> | ||||
| 	<video class="mk-media-video" | ||||
| 		:src="video.url" | ||||
| 		:title="video.name" | ||||
| 		controls | ||||
| 		@dblclick.prevent="onClick" | ||||
| 		ref="video" | ||||
| 		v-if="inlinePlayable" /> | ||||
| 	<a class="mk-media-video-thumbnail" | ||||
| 		:href="video.url" | ||||
| 		:style="imageStyle" | ||||
| 		@click.prevent="onClick" | ||||
| 		:title="video.name" | ||||
| 		v-else> | ||||
| 		%fa:R play-circle% | ||||
| 	</a> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import MkMediaVideoDialog from './media-video-dialog.vue'; | ||||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	props: ['video', 'inlinePlayable'], | ||||
| 	computed: { | ||||
| 		imageStyle(): any { | ||||
| 			return { | ||||
| 				'background-image': `url(${this.video.url}?thumbnail&size=512)` | ||||
| 			}; | ||||
| 		} | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		onClick() { | ||||
| 			const videoTag = this.$refs.video as (HTMLVideoElement | null) | ||||
| 			var start = 0 | ||||
| 			if (videoTag) { | ||||
| 				start = videoTag.currentTime | ||||
| 				videoTag.pause() | ||||
| 			} | ||||
| 			(this as any).os.new(MkMediaVideoDialog, { | ||||
| 				video: this.video, | ||||
| 				start, | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
| }) | ||||
| </script> | ||||
| 
 | ||||
| <style lang="stylus" scoped> | ||||
| .mk-media-video | ||||
| 	display block | ||||
| 	width 100% | ||||
| 	height 100% | ||||
| 	border-radius 4px | ||||
| .mk-media-video-thumbnail | ||||
| 	display flex | ||||
| 	justify-content center | ||||
| 	align-items center | ||||
| 	font-size 3.5em | ||||
| 
 | ||||
| 	cursor zoom-in | ||||
| 	overflow hidden | ||||
| 	background-position center | ||||
| 	background-size cover | ||||
| 	width 100% | ||||
| 	height 100% | ||||
| </style> | ||||
|  | @ -5,6 +5,7 @@ import timeline from './timeline.vue'; | |||
| import post from './post.vue'; | ||||
| import posts from './posts.vue'; | ||||
| import mediaImage from './media-image.vue'; | ||||
| import mediaVideo from './media-video.vue'; | ||||
| import drive from './drive.vue'; | ||||
| import postPreview from './post-preview.vue'; | ||||
| import subPostContent from './sub-post-content.vue'; | ||||
|  | @ -27,6 +28,7 @@ Vue.component('mk-timeline', timeline); | |||
| Vue.component('mk-post', post); | ||||
| Vue.component('mk-posts', posts); | ||||
| Vue.component('mk-media-image', mediaImage); | ||||
| Vue.component('mk-media-video', mediaVideo); | ||||
| Vue.component('mk-drive', drive); | ||||
| Vue.component('mk-post-preview', postPreview); | ||||
| Vue.component('mk-sub-post-content', subPostContent); | ||||
|  |  | |||
|  | @ -0,0 +1,36 @@ | |||
| <template> | ||||
| 	<a class="mk-media-video" | ||||
| 		:href="video.url" | ||||
| 		target="_blank" | ||||
| 		:style="imageStyle" | ||||
| 		:title="video.name"> | ||||
| 		%fa:R play-circle% | ||||
| 	</a> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue' | ||||
| export default Vue.extend({ | ||||
| 	props: ['video'], | ||||
| 	computed: { | ||||
| 		imageStyle(): any { | ||||
| 			return { | ||||
| 				'background-image': `url(${this.video.url}?thumbnail&size=512)` | ||||
| 			}; | ||||
| 		} | ||||
| 	},}) | ||||
| </script> | ||||
| 
 | ||||
| <style lang="stylus" scoped> | ||||
| .mk-media-video | ||||
| 	display flex | ||||
| 	justify-content center | ||||
| 	align-items center | ||||
| 
 | ||||
| 	font-size 3.5em | ||||
| 	overflow hidden | ||||
| 	background-position center | ||||
| 	background-size cover | ||||
| 	width 100% | ||||
| 	height 100% | ||||
| </style> | ||||
		Loading…
	
		Reference in New Issue