refactor: update title generation logic to improve user experience by generating titles in parallel with assistant responses

This commit is contained in:
Anish Sarkar 2026-03-09 01:28:53 +05:30
parent bd91b0bef2
commit e8cf677b25
5 changed files with 120 additions and 61 deletions

View file

@ -465,10 +465,7 @@ export default function NewChatPage() {
let isNewThread = false;
if (!currentThreadId) {
try {
// Create thread with truncated prompt as initial title
const initialTitle =
userQuery.trim().slice(0, 100) + (userQuery.trim().length > 100 ? "..." : "");
const newThread = await createThread(searchSpaceId, initialTitle);
const newThread = await createThread(searchSpaceId, "New Chat");
currentThreadId = newThread.id;
setThreadId(currentThreadId);
// Set currentThread so share button in header appears immediately

View file

@ -20,6 +20,7 @@ import {
} from "@/components/ui/dropdown-menu";
import { useLongPress } from "@/hooks/use-long-press";
import { useIsMobile } from "@/hooks/use-mobile";
import { useTypewriter } from "@/hooks/use-typewriter";
import { cn } from "@/lib/utils";
interface ChatListItemProps {
@ -44,6 +45,7 @@ export function ChatListItem({
const t = useTranslations("sidebar");
const isMobile = useIsMobile();
const [dropdownOpen, setDropdownOpen] = useState(false);
const animatedName = useTypewriter(name);
const { handlers: longPressHandlers, wasLongPress } = useLongPress(
useCallback(() => setDropdownOpen(true), [])
@ -69,7 +71,7 @@ export function ChatListItem({
)}
>
<MessageSquare className="h-4 w-4 shrink-0 text-muted-foreground" />
<span className="w-[calc(100%-3rem)] ">{name}</span>
<span className="w-[calc(100%-3rem)] ">{animatedName}</span>
</button>
{/* Actions dropdown - trigger hidden on mobile, long-press opens it instead */}

View file

@ -0,0 +1,49 @@
import { useEffect, useRef, useState } from "react";
/**
* Animates text changes with a typewriter reveal effect, but only when
* transitioning away from the `skipFor` placeholder (default "New Chat").
* All other text values are shown instantly without animation.
*/
export function useTypewriter(text: string, speed = 35, skipFor = "New Chat"): string {
const [displayed, setDisplayed] = useState(text);
const prevTextRef = useRef(text);
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
useEffect(() => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
const prevText = prevTextRef.current;
prevTextRef.current = text;
const shouldAnimate = prevText === skipFor && text !== skipFor && !!text;
if (!shouldAnimate) {
setDisplayed(text);
return;
}
let i = 0;
setDisplayed("");
intervalRef.current = setInterval(() => {
i++;
setDisplayed(text.slice(0, i));
if (i >= text.length) {
if (intervalRef.current) clearInterval(intervalRef.current);
intervalRef.current = null;
}
}, speed);
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
};
}, [text, speed, skipFor]);
return displayed;
}