your personal website on atproto - mirror
blento.app
1<script lang="ts" module>
2 export const videoPlayer: {
3 id: string | undefined;
4
5 show: (id: string) => void;
6 hide: () => void;
7 } = $state({
8 id: undefined,
9
10 show: (id: string) => {
11 videoPlayer.id = id;
12 },
13
14 hide: () => {
15 videoPlayer.id = undefined;
16 }
17 });
18</script>
19
20<script lang="ts">
21 import { cn } from '@foxui/core';
22 import { onDestroy, onMount } from 'svelte';
23
24 // Minimal Plyr interface for what we use
25 interface PlyrInstance {
26 source: {
27 type: string;
28 sources: { src: string; type: string }[];
29 };
30 on: (event: string, callback: () => void) => void;
31 play: () => void;
32 destroy: () => void;
33 }
34
35 interface PlyrConstructorType {
36 new (selector: string, options: Record<string, unknown>): PlyrInstance;
37 }
38
39 const { class: className }: { class?: string } = $props();
40
41 let PlyrConstructor: PlyrConstructorType | undefined = $state();
42
43 let player: PlyrInstance | undefined = $state();
44
45 onMount(async () => {
46 if (!PlyrConstructor) {
47 const plyrModule = (await import('plyr')) as unknown as { default: PlyrConstructorType };
48 PlyrConstructor = plyrModule.default;
49 }
50
51 player = new PlyrConstructor('.js-player', {
52 settings: ['captions', 'quality', 'loop', 'speed'],
53 controls: [
54 'play-large',
55 'play',
56 'progress',
57 'current-time',
58 'volume',
59 'settings',
60 'download',
61 'fullscreen'
62 ]
63 });
64
65 // set the video player to the id
66 if (videoPlayer.id) {
67 player.source = {
68 type: 'video',
69 sources: [
70 {
71 src: videoPlayer.id,
72 type: 'video/youtube'
73 }
74 ]
75 };
76 }
77
78 // when loaded play the video and go fullscreen
79 player.on('ready', () => {
80 player?.play();
81 //player.fullscreen.enter();
82 });
83 });
84
85 onDestroy(() => {
86 player?.destroy();
87 });
88
89 let glow = 50;
90</script>
91
92<svelte:head>
93 {#if videoPlayer.id}
94 <link rel="stylesheet" href="https://cdn.plyr.io/3.7.8/plyr.css" />
95 {/if}
96</svelte:head>
97
98<svelte:window
99 onkeydown={(e) => {
100 if (e.key === 'Escape') {
101 videoPlayer.hide();
102 }
103 }}
104/>
105
106{#key videoPlayer.id}
107 {#if videoPlayer.id}
108 <div class="fixed inset-0 z-100 flex h-screen w-screen items-center justify-center">
109 <button
110 onclick={() => videoPlayer.hide()}
111 class="absolute inset-0 bg-black/70 backdrop-blur-sm"
112 >
113 <span class="sr-only">Close</span>
114 </button>
115
116 <div
117 class={cn(
118 'relative mx-4 aspect-video max-h-screen w-full overflow-hidden rounded-xl border border-black bg-white object-cover sm:mx-20 dark:border-white/10 dark:bg-white/5',
119 className
120 )}
121 style="filter: url(#blur); width: 100%;"
122 >
123 <div class="">
124 <div
125 id="player"
126 class="h-full w-full overflow-hidden rounded-xl object-cover font-semibold text-black dark:text-white"
127 >
128 <div
129 class="js-player plyr__video-embed"
130 id="player"
131 data-plyr-provider="youtube"
132 data-plyr-embed-id={videoPlayer.id}
133 ></div>
134 </div>
135 </div>
136 </div>
137
138 <button
139 onclick={() => {
140 videoPlayer.hide();
141 }}
142 class="absolute top-2 right-2 z-20 rounded-full border border-white/10 bg-white/5 p-2 backdrop-blur-sm"
143 >
144 <svg
145 xmlns="http://www.w3.org/2000/svg"
146 viewBox="0 0 24 24"
147 fill="currentColor"
148 class="size-6"
149 >
150 <path
151 fill-rule="evenodd"
152 d="M5.47 5.47a.75.75 0 0 1 1.06 0L12 10.94l5.47-5.47a.75.75 0 1 1 1.06 1.06L13.06 12l5.47 5.47a.75.75 0 1 1-1.06 1.06L12 13.06l-5.47 5.47a.75.75 0 0 1-1.06-1.06L10.94 12 5.47 6.53a.75.75 0 0 1 0-1.06Z"
153 clip-rule="evenodd"
154 />
155 </svg>
156
157 <span class="sr-only">Close</span>
158 </button>
159 </div>
160 {/if}
161{/key}
162
163<svg width="0" height="0">
164 <filter id="blur" y="-50%" x="-50%" width="300%" height="300%">
165 <feGaussianBlur in="SourceGraphic" stdDeviation={glow} result="blurred" />
166 <feColorMatrix type="saturate" in="blurred" values="3" />
167 <feComposite in="SourceGraphic" operator="over" />
168 </filter>
169</svg>
170
171<style>
172 * {
173 --plyr-color-main: var(--color-accent-500);
174 }
175</style>