feat(chat): implement target comment navigation and highlight functionality in chat components

This commit is contained in:
Anish Sarkar 2026-01-27 22:14:02 +05:30
parent 6eedce839a
commit 72c421eeb1
5 changed files with 128 additions and 34 deletions

View file

@ -5,14 +5,16 @@ import {
MessagePrimitive,
useAssistantState,
} from "@assistant-ui/react";
import { useAtom, useAtomValue } from "jotai";
import { useAtom, useAtomValue, useSetAtom } from "jotai";
import { CheckIcon, CopyIcon, DownloadIcon, MessageSquare, RefreshCwIcon } from "lucide-react";
import type { FC } from "react";
import { useContext, useEffect, useRef, useState } from "react";
import { useContext, useEffect, useMemo, useRef, useState } from "react";
import {
addingCommentToMessageIdAtom,
clearTargetCommentIdAtom,
commentsCollapsedAtom,
commentsEnabledAtom,
targetCommentIdAtom,
} from "@/atoms/chat/current-thread.atom";
import { activeSearchSpaceIdAtom } from "@/atoms/search-spaces/search-space-query.atoms";
import { BranchPicker } from "@/components/assistant-ui/branch-picker";
@ -117,11 +119,23 @@ export const AssistantMessage: FC = () => {
const isLastMessage = useAssistantState(({ message }) => message?.isLast ?? false);
const isMessageStreaming = isThreadRunning && isLastMessage;
const { data: commentsData } = useComments({
const { data: commentsData, isSuccess: commentsLoaded } = useComments({
messageId: dbMessageId ?? 0,
enabled: !!dbMessageId,
});
// Target comment navigation - read target from global atom
const targetCommentId = useAtomValue(targetCommentIdAtom);
const clearTargetCommentId = useSetAtom(clearTargetCommentIdAtom);
// Check if target comment belongs to this message (including replies)
const hasTargetComment = useMemo(() => {
if (!targetCommentId || !commentsData?.comments) return false;
return commentsData.comments.some(
(c) => c.id === targetCommentId || c.replies?.some((r) => r.id === targetCommentId)
);
}, [targetCommentId, commentsData]);
const commentCount = commentsData?.total_count ?? 0;
const hasComments = commentCount > 0;
const isAddingComment = dbMessageId !== null && addingCommentToMessageId === dbMessageId;
@ -146,6 +160,24 @@ export const AssistantMessage: FC = () => {
return () => observer.disconnect();
}, []);
// Auto-open sheet on mobile/tablet when this message has the target comment
useEffect(() => {
if (hasTargetComment && !isDesktop && commentsLoaded) {
setIsSheetOpen(true);
}
}, [hasTargetComment, isDesktop, commentsLoaded]);
// Scroll message into view when it contains target comment (desktop)
useEffect(() => {
if (hasTargetComment && isDesktop && commentsLoaded && messageRef.current) {
// Small delay to ensure DOM is ready after comments render
const timeoutId = setTimeout(() => {
messageRef.current?.scrollIntoView({ behavior: "smooth", block: "center" });
}, 100);
return () => clearTimeout(timeoutId);
}
}, [hasTargetComment, isDesktop, commentsLoaded]);
const showCommentTrigger = searchSpaceId && commentsEnabled && !isMessageStreaming && dbMessageId;
// Determine sheet side based on screen size