datocms-plugin-record-comments 0.2.0 → 1.0.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/README.md +64 -4
- package/dist/assets/index-D7VcKz6i.css +1 -0
- package/dist/assets/index-UKydYRNj.js +251 -0
- package/dist/index.html +17 -0
- package/package.json +43 -43
- package/build/asset-manifest.json +0 -13
- package/build/index.html +0 -1
- package/build/robots.txt +0 -3
- package/build/static/css/main.19c0232f.css +0 -2
- package/build/static/css/main.19c0232f.css.map +0 -1
- package/build/static/js/main.255a6b09.js +0 -3
- package/build/static/js/main.255a6b09.js.LICENSE.txt +0 -59
- package/build/static/js/main.255a6b09.js.map +0 -1
- package/public/index.html +0 -11
- package/public/robots.txt +0 -3
- package/src/entrypoints/CommentsBar.tsx +0 -254
- package/src/entrypoints/NoLogModal.tsx +0 -43
- package/src/entrypoints/components/Comment.tsx +0 -260
- package/src/entrypoints/styles/comment.module.css +0 -134
- package/src/entrypoints/styles/commentbar.module.css +0 -3
- package/src/entrypoints/styles/modal.module.css +0 -13
- package/src/index.tsx +0 -45
- package/src/react-app-env.d.ts +0 -1
- package/src/utils/render.tsx +0 -6
- package/tsconfig.json +0 -26
package/public/index.html
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
-
</head>
|
|
7
|
-
<body>
|
|
8
|
-
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
9
|
-
<div id="root"></div>
|
|
10
|
-
</body>
|
|
11
|
-
</html>
|
package/public/robots.txt
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
import { RenderItemFormSidebarPanelCtx } from "datocms-plugin-sdk";
|
|
2
|
-
import {
|
|
3
|
-
AccountAttributes,
|
|
4
|
-
UserAttributes,
|
|
5
|
-
} from "datocms-plugin-sdk/dist/types/SiteApiSchema";
|
|
6
|
-
import { Button, Canvas } from "datocms-react-ui";
|
|
7
|
-
import { useEffect, useState } from "react";
|
|
8
|
-
import Comment from "./components/Comment";
|
|
9
|
-
import styles from "./styles/commentbar.module.css";
|
|
10
|
-
|
|
11
|
-
type PropTypes = {
|
|
12
|
-
ctx: RenderItemFormSidebarPanelCtx;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export type CommentType = {
|
|
16
|
-
dateISO: string;
|
|
17
|
-
comment: string;
|
|
18
|
-
author: {
|
|
19
|
-
name: string;
|
|
20
|
-
email: string;
|
|
21
|
-
};
|
|
22
|
-
usersWhoUpvoted: string[];
|
|
23
|
-
replies?: CommentType[];
|
|
24
|
-
parentCommentISO?: string;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const CommentsBar = ({ ctx }: PropTypes) => {
|
|
28
|
-
//this component is way too big, i should split it into smaller ones
|
|
29
|
-
const userEmail = (ctx.currentUser.attributes as UserAttributes)
|
|
30
|
-
.email as string;
|
|
31
|
-
const userName =
|
|
32
|
-
(ctx.currentUser.attributes as UserAttributes).full_name ||
|
|
33
|
-
`${(ctx.currentUser.attributes! as AccountAttributes).first_name} ${
|
|
34
|
-
(ctx.currentUser.attributes as AccountAttributes).last_name
|
|
35
|
-
}`;
|
|
36
|
-
let foundLog = false;
|
|
37
|
-
|
|
38
|
-
for (const field in ctx.fields) {
|
|
39
|
-
if (
|
|
40
|
-
ctx.fields[field]?.attributes.field_type === "json" &&
|
|
41
|
-
"comment_log" === ctx.fields[field]?.attributes.api_key
|
|
42
|
-
) {
|
|
43
|
-
foundLog = true;
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (foundLog) {
|
|
49
|
-
ctx.disableField("comment_log", true);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const initialState =
|
|
53
|
-
foundLog && ctx.formValues.comment_log
|
|
54
|
-
? (JSON.parse(ctx.formValues.comment_log as string) as CommentType[])
|
|
55
|
-
: [];
|
|
56
|
-
|
|
57
|
-
const [savedComments, setSavedComments] =
|
|
58
|
-
useState<CommentType[]>(initialState);
|
|
59
|
-
|
|
60
|
-
const handleOpenLogModal = async () => {
|
|
61
|
-
const result = await ctx.openModal({
|
|
62
|
-
id: "NoLogModal",
|
|
63
|
-
title: "Didn't find a log",
|
|
64
|
-
width: "l",
|
|
65
|
-
});
|
|
66
|
-
if (result === "goToModelEdit") {
|
|
67
|
-
ctx.navigateTo(`/admin/item_types/${ctx.itemType.id}`);
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const saveCommentHandler = () => {
|
|
72
|
-
if (!foundLog) {
|
|
73
|
-
handleOpenLogModal();
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const newComment: CommentType = {
|
|
78
|
-
dateISO: new Date().toISOString(),
|
|
79
|
-
comment: "",
|
|
80
|
-
author: {
|
|
81
|
-
name: userName,
|
|
82
|
-
email: userEmail,
|
|
83
|
-
},
|
|
84
|
-
usersWhoUpvoted: [],
|
|
85
|
-
replies: [],
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
setSavedComments((oldComments: CommentType[]) => {
|
|
89
|
-
const newComments = [...oldComments];
|
|
90
|
-
newComments.unshift(newComment);
|
|
91
|
-
return newComments;
|
|
92
|
-
});
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const deleteCommentHandler = (
|
|
96
|
-
dateISO: string,
|
|
97
|
-
parentCommentISO: string = ""
|
|
98
|
-
) => {
|
|
99
|
-
if (parentCommentISO) {
|
|
100
|
-
setSavedComments((oldComments: CommentType[]) => {
|
|
101
|
-
const newCommentsIntermediary = [...oldComments];
|
|
102
|
-
const parentComment = newCommentsIntermediary.find(
|
|
103
|
-
(comment) => comment.dateISO === parentCommentISO
|
|
104
|
-
);
|
|
105
|
-
parentComment!.replies = parentComment!.replies!.filter(
|
|
106
|
-
(comment) => comment.dateISO !== dateISO
|
|
107
|
-
);
|
|
108
|
-
const newComments = newCommentsIntermediary;
|
|
109
|
-
return newComments;
|
|
110
|
-
});
|
|
111
|
-
} else {
|
|
112
|
-
setSavedComments((oldComments: CommentType[]) => {
|
|
113
|
-
const newCommentsIntermediary = [...oldComments];
|
|
114
|
-
const newComments = newCommentsIntermediary.filter(
|
|
115
|
-
(comment) => comment.dateISO !== dateISO
|
|
116
|
-
);
|
|
117
|
-
return newComments;
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
const editCommentHandler = (
|
|
123
|
-
dateISO: string,
|
|
124
|
-
newValue: string,
|
|
125
|
-
parentCommentISO: string = ""
|
|
126
|
-
) => {
|
|
127
|
-
if (parentCommentISO) {
|
|
128
|
-
setSavedComments((oldComments: CommentType[]) => {
|
|
129
|
-
const newComments = [...oldComments];
|
|
130
|
-
const parentComment = newComments.find(
|
|
131
|
-
(comment) => comment.dateISO === parentCommentISO
|
|
132
|
-
);
|
|
133
|
-
const reply = parentComment!.replies!.find(
|
|
134
|
-
(comment: CommentType) => comment.dateISO === dateISO
|
|
135
|
-
);
|
|
136
|
-
reply!.comment = newValue;
|
|
137
|
-
return newComments;
|
|
138
|
-
});
|
|
139
|
-
} else {
|
|
140
|
-
setSavedComments((oldComments: CommentType[]) => {
|
|
141
|
-
const newComments = [...oldComments];
|
|
142
|
-
newComments.find((comment) => comment.dateISO === dateISO)!.comment =
|
|
143
|
-
newValue;
|
|
144
|
-
return newComments;
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const upvoteCommentHandler = (
|
|
150
|
-
dateISO: string,
|
|
151
|
-
userUpvotedThisComment: boolean,
|
|
152
|
-
parentCommentISO: string = ""
|
|
153
|
-
) => {
|
|
154
|
-
if (parentCommentISO) {
|
|
155
|
-
setSavedComments((oldComments: CommentType[]) => {
|
|
156
|
-
const newComments = [...oldComments];
|
|
157
|
-
const parentComment = newComments.find(
|
|
158
|
-
(comment) => comment.dateISO === parentCommentISO
|
|
159
|
-
);
|
|
160
|
-
const reply = parentComment!.replies!.find(
|
|
161
|
-
(comment: CommentType) => comment.dateISO === dateISO
|
|
162
|
-
);
|
|
163
|
-
if (userUpvotedThisComment) {
|
|
164
|
-
reply!.usersWhoUpvoted = reply!.usersWhoUpvoted.filter(
|
|
165
|
-
(userWhoUpvotedThisComment) =>
|
|
166
|
-
userWhoUpvotedThisComment !== userEmail
|
|
167
|
-
);
|
|
168
|
-
} else {
|
|
169
|
-
reply!.usersWhoUpvoted.push(userEmail);
|
|
170
|
-
}
|
|
171
|
-
return newComments;
|
|
172
|
-
});
|
|
173
|
-
} else {
|
|
174
|
-
setSavedComments((oldComments: CommentType[]) => {
|
|
175
|
-
const newComments = [...oldComments];
|
|
176
|
-
const upvotedComment = newComments.find(
|
|
177
|
-
(comment) => comment.dateISO === dateISO
|
|
178
|
-
);
|
|
179
|
-
if (userUpvotedThisComment) {
|
|
180
|
-
upvotedComment!.usersWhoUpvoted =
|
|
181
|
-
upvotedComment!.usersWhoUpvoted.filter(
|
|
182
|
-
(userWhoUpvotedThisComment) =>
|
|
183
|
-
userWhoUpvotedThisComment !== userEmail
|
|
184
|
-
);
|
|
185
|
-
} else {
|
|
186
|
-
upvotedComment!.usersWhoUpvoted.push(userEmail);
|
|
187
|
-
}
|
|
188
|
-
return newComments;
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
const replyCommentHandler = (parentCommentISO: string) => {
|
|
194
|
-
const newComment: CommentType = {
|
|
195
|
-
dateISO: new Date().toISOString(),
|
|
196
|
-
comment: "",
|
|
197
|
-
author: {
|
|
198
|
-
name: userName,
|
|
199
|
-
email: userEmail,
|
|
200
|
-
},
|
|
201
|
-
usersWhoUpvoted: [],
|
|
202
|
-
parentCommentISO,
|
|
203
|
-
};
|
|
204
|
-
setSavedComments((oldComments: CommentType[]) => {
|
|
205
|
-
const newComments = [...oldComments];
|
|
206
|
-
newComments
|
|
207
|
-
.find((comment) => comment.dateISO === parentCommentISO)
|
|
208
|
-
?.replies?.unshift(newComment);
|
|
209
|
-
return newComments;
|
|
210
|
-
});
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
useEffect(() => {
|
|
214
|
-
const objectIsEmpty = !Object.keys(savedComments).length;
|
|
215
|
-
if (foundLog && objectIsEmpty) {
|
|
216
|
-
ctx.setFieldValue("comment_log", null);
|
|
217
|
-
} else if (foundLog) {
|
|
218
|
-
const formatedComments = JSON.stringify(savedComments, null, 2);
|
|
219
|
-
const stateIsEqualToLog =
|
|
220
|
-
formatedComments === (ctx.formValues.comment_log as string);
|
|
221
|
-
if (!stateIsEqualToLog) {
|
|
222
|
-
ctx.setFieldValue("comment_log", formatedComments);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}, [savedComments, ctx, foundLog]);
|
|
226
|
-
|
|
227
|
-
return (
|
|
228
|
-
<Canvas ctx={ctx}>
|
|
229
|
-
<Button
|
|
230
|
-
fullWidth
|
|
231
|
-
className={styles["add-comment-button"]}
|
|
232
|
-
onClick={saveCommentHandler}
|
|
233
|
-
>
|
|
234
|
-
Add a new comment...
|
|
235
|
-
</Button>
|
|
236
|
-
{foundLog &&
|
|
237
|
-
savedComments.map((comment) => {
|
|
238
|
-
return (
|
|
239
|
-
<Comment
|
|
240
|
-
key={comment.dateISO}
|
|
241
|
-
deleteComment={deleteCommentHandler}
|
|
242
|
-
editComment={editCommentHandler}
|
|
243
|
-
upvoteComment={upvoteCommentHandler}
|
|
244
|
-
replyComment={replyCommentHandler}
|
|
245
|
-
commentObject={comment}
|
|
246
|
-
currentUserEmail={userEmail}
|
|
247
|
-
/>
|
|
248
|
-
);
|
|
249
|
-
})}
|
|
250
|
-
</Canvas>
|
|
251
|
-
);
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
export default CommentsBar;
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { RenderModalCtx } from "datocms-plugin-sdk";
|
|
2
|
-
import { Button, Canvas } from "datocms-react-ui";
|
|
3
|
-
import styles from "./styles/modal.module.css";
|
|
4
|
-
|
|
5
|
-
type PropTypes = {
|
|
6
|
-
ctx: RenderModalCtx;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
const NoLogModal = ({ ctx }: PropTypes) => {
|
|
10
|
-
const handleCancel = () => {
|
|
11
|
-
ctx.resolve("cancel");
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const handleGoToModel = () => {
|
|
15
|
-
ctx.resolve("goToModelEdit");
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<Canvas ctx={ctx}>
|
|
20
|
-
<div className={styles["error-explanation"]}>
|
|
21
|
-
<h2>A field is missing from your model!</h2>
|
|
22
|
-
<p>
|
|
23
|
-
You need to create a "comment log" JSON field on this model to save
|
|
24
|
-
comments.
|
|
25
|
-
</p>
|
|
26
|
-
<p className={styles["note"]}>
|
|
27
|
-
Note that the field must be of type "JSON" and its API key must be
|
|
28
|
-
"comment_log"
|
|
29
|
-
</p>
|
|
30
|
-
</div>
|
|
31
|
-
<div className={styles["buttons"]}>
|
|
32
|
-
<Button buttonType="negative" buttonSize="l" onClick={handleCancel}>
|
|
33
|
-
Cancel
|
|
34
|
-
</Button>
|
|
35
|
-
<Button buttonType="primary" buttonSize="l" onClick={handleGoToModel}>
|
|
36
|
-
Go to model editing
|
|
37
|
-
</Button>
|
|
38
|
-
</div>
|
|
39
|
-
</Canvas>
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export default NoLogModal;
|
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
-
import styles from "../styles/comment.module.css";
|
|
3
|
-
import Textarea from "react-textarea-autosize";
|
|
4
|
-
import ReactTimeAgo from "react-time-ago";
|
|
5
|
-
import { CommentType } from "../CommentsBar";
|
|
6
|
-
import {
|
|
7
|
-
faChevronUp,
|
|
8
|
-
faPen,
|
|
9
|
-
faReply,
|
|
10
|
-
faSave,
|
|
11
|
-
faTrashAlt,
|
|
12
|
-
} from "@fortawesome/free-solid-svg-icons";
|
|
13
|
-
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
14
|
-
|
|
15
|
-
type commentProps = {
|
|
16
|
-
deleteComment: (dateISO: string, parentCommentISO?: string) => void;
|
|
17
|
-
editComment: (
|
|
18
|
-
dateISO: string,
|
|
19
|
-
newValue: string,
|
|
20
|
-
parentCommentISO?: string
|
|
21
|
-
) => void;
|
|
22
|
-
upvoteComment: (
|
|
23
|
-
dateISO: string,
|
|
24
|
-
userUpvotedThisComment: boolean,
|
|
25
|
-
parentCommentISO?: string
|
|
26
|
-
) => void;
|
|
27
|
-
replyComment: (parentCommentISO: string) => void;
|
|
28
|
-
commentObject: CommentType;
|
|
29
|
-
currentUserEmail: string;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const Comment: React.FC<commentProps> = (props) => {
|
|
33
|
-
//this component is way too big, i should split it into smaller ones
|
|
34
|
-
const userUpvotedThisComment = !!props.commentObject.usersWhoUpvoted.find(
|
|
35
|
-
(userWhoUpvoted) => userWhoUpvoted === props.currentUserEmail
|
|
36
|
-
);
|
|
37
|
-
const commentSpan = useRef<HTMLDivElement>(null);
|
|
38
|
-
const [textAreaHeight, setTextAreaHeight] = useState(21);
|
|
39
|
-
const [isEditing, setIsEditing] = useState(!props.commentObject.comment);
|
|
40
|
-
const isNotAReply = "replies" in props.commentObject;
|
|
41
|
-
const userIsAuthor =
|
|
42
|
-
props.commentObject.author.email === props.currentUserEmail;
|
|
43
|
-
const md5 = require("md5");
|
|
44
|
-
const authorProfilePictureUrl =
|
|
45
|
-
"https://www.gravatar.com/avatar/" +
|
|
46
|
-
md5(props.commentObject.author.email) +
|
|
47
|
-
"?d=mp";
|
|
48
|
-
|
|
49
|
-
const replyClasses = isNotAReply ? "" : " " + styles.reply;
|
|
50
|
-
const commentClasses = styles.comment + replyClasses;
|
|
51
|
-
|
|
52
|
-
const [textAreaValue, setTextAreaValue] = useState(
|
|
53
|
-
props.commentObject.comment
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const toggleEdit = () => {
|
|
57
|
-
setIsEditing(true);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const editCommentHandler = () => {
|
|
61
|
-
if (!textAreaValue.trim()) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
setIsEditing(false);
|
|
65
|
-
if (isNotAReply) {
|
|
66
|
-
props.editComment(props.commentObject.dateISO, textAreaValue);
|
|
67
|
-
} else {
|
|
68
|
-
props.editComment(
|
|
69
|
-
props.commentObject.dateISO,
|
|
70
|
-
textAreaValue,
|
|
71
|
-
props.commentObject.parentCommentISO
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const deleteCommentHanlder = () => {
|
|
77
|
-
if (isNotAReply) {
|
|
78
|
-
props.deleteComment(props.commentObject.dateISO);
|
|
79
|
-
} else {
|
|
80
|
-
props.deleteComment(
|
|
81
|
-
props.commentObject.dateISO,
|
|
82
|
-
props.commentObject.parentCommentISO
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const upvoteCommentHandler = () => {
|
|
88
|
-
if (isNotAReply) {
|
|
89
|
-
props.upvoteComment(props.commentObject.dateISO, userUpvotedThisComment);
|
|
90
|
-
} else {
|
|
91
|
-
props.upvoteComment(
|
|
92
|
-
props.commentObject.dateISO,
|
|
93
|
-
userUpvotedThisComment,
|
|
94
|
-
props.commentObject.parentCommentISO
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const replyCommentHandler = () => {
|
|
100
|
-
props.replyComment(props.commentObject.dateISO);
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
const enterKeyHandler = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
|
104
|
-
if (event.key === "Enter") {
|
|
105
|
-
editCommentHandler();
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
const heightChangeHandler = (height: number) => {
|
|
110
|
-
setTextAreaHeight(height);
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
useEffect(() => {
|
|
114
|
-
const spanHeight = commentSpan.current?.clientHeight;
|
|
115
|
-
setTextAreaHeight(spanHeight!);
|
|
116
|
-
}, [commentSpan]);
|
|
117
|
-
|
|
118
|
-
const focousHandler = (event: React.FocusEvent<HTMLTextAreaElement>) => {
|
|
119
|
-
event.currentTarget.setSelectionRange(
|
|
120
|
-
event.currentTarget.value.length,
|
|
121
|
-
event.currentTarget.value.length
|
|
122
|
-
);
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
return (
|
|
126
|
-
<div className={commentClasses}>
|
|
127
|
-
{!isNotAReply && (
|
|
128
|
-
<div
|
|
129
|
-
style={{ height: 100 + textAreaHeight }}
|
|
130
|
-
className={styles["reply-line"]}
|
|
131
|
-
></div>
|
|
132
|
-
)}
|
|
133
|
-
<div className={styles["comment-main"]}>
|
|
134
|
-
<div className={styles["comment-body"]}>
|
|
135
|
-
{isEditing && (
|
|
136
|
-
<div className={styles["dialogbox"]}>
|
|
137
|
-
<div className={styles["body"]}>
|
|
138
|
-
<span
|
|
139
|
-
className={styles["tip"] + " " + styles["tip-down"]}
|
|
140
|
-
></span>
|
|
141
|
-
<div className={styles["message"]}>
|
|
142
|
-
<Textarea
|
|
143
|
-
autoFocus
|
|
144
|
-
onFocus={focousHandler}
|
|
145
|
-
onHeightChange={heightChangeHandler}
|
|
146
|
-
onKeyPress={enterKeyHandler}
|
|
147
|
-
onChange={(event) => setTextAreaValue(event.target.value)}
|
|
148
|
-
value={textAreaValue}
|
|
149
|
-
className={styles["comment-textarea"]}
|
|
150
|
-
/>
|
|
151
|
-
</div>
|
|
152
|
-
</div>
|
|
153
|
-
</div>
|
|
154
|
-
)}
|
|
155
|
-
{!isEditing && (
|
|
156
|
-
<div ref={commentSpan} className={styles["dialogbox"]}>
|
|
157
|
-
<div className={styles["body"]}>
|
|
158
|
-
<span
|
|
159
|
-
className={styles["tip"] + " " + styles["tip-down"]}
|
|
160
|
-
></span>
|
|
161
|
-
<div className={styles["message"]}>
|
|
162
|
-
<span>{textAreaValue}</span>
|
|
163
|
-
</div>
|
|
164
|
-
</div>
|
|
165
|
-
</div>
|
|
166
|
-
)}
|
|
167
|
-
<div
|
|
168
|
-
className={`${styles["comment__footer"]} ${styles["comments__item__timestamp"]}`}
|
|
169
|
-
>
|
|
170
|
-
<div className={styles["comment-footer"]}>
|
|
171
|
-
<div className={styles["author-info"]}>
|
|
172
|
-
<img
|
|
173
|
-
className={styles["author-profile-picture"]}
|
|
174
|
-
src={authorProfilePictureUrl}
|
|
175
|
-
alt={props.commentObject.author.name}
|
|
176
|
-
/>
|
|
177
|
-
</div>
|
|
178
|
-
{!isNotAReply && (
|
|
179
|
-
<div className={styles["reply-profile-picture-line"]}></div>
|
|
180
|
-
)}
|
|
181
|
-
<div className={styles["comment__buttons"]}>
|
|
182
|
-
<div>
|
|
183
|
-
<span>{props.commentObject.author.name}</span>
|
|
184
|
-
</div>
|
|
185
|
-
<div className={styles["comment__timestamps"]}>
|
|
186
|
-
<ReactTimeAgo date={new Date(props.commentObject.dateISO)} />
|
|
187
|
-
</div>
|
|
188
|
-
<div className={styles["comment__interface"]}>
|
|
189
|
-
<span
|
|
190
|
-
className={userUpvotedThisComment ? styles["upvoted"] : ""}
|
|
191
|
-
>
|
|
192
|
-
{props.commentObject.usersWhoUpvoted.length}
|
|
193
|
-
</span>
|
|
194
|
-
<button
|
|
195
|
-
className={`${styles["comment__button"]} ${
|
|
196
|
-
styles["upvotes"]
|
|
197
|
-
} ${userUpvotedThisComment ? styles["upvoted"] : ""}`}
|
|
198
|
-
onClick={upvoteCommentHandler}
|
|
199
|
-
>
|
|
200
|
-
<FontAwesomeIcon icon={faChevronUp} />
|
|
201
|
-
</button>
|
|
202
|
-
{userIsAuthor && props.commentObject.comment && !isEditing ? (
|
|
203
|
-
<button
|
|
204
|
-
className={styles["comment__button"]}
|
|
205
|
-
onClick={toggleEdit}
|
|
206
|
-
>
|
|
207
|
-
<FontAwesomeIcon icon={faPen} />
|
|
208
|
-
</button>
|
|
209
|
-
) : userIsAuthor ? (
|
|
210
|
-
<button
|
|
211
|
-
className={styles["comment__button"]}
|
|
212
|
-
onClick={editCommentHandler}
|
|
213
|
-
>
|
|
214
|
-
<FontAwesomeIcon icon={faSave} />
|
|
215
|
-
</button>
|
|
216
|
-
) : null}
|
|
217
|
-
{userIsAuthor && (
|
|
218
|
-
<button
|
|
219
|
-
className={styles["comment__button"]}
|
|
220
|
-
onClick={deleteCommentHanlder}
|
|
221
|
-
>
|
|
222
|
-
<FontAwesomeIcon icon={faTrashAlt} />
|
|
223
|
-
</button>
|
|
224
|
-
)}
|
|
225
|
-
{isNotAReply && (
|
|
226
|
-
<button
|
|
227
|
-
className={styles["comment__button"]}
|
|
228
|
-
onClick={replyCommentHandler}
|
|
229
|
-
>
|
|
230
|
-
<FontAwesomeIcon icon={faReply} />
|
|
231
|
-
</button>
|
|
232
|
-
)}
|
|
233
|
-
</div>
|
|
234
|
-
</div>
|
|
235
|
-
</div>
|
|
236
|
-
</div>
|
|
237
|
-
</div>
|
|
238
|
-
</div>
|
|
239
|
-
{isNotAReply && (
|
|
240
|
-
<div className={styles["comments__replies__item"]}>
|
|
241
|
-
{props.commentObject.replies?.map((reply) => {
|
|
242
|
-
return (
|
|
243
|
-
<Comment
|
|
244
|
-
key={reply.dateISO}
|
|
245
|
-
deleteComment={props.deleteComment}
|
|
246
|
-
editComment={props.editComment}
|
|
247
|
-
upvoteComment={props.upvoteComment}
|
|
248
|
-
replyComment={props.replyComment}
|
|
249
|
-
commentObject={reply}
|
|
250
|
-
currentUserEmail={props.currentUserEmail}
|
|
251
|
-
/>
|
|
252
|
-
);
|
|
253
|
-
})}
|
|
254
|
-
</div>
|
|
255
|
-
)}
|
|
256
|
-
</div>
|
|
257
|
-
);
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
export default Comment;
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
.comment-main {
|
|
2
|
-
display: flex;
|
|
3
|
-
justify-content: space-around;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
.author-profile-picture {
|
|
7
|
-
border-radius: 5px;
|
|
8
|
-
width: 50px;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.comment__buttons {
|
|
12
|
-
display: flex;
|
|
13
|
-
justify-content: left;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.comment__button {
|
|
17
|
-
background-color: transparent;
|
|
18
|
-
border: none;
|
|
19
|
-
color: var(--light-body-color);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.comment__button:hover {
|
|
23
|
-
cursor: pointer;
|
|
24
|
-
color: var(--dark-color);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
.comment {
|
|
28
|
-
margin-bottom: 3em;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.reply {
|
|
32
|
-
margin-bottom: 0;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.author-info {
|
|
36
|
-
display: flex;
|
|
37
|
-
flex-direction: column;
|
|
38
|
-
align-items: center;
|
|
39
|
-
padding: 1em;
|
|
40
|
-
flex-grow: 1;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.reply {
|
|
44
|
-
margin-left: 30px;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.comment-body {
|
|
48
|
-
flex-grow: 8;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.comment-textarea {
|
|
52
|
-
background-color: var(--lighter-bg-color);
|
|
53
|
-
border: solid var(--border-color);
|
|
54
|
-
resize: none;
|
|
55
|
-
font: inherit;
|
|
56
|
-
width: 100%;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.comment-footer {
|
|
60
|
-
font-size: var(--font-size-s);
|
|
61
|
-
display: flex;
|
|
62
|
-
justify-content: center;
|
|
63
|
-
align-items: center;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.comment__buttons {
|
|
67
|
-
display: flex;
|
|
68
|
-
flex-direction: column;
|
|
69
|
-
align-items: baseline;
|
|
70
|
-
width: 90%;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.comment__timestamps {
|
|
74
|
-
color: var(--light-body-color);
|
|
75
|
-
font-size: var(--font-size-xs);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.tip {
|
|
79
|
-
width: 0px;
|
|
80
|
-
height: 0px;
|
|
81
|
-
position: absolute;
|
|
82
|
-
background: transparent;
|
|
83
|
-
border: 10px solid var(--light-bg-color);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.tip-down {
|
|
87
|
-
bottom: -25px;
|
|
88
|
-
left: 10px;
|
|
89
|
-
border-right-color: transparent;
|
|
90
|
-
border-left-color: transparent;
|
|
91
|
-
border-bottom-color: transparent;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
.dialogbox .body {
|
|
95
|
-
position: relative;
|
|
96
|
-
max-width: 300px;
|
|
97
|
-
height: auto;
|
|
98
|
-
padding: 5px;
|
|
99
|
-
background-color: var(--light-bg-color);
|
|
100
|
-
border-radius: 3px;
|
|
101
|
-
border: 5px solid var(--light-bg-color);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
.body .message {
|
|
105
|
-
border-radius: 3px;
|
|
106
|
-
font-size: var(--font-size-s);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
.reply-line {
|
|
110
|
-
content: "";
|
|
111
|
-
width: 2px;
|
|
112
|
-
height: 80px;
|
|
113
|
-
background: var(--darker-border-color);
|
|
114
|
-
position: absolute;
|
|
115
|
-
left: 32px;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
.reply-profile-picture-line {
|
|
119
|
-
content: "";
|
|
120
|
-
width: 30px;
|
|
121
|
-
height: 2px;
|
|
122
|
-
background: var(--darker-border-color);
|
|
123
|
-
position: absolute;
|
|
124
|
-
left: 32px;
|
|
125
|
-
z-index: -1;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
.upvoted {
|
|
129
|
-
color: var(--dark-color);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
.comment__interface {
|
|
133
|
-
color: var(--light-body-color);
|
|
134
|
-
}
|