Skip to content

Commit e532187

Browse files
committed
feat: Comments reply
1 parent 76405e9 commit e532187

File tree

5 files changed

+122
-43
lines changed

5 files changed

+122
-43
lines changed

platforms/metagram/src/lib/dummyData.ts

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { CommentType } from "./types";
1+
import type { CommentType } from './types';
22

33
export const dummyPosts = Array.from({ length: 100 }, (_, i) => ({
44
id: i + 1,
@@ -17,31 +17,31 @@ export const dummyPosts = Array.from({ length: 100 }, (_, i) => ({
1717
export const comments: CommentType[] = Array.from({ length: 50 }, (_, i) => ({
1818
userImgSrc: 'https://picsum.photos/800',
1919
name: `user${i + 1}`,
20-
commentId: `${i + 1}`,
20+
commentId: `${i + 1}p`,
2121
comment: `this is the dummy comment which is commented by user${i + 1}`,
22-
isLiked: false,
23-
isDisliked: false,
24-
likeCount: 0,
22+
isUpVoted: false,
23+
isDownVoted: false,
24+
upVotes: 0,
2525
time: '2 minutes ago',
2626
replies: [
2727
{
2828
userImgSrc: 'https://picsum.photos/800',
2929
name: `user${i + 1}x`,
3030
commentId: `${i + 1}x`,
3131
comment: `this is the dummy reply which is replied by another${i}x`,
32-
isLiked: false,
33-
isDisliked: false,
34-
likeCount: 0,
32+
isUpVoted: false,
33+
isDownVoted: false,
34+
upVotes: 0,
3535
time: '1 minute ago',
3636
replies: [
3737
{
3838
userImgSrc: 'https://picsum.photos/800',
3939
name: `user${i + 1}a`,
4040
commentId: `${i + 1}a`,
4141
comment: `this is the dummy reply which is replied by another${i}a`,
42-
isLiked: false,
43-
isDisliked: false,
44-
likeCount: 0,
42+
isUpVoted: false,
43+
isDownVoted: false,
44+
upVotes: 0,
4545
time: '1 minute ago',
4646
replies: []
4747
}
@@ -52,9 +52,31 @@ export const comments: CommentType[] = Array.from({ length: 50 }, (_, i) => ({
5252
name: `user${i + 1}y`,
5353
commentId: `${i + 1}y`,
5454
comment: `this is the dummy reply which is replied by another${i}y`,
55-
isLiked: false,
56-
isDisliked: false,
57-
likeCount: 0,
55+
isUpVoted: false,
56+
isDownVoted: false,
57+
upVotes: 0,
58+
time: '1 minute ago',
59+
replies: []
60+
},
61+
{
62+
userImgSrc: 'https://picsum.photos/800',
63+
name: `user${i + 1}y`,
64+
commentId: `${i + 1}y`,
65+
comment: `this is the dummy reply which is replied by another${i}y`,
66+
isUpVoted: false,
67+
isDownVoted: false,
68+
upVotes: 0,
69+
time: '1 minute ago',
70+
replies: []
71+
},
72+
{
73+
userImgSrc: 'https://picsum.photos/800',
74+
name: `user${i + 1}y`,
75+
commentId: `${i + 1}y`,
76+
comment: `this is the dummy reply which is replied by another${i}y`,
77+
isUpVoted: false,
78+
isDownVoted: false,
79+
upVotes: 0,
5880
time: '1 minute ago',
5981
replies: []
6082
}

platforms/metagram/src/lib/fragments/Comment/Comment.svelte

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
99
interface ICommentProps extends HTMLAttributes<HTMLElement> {
1010
comment: CommentType;
11-
handleReply: () => void;
11+
handleReply: (id: string) => void;
1212
}
1313
14-
let visibleReplies = 2;
14+
let visibleReplies = $state(2);
1515
16-
const showMoreReplies = () => {
17-
visibleReplies = comment.replies.length;
18-
};
16+
const showMoreReplies = () => {
17+
visibleReplies = comment.replies.length;
18+
};
1919
2020
let { comment, handleReply, ...restProps }: ICommentProps = $props();
2121
</script>
@@ -31,56 +31,66 @@
3131
<div class="ms-12 mt-2 flex items-center gap-2">
3232
<button
3333
onclick={() => {
34-
if (!comment.isLiked) {
35-
comment.likeCount++;
36-
comment.isLiked = true;
37-
comment.isDisliked = false;
34+
if (!comment.isUpVoted) {
35+
comment.upVotes++;
36+
comment.isUpVoted = true;
37+
comment.isDownVoted = false;
3838
}
3939
}}
4040
>
4141
<Like
4242
size="18px"
43-
color={comment.isLiked
43+
color={comment.isUpVoted
4444
? 'var(--color-brand-burnt-orange)'
4545
: 'var(--color-black-600)'}
46-
fill={comment.isLiked
46+
fill={comment.isUpVoted
4747
? 'var(--color-brand-burnt-orange)'
4848
: 'var(--color-black-600)'}
4949
/>
5050
</button>
51-
<p class="text-black-600 font-semibold">{comment.likeCount}</p>
51+
<p class="text-black-600 font-semibold">{comment.upVotes}</p>
5252
<button
5353
onclick={() => {
54-
if (!comment.isDisliked) {
55-
comment.likeCount--;
56-
comment.isDisliked = true;
57-
comment.isLiked = false;
54+
if (!comment.isDownVoted) {
55+
comment.upVotes--;
56+
comment.isDownVoted = true;
57+
comment.isUpVoted = false;
5858
}
5959
}}
6060
>
6161
<Like
6262
size="18px"
63-
color={comment.isDisliked
63+
color={comment.isDownVoted
6464
? 'var(--color-brand-burnt-orange)'
6565
: 'var(--color-black-600)'}
66-
fill={comment.isDisliked
66+
fill={comment.isDownVoted
6767
? 'var(--color-brand-burnt-orange)'
6868
: 'var(--color-black-600)'}
6969
class="rotate-180"
7070
/>
7171
</button>
7272
<span class="bg-black-600 inline-block h-1 w-1 rounded-full"></span>
73-
<button onclick={handleReply} class="text-black-600 font-semibold">Reply</button>
73+
<button onclick={() => handleReply(comment.commentId)} class="text-black-600 font-semibold"
74+
>Reply</button
75+
>
7476
<span class="bg-black-600 inline-block h-1 w-1 rounded-full"></span>
7577
<p class="text-black-600">{comment.time}</p>
7678
</div>
7779
{#if comment?.replies?.length}
7880
<ul class="ms-12 mt-4 space-y-2">
79-
{#each comment.replies as reply}
81+
{#each comment.replies.slice(0, visibleReplies) as reply}
8082
<li>
8183
<CommentComponent comment={reply} {handleReply} />
8284
</li>
8385
{/each}
86+
{#if comment.replies.length > visibleReplies}
87+
<button
88+
onclick={showMoreReplies}
89+
class="text-brand-burnt-orange mt-1 text-sm font-medium"
90+
>
91+
See {comment.replies.length - visibleReplies} more replies
92+
</button>
93+
{/if}
8494
</ul>
8595
{/if}
8696
</article>

platforms/metagram/src/lib/fragments/Drawer/Drawer.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@
5555
onswipe={handleDrawerSwipe}
5656
class={cn(restProps.class)}
5757
>
58-
{@render children?.()}
58+
<div class="h-[100%] overflow-y-scroll">
59+
{@render children?.()}
60+
</div>
5961
</div>
6062

6163
<style>

platforms/metagram/src/lib/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ export type CommentType = {
1010
name: string;
1111
userImgSrc: string;
1212
comment: string;
13-
isLiked: boolean;
14-
isDisliked: boolean;
15-
likeCount: number;
13+
isUpVoted: boolean;
14+
isDownVoted: boolean;
15+
upVotes: number;
1616
time: string;
1717
replies: CommentType[];
1818
};

platforms/metagram/src/routes/(protected)/home/+page.svelte

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import { onMount } from 'svelte';
55
import type { CupertinoPane } from 'cupertino-pane';
66
import { Comment, MessageInput } from '$lib/fragments';
7-
7+
import type { CommentType } from '$lib/types';
8+
89
type PostData = {
910
id: number;
1011
avatar: string;
@@ -28,6 +29,8 @@
2829
let drawer: CupertinoPane | undefined = $state();
2930
let commentValue: string = $state('');
3031
let commentInput: HTMLInputElement | undefined = $state();
32+
let _comments = $state(comments);
33+
let activeReplyToId: string | null = $state(null);
3134
3235
const loadMore = () => {
3336
if (loading || currentIndex >= dummyPosts.length) return;
@@ -48,6 +51,41 @@
4851
loadMore();
4952
};
5053
54+
const handleSend = async () => {
55+
const newComment = {
56+
userImgSrc: 'https://www.gravatar.com/avatar/2c7d99fe281ecd3bcd65ab915bac6dd5?s=250',
57+
name: 'You',
58+
commentId: Date.now().toString(),
59+
comment: commentValue,
60+
isUpVoted: false,
61+
isDownVoted: false,
62+
upVotes: 0,
63+
time: 'Just now',
64+
replies: []
65+
};
66+
67+
if (activeReplyToId) {
68+
// Find the parent comment by id and push reply
69+
const addReplyToComment = (commentsArray: CommentType[]) => {
70+
for (const c of commentsArray) {
71+
if (c.commentId === activeReplyToId) {
72+
c.replies.push(newComment);
73+
return true;
74+
} else if (c.replies.length) {
75+
if (addReplyToComment(c.replies)) return true;
76+
}
77+
}
78+
return false;
79+
};
80+
addReplyToComment(_comments);
81+
} else {
82+
// If no activeReplyToId, add as a new parent comment
83+
_comments = [newComment, ..._comments];
84+
}
85+
commentValue = '';
86+
activeReplyToId = null;
87+
};
88+
5189
$effect(() => {
5290
listElement.addEventListener('scroll', onScroll);
5391
return () => listElement.removeEventListener('scroll', onScroll);
@@ -85,18 +123,25 @@
85123

86124
<Drawer bind:drawer>
87125
<ul class="pb-4">
88-
<h3 class="text-black-600 mb-6 text-center">32 Comments</h3>
89-
{#each comments as comment}
126+
<h3 class="text-black-600 mb-6 text-center">{comments.length} Comments</h3>
127+
{#each _comments as comment}
90128
<li class="mb-4">
91-
<Comment {comment} handleReply={() => commentInput?.focus()} />
129+
<Comment
130+
{comment}
131+
handleReply={(id) => {
132+
activeReplyToId = id;
133+
alert(id);
134+
commentInput?.focus();
135+
}}
136+
/>
92137
</li>
93138
{/each}
94139
<MessageInput
95140
class="mt-4"
96141
variant="comment"
97142
src="https://www.gravatar.com/avatar/2c7d99fe281ecd3bcd65ab915bac6dd5?s=250"
98143
bind:value={commentValue}
99-
handleSend={async () => alert('sdfs')}
144+
{handleSend}
100145
bind:input={commentInput}
101146
/>
102147
</ul>

0 commit comments

Comments
 (0)