-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add useScriptVimeo + Vimeo component (#8)
Co-authored-by: Harlan Wilton <[email protected]>
- Loading branch information
1 parent
c03df8d
commit 7626cea
Showing
6 changed files
with
256 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<script lang="ts" setup> | ||
import { useHead } from '#imports' | ||
import { VimeoEmbed } from '#components' | ||
useHead({ | ||
title: 'Vimeo component', | ||
}) | ||
function handlePlay() { | ||
console.log('Playing') | ||
} | ||
</script> | ||
|
||
<template> | ||
<VimeoEmbed video-id="76979871" width="640" height="400" :loop="true" @play="handlePlay" /> | ||
</template> | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<script lang="ts" setup> | ||
import { onMounted, useHead, useScriptVimeo } from '#imports' | ||
useHead({ | ||
title: 'Vimeo', | ||
}) | ||
onMounted(() => { | ||
const { Player } = useScriptVimeo() | ||
Player('player', { | ||
id: 76979871, | ||
width: 400, | ||
height: 400 | ||
}) | ||
}) | ||
</script> | ||
|
||
<template> | ||
<div id="player"></div> | ||
</template> | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
<template> | ||
<div ref="root" :id="id"> | ||
<slot /> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import { useIntersectionObserver } from "@vueuse/core"; | ||
Check failure on line 8 in src/runtime/components/VimeoEmbed.vue GitHub Actions / ci
|
||
import { ref, onBeforeUnmount, useId, useScriptVimeo } from "#imports"; | ||
Check failure on line 9 in src/runtime/components/VimeoEmbed.vue GitHub Actions / ci
|
||
const props = withDefaults( | ||
defineProps<{ | ||
videoId: string; | ||
lazy?: boolean; | ||
rootMargin?: string; | ||
width?: string | number; | ||
height?: string | number; | ||
options?: Object; | ||
loop?: boolean; | ||
autoplay?: boolean; | ||
controls?: boolean; | ||
}>(), | ||
{ | ||
lazy: true, | ||
rootMargin: "50px 50px 50px 50px", | ||
width: "640", | ||
height: "360", | ||
options: () => ({}), | ||
loop: false, | ||
autoplay: false, | ||
controls: true, | ||
} | ||
); | ||
// TODO: put events in <script> - after build it doesn't work for some reason | ||
// error: "both scripts must have same language type" even if they're both written in ts | ||
const events: string[] = [ | ||
"play", | ||
"playing", | ||
"pause", | ||
"ended", | ||
"timeupdate", | ||
"progress", | ||
"seeking", | ||
"seeked", | ||
"texttrackchange", | ||
"chapterchange", | ||
"cuechange", | ||
"cuepoint", | ||
"volumechange", | ||
"playbackratechange", | ||
"bufferstart", | ||
"bufferend", | ||
"error", | ||
"loaded", | ||
"durationchange", | ||
"fullscreenchange", | ||
"qualitychange", | ||
"camerachange", | ||
"resize", | ||
]; | ||
const emit = defineEmits([ | ||
"play", | ||
"playing", | ||
"pause", | ||
"ended", | ||
"timeupdate", | ||
"progress", | ||
"seeking", | ||
"seeked", | ||
"texttrackchange", | ||
"chapterchange", | ||
"cuechange", | ||
"cuepoint", | ||
"volumechange", | ||
"playbackratechange", | ||
"bufferstart", | ||
"bufferend", | ||
"error", | ||
"loaded", | ||
"durationchange", | ||
"fullscreenchange", | ||
"qualitychange", | ||
"camerachange", | ||
"resize", | ||
]); | ||
const _id = useId(); | ||
const id = _id.replace("-", "").replace("_", ""); | ||
const status: Ref<string | null> = ref(null); | ||
const root = ref(null); | ||
const { Player, $script } = useScriptVimeo({ | ||
trigger: props.lazy ? "manual" : undefined, | ||
}); | ||
let player: any; | ||
if (!props.lazy) $script.then(init); | ||
else { | ||
const { stop: stopIntersectionObserver } = useIntersectionObserver( | ||
root, | ||
([{ isIntersecting }]) => { | ||
if (isIntersecting && !$script.loaded) { | ||
$script.load().then(() => { | ||
init(); | ||
stopIntersectionObserver(); | ||
}); | ||
} | ||
}, | ||
{ rootMargin: props.rootMargin } | ||
); | ||
} | ||
onBeforeUnmount(() => player?.unload()); | ||
function init() { | ||
player = Player(id, { | ||
id: props.videoId, | ||
width: props.width, | ||
height: props.height, | ||
loop: props.loop, | ||
autoplay: props.autoplay, | ||
controls: props.controls, | ||
...props.options, | ||
}); | ||
for (const event of events) { | ||
player?.on(event, (e: any) => { | ||
emit(event as keyof typeof emit, e, player); | ||
status.value = event; | ||
}); | ||
} | ||
} | ||
function play() { | ||
player?.play(); | ||
} | ||
function pause() { | ||
player?.pause(); | ||
} | ||
function mute() { | ||
player?.setVolume(0); | ||
} | ||
function unmute(volume: number = 1) { | ||
player?.setVolume(volume); | ||
} | ||
defineExpose({ | ||
play, | ||
pause, | ||
mute, | ||
unmute, | ||
status, | ||
}); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { type Input, object, string } from 'valibot' | ||
import { useScript } from '#imports' | ||
import type { NuxtUseScriptOptions } from '#nuxt-scripts' | ||
|
||
export interface VimeoScriptApi { | ||
Player: any | ||
} | ||
|
||
export const VimeoScriptOptions = object({}) | ||
|
||
export type VimeoPlayer = ((...params: any[]) => void) | undefined | ||
|
||
export type VimeoScriptInput = Input<typeof VimeoScriptOptions> | ||
|
||
declare global { | ||
interface Window { | ||
Vimeo: VimeoScriptApi | ||
} | ||
} | ||
|
||
export function useScriptVimeo<T>(options?: VimeoScriptInput, _scriptOptions?: Omit<NuxtUseScriptOptions<T>, 'beforeInit' | 'use'>) { | ||
const scriptOptions: NuxtUseScriptOptions<T> = _scriptOptions || {} | ||
|
||
return useScript<VimeoScriptApi>({ | ||
key: 'vimeo', | ||
src: 'https://player.vimeo.com/api/player.js', | ||
...options, | ||
}, { | ||
...scriptOptions, | ||
use: () => { | ||
let Player: VimeoPlayer | ||
if (import.meta.client) { | ||
Player = function (...params: any[]) { | ||
return new window.Vimeo.Player(...params) | ||
} | ||
} | ||
return { Player } | ||
}, | ||
}) | ||
} |