"use client"; import { ActionBarPrimitive, AssistantIf, MessagePrimitive, ThreadPrimitive, useAssistantState, } from "@assistant-ui/react"; import { CheckIcon, CopyIcon } from "lucide-react"; import { type FC, type ReactNode, useState } from "react"; import { MarkdownText } from "@/components/assistant-ui/markdown-text"; import { ToolFallback } from "@/components/assistant-ui/tool-fallback"; import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button"; interface PublicThreadProps { footer?: ReactNode; } /** * Read-only thread component for public chat viewing. * No composer, no edit capabilities - just message display. */ export const PublicThread: FC = ({ footer }) => { return ( {/* Spacer to ensure footer doesn't overlap last message */}
{footer && (
{footer}
)} ); }; /** * User avatar component with fallback to initials */ interface AuthorMetadata { displayName: string | null; avatarUrl: string | null; } const UserAvatar: FC void }> = ({ displayName, avatarUrl, hasError, onError, }) => { const initials = displayName ? displayName .split(" ") .map((n) => n[0]) .join("") .toUpperCase() .slice(0, 2) : "U"; if (avatarUrl && !hasError) { return ( {displayName ); } return (
{initials}
); }; const PublicUserMessage: FC = () => { const metadata = useAssistantState(({ message }) => message?.metadata); const author = metadata?.custom?.author as AuthorMetadata | undefined; return (
{author && (
)}
); }; const UserAvatarWithState: FC = ({ displayName, avatarUrl }) => { const [hasError, setHasError] = useState(false); return ( setHasError(true)} /> ); }; const PublicAssistantMessage: FC = () => { return (
); }; const PublicAssistantActionBar: FC = () => { return ( message.isCopied}> !message.isCopied}> ); };