Download components/chat/Thread.tsx from Etiya/d2l-ui: direct link, hf CLI and curl.
- Browser
- Download file 1.78 kB
-
https://huggingface.co/spaces/Etiya/d2l-ui/resolve/main/components/chat/Thread.tsx
- Command line
-
hf download hf://spaces/Etiya/d2l-ui/components/chat/Thread.tsx
-
curl -L -o Thread.tsx https://huggingface.co/spaces/Etiya/d2l-ui/resolve/main/components/chat/Thread.tsx
1.78 kB
| "use client"; | |
| import { useEffect, useRef } from "react"; | |
| import { useChatStore } from "@/lib/chatStore"; | |
| import type { SourceDoc } from "@/lib/types"; | |
| import { AssistantMessage, ErrorMessage, UserMessage } from "./Message"; | |
| import { Thinking } from "./Thinking"; | |
| export function Thread({ | |
| onOpenSource, | |
| }: { | |
| onOpenSource?: (doc: SourceDoc, index: number) => void; | |
| }) { | |
| const conv = useChatStore((s) => | |
| s.activeId ? s.conversations[s.activeId] : null | |
| ); | |
| const ref = useRef<HTMLDivElement | null>(null); | |
| // Auto-scroll to bottom on new turns / when streaming tokens arrive | |
| const turns = conv?.turns ?? []; | |
| const lastTurn = turns[turns.length - 1]; | |
| useEffect(() => { | |
| const el = ref.current; | |
| if (!el) return; | |
| el.scrollTo({ top: el.scrollHeight, behavior: "smooth" }); | |
| }, [ | |
| turns.length, | |
| lastTurn?.pending, | |
| lastTurn?.response?.answer?.length, | |
| ]); | |
| if (!conv || conv.turns.length === 0) return null; | |
| return ( | |
| <div ref={ref} className="flex-1 overflow-y-auto min-h-0"> | |
| <div className="min-h-full flex flex-col justify-end max-w-[920px] mx-auto px-4 sm:px-6 py-8 space-y-6"> | |
| {conv.turns.map((t) => { | |
| const hasAnswer = Boolean(t.response?.answer); | |
| const showThinking = t.pending && !hasAnswer && !t.error; | |
| const showAnswer = !!t.response && (hasAnswer || !t.pending); | |
| return ( | |
| <div key={t.id} className="space-y-4"> | |
| <UserMessage text={t.question} /> | |
| {showThinking && <Thinking />} | |
| {t.error && <ErrorMessage turn={t} />} | |
| {showAnswer && ( | |
| <AssistantMessage turn={t} onOpenSource={onOpenSource} /> | |
| )} | |
| </div> | |
| ); | |
| })} | |
| </div> | |
| </div> | |
| ); | |
| } | |