legal-ai-assistant/frontend/components/assistant-ui/thread.tsx
2026-04-20 11:43:14 +02:00

64 lines
2.1 KiB
TypeScript

"use client";
import { type FC } from "react";
import { AuiIf, ThreadPrimitive, useAuiState } from "@assistant-ui/react";
import { ArrowDownIcon } from "lucide-react";
import { ThreadHeader } from "./header";
import { ThreadWelcome } from "./welcome";
import { AssistantMessage, UserMessage } from "./messages";
import { ThreadComposer } from "./composer";
import { TooltipIconButton } from "./tooltip-icon-button";
const ThreadMessage: FC = () => {
const role = useAuiState((s) => s.message.role);
if (role === "user") return <UserMessage />;
return <AssistantMessage />;
};
const ThreadScrollToBottom: FC = () => {
return (
<ThreadPrimitive.ScrollToBottom asChild>
<TooltipIconButton
tooltip="Scroll to bottom"
variant="outline"
className="absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible dark:border-border dark:bg-background dark:hover:bg-accent"
>
<ArrowDownIcon />
</TooltipIconButton>
</ThreadPrimitive.ScrollToBottom>
);
};
export const Thread: FC = () => {
return (
<ThreadPrimitive.Root
className="aui-root aui-thread-root @container flex h-full flex-col bg-background"
style={{
["--thread-max-width" as string]: "48rem",
["--composer-radius" as string]: "16px",
["--composer-padding" as string]: "12px",
}}
>
<ThreadHeader />
<ThreadPrimitive.Viewport
turnAnchor="top"
className="relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth px-4 pt-4"
>
<AuiIf condition={(s) => s.thread.isEmpty}>
<ThreadWelcome />
</AuiIf>
<ThreadPrimitive.Messages>
{() => <ThreadMessage />}
</ThreadPrimitive.Messages>
<ThreadPrimitive.ViewportFooter className="sticky bottom-0 mx-auto mt-auto flex w-full max-w-(--thread-max-width) flex-col gap-4 overflow-visible rounded-t-2xl bg-background pb-4 md:pb-6 pt-2">
<ThreadScrollToBottom />
<ThreadComposer />
</ThreadPrimitive.ViewportFooter>
</ThreadPrimitive.Viewport>
</ThreadPrimitive.Root>
);
};