Personal blog finxol.io
blog

Add Bluesky comments to blog posts #1

merged opened by finxol.io targeting main from feat/add-bsky-comments

Add a bsky post cid to have display comments directly in the blog post

Labels

None yet.

Participants 1
AT URI
at://did:plc:hpmpe3pzpdtxbmvhlwrevhju/sh.tangled.repo.pull/3m6ehz6pa3k22
+84 -101
Interdiff #3 โ†’ #4
.zed/settings.json

This file has not been changed.

+24 -68
app/components/BskyComments.vue
··· 29 29 30 30 <template> 31 31 <div class="md:w-[80%] mx-auto mt-16"> 32 - <div class="flex items-baseline gap-4"> 32 + <div class="flex items-baseline flex-col md:flex-row md:gap-4 mb-2 md:mb-0"> 33 33 <h3 class="font-bold text-xl">Join the conversation!</h3> 34 - <p class="text-gray-500 text-sm" title="Replies"> 35 - <Icon name="ri:reply-line" class="-mb-[2px] mr-1" /> 36 - {{post.post.replyCount}} 37 - </p> 38 - <p class="text-gray-500 text-sm" title="Likes"> 39 - <Icon name="ri:heart-3-line" class="-mb-[2px] mr-1" /> 40 - <span> 41 - {{post.post.likeCount}} 42 - </span> 43 - </p> 44 - <p class="text-gray-500 text-sm" title="Bookmarks"> 45 - <Icon name="ri:bookmark-line" class="-mb-[2px] mr-1" /> 46 - {{post.post.bookmarkCount}} 47 - </p> 34 + <div class="flex items-center gap-2"> 35 + <p class="text-gray-500 text-sm" title="Replies"> 36 + <Icon name="ri:reply-line" class="-mb-[2px] mr-1" /> 37 + {{post.post.replyCount}} 38 + </p> 39 + <p class="text-gray-500 text-sm" title="Likes"> 40 + <Icon name="ri:heart-3-line" class="-mb-[2px] mr-1" /> 41 + <span> 42 + {{post.post.likeCount}} 43 + </span> 44 + </p> 45 + <p class="text-gray-500 text-sm" title="Bookmarks"> 46 + <Icon name="ri:bookmark-line" class="-mb-[2px] mr-1" /> 47 + {{post.post.bookmarkCount}} 48 + </p> 49 + </div> 48 50 </div> 49 51 50 52 <p class="text-gray-600 text-md mb-6"> ··· 60 62 <div>No replies yet!</div> 61 63 </div> 62 64 63 - <div v-else v-for="reply in post.replies" class="mt-6"> 64 - <BskyPost :post="reply" :depth="0" /> 65 - 66 - <!-- <a :href="`https://bsky.app/profile/${reply.post.author.handle}`" class="flex items-center gap-2 text-blue-500 hover:underline w-fit"> 67 - <img :src="reply.post.author.avatar" :alt="reply.post.author.displayName" class="size-8 rounded-full" /> 68 - <span> 69 - {{ reply.post.author.displayName }} 70 - </span> 71 - </a> 72 - <div class="ml-10">{{ reply.post.record.text }}</div> 73 - <div class="flex items-baseline gap-4 ml-10 mt-2"> 74 - <p class="text-gray-500 text-sm" title="Replies"> 75 - <Icon name="ri:reply-line" class="-mb-[2px] mr-1" /> 76 - {{reply.post.replyCount}} 77 - </p> 78 - <p class="text-gray-500 text-sm" title="Likes"> 79 - <Icon name="ri:heart-3-line" class="-mb-[2px] mr-1" /> 80 - <span> 81 - {{reply.post.likeCount}} 82 - </span> 83 - </p> 84 - <p class="text-gray-500 text-sm" title="Bookmarks"> 85 - <Icon name="ri:bookmark-line" class="-mb-[2px] mr-1" /> 86 - {{reply.post.bookmarkCount}} 87 - </p> 88 - </div> 89 - 90 - <div v-for="rep in reply.replies" class="mt-6 ml-10"> 91 - <a :href="`https://bsky.app/profile/${rep.post.author.handle}`" class="flex items-center gap-2 text-blue-500 hover:underline w-fit"> 92 - <img :src="rep.post.author.avatar" :alt="rep.post.author.displayName" class="size-8 rounded-full" /> 93 - <span> 94 - {{ rep.post.author.displayName }} 95 - </span> 96 - </a> 97 - <div class="ml-10">{{ rep.post.record.text }}</div> 98 - <div class="flex items-baseline gap-4 ml-10 mt-2"> 99 - <p class="text-gray-500 text-sm" title="Replies"> 100 - <Icon name="ri:reply-line" class="-mb-[2px] mr-1" /> 101 - {{rep.post.replyCount}} 102 - </p> 103 - <p class="text-gray-500 text-sm" title="Likes"> 104 - <Icon name="ri:heart-3-line" class="-mb-[2px] mr-1" /> 105 - <span> 106 - {{rep.post.likeCount}} 107 - </span> 108 - </p> 109 - <p class="text-gray-500 text-sm" title="Bookmarks"> 110 - <Icon name="ri:bookmark-line" class="-mb-[2px] mr-1" /> 111 - {{rep.post.bookmarkCount}} 112 - </p> 113 - </div> 114 - </div> --> 115 - </div> 65 + <BskyPost 66 + v-else 67 + v-for="reply in post.replies" 68 + :key="reply.post.cid" 69 + :post="reply" 70 + :depth="0" 71 + /> 116 72 </div> 117 73 </div> 118 74 </template>
+59 -32
app/components/BskyPost.vue
··· 8 8 }>(); 9 9 const { post, depth } = toRefs(props); 10 10 11 - const MAX_DEPTH = 2; // Max number of replies to a reply 11 + const MAX_DEPTH = 3; // Max number of replies to a reply 12 + 13 + console.log(post); 12 14 </script> 13 15 14 16 <template> 15 - <div v-if="post && depth <= MAX_DEPTH" :class="['mt-6', depth > 0 ? 'ml-10' : '']"> 16 - <a :href="`https://bsky.app/profile/${post.post.author.handle}`" class="flex items-center gap-2 text-blue-500 hover:underline w-fit"> 17 + <div v-if="post && depth < MAX_DEPTH" class="mt-6 bsky-post"> 18 + <a :href="`https://bsky.app/profile/${post.post.author.handle}`"> 17 19 <img :src="post.post.author.avatar" :alt="post.post.author.displayName" class="size-8 rounded-full" /> 18 - <span> 19 - {{ post.post.author.displayName }} 20 - </span> 21 20 </a> 22 - <div class="ml-10">{{ post.post.record.text }}</div> 23 - <div class="flex items-baseline gap-4 ml-10 mt-2"> 24 - <p class="text-gray-500 text-sm" title="Replies"> 25 - <Icon name="ri:reply-line" class="-mb-[2px] mr-1" /> 26 - {{post.post.replyCount}} 27 - </p> 28 - <p class="text-gray-500 text-sm" title="Likes"> 29 - <Icon name="ri:heart-3-line" class="-mb-[2px] mr-1" /> 30 - <span> 31 - {{post.post.likeCount}} 32 - </span> 33 - </p> 34 - <p class="text-gray-500 text-sm" title="Bookmarks"> 35 - <Icon name="ri:bookmark-line" class="-mb-[2px] mr-1" /> 36 - {{post.post.bookmarkCount}} 37 - </p> 38 - </div> 39 - 40 - <div v-if="post.replies"> 41 - <div v-if="depth === MAX_DEPTH"> 42 - <a :href="`https://bsky.app/profile/${post.post.author.handle}/post/${extractPostId(post.post.uri)}`" class="text-gray-500 text-sm flex items-center gap-2 mt-4 ml-10"> 43 - View more replies on Bluesky 44 - <Icon name='ri:arrow-drop-right-line' /> 45 - </a> 21 + <div class="flex flex-col gap-1"> 22 + <a :href="`https://bsky.app/profile/${post.post.author.handle}`" class="text-md font-bold w-fit"> 23 + {{ post.post.author.displayName }} 24 + </a> 25 + <div> 26 + {{ post.post.record.text }} 46 27 </div> 47 - <div v-for="reply in post.replies"> 48 - <BskyPost v-if="reply.$type === 'app.bsky.feed.defs#threadViewPost'" :post="reply" :depth="depth + 1" /> 28 + <div class="flex items-baseline gap-4 mt-2"> 29 + <p class="text-gray-500 text-sm" title="Replies"> 30 + <Icon name="ri:reply-line" class="-mb-[2px] mr-1" /> 31 + {{post.post.replyCount}} 32 + </p> 33 + <p class="text-gray-500 text-sm" title="Likes"> 34 + <Icon name="ri:heart-3-line" class="-mb-[2px] mr-1" /> 35 + <span> 36 + {{post.post.likeCount}} 37 + </span> 38 + </p> 39 + <p class="text-gray-500 text-sm" title="Bookmarks"> 40 + <Icon name="ri:bookmark-line" class="-mb-[2px] mr-1" /> 41 + {{post.post.bookmarkCount}} 42 + </p> 49 43 </div> 44 + 45 + <div v-if="post.replies && post.replies.length > 0"> 46 + <div v-if="depth+1 === MAX_DEPTH"> 47 + <a :href="`https://bsky.app/profile/${post.post.author.handle}/post/${extractPostId(post.post.uri)}`" class="text-gray-500 text-sm flex items-center gap-2 mt-4"> 48 + View more replies on Bluesky 49 + <Icon name='ri:arrow-drop-right-line' /> 50 + </a> 51 + </div> 52 + <div v-else v-for="reply in post.replies"> 53 + <BskyPost v-if="reply.$type === 'app.bsky.feed.defs#threadViewPost'" :post="reply" :depth="depth + 1" /> 54 + </div> 55 + </div> 50 56 </div> 51 57 </div> 52 58 </template> 59 + 60 + <style scoped> 61 + .bsky-post { 62 + @apply gap-2 md:gap-4; 63 + 64 + display: grid; 65 + grid-template-columns: auto 1fr; 66 + grid-template-areas: 67 + "avatar content"; 68 + align-items: start; 69 + 70 + & > a:has(> img) { 71 + grid-area: avatar; 72 + } 73 + 74 + & > div { 75 + grid-area: content; 76 + } 77 + 78 + } 79 + </style>
app/components/ShareActions.vue

This file has not been changed.

+1 -1
app/pages/posts/[...slug].vue
··· 95 95 <BskyComments v-if="post.bskyCid" :cid="post.bskyCid" /> 96 96 97 97 <template #fallback> 98 - <h1 class="text-xl font-bold text-stone-600">Loading comments...</h1> 98 + <h1 class="md:w-[80%] mx-auto mt-16 text-xl font-bold text-stone-600">Loading comments...</h1> 99 99 </template> 100 100 </Suspense> 101 101
app/util/atproto.ts

This file has not been changed.

blog.config.ts

This file has not been changed.

content/posts/blog-template.md

This file has not been changed.

content/posts/embracing-atproto-pt-1-hosting-pds.md

This file has not been changed.

content/posts/embracing-atproto-pt-2-tangled-knot.md

This file has not been changed.

content/posts/extending-openauth.md

This file has not been changed.

content.config.ts

This file has not been changed.

deno.jsonc

This file has not been changed.

globals.ts

This file has not been changed.

package.json

This file has not been changed.

pnpm-lock.yaml

This file has not been changed.

tsconfig.json

This file has not been changed.

History

5 rounds 1 comment
sign up or login to add to the discussion
10 commits
expand
chore: add bsky post cid to content schema
chore: add deps
feat: first draft at bsky replies
fix: add loading state
feat: improve appearance
feat: add icons and bsky stats
feat: add bsky post CIDs to more blog posts
feat: show reply replies, max depth 2
fix: properly align elements
fix: max depth truncate + post elements alignment
expand 0 comments
pull request successfully merged
8 commits
expand
chore: add bsky post cid to content schema
chore: add deps
feat: first draft at bsky replies
fix: add loading state
feat: improve appearance
feat: add icons and bsky stats
feat: add bsky post CIDs to more blog posts
feat: show reply replies, max depth 2
expand 1 comment

Still needs some minor adjustments

3 commits
expand
chore: add bsky post cid to content schema
chore: add deps
feat: first draft at bsky replies
expand 0 comments
1 commit
expand
chore: add bsky post cid to content schema
expand 0 comments
1 commit
expand
chore: add bsky post cid to content schema
expand 0 comments