Add a bsky post cid to have display comments directly in the blog post
.zed/settings.json
.zed/settings.json
This file has not been changed.
+78
-12
app/components/BskyComments.vue
+78
-12
app/components/BskyComments.vue
···
22
}
23
24
if (data.value.$type === "app.bsky.feed.defs#threadViewPost") {
25
post.value = data.value;
26
}
27
</script>
28
29
<template>
30
-
<h3>Join the conversation!</h3>
31
32
-
<div v-if="err">
33
-
<div>{{ err }}</div>
34
-
</div>
35
36
-
<div v-if="post">
37
-
<div v-if="post.post.replyCount === 0">
38
-
<div>No replies yet!</div>
39
</div>
40
41
-
<div v-else>
42
-
<p>{{post.post.replyCount}} replies</p>
43
44
-
<div v-for="reply in post.replies">
45
-
<a :href="`https://bsky.app/profile/${reply.post.author.handle}`" class="text-blue-500 hover:underline">
46
{{ reply.post.author.displayName }}
47
</a>
48
-
<div>{{ reply.post.record.text }}</div>
49
</div>
50
</div>
51
</div>
···
22
}
23
24
if (data.value.$type === "app.bsky.feed.defs#threadViewPost") {
25
+
console.log(data.value);
26
post.value = data.value;
27
}
28
</script>
29
30
<template>
31
+
<div class="md:w-[80%] mx-auto mt-16">
32
+
<div class="flex items-baseline gap-4">
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>
48
+
</div>
49
50
+
<p class="text-gray-600 text-md mb-6">
51
+
<a class="underline" :href="`https://bsky.app/profile/${post.post.author.handle}/post/${cid}`">Reply on Bluesky</a> to take part in the discussion.
52
+
</p>
53
54
+
<div v-if="err">
55
+
<div>{{ err }}</div>
56
</div>
57
58
+
<div v-if="post">
59
+
<div v-if="post.post.replyCount === 0">
60
+
<div>No replies yet!</div>
61
+
</div>
62
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>
116
</div>
117
</div>
+4
app/pages/posts/[...slug].vue
+4
app/pages/posts/[...slug].vue
+8
-1
app/util/atproto.ts
+8
-1
app/util/atproto.ts
···
26
});
27
28
if (!ok) {
29
console.error("Error fetching thread:", data.error);
30
return { $type: "app.bsky.feed.defs#notFoundPost" };
31
}
···
35
}
36
37
return { $type: "app.bsky.feed.defs#notFoundPost" };
38
+
}
39
+
40
+
export function extractPostId(uri: ResourceUri) {
41
+
if (uri.includes("app.bsky.feed.post")) {
42
+
const parts = uri.split("/");
43
+
return parts.at(-1);
44
+
}
45
+
return "";
46
}
blog.config.ts
blog.config.ts
This file has not been changed.
content/posts/embracing-atproto-pt-2-tangled-knot.md
content/posts/embracing-atproto-pt-2-tangled-knot.md
This file has not been changed.
content.config.ts
content.config.ts
This file has not been changed.
globals.ts
globals.ts
This file has not been changed.
package.json
package.json
This file has not been changed.
pnpm-lock.yaml
pnpm-lock.yaml
This file has not been changed.
tsconfig.json
tsconfig.json
This file has not been changed.
+52
app/components/BskyPost.vue
+52
app/components/BskyPost.vue
···
···
1
+
<script setup lang="ts">
2
+
import type { AppBskyFeedDefs } from "@atcute/bluesky";
3
+
import { extractPostId } from "~/util/atproto";
4
+
5
+
const props = defineProps<{
6
+
post: AppBskyFeedDefs.ThreadViewPost;
7
+
depth: number;
8
+
}>();
9
+
const { post, depth } = toRefs(props);
10
+
11
+
const MAX_DEPTH = 2; // Max number of replies to a reply
12
+
</script>
13
+
14
+
<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
+
<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
+
</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>
46
+
</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" />
49
+
</div>
50
+
</div>
51
+
</div>
52
+
</template>
+1
content/posts/blog-template.md
+1
content/posts/blog-template.md
+1
content/posts/embracing-atproto-pt-1-hosting-pds.md
+1
content/posts/embracing-atproto-pt-1-hosting-pds.md
+1
content/posts/extending-openauth.md
+1
content/posts/extending-openauth.md
History
5 rounds
1 comment
10 commits
expand
collapse
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
collapse
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
Still needs some minor adjustments