Skip to content

Commit b31e233

Browse files
committed
native video player
1 parent 0858441 commit b31e233

5 files changed

Lines changed: 3840 additions & 2176 deletions

File tree

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "@jsonms/demo",
33
"private": true,
44
"type": "module",
5-
"version": "0.1.12",
5+
"version": "0.1.13",
66
"scripts": {
77
"dev": "vite",
88
"build": "run-p type-check \"build-only {@}\" --",
@@ -13,12 +13,12 @@
1313
"setup-hooks": "cp .pre-commit .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit"
1414
},
1515
"dependencies": {
16-
"@mdi/font": "7.4.47",
1716
"@jsonms/vue3": "^1.0.7",
17+
"@mdi/font": "7.4.47",
1818
"core-js": "^3.37.1",
1919
"roboto-fontface": "*",
2020
"vue": "^3.4.31",
21-
"vuetify": "^3.6.14"
21+
"vuetify": "^3.10.7"
2222
},
2323
"devDependencies": {
2424
"@eslint/js": "^9.14.0",

src/components/Carousels.vue

Lines changed: 98 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,42 @@
2222
v-for="(presentation, presentationIdx) in data.home.presentation"
2323
:key="presentation.hash"
2424
>
25-
<div v-if="data.home.presentation[slide].type === 'youtube'" class="youtube-responsive">
25+
<div
26+
v-if="presentation.type === 'media'"
27+
class="media-responsive"
28+
@mousemove="onMouseMoveVideo"
29+
>
30+
<video
31+
ref="video"
32+
controlsList="nodownload"
33+
disablepictureinpicture
34+
preload="auto"
35+
@play="onVideoPlay"
36+
@pause="onVideoPause"
37+
@end="onVideoEnd"
38+
@loadedmetadata="onLoadedMetadata"
39+
>
40+
<source
41+
:src="getFilePath(presentation.media)"
42+
:type="presentation.media?.meta.type"
43+
>
44+
Your browser does not support the video tag.
45+
</video>
46+
<div class="video-btn">
47+
<v-fade-transition>
48+
<v-btn v-if="hoveringVideo" :variant="videoPlaying ? 'tonal' : 'elevated'" color="primary" icon size="x-large" @click="toggleVideo">
49+
<v-icon v-if="!videoPlaying" icon="mdi-play" />
50+
<v-icon v-else icon="mdi-pause" />
51+
</v-btn>
52+
</v-fade-transition>
53+
</div>
54+
</div>
55+
<div v-if="presentation.type === 'youtube'" class="youtube-responsive">
2656
<iframe
2757
:src="getYoutubeUrl(presentation)"
2858
title="YouTube video player"
2959
frameborder="0"
30-
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; web-share"
60+
allow="accelerometer; clipboard-write; encrypted-media; gyroscope; web-share"
3161
referrerpolicy="strict-origin-when-cross-origin"
3262
allowfullscreen
3363
/>
@@ -55,10 +85,13 @@
5585

5686
<script setup lang="ts">
5787
import {useJsonMs} from "@/plugins/jsonms";
58-
import type {JmsHomePresentationItems} from "@/jms/typings";
88+
import type {JmsHomePresentationItem} from "@/jms/typings";
5989
6090
const slide = ref(0);
61-
const { data, locale } = useJsonMs();
91+
const hoveringVideo = ref(true);
92+
const video = ref<HTMLVideoElement[]>([])
93+
const videoPlaying = ref(false);
94+
const { data, locale, getFilePath } = useJsonMs();
6295
6396
const onCtaClick = () => {
6497
slide.value++;
@@ -74,7 +107,48 @@ const slideColor = computed((): string => {
74107
return data.value.home.presentation[slide.value].color || 'primary';
75108
})
76109
77-
function getYoutubeUrl(presentation: JmsHomePresentationItems) {
110+
function toggleVideo() {
111+
if (video.value.length > 0) {
112+
videoPlaying.value = !videoPlaying.value;
113+
const player = video.value[video.value.length - 1];
114+
videoPlaying.value ? player.play() : player.pause();
115+
}
116+
}
117+
118+
let mouseMoveVideoTimeout: any = null;
119+
function onMouseMoveVideo() {
120+
hoveringVideo.value = true;
121+
clearTimeout(mouseMoveVideoTimeout);
122+
mouseMoveVideoTimeout = setTimeout(() => {
123+
if (videoPlaying.value) {
124+
hoveringVideo.value = false;
125+
}
126+
}, 2000);
127+
}
128+
129+
const onLoadedMetadata = () => {
130+
if (!video.value) return
131+
const player = video.value[video.value.length - 1];
132+
player.currentTime = 0.01
133+
}
134+
135+
function onVideoPlay() {
136+
videoPlaying.value = true;
137+
hoveringVideo.value = false;
138+
}
139+
140+
function onVideoPause() {
141+
videoPlaying.value = false;
142+
}
143+
144+
function onVideoEnd() {
145+
videoPlaying.value = false;
146+
if (video.value.length > 0) {
147+
video.value[video.value.length - 1].currentTime = 0;
148+
}
149+
}
150+
151+
function getYoutubeUrl(presentation: JmsHomePresentationItem) {
78152
if (presentation.youtube) {
79153
const code = getYoutubeCode(presentation.youtube);
80154
return 'https://www.youtube.com/embed/' + code + '?controls=0&rel=0';
@@ -105,6 +179,25 @@ watch(() => slide.value, () => {
105179
</script>
106180

107181
<style lang="scss" scoped>
182+
.media-responsive {
183+
width: 100%;
184+
height: 100%;
185+
overflow: hidden;
186+
}
187+
.media-responsive video {
188+
height: 100vh;
189+
min-width: 100%;
190+
float: left;
191+
}
192+
.media-responsive {
193+
.video-btn {
194+
z-index: 2;
195+
position: absolute;
196+
top: 50%;
197+
left: 50%;
198+
transform: translate(-50%, -50%);
199+
}
200+
}
108201
.youtube-responsive iframe {
109202
position: absolute;
110203
inset: 0;

src/jms/typings.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ export interface JmsFile {
2828
}
2929

3030
export interface JmsHomePresentationItem {
31-
type: 'text' | 'youtube'
31+
type: 'text' | 'media' | 'youtube'
3232
title: JmsLocaleSet<string> | null
33+
media: JmsFile | null
3334
youtube: string | null
3435
body: JmsLocaleSet<string | null> | null
3536
cta: JmsLocaleSet<string> | null

src/plugins/vuetify.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@
77
// Styles
88
import '@mdi/font/css/materialdesignicons.css'
99
import 'vuetify/styles'
10+
// import { VVideo } from 'vuetify/labs/VVideo'
1011

1112
// Composables
1213
import { createVuetify } from 'vuetify'
1314

1415
// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
1516
export default createVuetify({
17+
// components: {
18+
// VVideo,
19+
// },
1620
theme: {
1721
defaultTheme: 'light',
1822
},

0 commit comments

Comments
 (0)