[READ-ONLY] Mirror of https://github.com/flo-bit/ui-kit. 🦊 fox ui, svelte 5 and tailwind 4 flo-bit.dev/ui-kit/
svelte tailwindcss ui-components
0

Configure Feed

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

add multi image post

Florian (Mar 2, 2025, 10:50 PM +0100) c74b0fa1 a7056bc6

+181 -10
+137
src/lib/assets/bluesky-posts.json
··· 306 306 "quoteCount": 0, 307 307 "indexedAt": "2025-02-23T15:16:49.557Z", 308 308 "labels": [] 309 + }, 310 + { 311 + "uri": "at://did:plc:257wekqxg4hyapkq6k47igmp/app.bsky.feed.post/3ljgfoyheyc2b", 312 + "cid": "bafyreig6ezdxinopozy525yplmkl62ywju2rzn5rv5tmlaqnahnsasaf3i", 313 + "author": { 314 + "did": "did:plc:257wekqxg4hyapkq6k47igmp", 315 + "handle": "flo-bit.dev", 316 + "displayName": "flo-bit", 317 + "avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:257wekqxg4hyapkq6k47igmp/bafkreib3idjnvcejkgivewbt4jji4wuv2f4rx6tuzwe6xqrzyajp4lmpjm@jpeg", 318 + "associated": { 319 + "chat": { 320 + "allowIncoming": "all" 321 + } 322 + }, 323 + "labels": [], 324 + "createdAt": "2024-11-08T02:10:04.377Z" 325 + }, 326 + "record": { 327 + "$type": "app.bsky.feed.post", 328 + "createdAt": "2025-03-02T21:42:17.766Z", 329 + "embed": { 330 + "$type": "app.bsky.embed.images", 331 + "images": [ 332 + { 333 + "alt": "screenshot of ui kit showing two social media posts, one with a video and one with links and an image ", 334 + "aspectRatio": { 335 + "height": 1472, 336 + "width": 1410 337 + }, 338 + "image": { 339 + "$type": "blob", 340 + "ref": { 341 + "$link": "bafkreigwg43qyxoq3q7vraoyyk3j7vaszvsd4t2bjsqdgvlw6rwgwcrrwm" 342 + }, 343 + "mimeType": "image/jpeg", 344 + "size": 555424 345 + } 346 + }, 347 + { 348 + "alt": "screenshot of a heatmap component", 349 + "aspectRatio": { 350 + "height": 442, 351 + "width": 1414 352 + }, 353 + "image": { 354 + "$type": "blob", 355 + "ref": { 356 + "$link": "bafkreif4x3rlhaazt2gij56zkqwiue6udzzltnsf4vtxm3obcqqccdqvja" 357 + }, 358 + "mimeType": "image/jpeg", 359 + "size": 202538 360 + } 361 + }, 362 + { 363 + "alt": "screenshot of a audio player component showing the waveform of the audio", 364 + "aspectRatio": { 365 + "height": 360, 366 + "width": 1428 367 + }, 368 + "image": { 369 + "$type": "blob", 370 + "ref": { 371 + "$link": "bafkreicdsnchw7oorja3zawcl5ukadczmh6bv22vfmbz2yw5eq3wmfj5xu" 372 + }, 373 + "mimeType": "image/jpeg", 374 + "size": 79355 375 + } 376 + }, 377 + { 378 + "alt": "screenshot of a login with bluesky modal where you can enter your bluesky handle", 379 + "aspectRatio": { 380 + "height": 804, 381 + "width": 1006 382 + }, 383 + "image": { 384 + "$type": "blob", 385 + "ref": { 386 + "$link": "bafkreidql2zac2efayojuvvw564qikmvbbdyhnl6pdm66ryiui2nlexbmy" 387 + }, 388 + "mimeType": "image/jpeg", 389 + "size": 115154 390 + } 391 + } 392 + ] 393 + }, 394 + "langs": [ 395 + "en" 396 + ], 397 + "text": "one of my goals with my svelte ui kit is making components that allow me to quickly make lots of different web apps, which is why I'm adding lots of components that aren't in most ui kits (afaik).\n\nsome examples:\n- social media post\n- heatmap\n- waveform audio player\n- login with bluesky modal\n[1/2]" 398 + }, 399 + "embed": { 400 + "$type": "app.bsky.embed.images#view", 401 + "images": [ 402 + { 403 + "thumb": "https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:257wekqxg4hyapkq6k47igmp/bafkreigwg43qyxoq3q7vraoyyk3j7vaszvsd4t2bjsqdgvlw6rwgwcrrwm@jpeg", 404 + "fullsize": "https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:257wekqxg4hyapkq6k47igmp/bafkreigwg43qyxoq3q7vraoyyk3j7vaszvsd4t2bjsqdgvlw6rwgwcrrwm@jpeg", 405 + "alt": "screenshot of ui kit showing two social media posts, one with a video and one with links and an image ", 406 + "aspectRatio": { 407 + "height": 1472, 408 + "width": 1410 409 + } 410 + }, 411 + { 412 + "thumb": "https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:257wekqxg4hyapkq6k47igmp/bafkreif4x3rlhaazt2gij56zkqwiue6udzzltnsf4vtxm3obcqqccdqvja@jpeg", 413 + "fullsize": "https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:257wekqxg4hyapkq6k47igmp/bafkreif4x3rlhaazt2gij56zkqwiue6udzzltnsf4vtxm3obcqqccdqvja@jpeg", 414 + "alt": "screenshot of a heatmap component", 415 + "aspectRatio": { 416 + "height": 442, 417 + "width": 1414 418 + } 419 + }, 420 + { 421 + "thumb": "https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:257wekqxg4hyapkq6k47igmp/bafkreicdsnchw7oorja3zawcl5ukadczmh6bv22vfmbz2yw5eq3wmfj5xu@jpeg", 422 + "fullsize": "https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:257wekqxg4hyapkq6k47igmp/bafkreicdsnchw7oorja3zawcl5ukadczmh6bv22vfmbz2yw5eq3wmfj5xu@jpeg", 423 + "alt": "screenshot of a audio player component showing the waveform of the audio", 424 + "aspectRatio": { 425 + "height": 360, 426 + "width": 1428 427 + } 428 + }, 429 + { 430 + "thumb": "https://cdn.bsky.app/img/feed_thumbnail/plain/did:plc:257wekqxg4hyapkq6k47igmp/bafkreidql2zac2efayojuvvw564qikmvbbdyhnl6pdm66ryiui2nlexbmy@jpeg", 431 + "fullsize": "https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:257wekqxg4hyapkq6k47igmp/bafkreidql2zac2efayojuvvw564qikmvbbdyhnl6pdm66ryiui2nlexbmy@jpeg", 432 + "alt": "screenshot of a login with bluesky modal where you can enter your bluesky handle", 433 + "aspectRatio": { 434 + "height": 804, 435 + "width": 1006 436 + } 437 + } 438 + ] 439 + }, 440 + "replyCount": 1, 441 + "repostCount": 0, 442 + "likeCount": 0, 443 + "quoteCount": 0, 444 + "indexedAt": "2025-03-02T21:42:25.055Z", 445 + "labels": [] 309 446 } 310 447 ] 311 448 }
+29 -1
src/lib/preview/PostPreview.svelte
··· 9 9 let blueskyPosts: PostData[] | null = $derived( 10 10 data.posts.map((post: unknown) => { 11 11 return blueskyPostToPostData(post); 12 - }) 12 + }).reverse() 13 13 ); 14 + 15 + // onMount(async () => { 16 + // let uris = [ 17 + // 'at://did:plc:257wekqxg4hyapkq6k47igmp/app.bsky.feed.post/3lj3hqgiynk2v', 18 + // 'at://did:plc:257wekqxg4hyapkq6k47igmp/app.bsky.feed.post/3lj6idw2ibc22', 19 + // 'at://did:plc:257wekqxg4hyapkq6k47igmp/app.bsky.feed.post/3lj6hwahre222', 20 + // 'at://did:plc:257wekqxg4hyapkq6k47igmp/app.bsky.feed.post/3liu4v5sa7s2a', 21 + // 'at://did:plc:257wekqxg4hyapkq6k47igmp/app.bsky.feed.post/3ljgfoyheyc2b' 22 + // ]; 23 + // const params = new URLSearchParams(); 24 + // uris.forEach((uri) => params.append('uris', uri)); 25 + 26 + // const response = await fetch( 27 + // `https://public.api.bsky.app/xrpc/app.bsky.feed.getPosts?${params.toString()}` 28 + // ); 29 + 30 + // const data = await response.json(); 31 + 32 + // // download data as json 33 + // const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); 34 + // const url = URL.createObjectURL(blob); 35 + // const a = document.createElement('a'); 36 + // a.href = url; 37 + // a.download = 'data.json'; 38 + // a.click(); 39 + 40 + // }); 41 + 14 42 15 43 </script> 16 44
+15 -9
src/lib/components/post/embeds/Images.svelte
··· 4 4 const { data }: { data: PostEmbedImage } = $props(); 5 5 </script> 6 6 7 - {#snippet imageSnippet(image: { 8 - alt: string; 9 - thumb: string; 10 - fullsize: string; 11 - aspectRatio?: { width: number; height: number }; 12 - })} 7 + {#snippet imageSnippet( 8 + image: { 9 + alt: string; 10 + thumb: string; 11 + fullsize: string; 12 + aspectRatio?: { width: number; height: number }; 13 + }, 14 + className?: string 15 + )} 13 16 <img 14 17 loading="lazy" 15 18 src={image.thumb} ··· 17 20 style={image.aspectRatio 18 21 ? `aspect-ratio: ${image.aspectRatio.width} / ${image.aspectRatio.height}` 19 22 : 'aspect-ratio: 1 / 1'} 20 - class="border-base-500/20 dark:border-base-400/20 w-full rounded-2xl border object-cover" 23 + class={[ 24 + 'border-base-500/20 dark:border-base-400/20 w-full rounded-2xl border object-cover', 25 + className 26 + ]} 21 27 /> 22 28 {/snippet} 23 29 24 30 {#if data.images.length === 1} 25 31 {@render imageSnippet(data.images[0])} 26 32 {:else} 27 - <div class="grid grid-cols-2 gap-4"> 33 + <div class="columns-2 gap-4"> 28 34 {#each data.images as image} 29 - {@render imageSnippet(image)} 35 + {@render imageSnippet(image, 'mb-4')} 30 36 {/each} 31 37 </div> 32 38 {/if}