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>
|
||||
<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);
|
||||
|
|
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 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);
|
||||
|
|
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…
Reference in a new issue