your personal website on atproto - mirror
blento.app
1<script lang="ts">
2 import { getDidContext } from '$lib/website/context';
3 import { getBlobURL } from '$lib/atproto';
4 import { onMount } from 'svelte';
5 import type { ContentComponentProps } from '../types';
6
7 let { item = $bindable() }: ContentComponentProps = $props();
8
9 const did = getDidContext();
10
11 let element: HTMLVideoElement | undefined = $state();
12
13 onMount(async () => {
14 const el = element;
15 if (!el) return;
16
17 el.muted = true;
18
19 // If we already have an objectUrl (preview before upload), use it directly
20 if (item.cardData.objectUrl) {
21 el.src = item.cardData.objectUrl;
22 el.play().catch((e) => {
23 console.error('Video play error:', e);
24 });
25 return;
26 }
27
28 // Fetch the video blob from the PDS
29 if (item.cardData.video?.video && typeof item.cardData.video.video === 'object') {
30 try {
31 const blobUrl = await getBlobURL({ did, blob: item.cardData.video.video });
32 const res = await fetch(blobUrl);
33 if (!res.ok) throw new Error(res.statusText);
34 const blob = await res.blob();
35 const url = URL.createObjectURL(blob);
36 el.src = url;
37 el.play().catch((e) => {
38 console.error('Video play error:', e);
39 });
40 } catch (e) {
41 console.error('Failed to load video:', e);
42 }
43 }
44 });
45</script>
46
47{#key item.cardData.video || item.cardData.objectUrl}
48 <video
49 bind:this={element}
50 muted
51 loop
52 autoplay
53 playsinline
54 class={[
55 'absolute inset-0 h-full w-full object-cover opacity-100 transition-transform duration-300 ease-in-out',
56 item.cardData.href ? 'group-hover:scale-102' : ''
57 ]}
58 ></video>
59{/key}
60{#if item.cardData.href}
61 <a
62 href={item.cardData.href}
63 class="absolute inset-0 h-full w-full"
64 target="_blank"
65 rel="noopener noreferrer"
66 >
67 <span class="sr-only">
68 {item.cardData.hrefText ?? 'Learn more'}
69 </span>
70
71 <div
72 class="bg-base-800/30 border-base-900/30 absolute top-2 right-2 rounded-full border p-1 text-white opacity-50 backdrop-blur-lg group-focus-within:opacity-100 group-hover:opacity-100"
73 >
74 <svg
75 xmlns="http://www.w3.org/2000/svg"
76 fill="none"
77 viewBox="0 0 24 24"
78 stroke-width="2.5"
79 stroke="currentColor"
80 class="size-4"
81 >
82 <path
83 stroke-linecap="round"
84 stroke-linejoin="round"
85 d="m4.5 19.5 15-15m0 0H8.25m11.25 0v11.25"
86 />
87 </svg>
88 </div>
89 </a>
90{/if}