-
Notifications
You must be signed in to change notification settings - Fork 0
/
CommentList.re
executable file
·112 lines (107 loc) · 3.58 KB
/
CommentList.re
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
open Belt;
open Utils;
requireCSS("src/CommentList.css");
type action =
| Toggle(option(string));
type state = {collapsed_comments: Set.Int.t};
let initialState = {collapsed_comments: Set.Int.empty};
let toggleComment = (collapsed, idMaybe: option(string)) =>
switch (idMaybe) {
| Some(idString) =>
let id = int_of_string(idString);
if (Set.Int.has(collapsed, id)) {
Set.Int.remove(collapsed, id);
} else {
Set.Int.add(collapsed, id);
};
| None => collapsed
};
[@react.component]
let make = (~story: StoryData.story_with_comments) => {
let (state, dispatch) =
React.useReducer(
(state, action) =>
switch (action) {
| Toggle(commentId) => {
collapsed_comments:
toggleComment(state.collapsed_comments, commentId),
}
},
initialState,
);
let getCommentIdFromEvent = (event: ReactEvent.Mouse.t) =>
getAttribute(ReactEvent.Mouse.currentTarget(event), "name");
let renderCommentText = (textMaybe: option(string)) =>
switch (textMaybe) {
| Some(text) => <div dangerouslySetInnerHTML={dangerousHtml(text)} />
| None => React.string("missing comment")
};
let rec renderCommentKids = (comment: StoryData.comment_present) =>
renderCommentList(comment.kids)
and renderComment = (id: int) => {
let commentMaybe = Map.Int.get(story.comments, id);
<div key={string_of_int(id)}>
{switch (commentMaybe) {
| Some(commentPresentOrDeleted) =>
switch (commentPresentOrDeleted) {
| StoryData.CommentPresent(comment) =>
let openComment =
!Set.Int.has(state.collapsed_comments, comment.id);
<div className="CommentList_comment">
<div
className="CommentList_disclosureRow CommentList_inline"
name={string_of_int(comment.id)}
onClick={event =>
dispatch(Toggle(getCommentIdFromEvent(event)))
}>
<img
alt={openComment ? "hide" : "show"}
src={
openComment
? requireAssetURI("src/disclosure90.png")
: requireAssetURI("src/disclosure.png")
}
className="CommentList_disclosure CommentList_muted"
/>
<span className="CommentList_muted">
{
let time = fromNow(comment.time);
let by = comment.by;
React.string({j| $time by $by|j});
}
</span>
</div>
{if (openComment) {
<div className="CommentList_commentBody">
{renderCommentText(comment.text)}
{renderCommentKids(comment)}
</div>;
} else {
<noscript />;
}}
</div>;
| StoryData.CommentDeleted(_) =>
<div className="CommentList_error">
{React.string(
"[comment deleted (id=" ++ string_of_int(id) ++ ")]",
)}
</div>
}
| None =>
<div className="CommentList_error">
{React.string(
"[comment not loaded (id=" ++ string_of_int(id) ++ ")]",
)}
</div>
}}
</div>;
}
and renderCommentList = (commentIds: option(array(int))) =>
switch (commentIds) {
| Some(ids) =>
let commentList = Array.map(ids, id => renderComment(id));
<div> {React.array(commentList)} </div>;
| None => <div />
};
renderCommentList(story.kids);
};