Merge pull request #1304 from rinsuki/features/implement-media-video
Implement mk-media-video
This commit is contained in:
		
						commit
						4189ffd5e4
					
				
					 6 changed files with 179 additions and 1 deletions
				
			
		| 
						 | 
					@ -1,7 +1,8 @@
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
<div class="mk-media-list" :data-count="mediaList.length">
 | 
					<div class="mk-media-list" :data-count="mediaList.length">
 | 
				
			||||||
	<template v-for="media in mediaList">
 | 
						<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>
 | 
						</template>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,7 @@ import analogClock from './analog-clock.vue';
 | 
				
			||||||
import ellipsisIcon from './ellipsis-icon.vue';
 | 
					import ellipsisIcon from './ellipsis-icon.vue';
 | 
				
			||||||
import mediaImage from './media-image.vue';
 | 
					import mediaImage from './media-image.vue';
 | 
				
			||||||
import mediaImageDialog from './media-image-dialog.vue';
 | 
					import mediaImageDialog from './media-image-dialog.vue';
 | 
				
			||||||
 | 
					import mediaVideo from './media-video.vue';
 | 
				
			||||||
import notifications from './notifications.vue';
 | 
					import notifications from './notifications.vue';
 | 
				
			||||||
import postForm from './post-form.vue';
 | 
					import postForm from './post-form.vue';
 | 
				
			||||||
import repostForm from './repost-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-ellipsis-icon', ellipsisIcon);
 | 
				
			||||||
Vue.component('mk-media-image', mediaImage);
 | 
					Vue.component('mk-media-image', mediaImage);
 | 
				
			||||||
Vue.component('mk-media-image-dialog', mediaImageDialog);
 | 
					Vue.component('mk-media-image-dialog', mediaImageDialog);
 | 
				
			||||||
 | 
					Vue.component('mk-media-video', mediaVideo);
 | 
				
			||||||
Vue.component('mk-notifications', notifications);
 | 
					Vue.component('mk-notifications', notifications);
 | 
				
			||||||
Vue.component('mk-post-form', postForm);
 | 
					Vue.component('mk-post-form', postForm);
 | 
				
			||||||
Vue.component('mk-repost-form', repostForm);
 | 
					Vue.component('mk-repost-form', repostForm);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										70
									
								
								src/web/app/desktop/views/components/media-video-dialog.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/web/app/desktop/views/components/media-video-dialog.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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>
 | 
				
			||||||
							
								
								
									
										67
									
								
								src/web/app/desktop/views/components/media-video.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/web/app/desktop/views/components/media-video.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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 post from './post.vue';
 | 
				
			||||||
import posts from './posts.vue';
 | 
					import posts from './posts.vue';
 | 
				
			||||||
import mediaImage from './media-image.vue';
 | 
					import mediaImage from './media-image.vue';
 | 
				
			||||||
 | 
					import mediaVideo from './media-video.vue';
 | 
				
			||||||
import drive from './drive.vue';
 | 
					import drive from './drive.vue';
 | 
				
			||||||
import postPreview from './post-preview.vue';
 | 
					import postPreview from './post-preview.vue';
 | 
				
			||||||
import subPostContent from './sub-post-content.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-post', post);
 | 
				
			||||||
Vue.component('mk-posts', posts);
 | 
					Vue.component('mk-posts', posts);
 | 
				
			||||||
Vue.component('mk-media-image', mediaImage);
 | 
					Vue.component('mk-media-image', mediaImage);
 | 
				
			||||||
 | 
					Vue.component('mk-media-video', mediaVideo);
 | 
				
			||||||
Vue.component('mk-drive', drive);
 | 
					Vue.component('mk-drive', drive);
 | 
				
			||||||
Vue.component('mk-post-preview', postPreview);
 | 
					Vue.component('mk-post-preview', postPreview);
 | 
				
			||||||
Vue.component('mk-sub-post-content', subPostContent);
 | 
					Vue.component('mk-sub-post-content', subPostContent);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										36
									
								
								src/web/app/mobile/views/components/media-video.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/web/app/mobile/views/components/media-video.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue