Files
yt2press/docs/.vitepress/theme/components/Video.vue
T
2026-09-24 08:48:40 +07:00

113 lines
2.6 KiB
Vue

<template>
<Teleport to="body">
<div :class="$style.container">
<YouTube ref="yt" v-if="youtubeID" :id="youtubeID" />
<video
v-else-if="videoURL"
controls
:src="videoURL"
ref="video"
@error="onVideoNotFound"
/>
</div>
</Teleport>
</template>
<script setup lang="ts">
import { useData } from "vitepress";
import { computed, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from "vue";
import YouTube from "./YouTube.vue";
const { frontmatter } = useData<{ video?: string }>();
const videoURL = computed(() => frontmatter.value?.video);
const videoEl = useTemplateRef("video");
const ytEl = useTemplateRef("yt");
const youtubeID = ref("");
function setImgClick() {
document.removeEventListener("click", imgClickListener);
document.addEventListener("click", imgClickListener);
document.querySelectorAll("img").forEach((img) => {
const [, min, sec] = /^(\d+)\:(\d+)$/.exec(img.alt) || [];
const t = min && sec ? parseInt(min) * 60 + parseInt(sec) : null;
if (!t) return;
img.title = img.title || img.alt;
});
}
function imgClickListener(ev: PointerEvent) {
if (!(ev.target instanceof HTMLImageElement)) return;
const img = ev.target;
const [, min, sec] = /^(\d+)\:(\d+)$/.exec(img.alt) || [];
const t = min && sec ? parseInt(min) * 60 + parseInt(sec) : null;
if (!t) return;
if (videoEl.value) {
videoEl.value.currentTime = t;
} else if (ytEl.value) {
ytEl.value.seekTo(t);
}
}
watch(videoURL, () => {
setImgClick();
});
function onVideoNotFound() {
const m = /\[(.+?)\]\.\S+$/.exec(videoURL.value || "") || [];
youtubeID.value = m[1] || "";
}
function onOrientationChanged() {
if (window.screen.orientation.type.startsWith("landscape")) {
if (videoEl.value) {
videoEl.value.requestFullscreen();
return;
} else if (ytEl.value) {
ytEl.value.requestFullscreen();
return;
}
}
if (document.fullscreenElement) {
document.exitFullscreen();
}
}
onMounted(() => {
setTimeout(() => setImgClick(), 500);
if (window.screen?.orientation) {
window.screen.orientation.addEventListener("change", onOrientationChanged);
}
});
onBeforeUnmount(() => {
if (window.screen?.orientation) {
window.screen.orientation.removeEventListener("change", onOrientationChanged);
}
if (document.fullscreenElement) {
document.exitFullscreen();
}
});
</script>
<style module>
.container {
width: 400px;
overflow: visible;
position: fixed;
bottom: 10px;
left: 10px;
z-index: 100;
> * {
width: 100%;
}
}
</style>