your personal website on atproto - mirror
blento.app
1<script lang="ts">
2 import type { Item } from '$lib/types';
3 import { onMount } from 'svelte';
4 import { getAdditionalUserData } from '$lib/website/context';
5 import { getCDNImageBlobUrl, parseUri } from '$lib/atproto';
6 import { loadGrainGalleryData } from './helpers';
7
8 import { ImageMasonry } from '@foxui/visual';
9 import { openImageViewer } from '$lib/components/image-viewer/imageViewer.svelte';
10
11 interface PhotoItem {
12 uri: string;
13 value: {
14 photo: { $type: 'blob'; ref: { $link: string } };
15 aspectRatio: { width: number; height: number };
16 position?: number;
17 };
18 }
19
20 let { item }: { item: Item } = $props();
21
22 const data = getAdditionalUserData();
23 // svelte-ignore state_referenced_locally
24 let feed = $state(
25 (data[item.cardType] as Record<string, PhotoItem[]> | undefined)?.[item.cardData.galleryUri]
26 );
27
28 onMount(async () => {
29 if (!feed) {
30 feed = ((await loadGrainGalleryData([item])) as Record<string, PhotoItem[]> | undefined)?.[
31 item.cardData.galleryUri
32 ];
33
34 data[item.cardType] = feed;
35 }
36 });
37
38 let images = $derived(
39 (feed
40 ?.toSorted((a: PhotoItem, b: PhotoItem) => {
41 return (a.value.position ?? 0) - (b.value.position ?? 0);
42 })
43 .map((i: PhotoItem) => {
44 const item = parseUri(i.uri);
45 const src = getCDNImageBlobUrl({ did: item?.repo, blob: i.value.photo });
46 return {
47 src,
48 name: '',
49 width: i.value.aspectRatio.width,
50 height: i.value.aspectRatio.height,
51 position: i.value.position ?? 0,
52 onclick: src ? () => openImageViewer(src) : undefined
53 };
54 })
55 .filter((i) => i.src !== undefined) || []) as {
56 src: string;
57 name: string;
58 width: number;
59 height: number;
60 position: number;
61 onclick?: () => void;
62 }[]
63 );
64</script>
65
66<div class="photo-gallery-card z-10 flex h-full w-full flex-col gap-4 overflow-y-scroll p-4">
67 <div class="gallery-compact">
68 <ImageMasonry images={images ?? []} showNames={false} maxColumns={2} />
69 </div>
70 <div class="gallery-wide">
71 <ImageMasonry images={images ?? []} showNames={false} maxColumns={3} />
72 </div>
73</div>
74
75<style>
76 .gallery-wide {
77 display: none;
78 }
79
80 @container card (width >= 28rem) {
81 .gallery-compact {
82 display: none;
83 }
84
85 .gallery-wide {
86 display: block;
87 }
88 }
89</style>