Personal Site
0
fork

Configure Feed

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

Add embed content

TODO: make links look a little nicer

+106 -8
+106 -8
src/components/home/feeds/Post.astro
··· 3 3 import { type Blob, type LegacyBlob } from "@atcute/lexicons"; 4 4 import { AppBskyFeedPost } from "@atcute/bluesky"; 5 5 import { segmentize } from "@atcute/bluesky-richtext-segmenter"; 6 - import { type Author, understoodDid, type embed } from "./post-types"; 6 + import { 7 + type Author, 8 + understoodDid, 9 + type embed, 10 + type embedImages, 11 + type embedVideo, 12 + type embedExternal, 13 + type embedRecord, 14 + type embedRecordWithMedia, 15 + } from "./post-types"; 7 16 import { 8 17 images, 9 18 video, ··· 117 126 <div class="post-text">{ 118 127 !post.facets 119 128 ? post.text 120 - : segmentize(post.text.trim(), post.facets).map((x) => { 121 - console.log(x); 122 - return !x.features 129 + : segmentize(post.text.trim(), post.facets).map((x) => !x.features 123 130 ? x.text 124 131 : x.features.reduce( 125 132 (acc, cur) => ··· 131 138 <a href={`https://deer.social/hashtag/${cur.tag}`}>{acc}</a> 132 139 ), 133 140 x.text, 134 - ); 135 - }) 141 + )) 136 142 } 137 143 </div> 138 - <div class="embed">{(() => {})()}</div> 144 + { 145 + embed && ( 146 + <div class="embed"> 147 + {(() => { 148 + const images = (img: embedImages) => 149 + img.images.map((image) => ( 150 + <img src={cidSrc(image.cid, author.did)} alt={image.alt} /> 151 + )); 152 + const video = (vid: embedVideo) => ( 153 + <video 154 + controls 155 + crossorigin="anonymous" 156 + src={cidSrc(vid.cid, author.did)} 157 + aria-label={vid.alt} 158 + > 159 + {vid.subtitles && 160 + vid.subtitles.map((track, i) => ( 161 + <track 162 + default={i === 0} 163 + kind="captions" 164 + srclang={track.lang} 165 + src={cidSrc(track.cid, author.did)} 166 + /> 167 + ))} 168 + </video> 169 + ); 170 + const external = (external: embedExternal) => ( 171 + <a href={external.url} class="external"> 172 + {external.thumb && ( 173 + <img src={cidSrc(external.thumb, author.did)} alt="" /> 174 + )} 175 + <span>{external.title}</span> 176 + </a> 177 + ); 178 + const record = (record: embedRecord) => { 179 + const uriFragments = record.uri.match( 180 + new RegExp( 181 + "at:\/\/(?<did>did:(?:plc|web):[^\/]*)\/(?<nsid>[^\/]*)\/(?<rkey>.*)", 182 + ), 183 + ); 184 + let rkey: string = uriFragments?.groups?.rkey ?? ""; 185 + return record.record && record.author ? ( 186 + <Astro.self 187 + post={record.record} 188 + author={record.author} 189 + {rkey} 190 + nested 191 + /> 192 + ) : ( 193 + <div class="post"> 194 + Read More on 195 + <a 196 + href={`https://deer.social/profile/${author.did}/post/${rkey}`} 197 + > 198 + deer.social 199 + </a> 200 + </div> 201 + ); 202 + }; 203 + const recordWithMedia = (recordWMedia: embedRecordWithMedia) => { 204 + const quoted = record(recordWMedia.record); 205 + const media = 206 + recordWMedia.media.$type === "app.bsky.embed.images" 207 + ? images(recordWMedia.media) 208 + : recordWMedia.media.$type === "app.bsky.embed.video" 209 + ? video(recordWMedia.media) 210 + : external(recordWMedia.media); 211 + return ( 212 + <> 213 + {media} 214 + {quoted} 215 + </> 216 + ); 217 + }; 218 + 219 + switch (embed.$type) { 220 + case "app.bsky.embed.images": 221 + return images(embed); 222 + case "app.bsky.embed.video": 223 + return video(embed); 224 + case "app.bsky.embed.external": 225 + return external(embed); 226 + case "app.bsky.embed.record": 227 + return record(embed); 228 + case "app.bsky.embed.recordWithMedia": 229 + return recordWithMedia(embed); 230 + } 231 + })()} 232 + </div> 233 + ) 234 + } 139 235 </div> 140 236 </section> 141 237 </article> 142 238 143 239 <style> 144 - .post { 240 + .post, 241 + .external { 242 + display: block; 145 243 border-image: var(--box-tlbr-png) 10 10 fill / 20px 20px round; 146 244 padding: 30px; 147 245 }