your personal website on atproto - mirror blento.app
24
fork

Configure Feed

Select the types of activity you want to include in your feed.

at button 127 lines 3.2 kB view raw
1<script lang="ts"> 2 import { Button, Input, Label, Modal, Subheading } from '@foxui/core'; 3 import type { CreationModalComponentProps } from '../types'; 4 import { onMount } from 'svelte'; 5 import { getDidContext } from '$lib/website/context'; 6 import { getAuthorFeed } from '$lib/atproto/methods'; 7 8 let { item = $bindable(), oncreate, oncancel }: CreationModalComponentProps = $props(); 9 10 let did = getDidContext(); 11 12 let mediaList: { fullsize: string; isVideo?: boolean; playlist?: string; thumbnail?: string }[] = 13 $state([]); 14 15 let isLoading = $state(true); 16 17 onMount(async () => { 18 const authorFeed = await getAuthorFeed({ did }); 19 20 for (let post of authorFeed?.feed ?? []) { 21 let images = 22 post.post.embed?.$type === 'app.bsky.embed.images#view' ? post.post.embed : undefined; 23 24 for (let image of images?.images ?? []) { 25 mediaList.push(image); 26 } 27 28 if ( 29 post.post.embed?.$type === 'app.bsky.embed.video#view' && 30 post.post.embed.thumbnail && 31 post.post.embed.playlist 32 ) { 33 mediaList.push({ 34 ...post.post.embed, 35 isVideo: true, 36 fullsize: '' 37 }); 38 } 39 } 40 41 isLoading = false; 42 }); 43 44 let selected = $state(); 45</script> 46 47<Modal 48 bind:open={ 49 () => true, 50 (change) => { 51 if (!change) oncancel(); 52 } 53 } 54 closeButton={false} 55 class="flex max-h-screen flex-col" 56> 57 <Subheading>Select an image or video</Subheading> 58 59 <div 60 class="bg-base-100 dark:bg-base-950 grid h-[50dvh] grid-cols-2 gap-4 overflow-y-scroll rounded-2xl p-4 lg:grid-cols-3" 61 > 62 {#each mediaList as media (media.thumbnail || media.playlist)} 63 <button 64 onclick={() => { 65 console.log(media); 66 selected = media; 67 if (media.isVideo) { 68 item.cardData = { 69 video: media 70 }; 71 } else item.cardData.image = media; 72 }} 73 class="relative cursor-pointer" 74 > 75 <img 76 src={media.fullsize || media.thumbnail} 77 alt="" 78 class={[ 79 'h-32 w-full rounded-xl object-cover', 80 selected === media 81 ? 'outline-accent-500 opacity-100 outline-2 -outline-offset-2' 82 : 'opacity-80' 83 ]} 84 /> 85 {#if media.isVideo} 86 <div class="absolute inset-0 inline-flex items-center justify-center"> 87 <svg 88 xmlns="http://www.w3.org/2000/svg" 89 viewBox="0 0 24 24" 90 fill="currentColor" 91 class="text-accent-500 size-6" 92 > 93 <path 94 d="M4.5 4.5a3 3 0 0 0-3 3v9a3 3 0 0 0 3 3h8.25a3 3 0 0 0 3-3v-9a3 3 0 0 0-3-3H4.5ZM19.94 18.75l-2.69-2.69V7.94l2.69-2.69c.944-.945 2.56-.276 2.56 1.06v11.38c0 1.336-1.616 2.005-2.56 1.06Z" 95 /> 96 </svg> 97 </div> 98 {/if} 99 </button> 100 {/each} 101 {#if isLoading} 102 <span class="col-span-full p-4 text-lg italic">Loading your media...</span> 103 {:else if mediaList.length === 0} 104 <span class="col-span-full p-4 text-lg italic" 105 >No media found, upload an image or video to bluesky to see it here.</span 106 > 107 {/if} 108 </div> 109 110 <Label class="mt-4">Link (optional):</Label> 111 <Input bind:value={item.cardData.href} /> 112 113 <div class="mt-4 flex justify-end gap-2"> 114 <Button 115 onclick={() => { 116 oncancel(); 117 }} 118 variant="ghost">Cancel</Button 119 > 120 <Button 121 disabled={!selected} 122 onclick={async () => { 123 oncreate(); 124 }}>Create</Button 125 > 126 </div> 127</Modal>