Skip to content

Commit 6acde48

Browse files
committed
Add comment/reaction toggles to Toolbar
1 parent 4360101 commit 6acde48

2 files changed

Lines changed: 69 additions & 48 deletions

File tree

apps/web/app/s/[videoId]/Share.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@ export const Share = ({
492492
<Toolbar
493493
onOptimisticComment={handleOptimisticComment}
494494
onCommentSuccess={handleCommentSuccess}
495+
disableComments={areCommentStampsDisabled}
496+
disableReactions={areReactionStampsDisabled}
495497
data={data}
496498
/>
497499
</div>
@@ -527,10 +529,8 @@ export const Share = ({
527529
<Toolbar
528530
onOptimisticComment={handleOptimisticComment}
529531
onCommentSuccess={handleCommentSuccess}
530-
disableReactions={
531-
videoSettings?.disableReactions ??
532-
data.orgSettings?.disableReactions
533-
}
532+
disableComments={areCommentStampsDisabled}
533+
disableReactions={areReactionStampsDisabled}
534534
data={data}
535535
/>
536536
</div>

apps/web/app/s/[videoId]/_components/Toolbar.tsx

Lines changed: 65 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,47 @@ interface ToolbarProps {
1515
data: VideoData;
1616
onOptimisticComment?: (comment: CommentType) => void;
1717
onCommentSuccess?: (comment: CommentType) => void;
18+
disableComments?: boolean;
1819
disableReactions?: boolean;
1920
}
2021

22+
interface EmojiButtonProps {
23+
label: string;
24+
emoji: string;
25+
onClick: () => void;
26+
}
27+
28+
const EmojiButton = ({ label, emoji, onClick }: EmojiButtonProps) => (
29+
<motion.div layout className="relative size-10">
30+
<motion.button
31+
layout
32+
className="inline-flex relative justify-center items-center p-1 text-xl leading-6 align-middle bg-transparent rounded-full transition-colors ease-in-out size-full font-emoji sm:text-2xl duration-600 hover:bg-gray-200 active:bg-blue-500 active:duration-0"
33+
role="img"
34+
aria-label={label ? label : ""}
35+
aria-hidden={label ? "false" : "true"}
36+
onClick={onClick}
37+
>
38+
{emoji}
39+
</motion.button>
40+
</motion.div>
41+
);
42+
2143
export const Toolbar = ({
2244
data,
2345
onOptimisticComment,
2446
onCommentSuccess,
47+
disableComments,
2548
disableReactions,
2649
}: ToolbarProps) => {
2750
const user = useCurrentUser();
2851
const [commentBoxOpen, setCommentBoxOpen] = useState(false);
2952
const [comment, setComment] = useState("");
3053
const [showAuthOverlay, setShowAuthOverlay] = useState(false);
54+
const canComment = !disableComments;
55+
const canReact = !disableReactions;
3156

3257
const handleEmojiClick = async (emoji: string) => {
33-
if (!user) return;
58+
if (!canReact || !user) return;
3459
const videoElement = document.querySelector("video") as HTMLVideoElement;
3560
const currentTime = videoElement?.currentTime || 0;
3661
const optimisticComment: CommentType = {
@@ -71,7 +96,7 @@ export const Toolbar = ({
7196
};
7297

7398
const handleCommentSubmit = async () => {
74-
if (comment.length === 0 || !user) {
99+
if (!canComment || comment.length === 0 || !user) {
75100
return;
76101
}
77102
const videoElement = document.querySelector("video") as HTMLVideoElement;
@@ -113,22 +138,9 @@ export const Toolbar = ({
113138
}
114139
};
115140

116-
const Emoji = ({ label, emoji }: { label: string; emoji: string }) => (
117-
<motion.div layout className="relative size-10">
118-
<motion.button
119-
layout
120-
className="inline-flex relative justify-center items-center p-1 text-xl leading-6 align-middle bg-transparent rounded-full transition-colors ease-in-out size-full font-emoji sm:text-2xl duration-600 hover:bg-gray-200 active:bg-blue-500 active:duration-0"
121-
role="img"
122-
aria-label={label ? label : ""}
123-
aria-hidden={label ? "false" : "true"}
124-
onClick={() => handleEmojiClick(emoji)}
125-
>
126-
{emoji}
127-
</motion.button>
128-
</motion.div>
129-
);
130-
131141
useEffect(() => {
142+
if (!canComment) return;
143+
132144
const handleKeyPress = (e: KeyboardEvent) => {
133145
if (
134146
e.key.toLowerCase() === "c" &&
@@ -161,9 +173,10 @@ export const Toolbar = ({
161173
return () => {
162174
window.removeEventListener("keydown", handleKeyPress);
163175
};
164-
}, [commentBoxOpen, user]);
176+
}, [canComment, commentBoxOpen, user]);
165177

166178
const handleCommentClick = () => {
179+
if (!canComment) return;
167180
if (!user) {
168181
setShowAuthOverlay(true);
169182
return;
@@ -175,7 +188,7 @@ export const Toolbar = ({
175188
setCommentBoxOpen(true);
176189
};
177190

178-
if (disableReactions) {
191+
if (!canComment && !canReact) {
179192
return null;
180193
}
181194

@@ -186,7 +199,7 @@ export const Toolbar = ({
186199
className="flex overflow-hidden p-2 mx-auto max-w-full bg-white rounded-full border border-gray-5 md:max-w-fit"
187200
>
188201
<AnimatePresence initial={false} mode="popLayout">
189-
{commentBoxOpen ? (
202+
{commentBoxOpen && canComment ? (
190203
<motion.div
191204
layout
192205
key="comment-box"
@@ -252,33 +265,41 @@ export const Toolbar = ({
252265
transition={{ duration: 0.2, ease: "easeInOut" }}
253266
className="flex flex-col gap-2 items-center mx-auto w-full md:justify-center sm:grid sm:grid-flow-col md:w-fit min-h-[28px]"
254267
>
255-
{/* Emoji reactions row */}
256-
<div className="flex gap-2 justify-evenly items-center w-full md:w-fit md:justify-center">
257-
{REACTIONS.map((reaction) => (
258-
<Emoji
259-
key={reaction.emoji}
260-
emoji={reaction.emoji}
261-
label={reaction.label}
262-
/>
263-
))}
264-
</div>
268+
{canReact && (
269+
<div className="flex gap-2 justify-evenly items-center w-full md:w-fit md:justify-center">
270+
{REACTIONS.map((reaction) => (
271+
<EmojiButton
272+
key={reaction.emoji}
273+
emoji={reaction.emoji}
274+
label={reaction.label}
275+
onClick={() => handleEmojiClick(reaction.emoji)}
276+
/>
277+
))}
278+
</div>
279+
)}
265280

266-
{/* Separator - hidden on mobile, visible on desktop */}
267-
<motion.div className="hidden sm:block w-px bg-gray-5 h-[16px] mx-4" />
281+
{canReact && canComment && (
282+
<motion.div className="hidden sm:block w-px bg-gray-5 h-[16px] mx-4" />
283+
)}
268284

269-
{/* Comment button - full width on mobile, normal on desktop */}
270-
<div className="ml-auto w-full sm:w-auto">
271-
<MotionButton
272-
onClick={handleCommentClick}
273-
variant="dark"
274-
layout="position"
275-
kbd="c"
276-
size="sm"
277-
className="mx-auto w-fit"
285+
{canComment && (
286+
<div
287+
className={
288+
canReact ? "ml-auto w-full sm:w-auto" : "w-full sm:w-auto"
289+
}
278290
>
279-
Comment
280-
</MotionButton>
281-
</div>
291+
<MotionButton
292+
onClick={handleCommentClick}
293+
variant="dark"
294+
layout="position"
295+
kbd="c"
296+
size="sm"
297+
className="mx-auto w-fit"
298+
>
299+
Comment
300+
</MotionButton>
301+
</div>
302+
)}
282303
</motion.div>
283304
)}
284305
</AnimatePresence>

0 commit comments

Comments
 (0)