A web component that renders a collection of Bluesky comments. (Doesn't work)
BlueskyCommmentSection.astro
102 lines 2.7 kB view raw
1<script> 2 import { AtpAgent } from '@atproto/api'; 3 import { 4 isThreadViewPost, 5 type PostView, 6 } from '@atproto/api/dist/client/types/app/bsky/feed/defs'; 7 8 export class BlueskyCommentsSection extends HTMLElement { 9 static agent = new AtpAgent({ 10 service: new URL('https://api.bsky.app'), 11 }); 12 13 constructor() { 14 super(); 15 } 16 17 connectedCallback() { 18 this.getComments() 19 .then((comments) => { 20 comments.forEach((comment) => this.createCommentArticle(comment)); 21 }) 22 .catch(console.error); 23 } 24 25 async getComments() { 26 const { blueskyDid, blogTitle } = this.dataset; 27 28 if (!blueskyDid) throw new Error('A Bluesky DID is required!'); 29 30 if (!blogTitle) throw new Error('A blog title is required!'); 31 32 const post = await BlueskyCommentsSection.agent.app.bsky.feed 33 .searchPosts({ 34 q: `#blog #${blogTitle.toLowerCase().replaceAll(' ', '-')}`, 35 author: blueskyDid, 36 limit: 1, 37 }) 38 .then(({ data }) => { 39 if (!data.posts) return undefined; 40 41 return data.posts[0]; 42 }); 43 44 if (!post) return []; 45 46 if (post.replyCount === 0) return []; 47 48 const comments = await BlueskyCommentsSection.agent 49 .getPostThread({ 50 uri: post.uri, 51 depth: 1, 52 }) 53 .then(({ data }) => { 54 if (!isThreadViewPost(data.thread)) return []; 55 56 if (!data.thread.replies) return []; 57 58 return data.thread.replies 59 .filter(isThreadViewPost) 60 .map((reply) => reply.post); 61 }); 62 63 return comments; 64 } 65 66 createCommentArticle(comment: PostView) { 67 const { likeCount = 0, repostCount = 0, replyCount = 0 } = comment; 68 69 const commentArticle = document.createElement('article', { 70 is: 'bluesky-comment', 71 }); 72 73 commentArticle.setAttribute( 74 'display-name', 75 comment.author.displayName ?? 'Unknown' 76 ); 77 78 commentArticle.setAttribute( 79 'handle', 80 comment.author.handle ?? 'unknown-handle' 81 ); 82 83 commentArticle.setAttribute('likes', likeCount.toString()); 84 commentArticle.setAttribute('replies', replyCount.toString()); 85 commentArticle.setAttribute('reposts', repostCount.toString()); 86 87 const body = document.createElement('span'); 88 body.setAttribute('slot', 'default'); 89 body.innerText = comment.record.text as string; 90 91 commentArticle.appendChild(body); 92 93 this.appendChild(commentArticle); 94 } 95 } 96 97 customElements.define('bluesky-comments-section', BlueskyCommentsSection, { 98 extends: 'section', 99 }); 100</script> 101 102<template id={'bluesky-comments-section'}></template>