Personal Site
0
fork

Configure Feed

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

Extract embed types and handlers into their own files

+202 -160
+23 -160
src/components/home/feeds/Post.astro
··· 9 9 import { AppBskyFeedPost } from "@atcute/bluesky"; 10 10 import { throws, type Prettify } from "/utils"; 11 11 import BoxTlbr from "/assets/box-tlbr.png"; 12 - 13 - export interface Author { 14 - did: `did:${string}:${string}`; 15 - handle: `${string}.${string}`; 16 - displayName?: string; 17 - avatar?: `${string}:${string}`; 18 - } 12 + import { 13 + type Author, 14 + understoodDid, 15 + type embed, 16 + type embedExternal, 17 + type embedImages, 18 + type embedRecord, 19 + type embedRecordWithMedia, 20 + type embedVideo, 21 + } from "./post-types"; 22 + import { 23 + images, 24 + video, 25 + external, 26 + record, 27 + recordWithMedia, 28 + } from "./post-embeds"; 19 29 20 30 interface Props { 21 31 post: AppBskyFeedPost.Main; ··· 25 35 26 36 const { post, author, nested = false } = Astro.props; 27 37 28 - const understoodDid = ( 29 - did: `did:${string}:${string}`, 30 - ): did is `did:${"plc" | "web"}:${string}` => 31 - did.startsWith("did:web") || did.startsWith("did:plc"); 32 38 // resolve the pds. bit hacky but should work 33 39 const pds = await docResolver 34 40 .resolve(understoodDid(author.did) ? author.did : "did:plc:failure") ··· 51 57 pds, 52 58 ).toString(); 53 59 54 - // types 55 - type embedImages = { 56 - $type: "app.bsky.embed.images"; 57 - images: { alt: string; cid: Blob | LegacyBlob }[]; 58 - }; 59 - 60 - type embedVideo = { 61 - $type: "app.bsky.embed.video"; 62 - cid: Blob | LegacyBlob; 63 - alt: string | undefined; 64 - subtitles: 65 - | { 66 - cid: Blob | LegacyBlob; 67 - lang: string; 68 - }[] 69 - | undefined; 70 - }; 71 - 72 - type embedExternal = { 73 - $type: "app.bsky.embed.external"; 74 - title: string; 75 - url: string; 76 - thumb: Blob | LegacyBlob | undefined; 77 - }; 78 - type embedRecord = { 79 - $type: "app.bsky.embed.record"; 80 - record: AppBskyFeedPost.Main | null; 81 - author: Author | null; 82 - }; 83 - 84 - type embedRecordWithMedia = { 85 - $type: "app.bsky.embed.recordWithMedia"; 86 - record: embedRecord; 87 - media: embedImages | embedVideo | embedExternal; 88 - }; 89 - 90 - type embed = 91 - | embedImages 92 - | embedVideo 93 - | embedExternal 94 - | embedRecord 95 - | embedRecordWithMedia; 96 - 97 - // generate embed types 98 - const images = ( 99 - images: { alt: string; image: Blob | LegacyBlob }[], 100 - ): embedImages => ({ 101 - $type: "app.bsky.embed.images", 102 - images: images.map((image) => ({ 103 - alt: image.alt, 104 - cid: image.image, 105 - })), 106 - }); 107 - 108 - const video = ( 109 - video: Blob | LegacyBlob, 110 - alt: string | undefined, 111 - captions: 112 - | { 113 - file: Blob | LegacyBlob; 114 - lang: string; 115 - }[] 116 - | undefined, 117 - ): embedVideo => ({ 118 - $type: "app.bsky.embed.video", 119 - cid: video, 120 - alt: alt, 121 - subtitles: 122 - captions && 123 - captions.map((captions) => ({ 124 - cid: captions.file, 125 - lang: captions.lang, 126 - })), 127 - }); 128 - 129 - const external = (external: { 130 - title: string; 131 - uri: `${string}:${string}`; 132 - thumb?: Blob | LegacyBlob | undefined; 133 - }): embedExternal => ({ 134 - $type: "app.bsky.embed.external", 135 - title: external.title, 136 - url: external.uri, 137 - thumb: external.thumb, 138 - }); 139 - 140 - const record = async (uri: ResourceUri): Promise<Prettify<embedRecord>> => { 141 - if (nested) 142 - return { $type: "app.bsky.embed.record", record: null, author: null }; 143 - const data = await client 144 - .get("app.bsky.feed.getPosts", { 145 - params: { 146 - uris: [uri], 147 - }, 148 - }) 149 - .then(({ ok, data }) => 150 - ok ? data : throws(data.error + "\n" + data.message), 151 - ); 152 - 153 - return { 154 - $type: "app.bsky.embed.record", 155 - record: is(AppBskyFeedPost.mainSchema, data.posts[0].record) 156 - ? data.posts[0].record 157 - : throws("Malformed embeded post"), 158 - author: { 159 - did: data.posts[0].author.did, 160 - displayName: data.posts[0].author.displayName, 161 - handle: data.posts[0].author.handle, 162 - avatar: data.posts[0].author.avatar, 163 - }, 164 - }; 165 - }; 166 - 167 - const recordWithMedia = async ( 168 - uri: ResourceUri, 169 - media: 170 - | { 171 - $type: "app.bsky.embed.images"; 172 - images: { alt: string; image: Blob | LegacyBlob }[]; 173 - } 174 - | { 175 - $type: "app.bsky.embed.video"; 176 - video: Blob | LegacyBlob; 177 - alt?: string | undefined; 178 - captions?: { lang: string; file: Blob | LegacyBlob }[] | undefined; 179 - } 180 - | { 181 - $type: "app.bsky.embed.external"; 182 - external: { 183 - title: string; 184 - uri: `${string}:${string}`; 185 - thumb?: Blob | LegacyBlob | undefined; 186 - }; 187 - }, 188 - ): Promise<embedRecordWithMedia> => { 189 - return { 190 - $type: "app.bsky.embed.recordWithMedia", 191 - record: await record(uri), 192 - media: 193 - media.$type === "app.bsky.embed.images" 194 - ? images(media.images) 195 - : media.$type === "app.bsky.embed.video" 196 - ? video(media.video, media.alt, media.captions) 197 - : external(media.external), 198 - }; 199 - }; 200 - 201 60 const embed: embed | null = await (async () => { 202 61 if (!post.embed) return null; 203 62 switch (post.embed.$type) { ··· 211 70 return external(post.embed.external); 212 71 213 72 case "app.bsky.embed.record": 214 - return await record(post.embed.record.uri); 73 + return await record(post.embed.record.uri, nested); 215 74 216 75 case "app.bsky.embed.recordWithMedia": 217 - return recordWithMedia(post.embed.record.record.uri, post.embed.media); 76 + return recordWithMedia( 77 + post.embed.record.record.uri, 78 + post.embed.media, 79 + nested, 80 + ); 218 81 } 219 82 })(); 220 83 ---
+123
src/components/home/feeds/post-embeds.ts
··· 1 + import { AppBskyFeedPost } from "@atcute/bluesky"; 2 + import { 3 + type LegacyBlob, 4 + type Blob, 5 + type ResourceUri, 6 + is, 7 + } from "@atcute/lexicons"; 8 + import { client } from "./atproto"; 9 + import type { 10 + embedImages, 11 + embedVideo, 12 + embedExternal, 13 + embedRecord, 14 + embedRecordWithMedia, 15 + } from "./post-types"; 16 + import { throws, type Prettify } from "/utils"; 17 + 18 + export const images = ( 19 + images: { alt: string; image: Blob | LegacyBlob }[], 20 + ): embedImages => ({ 21 + $type: "app.bsky.embed.images", 22 + images: images.map((image) => ({ 23 + alt: image.alt, 24 + cid: image.image, 25 + })), 26 + }); 27 + 28 + export const video = ( 29 + video: Blob | LegacyBlob, 30 + alt: string | undefined, 31 + captions: 32 + | { 33 + file: Blob | LegacyBlob; 34 + lang: string; 35 + }[] 36 + | undefined, 37 + ): embedVideo => ({ 38 + $type: "app.bsky.embed.video", 39 + cid: video, 40 + alt: alt, 41 + subtitles: 42 + captions && 43 + captions.map((captions) => ({ 44 + cid: captions.file, 45 + lang: captions.lang, 46 + })), 47 + }); 48 + 49 + export const external = (external: { 50 + title: string; 51 + uri: `${string}:${string}`; 52 + thumb?: Blob | LegacyBlob | undefined; 53 + }): embedExternal => ({ 54 + $type: "app.bsky.embed.external", 55 + title: external.title, 56 + url: external.uri, 57 + thumb: external.thumb, 58 + }); 59 + 60 + export const record = async ( 61 + uri: ResourceUri, 62 + nested: boolean, 63 + ): Promise<Prettify<embedRecord>> => { 64 + if (nested) 65 + return { $type: "app.bsky.embed.record", record: null, author: null }; 66 + const data = await client 67 + .get("app.bsky.feed.getPosts", { 68 + params: { 69 + uris: [uri], 70 + }, 71 + }) 72 + .then(({ ok, data }) => 73 + ok ? data : throws(data.error + "\n" + data.message), 74 + ); 75 + 76 + return { 77 + $type: "app.bsky.embed.record", 78 + record: is(AppBskyFeedPost.mainSchema, data.posts[0].record) 79 + ? data.posts[0].record 80 + : throws("Malformed embeded post"), 81 + author: { 82 + did: data.posts[0].author.did, 83 + displayName: data.posts[0].author.displayName, 84 + handle: data.posts[0].author.handle, 85 + avatar: data.posts[0].author.avatar, 86 + }, 87 + }; 88 + }; 89 + 90 + export const recordWithMedia = async ( 91 + uri: ResourceUri, 92 + media: 93 + | { 94 + $type: "app.bsky.embed.images"; 95 + images: { alt: string; image: Blob | LegacyBlob }[]; 96 + } 97 + | { 98 + $type: "app.bsky.embed.video"; 99 + video: Blob | LegacyBlob; 100 + alt?: string | undefined; 101 + captions?: { lang: string; file: Blob | LegacyBlob }[] | undefined; 102 + } 103 + | { 104 + $type: "app.bsky.embed.external"; 105 + external: { 106 + title: string; 107 + uri: `${string}:${string}`; 108 + thumb?: Blob | LegacyBlob | undefined; 109 + }; 110 + }, 111 + nested: boolean, 112 + ): Promise<embedRecordWithMedia> => { 113 + return { 114 + $type: "app.bsky.embed.recordWithMedia", 115 + record: await record(uri, nested), 116 + media: 117 + media.$type === "app.bsky.embed.images" 118 + ? images(media.images) 119 + : media.$type === "app.bsky.embed.video" 120 + ? video(media.video, media.alt, media.captions) 121 + : external(media.external), 122 + }; 123 + };
+56
src/components/home/feeds/post-types.ts
··· 1 + import type { AppBskyFeedPost } from "@atcute/bluesky"; 2 + import type { Blob, LegacyBlob } from "@atcute/lexicons"; 3 + 4 + export interface Author { 5 + did: `did:${string}:${string}`; 6 + handle: `${string}.${string}`; 7 + displayName?: string; 8 + avatar?: `${string}:${string}`; 9 + } 10 + 11 + export const understoodDid = ( 12 + did: `did:${string}:${string}`, 13 + ): did is `did:${"plc" | "web"}:${string}` => 14 + did.startsWith("did:web") || did.startsWith("did:plc"); 15 + 16 + export type embedImages = { 17 + $type: "app.bsky.embed.images"; 18 + images: { alt: string; cid: Blob | LegacyBlob }[]; 19 + }; 20 + 21 + export type embedVideo = { 22 + $type: "app.bsky.embed.video"; 23 + cid: Blob | LegacyBlob; 24 + alt: string | undefined; 25 + subtitles: 26 + | { 27 + cid: Blob | LegacyBlob; 28 + lang: string; 29 + }[] 30 + | undefined; 31 + }; 32 + 33 + export type embedExternal = { 34 + $type: "app.bsky.embed.external"; 35 + title: string; 36 + url: string; 37 + thumb: Blob | LegacyBlob | undefined; 38 + }; 39 + export type embedRecord = { 40 + $type: "app.bsky.embed.record"; 41 + record: AppBskyFeedPost.Main | null; 42 + author: Author | null; 43 + }; 44 + 45 + export type embedRecordWithMedia = { 46 + $type: "app.bsky.embed.recordWithMedia"; 47 + record: embedRecord; 48 + media: embedImages | embedVideo | embedExternal; 49 + }; 50 + 51 + export type embed = 52 + | embedImages 53 + | embedVideo 54 + | embedExternal 55 + | embedRecord 56 + | embedRecordWithMedia;