tangled
alpha
login
or
join now
finxol.io
/
blog
0
fork
atom
Personal blog
finxol.io
blog
0
fork
atom
overview
issues
pulls
pipelines
feat: show reply replies, max depth 2
finxol.io
4 months ago
e61c1bea
e4c3a778
verified
This commit was signed with the committer's
known signature
.
finxol.io
SSH Key Fingerprint:
SHA256:olFE3asYdoBMScuJOt60UxXdJ0RFdGv5kVKrdOtIcPI=
+95
-7
3 changed files
expand all
collapse all
unified
split
app
components
BskyComments.vue
BskyPost.vue
util
atproto.ts
+35
-7
app/components/BskyComments.vue
reviewed
···
31
31
<div class="md:w-[80%] mx-auto mt-16">
32
32
<div class="flex items-baseline gap-4">
33
33
<h3 class="font-bold text-xl">Join the conversation!</h3>
34
34
-
<p class="text-gray-500 text-sm">
34
34
+
<p class="text-gray-500 text-sm" title="Replies">
35
35
<Icon name="ri:reply-line" class="-mb-[2px] mr-1" />
36
36
{{post.post.replyCount}}
37
37
</p>
38
38
-
<p class="text-gray-500 text-sm">
38
38
+
<p class="text-gray-500 text-sm" title="Likes">
39
39
<Icon name="ri:heart-3-line" class="-mb-[2px] mr-1" />
40
40
<span>
41
41
{{post.post.likeCount}}
42
42
</span>
43
43
</p>
44
44
-
<p class="text-gray-500 text-sm">
44
44
+
<p class="text-gray-500 text-sm" title="Bookmarks">
45
45
<Icon name="ri:bookmark-line" class="-mb-[2px] mr-1" />
46
46
{{post.post.bookmarkCount}}
47
47
</p>
···
61
61
</div>
62
62
63
63
<div v-else v-for="reply in post.replies" class="mt-6">
64
64
-
<a :href="`https://bsky.app/profile/${reply.post.author.handle}`" class="flex items-center gap-2 text-blue-500 hover:underline w-fit">
64
64
+
<BskyPost :post="reply" :depth="0" />
65
65
+
66
66
+
<!-- <a :href="`https://bsky.app/profile/${reply.post.author.handle}`" class="flex items-center gap-2 text-blue-500 hover:underline w-fit">
65
67
<img :src="reply.post.author.avatar" :alt="reply.post.author.displayName" class="size-8 rounded-full" />
66
68
<span>
67
69
{{ reply.post.author.displayName }}
···
69
71
</a>
70
72
<div class="ml-10">{{ reply.post.record.text }}</div>
71
73
<div class="flex items-baseline gap-4 ml-10 mt-2">
72
72
-
<p class="text-gray-500 text-sm">
74
74
+
<p class="text-gray-500 text-sm" title="Replies">
73
75
<Icon name="ri:reply-line" class="-mb-[2px] mr-1" />
74
76
{{reply.post.replyCount}}
75
77
</p>
76
76
-
<p class="text-gray-500 text-sm">
78
78
+
<p class="text-gray-500 text-sm" title="Likes">
77
79
<Icon name="ri:heart-3-line" class="-mb-[2px] mr-1" />
78
80
<span>
79
81
{{reply.post.likeCount}}
80
82
</span>
81
83
</p>
82
82
-
<p class="text-gray-500 text-sm">
84
84
+
<p class="text-gray-500 text-sm" title="Bookmarks">
83
85
<Icon name="ri:bookmark-line" class="-mb-[2px] mr-1" />
84
86
{{reply.post.bookmarkCount}}
85
87
</p>
86
88
</div>
89
89
+
90
90
+
<div v-for="rep in reply.replies" class="mt-6 ml-10">
91
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
92
+
<img :src="rep.post.author.avatar" :alt="rep.post.author.displayName" class="size-8 rounded-full" />
93
93
+
<span>
94
94
+
{{ rep.post.author.displayName }}
95
95
+
</span>
96
96
+
</a>
97
97
+
<div class="ml-10">{{ rep.post.record.text }}</div>
98
98
+
<div class="flex items-baseline gap-4 ml-10 mt-2">
99
99
+
<p class="text-gray-500 text-sm" title="Replies">
100
100
+
<Icon name="ri:reply-line" class="-mb-[2px] mr-1" />
101
101
+
{{rep.post.replyCount}}
102
102
+
</p>
103
103
+
<p class="text-gray-500 text-sm" title="Likes">
104
104
+
<Icon name="ri:heart-3-line" class="-mb-[2px] mr-1" />
105
105
+
<span>
106
106
+
{{rep.post.likeCount}}
107
107
+
</span>
108
108
+
</p>
109
109
+
<p class="text-gray-500 text-sm" title="Bookmarks">
110
110
+
<Icon name="ri:bookmark-line" class="-mb-[2px] mr-1" />
111
111
+
{{rep.post.bookmarkCount}}
112
112
+
</p>
113
113
+
</div>
114
114
+
</div> -->
87
115
</div>
88
116
</div>
89
117
</div>
+52
app/components/BskyPost.vue
reviewed
···
1
1
+
<script setup lang="ts">
2
2
+
import type { AppBskyFeedDefs } from "@atcute/bluesky";
3
3
+
import { extractPostId } from "~/util/atproto";
4
4
+
5
5
+
const props = defineProps<{
6
6
+
post: AppBskyFeedDefs.ThreadViewPost;
7
7
+
depth: number;
8
8
+
}>();
9
9
+
const { post, depth } = toRefs(props);
10
10
+
11
11
+
const MAX_DEPTH = 2; // Max number of replies to a reply
12
12
+
</script>
13
13
+
14
14
+
<template>
15
15
+
<div v-if="post && depth <= MAX_DEPTH" :class="['mt-6', depth > 0 ? 'ml-10' : '']">
16
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
17
+
<img :src="post.post.author.avatar" :alt="post.post.author.displayName" class="size-8 rounded-full" />
18
18
+
<span>
19
19
+
{{ post.post.author.displayName }}
20
20
+
</span>
21
21
+
</a>
22
22
+
<div class="ml-10">{{ post.post.record.text }}</div>
23
23
+
<div class="flex items-baseline gap-4 ml-10 mt-2">
24
24
+
<p class="text-gray-500 text-sm" title="Replies">
25
25
+
<Icon name="ri:reply-line" class="-mb-[2px] mr-1" />
26
26
+
{{post.post.replyCount}}
27
27
+
</p>
28
28
+
<p class="text-gray-500 text-sm" title="Likes">
29
29
+
<Icon name="ri:heart-3-line" class="-mb-[2px] mr-1" />
30
30
+
<span>
31
31
+
{{post.post.likeCount}}
32
32
+
</span>
33
33
+
</p>
34
34
+
<p class="text-gray-500 text-sm" title="Bookmarks">
35
35
+
<Icon name="ri:bookmark-line" class="-mb-[2px] mr-1" />
36
36
+
{{post.post.bookmarkCount}}
37
37
+
</p>
38
38
+
</div>
39
39
+
40
40
+
<div v-if="post.replies">
41
41
+
<div v-if="depth === MAX_DEPTH">
42
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
43
+
View more replies on Bluesky
44
44
+
<Icon name='ri:arrow-drop-right-line' />
45
45
+
</a>
46
46
+
</div>
47
47
+
<div v-for="reply in post.replies">
48
48
+
<BskyPost v-if="reply.$type === 'app.bsky.feed.defs#threadViewPost'" :post="reply" :depth="depth + 1" />
49
49
+
</div>
50
50
+
</div>
51
51
+
</div>
52
52
+
</template>
+8
app/util/atproto.ts
reviewed
···
36
36
37
37
return { $type: "app.bsky.feed.defs#notFoundPost" };
38
38
}
39
39
+
40
40
+
export function extractPostId(uri: ResourceUri) {
41
41
+
if (uri.includes("app.bsky.feed.post")) {
42
42
+
const parts = uri.split("/");
43
43
+
return parts.at(-1);
44
44
+
}
45
45
+
return "";
46
46
+
}