your personal website on atproto - mirror
blento.app
1<script lang="ts">
2 import { onMount } from 'svelte';
3 import Icon from './Icon.svelte';
4 import {
5 getAdditionalUserData,
6 getDidContext,
7 getHandleContext,
8 getIsMobile
9 } from '$lib/website/context';
10 import type { ContentComponentProps } from '../types';
11 import { RelativeTime } from '@foxui/time';
12 import { Badge } from '@foxui/core';
13 import { CardDefinitionsByType } from '..';
14 import { browser } from '$app/environment';
15
16 let { item = $bindable() }: ContentComponentProps = $props();
17
18 let isMobile = getIsMobile();
19
20 let isLoaded = $state(false);
21
22 const data = getAdditionalUserData();
23
24 let latestLivestream = $state(
25 data[item.cardType] as
26 | {
27 createdAt: string;
28 title: string;
29 thumb?: string;
30 href: string;
31 online?: boolean;
32 }
33 | undefined
34 );
35
36 let did = getDidContext();
37 let handle = getHandleContext();
38
39 onMount(async () => {
40 if (!latestLivestream) {
41 latestLivestream = (await CardDefinitionsByType[item.cardType]?.loadData?.([], {
42 did,
43 handle
44 })) as
45 | {
46 createdAt: string;
47 title: string;
48 thumb?: string;
49 href: string;
50 online?: boolean;
51 }
52 | undefined;
53
54 data[item.cardType] = latestLivestream;
55
56 isLoaded = true;
57 }
58 });
59</script>
60
61<div class="h-full overflow-y-scroll p-4">
62 {#if latestLivestream}
63 <div class="flex min-h-full flex-col justify-between">
64 <div>
65 <div class="mb-4 flex items-center gap-2">
66 <Icon class="size-6" />
67 <div class="font-semibold">Latest Livestream</div>
68 </div>
69
70 <div class="mb-2 flex items-center gap-2">
71 <div class="text-xs font-medium">
72 started <RelativeTime date={new Date(latestLivestream.createdAt)} locale="en-US" /> ago
73 </div>
74 {#if latestLivestream.online === true}
75 <Badge size="sm">
76 <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
77 <circle cx="50" cy="50" r="30" fill="currentColor" />
78 </svg>
79
80 <span class="accent:text-base-900">live</span></Badge
81 >
82 {:else if latestLivestream.online === false}
83 <Badge size="sm" class="accent:text-base-900">ended</Badge>
84 {:else}
85 <div class="h-5.5"></div>
86 {/if}
87 </div>
88
89 <a href={latestLivestream?.href} target="_blank" rel="noopener noreferrer">
90 <div
91 class="text-accent-700 dark:text-accent-300 accent:text-accent-950 hover:accent:text-accent-900 hover:text-accent-600 dark:hover:text-accent-400 text-xl font-semibold transition-colors duration-150"
92 >
93 {latestLivestream?.title}
94 </div>
95 </a>
96 </div>
97
98 {#if browser && ((isMobile() && item.mobileH >= 7) || (!isMobile() && item.h >= 4)) && latestLivestream?.thumb}
99 <a href={latestLivestream?.href} target="_blank" rel="noopener noreferrer">
100 <img
101 class="my-4 max-h-32 w-full rounded-xl object-cover"
102 src={latestLivestream?.thumb}
103 alt=""
104 />
105 <span class="sr-only">open livestream</span>
106 </a>
107 {/if}
108 </div>
109 {:else if isLoaded}
110 <div class="flex h-full w-full items-center justify-center">No latest stream found!</div>
111 {:else}
112 <div class="flex h-full w-full items-center justify-center">Looking for the latest stream</div>
113 {/if}
114</div>