Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use custom video player #28

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions assets/scss/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@

// transitions
@import "transitions/fade";

// vendors
@import "vendors/plyr";
53 changes: 0 additions & 53 deletions assets/scss/vendors/_plyr.scss

This file was deleted.

21 changes: 21 additions & 0 deletions components/molecules/VRoadizVideo/Background.stories.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script setup lang="ts">
import document from '~/assets/stories/fixtures/documents/vimeo-01.json'
</script>

<template>
<NuxtStory>
<NuxtStoryVariant title="Background">
<VRoadizVideo :document="document" :class="$style.video" background />

Check warning on line 8 in components/molecules/VRoadizVideo/Background.stories.vue

View workflow job for this annotation

GitHub Actions / lint

':class' should be on a new line

Check warning on line 8 in components/molecules/VRoadizVideo/Background.stories.vue

View workflow job for this annotation

GitHub Actions / lint

'background' should be on a new line
</NuxtStoryVariant>

<NuxtStoryVariant title="Background">
<VRoadizVideo :document="document" width="500" height="1200" :class="$style.video" background />

Check warning on line 12 in components/molecules/VRoadizVideo/Background.stories.vue

View workflow job for this annotation

GitHub Actions / lint

'width' should be on a new line

Check warning on line 12 in components/molecules/VRoadizVideo/Background.stories.vue

View workflow job for this annotation

GitHub Actions / lint

'height' should be on a new line

Check warning on line 12 in components/molecules/VRoadizVideo/Background.stories.vue

View workflow job for this annotation

GitHub Actions / lint

':class' should be on a new line

Check warning on line 12 in components/molecules/VRoadizVideo/Background.stories.vue

View workflow job for this annotation

GitHub Actions / lint

'background' should be on a new line
</NuxtStoryVariant>
</NuxtStory>
</template>

<style lang="scss" module>
.video {
max-width: rem(600);
}
</style>
26 changes: 26 additions & 0 deletions components/molecules/VRoadizVideo/BackgroundCover.stories.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script setup lang="ts">
import document from '~/assets/stories/fixtures/documents/vimeo-01.json'
</script>

<template>
<NuxtStory>
<div :class="$style.wrapper">
<VRoadizVideo :document="document" fit="cover" :class="$style.video" background />

Check warning on line 8 in components/molecules/VRoadizVideo/BackgroundCover.stories.vue

View workflow job for this annotation

GitHub Actions / lint

'fit' should be on a new line

Check warning on line 8 in components/molecules/VRoadizVideo/BackgroundCover.stories.vue

View workflow job for this annotation

GitHub Actions / lint

':class' should be on a new line

Check warning on line 8 in components/molecules/VRoadizVideo/BackgroundCover.stories.vue

View workflow job for this annotation

GitHub Actions / lint

'background' should be on a new line
</div>
</NuxtStory>
</template>

<style lang="scss" module>
.root {
position: relative;
}

.wrapper {
--v-player-height: 100%;
--v-player-video-object-fit: cover;

position: absolute;
height: 100svh;
inset: 0;
}
</style>
27 changes: 27 additions & 0 deletions components/molecules/VRoadizVideo/ThumbnailInteraction.stories.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script setup lang="ts">
import document from '~/assets/stories/fixtures/documents/vimeo-01.json'
</script>

<template>
<NuxtStory>
<NuxtStoryVariant title="Default">
<VRoadizVideo :document="document" :class="$style.video" />

Check warning on line 8 in components/molecules/VRoadizVideo/ThumbnailInteraction.stories.vue

View workflow job for this annotation

GitHub Actions / lint

':class' should be on a new line
</NuxtStoryVariant>
<NuxtStoryVariant title="Thumb slot">
<VRoadizVideo :document="{ ...document, thumbnail: undefined }" :class="$style.video">
<VRoadizImage :document="document.thumbnail" />
</VRoadizVideo>
</NuxtStoryVariant>
<NuxtStoryVariant title="Thumb slot with custom props">
<VRoadizVideo :document="document" :class="$style.video">
<VRoadizImage :document="document.thumbnail" width="600" height="600" sizes="600px" />
</VRoadizVideo>
</NuxtStoryVariant>
</NuxtStory>
</template>

<style lang="scss" module>
.video {
width: rem(600);
}
</style>
146 changes: 146 additions & 0 deletions components/molecules/VRoadizVideo/VRoadizVideo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<script lang="ts" setup>
import type { RoadizDocument } from '@roadiz/types'
import type { PropType } from 'vue'
import { isImage } from '~/utils/roadiz/document'
import { commonVideoProps, videoAttributes, videoSrc } from '~/utils/video/video-props'
import { getVideoAttrsValues } from '~/utils/video/video-attributes'

const props = defineProps({
...commonVideoProps,
...videoAttributes,
document: { type: Object as PropType<RoadizDocument>, required: true },
thumbnail: { type: Object as PropType<RoadizDocument> },
hideThumbnail: Boolean,
})

const hadInteraction = ref(false)
const onClick = (event: Event) => {
if (event.defaultPrevented || !props.playsinline) return

hadInteraction.value = true
}
const onVideoEnded = () => (hadInteraction.value = false)

const displayedThumbnail = computed(() => {
const documents = [props.thumbnail, props.document?.thumbnail, props.document]
return documents.find(document => isImage(document))
})

const filteredVideoProps = computed(() => {
return Object.keys(props).reduce((acc, key) => {
// @ts-expect-error TODO: use pick() here
if (commonVideoProps[key] || videoAttributes[key] || videoSrc[key]) acc[key] = props[key]
return acc
}, {})
})

const dimension = computed(() => {
return {
width: props.document.imageWidth,
height: props.document.imageHeight,
}
})

const videoRatio = computed(() => {
return Number(dimension.value.width) / Number(dimension.value.height)
})

const embedVideoAttrs = computed(() => {
return {
embedPlatform: props.document.embedPlatform,
embedId: props.document.embedId,
src: props.document.relativePath,
altSources: props.document.altSources,
...dimension.value,
...getVideoAttrsValues(props, !!props?.background),
...filteredVideoProps.value,
}
})
</script>

<template>
<VVideoPlayer
v-if="hideThumbnail || props.background"
v-bind="embedVideoAttrs"
/>
<div
v-else
:class="[$style.root, hadInteraction && $style['root--had-interaction']]"
>
<VButton
:label="$t('watch_the_video')"
theme="dark"
icon-name="play"
filled
:class="$style.button"
@click="onClick"
/>
<slot>
<VRoadizImage
v-if="displayedThumbnail"
:document="displayedThumbnail"
:class="$style.thumbnail"
@click="onClick"
/>
<div
v-else
:class="[$style.thumbnail, $style['thumbnail--placeholder']]"
:style="{ aspectRatio: videoRatio || 16 / 9 }"
/>
</slot>
<VVideoPlayer
v-if="hadInteraction"
v-bind="embedVideoAttrs"
:autoplay="true"
:plyr="{ listener: { ended: onVideoEnded } }"
/>
</div>
</template>

<style lang="scss" module="">
.root {
--v-player-position: absolute;
--v-player-height: 100%;
--v-player-width: 100%;

position: relative;
display: flex;
align-items: center;
justify-content: center;
}

.button {
--v-button-position: absolute;

z-index: 1;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

@include v-button-size('m');

@include media('>=lg') {
@include v-button-size('l');
}

.root--had-interaction & {
pointer-events: none;
visibility: hidden;
}
}

.thumbnail {
width: 100%;
cursor: pointer;

.root--had-interaction & {
pointer-events: none;
visibility: hidden;
}

&--placeholder {
aspect-ratio: 16 / 9;
background-color: color(grey-50);
}
}
</style>
12 changes: 12 additions & 0 deletions components/molecules/VVideo/Mp4.stories.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script setup lang="ts">
</script>

<template>
<NuxtStory>
<VVideoPlayer
src="/stories/videos/01.mp4"
width="640"
height="264"
/>
</NuxtStory>
</template>
13 changes: 13 additions & 0 deletions components/molecules/VVideo/Mp4Background.stories.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script setup lang="ts">
</script>

<template>
<NuxtStory>
<VVideoPlayer
src="/stories/videos/01.mp4"
width="640"
height="264"
background
/>
</NuxtStory>
</template>
36 changes: 36 additions & 0 deletions components/molecules/VVideo/Mp4BackgroundCover.stories.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script setup lang="ts">
</script>

<template>
<NuxtStory>
<div :class="$style.root">
<VVideoPlayer
src="/stories/videos/01.mp4"
width="640"
height="264"
background
fit="cover"
:class="$style.video"
/>
</div>
</NuxtStory>
</template>

<style module lang="scss">
.root {
--v-player-width: 100%;
--v-player-height: 100%;

--v-player-height: 100%;
--v-player-video-width: 100%;
--v-player-video-height: 100%;

width: 300px;
height: 300px;
border: 1px solid #000;
}

.video {

}
</style>
Loading
Loading