pukaad-ui-lib 1.201.0 → 1.202.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/runtime/components/comment.vue +5 -3
- package/dist/runtime/components/image/image-cropper.d.vue.ts +2 -2
- package/dist/runtime/components/image/image-cropper.vue.d.ts +2 -2
- package/dist/runtime/components/input/input-file.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-file.vue.d.ts +1 -1
- package/dist/runtime/components/input/input-password.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-password.vue.d.ts +1 -1
- package/dist/runtime/components/input/input-slider.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-slider.vue.d.ts +1 -1
- package/dist/runtime/components/input/input-textarea.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-textarea.vue.d.ts +1 -1
- package/dist/runtime/components/modal/modal-password-confirmed.d.vue.ts +1 -1
- package/dist/runtime/components/modal/modal-password-confirmed.vue.d.ts +1 -1
- package/dist/runtime/components/modal/modal-password-verify.d.vue.ts +1 -1
- package/dist/runtime/components/modal/modal-password-verify.vue.d.ts +1 -1
- package/package.json +1 -1
- package/dist/runtime/components/comments/CommentSection.d.vue.ts +0 -49
- package/dist/runtime/components/comments/CommentSection.vue +0 -360
- package/dist/runtime/components/comments/CommentSection.vue.d.ts +0 -49
package/dist/module.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
</div>
|
|
6
6
|
<div class="flex flex-col gap-[16px]">
|
|
7
7
|
<div class="flex gap-[8px] w-full">
|
|
8
|
-
<Avatar :size="30" />
|
|
8
|
+
<Avatar :size="30" :src="currentUser.avatar" />
|
|
9
9
|
<div
|
|
10
10
|
ref="mainInputRef"
|
|
11
11
|
contenteditable="true"
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
<div class="flex gap-[8px]">
|
|
41
41
|
<Avatar
|
|
42
42
|
:size="30"
|
|
43
|
+
:src="cmt.user.avatar"
|
|
43
44
|
class="cursor-pointer"
|
|
44
45
|
@click="onViewProfileComment(cmt.user.id)"
|
|
45
46
|
/>
|
|
@@ -121,7 +122,7 @@
|
|
|
121
122
|
</div>
|
|
122
123
|
<div v-if="replyingToId === cmt.id" class="flex flex-col gap-[16px]">
|
|
123
124
|
<div class="flex gap-[8px] w-full">
|
|
124
|
-
<Avatar :size="30" />
|
|
125
|
+
<Avatar :size="30" :src="currentUser.avatar" />
|
|
125
126
|
<div class="flex-1">
|
|
126
127
|
<div
|
|
127
128
|
:ref="(el) => setReplyInputRef(el, cmt.id)"
|
|
@@ -169,6 +170,7 @@
|
|
|
169
170
|
<div class="flex gap-[8px]">
|
|
170
171
|
<Avatar
|
|
171
172
|
:size="30"
|
|
173
|
+
:src="reply.user.avatar"
|
|
172
174
|
class="cursor-pointer"
|
|
173
175
|
@click="onViewProfileComment(reply.user.id)"
|
|
174
176
|
/>
|
|
@@ -242,7 +244,7 @@
|
|
|
242
244
|
class="flex flex-col gap-[16px]"
|
|
243
245
|
>
|
|
244
246
|
<div class="flex gap-[8px] w-full">
|
|
245
|
-
<Avatar :size="30" />
|
|
247
|
+
<Avatar :size="30" :src="currentUser.avatar" />
|
|
246
248
|
<div class="flex-1">
|
|
247
249
|
<div
|
|
248
250
|
:ref="(el) => setReplyInputRef(el, reply.id)"
|
|
@@ -64,15 +64,15 @@ declare const __VLS_export: import("vue").DefineComponent<ImageCropperProps, {
|
|
|
64
64
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ImageCropperProps> & Readonly<{}>, {
|
|
65
65
|
src: string;
|
|
66
66
|
center: boolean;
|
|
67
|
-
background: boolean;
|
|
68
|
-
modal: boolean;
|
|
69
67
|
responsive: boolean;
|
|
70
68
|
restore: boolean;
|
|
71
69
|
checkCrossOrigin: boolean;
|
|
72
70
|
checkOrientation: boolean;
|
|
73
71
|
crossorigin: "" | "anonymous" | "use-credentials";
|
|
72
|
+
modal: boolean;
|
|
74
73
|
guides: boolean;
|
|
75
74
|
highlight: boolean;
|
|
75
|
+
background: boolean;
|
|
76
76
|
autoCrop: boolean;
|
|
77
77
|
movable: boolean;
|
|
78
78
|
rotatable: boolean;
|
|
@@ -64,15 +64,15 @@ declare const __VLS_export: import("vue").DefineComponent<ImageCropperProps, {
|
|
|
64
64
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ImageCropperProps> & Readonly<{}>, {
|
|
65
65
|
src: string;
|
|
66
66
|
center: boolean;
|
|
67
|
-
background: boolean;
|
|
68
|
-
modal: boolean;
|
|
69
67
|
responsive: boolean;
|
|
70
68
|
restore: boolean;
|
|
71
69
|
checkCrossOrigin: boolean;
|
|
72
70
|
checkOrientation: boolean;
|
|
73
71
|
crossorigin: "" | "anonymous" | "use-credentials";
|
|
72
|
+
modal: boolean;
|
|
74
73
|
guides: boolean;
|
|
75
74
|
highlight: boolean;
|
|
75
|
+
background: boolean;
|
|
76
76
|
autoCrop: boolean;
|
|
77
77
|
movable: boolean;
|
|
78
78
|
rotatable: boolean;
|
|
@@ -31,8 +31,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
31
31
|
fullHeight: boolean;
|
|
32
32
|
name: string;
|
|
33
33
|
limit: number;
|
|
34
|
-
disabledErrorMessage: boolean;
|
|
35
34
|
accept: string;
|
|
35
|
+
disabledErrorMessage: boolean;
|
|
36
36
|
labelIcon: string;
|
|
37
37
|
disabledDrop: boolean;
|
|
38
38
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -31,8 +31,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
|
|
|
31
31
|
fullHeight: boolean;
|
|
32
32
|
name: string;
|
|
33
33
|
limit: number;
|
|
34
|
-
disabledErrorMessage: boolean;
|
|
35
34
|
accept: string;
|
|
35
|
+
disabledErrorMessage: boolean;
|
|
36
36
|
labelIcon: string;
|
|
37
37
|
disabledDrop: boolean;
|
|
38
38
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -22,8 +22,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
22
22
|
}>, {
|
|
23
23
|
id: string;
|
|
24
24
|
name: string;
|
|
25
|
-
new: boolean;
|
|
26
25
|
disabledForgotPassword: boolean;
|
|
26
|
+
new: boolean;
|
|
27
27
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
28
28
|
declare const _default: typeof __VLS_export;
|
|
29
29
|
export default _default;
|
|
@@ -22,8 +22,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
22
22
|
}>, {
|
|
23
23
|
id: string;
|
|
24
24
|
name: string;
|
|
25
|
-
new: boolean;
|
|
26
25
|
disabledForgotPassword: boolean;
|
|
26
|
+
new: boolean;
|
|
27
27
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
28
28
|
declare const _default: typeof __VLS_export;
|
|
29
29
|
export default _default;
|
|
@@ -12,9 +12,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
12
12
|
label: string;
|
|
13
13
|
color: InputSliderColor;
|
|
14
14
|
fullWidth: boolean;
|
|
15
|
+
step: number;
|
|
15
16
|
max: number;
|
|
16
17
|
min: number;
|
|
17
|
-
step: number;
|
|
18
18
|
lineHeight: number | string;
|
|
19
19
|
appearance: boolean;
|
|
20
20
|
thumbSize: number | string;
|
|
@@ -12,9 +12,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
12
12
|
label: string;
|
|
13
13
|
color: InputSliderColor;
|
|
14
14
|
fullWidth: boolean;
|
|
15
|
+
step: number;
|
|
15
16
|
max: number;
|
|
16
17
|
min: number;
|
|
17
|
-
step: number;
|
|
18
18
|
lineHeight: number | string;
|
|
19
19
|
appearance: boolean;
|
|
20
20
|
thumbSize: number | string;
|
|
@@ -45,10 +45,10 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
45
45
|
id: string;
|
|
46
46
|
name: string;
|
|
47
47
|
limit: number;
|
|
48
|
+
resize: "none" | "both" | "horizontal" | "vertical";
|
|
48
49
|
disabledErrorMessage: boolean;
|
|
49
50
|
disabledBorder: boolean;
|
|
50
51
|
showCounter: boolean;
|
|
51
|
-
resize: "none" | "both" | "horizontal" | "vertical";
|
|
52
52
|
readonly: boolean;
|
|
53
53
|
rows: number;
|
|
54
54
|
heightScroll: boolean;
|
|
@@ -45,10 +45,10 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
45
45
|
id: string;
|
|
46
46
|
name: string;
|
|
47
47
|
limit: number;
|
|
48
|
+
resize: "none" | "both" | "horizontal" | "vertical";
|
|
48
49
|
disabledErrorMessage: boolean;
|
|
49
50
|
disabledBorder: boolean;
|
|
50
51
|
showCounter: boolean;
|
|
51
|
-
resize: "none" | "both" | "horizontal" | "vertical";
|
|
52
52
|
readonly: boolean;
|
|
53
53
|
rows: number;
|
|
54
54
|
heightScroll: boolean;
|
|
@@ -24,8 +24,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
24
24
|
onClose?: (() => any) | undefined;
|
|
25
25
|
}>, {
|
|
26
26
|
title: string;
|
|
27
|
-
disabledForgotPassword: boolean;
|
|
28
27
|
confirmText: string;
|
|
28
|
+
disabledForgotPassword: boolean;
|
|
29
29
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
30
30
|
declare const _default: typeof __VLS_export;
|
|
31
31
|
export default _default;
|
|
@@ -24,8 +24,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
24
24
|
onClose?: (() => any) | undefined;
|
|
25
25
|
}>, {
|
|
26
26
|
title: string;
|
|
27
|
-
disabledForgotPassword: boolean;
|
|
28
27
|
confirmText: string;
|
|
28
|
+
disabledForgotPassword: boolean;
|
|
29
29
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
30
30
|
declare const _default: typeof __VLS_export;
|
|
31
31
|
export default _default;
|
|
@@ -28,8 +28,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
28
28
|
}>, {
|
|
29
29
|
title: string;
|
|
30
30
|
mode: "login" | "secure";
|
|
31
|
-
disabledForgotPassword: boolean;
|
|
32
31
|
confirmText: string;
|
|
32
|
+
disabledForgotPassword: boolean;
|
|
33
33
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
34
34
|
declare const _default: typeof __VLS_export;
|
|
35
35
|
export default _default;
|
|
@@ -28,8 +28,8 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {},
|
|
|
28
28
|
}>, {
|
|
29
29
|
title: string;
|
|
30
30
|
mode: "login" | "secure";
|
|
31
|
-
disabledForgotPassword: boolean;
|
|
32
31
|
confirmText: string;
|
|
32
|
+
disabledForgotPassword: boolean;
|
|
33
33
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
34
34
|
declare const _default: typeof __VLS_export;
|
|
35
35
|
export default _default;
|
package/package.json
CHANGED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
interface ProfileData {
|
|
2
|
-
profile_name: string;
|
|
3
|
-
profile_path: {
|
|
4
|
-
path_name: string;
|
|
5
|
-
};
|
|
6
|
-
profile_image: {
|
|
7
|
-
image_url: string;
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
interface CommentData {
|
|
11
|
-
id: string | number;
|
|
12
|
-
content: string;
|
|
13
|
-
createdAt?: string;
|
|
14
|
-
created_at?: string;
|
|
15
|
-
likeCount?: number;
|
|
16
|
-
like_count?: number;
|
|
17
|
-
isLiked?: boolean;
|
|
18
|
-
is_like?: boolean;
|
|
19
|
-
profileData?: ProfileData;
|
|
20
|
-
user?: any;
|
|
21
|
-
comment_reply?: CommentData[];
|
|
22
|
-
reply?: CommentData[];
|
|
23
|
-
}
|
|
24
|
-
type __VLS_Props = {
|
|
25
|
-
comments: CommentData[];
|
|
26
|
-
currentUser?: any;
|
|
27
|
-
isLoading?: boolean;
|
|
28
|
-
isSubmitting?: boolean;
|
|
29
|
-
isLoggedIn?: boolean;
|
|
30
|
-
};
|
|
31
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
32
|
-
submit: (text: string) => any;
|
|
33
|
-
reply: (commentId: string | number, text: string) => any;
|
|
34
|
-
"like-comment": (comment: CommentData) => any;
|
|
35
|
-
"like-reply": (reply: CommentData) => any;
|
|
36
|
-
like: (comment: CommentData) => any;
|
|
37
|
-
profileClick: (pathName: string) => any;
|
|
38
|
-
login: () => any;
|
|
39
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
40
|
-
onSubmit?: ((text: string) => any) | undefined;
|
|
41
|
-
onReply?: ((commentId: string | number, text: string) => any) | undefined;
|
|
42
|
-
"onLike-comment"?: ((comment: CommentData) => any) | undefined;
|
|
43
|
-
"onLike-reply"?: ((reply: CommentData) => any) | undefined;
|
|
44
|
-
onLike?: ((comment: CommentData) => any) | undefined;
|
|
45
|
-
onProfileClick?: ((pathName: string) => any) | undefined;
|
|
46
|
-
onLogin?: (() => any) | undefined;
|
|
47
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
48
|
-
declare const _default: typeof __VLS_export;
|
|
49
|
-
export default _default;
|
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="py-[16px] flex flex-col gap-[16px]">
|
|
3
|
-
<!-- Header Section -->
|
|
4
|
-
<div class="flex gap-[8px] items-center">
|
|
5
|
-
<div class="font-title-medium-prominent">ความคิดเห็น</div>
|
|
6
|
-
<div class="text-gray font-title-medium">
|
|
7
|
-
{{ props.comments?.length || 0 }}
|
|
8
|
-
</div>
|
|
9
|
-
</div>
|
|
10
|
-
|
|
11
|
-
<!-- Loading State -->
|
|
12
|
-
<div v-if="props.isLoading" class="flex justify-center py-4">
|
|
13
|
-
<Icon name="line-md:loading-loop" size="32" class="text-primary" />
|
|
14
|
-
</div>
|
|
15
|
-
|
|
16
|
-
<!-- Add Comment Form -->
|
|
17
|
-
<div v-if="props.isLoggedIn">
|
|
18
|
-
<form class="space-y-[8px]" @submit.prevent="handleLocalSubmit">
|
|
19
|
-
<div class="flex gap-[16px] items-center">
|
|
20
|
-
<Avatar
|
|
21
|
-
:size="30"
|
|
22
|
-
:src="
|
|
23
|
-
props.currentUser?.profile_image?.image_url || props.currentUser?.avatar
|
|
24
|
-
"
|
|
25
|
-
/>
|
|
26
|
-
<div class="w-auto flex-1" @click="isButtonComment = true">
|
|
27
|
-
<InputTextarea
|
|
28
|
-
v-model="commentText"
|
|
29
|
-
resize="none"
|
|
30
|
-
rows="1"
|
|
31
|
-
full-width
|
|
32
|
-
placeholder="เพิ่มความคิดเห็น"
|
|
33
|
-
/>
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
|
|
37
|
-
<!-- Action Buttons -->
|
|
38
|
-
<div v-if="isButtonComment" class="flex justify-end">
|
|
39
|
-
<div class="flex gap-[8px] w-[140px]">
|
|
40
|
-
<Button
|
|
41
|
-
size="tiny"
|
|
42
|
-
full-width
|
|
43
|
-
full-rounded
|
|
44
|
-
color="black"
|
|
45
|
-
variant="outline"
|
|
46
|
-
@click="clearTextfields"
|
|
47
|
-
>
|
|
48
|
-
ยกเลิก
|
|
49
|
-
</Button>
|
|
50
|
-
<Button
|
|
51
|
-
full-width
|
|
52
|
-
size="tiny"
|
|
53
|
-
full-rounded
|
|
54
|
-
color="primary"
|
|
55
|
-
type="submit"
|
|
56
|
-
:loading="props.isSubmitting"
|
|
57
|
-
:disabled="!commentText.trim().length"
|
|
58
|
-
>
|
|
59
|
-
ส่ง
|
|
60
|
-
</Button>
|
|
61
|
-
</div>
|
|
62
|
-
</div>
|
|
63
|
-
</form>
|
|
64
|
-
</div>
|
|
65
|
-
<div v-else class="bg-bright p-4 rounded-lg text-center text-gray">
|
|
66
|
-
กรุณา<a class="text-primary cursor-pointer px-1" @click="emit('login')"
|
|
67
|
-
>เข้าสู่ระบบ</a
|
|
68
|
-
>เพื่อแสดงความคิดเห็น
|
|
69
|
-
</div>
|
|
70
|
-
|
|
71
|
-
<!-- Comments List -->
|
|
72
|
-
<div
|
|
73
|
-
v-for="(comment, commentIndex) in props.comments"
|
|
74
|
-
:key="comment.id"
|
|
75
|
-
class="flex flex-col gap-[16px]"
|
|
76
|
-
>
|
|
77
|
-
<!-- Main Comment -->
|
|
78
|
-
<div
|
|
79
|
-
class="flex flex-col gap-[4px]"
|
|
80
|
-
@mouseenter="() => handleMouseEnter(commentIndex)"
|
|
81
|
-
@mouseleave="() => handleMouseLeave(commentIndex)"
|
|
82
|
-
>
|
|
83
|
-
<div class="flex gap-[8px]">
|
|
84
|
-
<div
|
|
85
|
-
class="cursor-pointer"
|
|
86
|
-
@click="
|
|
87
|
-
emit(
|
|
88
|
-
'profileClick',
|
|
89
|
-
comment.profileData?.profile_path?.path_name || comment.user?.path_name || comment.user?.id
|
|
90
|
-
)
|
|
91
|
-
"
|
|
92
|
-
>
|
|
93
|
-
<Avatar
|
|
94
|
-
:size="30"
|
|
95
|
-
:src="
|
|
96
|
-
comment.profileData?.profile_image?.image_url || comment.user?.avatar
|
|
97
|
-
"
|
|
98
|
-
/>
|
|
99
|
-
</div>
|
|
100
|
-
|
|
101
|
-
<div class="flex flex-col w-full">
|
|
102
|
-
<Card
|
|
103
|
-
padding="8"
|
|
104
|
-
disabled-background
|
|
105
|
-
class="flex flex-col bg-bright gap-[4px]"
|
|
106
|
-
>
|
|
107
|
-
<div
|
|
108
|
-
class="font-body-large-prominent cursor-pointer"
|
|
109
|
-
@click="
|
|
110
|
-
emit(
|
|
111
|
-
'profileClick',
|
|
112
|
-
comment.profileData?.profile_path?.path_name || comment.user?.path_name || comment.user?.id
|
|
113
|
-
)
|
|
114
|
-
"
|
|
115
|
-
>
|
|
116
|
-
{{
|
|
117
|
-
comment.profileData?.profile_name || comment.user?.name || "\u0E44\u0E21\u0E48\u0E17\u0E23\u0E32\u0E1A\u0E0A\u0E37\u0E48\u0E2D"
|
|
118
|
-
}}
|
|
119
|
-
</div>
|
|
120
|
-
|
|
121
|
-
<div class="font-body-large max-w-[768px] break-words">
|
|
122
|
-
{{ comment.content }}
|
|
123
|
-
</div>
|
|
124
|
-
</Card>
|
|
125
|
-
</div>
|
|
126
|
-
</div>
|
|
127
|
-
|
|
128
|
-
<!-- Comment Actions -->
|
|
129
|
-
<div
|
|
130
|
-
class="flex gap-[16px] ps-[38px] items-center text-gray font-body-large"
|
|
131
|
-
>
|
|
132
|
-
<div>{{ comment.createdAt || comment.created_at }}</div>
|
|
133
|
-
|
|
134
|
-
<div class="flex gap-[4px]">
|
|
135
|
-
<Button
|
|
136
|
-
disabled-padding
|
|
137
|
-
prepend-icon="fa6-regular:thumbs-up"
|
|
138
|
-
variant="text"
|
|
139
|
-
:color="
|
|
140
|
-
comment.isLiked ?? comment.is_like ? 'primary' : 'black'
|
|
141
|
-
"
|
|
142
|
-
:icon-size="20"
|
|
143
|
-
:loading="likeLoadingStates[comment.id]"
|
|
144
|
-
@click="emit('like-comment', comment)"
|
|
145
|
-
/>
|
|
146
|
-
<div>{{ comment.likeCount ?? comment.like_count ?? 0 }}</div>
|
|
147
|
-
</div>
|
|
148
|
-
|
|
149
|
-
<div
|
|
150
|
-
v-if="props.isLoggedIn"
|
|
151
|
-
class="cursor-pointer"
|
|
152
|
-
@click="openReplyForm(comment)"
|
|
153
|
-
>
|
|
154
|
-
ตอบกลับ
|
|
155
|
-
</div>
|
|
156
|
-
</div>
|
|
157
|
-
|
|
158
|
-
<!-- Toggle Replies -->
|
|
159
|
-
<div
|
|
160
|
-
v-if="comment.comment_reply?.length || comment.reply?.length"
|
|
161
|
-
class="flex gap-[8px] ps-[38px] items-center text-primary font-body-large cursor-pointer w-fit"
|
|
162
|
-
@click="
|
|
163
|
-
showRepliesStates[commentIndex] = !showRepliesStates[commentIndex]
|
|
164
|
-
"
|
|
165
|
-
>
|
|
166
|
-
<div>
|
|
167
|
-
การตอบกลับ
|
|
168
|
-
{{ comment.comment_reply?.length || comment.reply?.length }} รายการ
|
|
169
|
-
</div>
|
|
170
|
-
<Icon
|
|
171
|
-
:name="
|
|
172
|
-
showRepliesStates[commentIndex] ? 'heroicons:chevron-up-solid' : 'heroicons:chevron-down-solid'
|
|
173
|
-
"
|
|
174
|
-
size="20"
|
|
175
|
-
/>
|
|
176
|
-
</div>
|
|
177
|
-
</div>
|
|
178
|
-
|
|
179
|
-
<!-- Replies -->
|
|
180
|
-
<div
|
|
181
|
-
v-if="
|
|
182
|
-
showRepliesStates[commentIndex] && (comment.comment_reply || comment.reply)
|
|
183
|
-
"
|
|
184
|
-
class="flex flex-col gap-[16px]"
|
|
185
|
-
>
|
|
186
|
-
<div
|
|
187
|
-
v-for="(reply, replyIndex) in comment.comment_reply || comment.reply"
|
|
188
|
-
:key="reply.id"
|
|
189
|
-
class="ps-[38px] flex flex-col gap-[4px]"
|
|
190
|
-
>
|
|
191
|
-
<div class="flex gap-[8px]">
|
|
192
|
-
<div>
|
|
193
|
-
<Avatar
|
|
194
|
-
:size="30"
|
|
195
|
-
:src="
|
|
196
|
-
reply.profileData?.profile_image?.image_url || reply.user?.avatar
|
|
197
|
-
"
|
|
198
|
-
class="cursor-pointer"
|
|
199
|
-
@click="
|
|
200
|
-
emit(
|
|
201
|
-
'profileClick',
|
|
202
|
-
reply.profileData?.profile_path?.path_name || reply.user?.path_name || reply.user?.id
|
|
203
|
-
)
|
|
204
|
-
"
|
|
205
|
-
/>
|
|
206
|
-
</div>
|
|
207
|
-
|
|
208
|
-
<div class="flex flex-col w-full">
|
|
209
|
-
<Card
|
|
210
|
-
padding="8"
|
|
211
|
-
disabled-background
|
|
212
|
-
class="flex flex-col bg-bright gap-[4px]"
|
|
213
|
-
>
|
|
214
|
-
<div
|
|
215
|
-
class="font-body-large-prominent cursor-pointer"
|
|
216
|
-
@click="
|
|
217
|
-
emit(
|
|
218
|
-
'profileClick',
|
|
219
|
-
reply.profileData?.profile_path?.path_name || reply.user?.path_name || reply.user?.id
|
|
220
|
-
)
|
|
221
|
-
"
|
|
222
|
-
>
|
|
223
|
-
{{
|
|
224
|
-
reply.profileData?.profile_name || reply.user?.name || "\u0E44\u0E21\u0E48\u0E17\u0E23\u0E32\u0E1A\u0E0A\u0E37\u0E48\u0E2D"
|
|
225
|
-
}}
|
|
226
|
-
</div>
|
|
227
|
-
|
|
228
|
-
<div class="font-body-large max-w-[768px] break-words">
|
|
229
|
-
{{ reply.content }}
|
|
230
|
-
</div>
|
|
231
|
-
</Card>
|
|
232
|
-
</div>
|
|
233
|
-
</div>
|
|
234
|
-
|
|
235
|
-
<!-- Reply Actions -->
|
|
236
|
-
<div
|
|
237
|
-
class="flex gap-[16px] ps-[38px] items-center text-gray font-body-large"
|
|
238
|
-
>
|
|
239
|
-
<div>{{ reply.createdAt || reply.created_at }}</div>
|
|
240
|
-
|
|
241
|
-
<div class="flex gap-[4px]">
|
|
242
|
-
<Button
|
|
243
|
-
disabled-padding
|
|
244
|
-
prepend-icon="fa6-regular:thumbs-up"
|
|
245
|
-
variant="text"
|
|
246
|
-
:color="reply.isLiked ?? reply.is_like ? 'primary' : 'black'"
|
|
247
|
-
:icon-size="20"
|
|
248
|
-
:loading="likeLoadingStates[reply.id]"
|
|
249
|
-
@click="emit('like-reply', reply)"
|
|
250
|
-
/>
|
|
251
|
-
<div>{{ reply.likeCount ?? reply.like_count ?? 0 }}</div>
|
|
252
|
-
</div>
|
|
253
|
-
</div>
|
|
254
|
-
</div>
|
|
255
|
-
</div>
|
|
256
|
-
|
|
257
|
-
<!-- Reply Form (Inline) -->
|
|
258
|
-
<div
|
|
259
|
-
v-if="replyingTo === comment.id"
|
|
260
|
-
class="px-[38px] flex flex-col gap-[8px]"
|
|
261
|
-
>
|
|
262
|
-
<div class="flex gap-[16px]">
|
|
263
|
-
<Avatar
|
|
264
|
-
:size="30"
|
|
265
|
-
:src="
|
|
266
|
-
props.currentUser?.profile_image?.image_url || props.currentUser?.avatar || 'https://avatar.iran.liara.run/public?random=1'
|
|
267
|
-
"
|
|
268
|
-
/>
|
|
269
|
-
|
|
270
|
-
<div class="w-auto flex-1">
|
|
271
|
-
<InputTextarea
|
|
272
|
-
ref="replyInput"
|
|
273
|
-
v-model="replyText"
|
|
274
|
-
resize="none"
|
|
275
|
-
rows="1"
|
|
276
|
-
full-width
|
|
277
|
-
:placeholder="`\u0E15\u0E2D\u0E1A\u0E01\u0E25\u0E31\u0E1A ${comment.profileData?.profile_name || comment.user?.name || '\u0E44\u0E21\u0E48\u0E17\u0E23\u0E32\u0E1A\u0E0A\u0E37\u0E48\u0E2D'}...`"
|
|
278
|
-
/>
|
|
279
|
-
</div>
|
|
280
|
-
</div>
|
|
281
|
-
|
|
282
|
-
<div class="flex justify-end">
|
|
283
|
-
<div class="flex gap-[8px] w-[140px]">
|
|
284
|
-
<Button
|
|
285
|
-
size="tiny"
|
|
286
|
-
full-width
|
|
287
|
-
full-rounded
|
|
288
|
-
color="black"
|
|
289
|
-
variant="outline"
|
|
290
|
-
@click="closeReplyForm"
|
|
291
|
-
>
|
|
292
|
-
ยกเลิก
|
|
293
|
-
</Button>
|
|
294
|
-
<Button
|
|
295
|
-
full-width
|
|
296
|
-
size="tiny"
|
|
297
|
-
full-rounded
|
|
298
|
-
color="primary"
|
|
299
|
-
:loading="replyLoadingStates[comment.id]"
|
|
300
|
-
:disabled="!replyText.trim().length"
|
|
301
|
-
@click="handleLocalReply(comment)"
|
|
302
|
-
>
|
|
303
|
-
ส่ง
|
|
304
|
-
</Button>
|
|
305
|
-
</div>
|
|
306
|
-
</div>
|
|
307
|
-
</div>
|
|
308
|
-
</div>
|
|
309
|
-
</div>
|
|
310
|
-
</template>
|
|
311
|
-
|
|
312
|
-
<script setup>
|
|
313
|
-
import { ref, reactive, nextTick } from "vue";
|
|
314
|
-
const props = defineProps({
|
|
315
|
-
comments: { type: Array, required: true },
|
|
316
|
-
currentUser: { type: null, required: false },
|
|
317
|
-
isLoading: { type: Boolean, required: false },
|
|
318
|
-
isSubmitting: { type: Boolean, required: false },
|
|
319
|
-
isLoggedIn: { type: Boolean, required: false }
|
|
320
|
-
});
|
|
321
|
-
const emit = defineEmits(["submit", "reply", "like", "like-comment", "like-reply", "profileClick", "login"]);
|
|
322
|
-
const commentText = ref("");
|
|
323
|
-
const replyText = ref("");
|
|
324
|
-
const replyingTo = ref(null);
|
|
325
|
-
const isButtonComment = ref(false);
|
|
326
|
-
const showRepliesStates = reactive({});
|
|
327
|
-
const likeLoadingStates = reactive({});
|
|
328
|
-
const replyLoadingStates = reactive({});
|
|
329
|
-
const replyInput = ref();
|
|
330
|
-
const handleLocalSubmit = () => {
|
|
331
|
-
if (!commentText.value.trim()) return;
|
|
332
|
-
emit("submit", commentText.value);
|
|
333
|
-
commentText.value = "";
|
|
334
|
-
};
|
|
335
|
-
const handleLocalReply = (comment) => {
|
|
336
|
-
if (!replyText.value.trim()) return;
|
|
337
|
-
emit("reply", comment.id, replyText.value);
|
|
338
|
-
replyText.value = "";
|
|
339
|
-
closeReplyForm();
|
|
340
|
-
};
|
|
341
|
-
const openReplyForm = async (comment) => {
|
|
342
|
-
replyingTo.value = comment.id;
|
|
343
|
-
const targetName = comment.profileData?.profile_name || comment.user?.name;
|
|
344
|
-
replyText.value = targetName ? `@${targetName} ` : "";
|
|
345
|
-
await nextTick();
|
|
346
|
-
replyInput.value?.focus();
|
|
347
|
-
};
|
|
348
|
-
const closeReplyForm = () => {
|
|
349
|
-
replyingTo.value = null;
|
|
350
|
-
replyText.value = "";
|
|
351
|
-
};
|
|
352
|
-
const clearTextfields = () => {
|
|
353
|
-
commentText.value = "";
|
|
354
|
-
isButtonComment.value = false;
|
|
355
|
-
};
|
|
356
|
-
const handleMouseEnter = (i) => {
|
|
357
|
-
};
|
|
358
|
-
const handleMouseLeave = (i) => {
|
|
359
|
-
};
|
|
360
|
-
</script>
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
interface ProfileData {
|
|
2
|
-
profile_name: string;
|
|
3
|
-
profile_path: {
|
|
4
|
-
path_name: string;
|
|
5
|
-
};
|
|
6
|
-
profile_image: {
|
|
7
|
-
image_url: string;
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
interface CommentData {
|
|
11
|
-
id: string | number;
|
|
12
|
-
content: string;
|
|
13
|
-
createdAt?: string;
|
|
14
|
-
created_at?: string;
|
|
15
|
-
likeCount?: number;
|
|
16
|
-
like_count?: number;
|
|
17
|
-
isLiked?: boolean;
|
|
18
|
-
is_like?: boolean;
|
|
19
|
-
profileData?: ProfileData;
|
|
20
|
-
user?: any;
|
|
21
|
-
comment_reply?: CommentData[];
|
|
22
|
-
reply?: CommentData[];
|
|
23
|
-
}
|
|
24
|
-
type __VLS_Props = {
|
|
25
|
-
comments: CommentData[];
|
|
26
|
-
currentUser?: any;
|
|
27
|
-
isLoading?: boolean;
|
|
28
|
-
isSubmitting?: boolean;
|
|
29
|
-
isLoggedIn?: boolean;
|
|
30
|
-
};
|
|
31
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
32
|
-
submit: (text: string) => any;
|
|
33
|
-
reply: (commentId: string | number, text: string) => any;
|
|
34
|
-
"like-comment": (comment: CommentData) => any;
|
|
35
|
-
"like-reply": (reply: CommentData) => any;
|
|
36
|
-
like: (comment: CommentData) => any;
|
|
37
|
-
profileClick: (pathName: string) => any;
|
|
38
|
-
login: () => any;
|
|
39
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
40
|
-
onSubmit?: ((text: string) => any) | undefined;
|
|
41
|
-
onReply?: ((commentId: string | number, text: string) => any) | undefined;
|
|
42
|
-
"onLike-comment"?: ((comment: CommentData) => any) | undefined;
|
|
43
|
-
"onLike-reply"?: ((reply: CommentData) => any) | undefined;
|
|
44
|
-
onLike?: ((comment: CommentData) => any) | undefined;
|
|
45
|
-
onProfileClick?: ((pathName: string) => any) | undefined;
|
|
46
|
-
onLogin?: (() => any) | undefined;
|
|
47
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
48
|
-
declare const _default: typeof __VLS_export;
|
|
49
|
-
export default _default;
|