your personal website on atproto - mirror blento.app
at signup 175 lines 4.0 kB view raw
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>