ReactionBar.tsx
Raw
1import { ALLOWED_REACTIONS } from "../constants.ts";
2import type { SessionUser } from "../middleware/session.ts";
3
4export interface ReactionCount {
5 emoji: string;
6 count: number;
7 userReacted: boolean;
8}
9
10interface ReactionBarProps {
11 reactions: ReactionCount[];
12 postUrl: string;
13 commentId?: number;
14 user: SessionUser | null;
15}
16
17export function ReactionBar({
18 reactions,
19 postUrl,
20 commentId,
21 user,
22}: ReactionBarProps) {
23 if (!user && reactions.length === 0) return null;
24 const existing = new Set(reactions.map((r) => r.emoji));
25 const all = [...ALLOWED_REACTIONS];
26 return (
27 <div class="reaction-bar">
28 {reactions.map((r) => {
29 const unsafeEmoji = r.emoji;
30 return (
31 <form method="POST" action={postUrl} class="reaction-form">
32 {commentId != null && (
33 <input
34 type="hidden"
35 name="comment_id"
36 value={String(commentId)}
37 />
38 )}
39 <input type="hidden" name="emoji" value={r.emoji} />
40 <button
41 type="submit"
42 class={`reaction-btn${r.userReacted ? " reacted" : ""}`}
43 disabled={!user}
44 safe
45 >
46 {`${unsafeEmoji} ${r.count}`}
47 </button>
48 </form>
49 );
50 })}
51 {!!user && (
52 <details class="reaction-picker">
53 <summary class="reaction-add-btn">+</summary>
54 <div class="reaction-picker-dropdown">
55 {all
56 .filter((e) => !existing.has(e))
57 .map((e) => (
58 <form
59 method="POST"
60 action={postUrl}
61 class="reaction-form"
62 >
63 {commentId != null && (
64 <input
65 type="hidden"
66 name="comment_id"
67 value={String(commentId)}
68 />
69 )}
70 <input
71 type="hidden"
72 name="emoji"
73 value={e}
74 />
75 <button
76 type="submit"
77 class="reaction-picker-btn"
78 safe
79 >
80 {e}
81 </button>
82 </form>
83 ))}
84 </div>
85 </details>
86 )}
87 </div>
88 );
89}
90