Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

reactions.tsx

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

reactions.tsxBlame68 lines · 1 contributor
6fc53bdClaude1/**
2 * Reactions bar — displays current counts + a "+ react" picker.
3 * Works without JavaScript: each emoji is its own POST form.
4 */
5
6import type { FC } from "hono/jsx";
7import {
8 ALLOWED_EMOJIS,
9 EMOJI_GLYPH,
10 type Emoji,
11 type ReactionSummary,
12 type TargetType,
13} from "../lib/reactions";
14
15export const ReactionsBar: FC<{
16 targetType: TargetType;
17 targetId: string;
18 summaries: ReactionSummary[];
19 canReact: boolean;
20}> = ({ targetType, targetId, summaries, canReact }) => {
21 const byEmoji = new Map<Emoji, ReactionSummary>();
22 for (const s of summaries) byEmoji.set(s.emoji, s);
23
24 const action = (emoji: Emoji) =>
25 `/api/reactions/${targetType}/${targetId}/${emoji}/toggle`;
26
27 const visible = summaries.filter((s) => s.count > 0);
28
29 return (
30 <div class="reactions" data-target={`${targetType}:${targetId}`}>
31 {visible.map((s) => (
001af43Claude32 <form method="post" action={action(s.emoji)} style="display: inline">
6fc53bdClaude33 <button
34 type="submit"
35 class={`reaction-btn ${s.reactedByMe ? "active" : ""}`}
36 title={s.emoji.replace(/_/g, " ")}
37 disabled={!canReact}
38 >
39 <span>{EMOJI_GLYPH[s.emoji]}</span>
40 <span class="reaction-count">{s.count}</span>
41 </button>
42 </form>
43 ))}
44 {canReact && (
45 <details class="reaction-picker">
46 <summary class="reaction-btn" title="Add reaction">
47 {"\u271A"}
48 </summary>
49 <div style="display: flex; gap: 4px; padding: 4px">
50 {ALLOWED_EMOJIS.filter((e) => !byEmoji.get(e)?.reactedByMe).map(
51 (emoji) => (
001af43Claude52 <form method="post" action={action(emoji)} style="display: inline">
6fc53bdClaude53 <button
54 type="submit"
55 class="reaction-btn"
56 title={emoji.replace(/_/g, " ")}
57 >
58 <span>{EMOJI_GLYPH[emoji]}</span>
59 </button>
60 </form>
61 )
62 )}
63 </div>
64 </details>
65 )}
66 </div>
67 );
68};