feat: add inline mentions in comments

This commit is contained in:
gosangam
2026-06-13 13:10:34 +05:30
parent 37305201bd
commit eb0c981d3c
5 changed files with 272 additions and 11 deletions
+22 -1
View File
@@ -11,6 +11,7 @@
*/
import { useEffect, useRef, useState } from "react";
import Link from "next/link";
import { HiHeart, HiOutlineHeart } from "react-icons/hi2";
import { Pin } from "lucide-react";
import { toast } from "sonner";
@@ -20,6 +21,26 @@ import { UserAvatar } from "@/components/ui/user-avatar";
import { timeAgo } from "@/lib/time";
import { CommentMenu } from "./comment-menu";
// Split a comment body into text + clickable @handle links. The capturing
// group keeps the delimiters so they can be turned into profile links.
const MENTION_TOKEN = /(@[A-Za-z0-9_]+)/g;
function renderBody(text: string) {
return text.split(MENTION_TOKEN).map((part, i) => {
if (part.length > 1 && part[0] === "@") {
return (
<Link
key={i}
href={`/u/${part.slice(1)}`}
className="font-medium text-primary hover:underline"
>
{part}
</Link>
);
}
return part;
});
}
export function CommentRow({
comment,
viewerId,
@@ -151,7 +172,7 @@ export function CommentRow({
@{comment.reply_to_handle}{" "}
</span>
) : null}
{comment.body}
{renderBody(comment.body)}
</p>
{/* Inline action row */}
@@ -37,6 +37,7 @@ import { useMediaQuery } from "@/components/selection-toolbar/shared";
import { Drawer, DrawerContent } from "@/components/ui/drawer";
import { ConfirmModal } from "@/components/ui/confirm-modal";
import { EmojiPicker } from "@/components/ui/emoji-picker";
import { MentionTextarea } from "@/components/social/mention-textarea";
import { CommentRow } from "./comment-row";
import { ReportCommentModal } from "./comment-report-modal";
@@ -324,20 +325,15 @@ export function PostCommentsDrawer({
) : null}
<div className="flex items-end gap-2">
<EmojiPicker onSelect={insertEmoji} />
<textarea
<MentionTextarea
ref={inputRef}
value={draft}
onChange={(e) => setDraft(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
submit();
}
}}
onChange={setDraft}
onSubmit={submit}
rows={1}
maxLength={2000}
placeholder={replyTo ? "Write a reply…" : "Add a comment…"}
className="flex-1 resize-none rounded-lg border border-border bg-background px-3 py-2 text-base sm:text-sm text-foreground outline-none focus-visible:ring-2 focus-visible:ring-primary/40 max-h-32"
className="w-full resize-none rounded-lg border border-border bg-background px-3 py-2 text-base sm:text-sm text-foreground outline-none focus-visible:ring-2 focus-visible:ring-primary/40 max-h-32"
/>
<button
type="button"