160 lines
5.3 KiB
TypeScript
160 lines
5.3 KiB
TypeScript
"use client";
|
|
|
|
import { type FC } from "react";
|
|
import {
|
|
ActionBarMorePrimitive,
|
|
ActionBarPrimitive,
|
|
AuiIf,
|
|
BranchPickerPrimitive,
|
|
ErrorPrimitive,
|
|
MessagePrimitive,
|
|
useAuiState,
|
|
} from "@assistant-ui/react";
|
|
import {
|
|
CheckIcon,
|
|
ChevronLeftIcon,
|
|
ChevronRightIcon,
|
|
CopyIcon,
|
|
DownloadIcon,
|
|
MoreHorizontalIcon,
|
|
RefreshCwIcon,
|
|
ScaleIcon,
|
|
} from "lucide-react";
|
|
import { cn } from "@/lib/utils";
|
|
import { MarkdownText } from "./markdown-text";
|
|
import { ToolFallback } from "./tool-fallback";
|
|
import { TooltipIconButton } from "./tooltip-icon-button";
|
|
|
|
const MessageError: FC = () => {
|
|
return (
|
|
<MessagePrimitive.Error>
|
|
<ErrorPrimitive.Root className="mt-2 rounded-md border border-destructive bg-destructive/10 p-3 text-destructive text-sm">
|
|
<ErrorPrimitive.Message className="line-clamp-2" />
|
|
</ErrorPrimitive.Root>
|
|
</MessagePrimitive.Error>
|
|
);
|
|
};
|
|
|
|
const AssistantActionBar: FC = () => {
|
|
return (
|
|
<ActionBarPrimitive.Root
|
|
hideWhenRunning
|
|
autohide="not-last"
|
|
autohideFloat="single-branch"
|
|
className="col-start-3 row-start-2 -ml-1 flex gap-1 text-muted-foreground"
|
|
>
|
|
<ActionBarPrimitive.Copy asChild>
|
|
<TooltipIconButton tooltip="Kopírovať">
|
|
<AuiIf condition={(s) => s.message.isCopied}>
|
|
<CheckIcon />
|
|
</AuiIf>
|
|
<AuiIf condition={(s) => !s.message.isCopied}>
|
|
<CopyIcon />
|
|
</AuiIf>
|
|
</TooltipIconButton>
|
|
</ActionBarPrimitive.Copy>
|
|
<ActionBarPrimitive.Reload asChild>
|
|
<TooltipIconButton tooltip="Obnoviť">
|
|
<RefreshCwIcon />
|
|
</TooltipIconButton>
|
|
</ActionBarPrimitive.Reload>
|
|
<ActionBarMorePrimitive.Root>
|
|
<ActionBarMorePrimitive.Trigger asChild>
|
|
<TooltipIconButton tooltip="Viac" className="data-[state=open]:bg-accent">
|
|
<MoreHorizontalIcon />
|
|
</TooltipIconButton>
|
|
</ActionBarMorePrimitive.Trigger>
|
|
<ActionBarMorePrimitive.Content
|
|
side="bottom"
|
|
align="start"
|
|
className="z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md"
|
|
>
|
|
<ActionBarPrimitive.ExportMarkdown asChild>
|
|
<ActionBarMorePrimitive.Item className="flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent">
|
|
<DownloadIcon className="size-4" />
|
|
Export ako Markdown
|
|
</ActionBarMorePrimitive.Item>
|
|
</ActionBarPrimitive.ExportMarkdown>
|
|
</ActionBarMorePrimitive.Content>
|
|
</ActionBarMorePrimitive.Root>
|
|
</ActionBarPrimitive.Root>
|
|
);
|
|
};
|
|
|
|
export const BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({
|
|
className,
|
|
...rest
|
|
}) => {
|
|
return (
|
|
<BranchPickerPrimitive.Root
|
|
hideWhenSingleBranch
|
|
className={cn(
|
|
"mr-2 -ml-2 inline-flex items-center text-muted-foreground text-xs",
|
|
className,
|
|
)}
|
|
{...rest}
|
|
>
|
|
<BranchPickerPrimitive.Previous asChild>
|
|
<TooltipIconButton tooltip="Predchádzajúci">
|
|
<ChevronLeftIcon />
|
|
</TooltipIconButton>
|
|
</BranchPickerPrimitive.Previous>
|
|
<span className="font-medium">
|
|
<BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />
|
|
</span>
|
|
<BranchPickerPrimitive.Next asChild>
|
|
<TooltipIconButton tooltip="Ďalší">
|
|
<ChevronRightIcon />
|
|
</TooltipIconButton>
|
|
</BranchPickerPrimitive.Next>
|
|
</BranchPickerPrimitive.Root>
|
|
);
|
|
};
|
|
|
|
export const AssistantMessage: FC = () => {
|
|
return (
|
|
<MessagePrimitive.Root
|
|
className="fade-in slide-in-from-bottom-1 relative mx-auto w-full max-w-(--thread-max-width) animate-in py-3 duration-150"
|
|
data-role="assistant"
|
|
>
|
|
<div className="flex gap-3 px-2">
|
|
<div className="size-7 rounded-full bg-blue-600/20 border border-blue-500/30 flex items-center justify-center shrink-0 mt-0.5">
|
|
<ScaleIcon className="size-3.5 text-blue-400" />
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<div className="text-foreground leading-relaxed">
|
|
<MessagePrimitive.Parts>
|
|
{({ part }) => {
|
|
if (part.type === "text") return <MarkdownText />;
|
|
if (part.type === "tool-call")
|
|
return part.toolUI ?? <ToolFallback {...part} />;
|
|
return null;
|
|
}}
|
|
</MessagePrimitive.Parts>
|
|
<MessageError />
|
|
</div>
|
|
<div className="mt-1 flex">
|
|
<BranchPicker />
|
|
<AssistantActionBar />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</MessagePrimitive.Root>
|
|
);
|
|
};
|
|
|
|
export const UserMessage: FC = () => {
|
|
return (
|
|
<MessagePrimitive.Root
|
|
className="fade-in slide-in-from-bottom-1 mx-auto grid w-full max-w-(--thread-max-width) animate-in auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 py-3 duration-150 [&:where(>*)]:col-start-2"
|
|
data-role="user"
|
|
>
|
|
<div className="relative col-start-2 min-w-0">
|
|
<div className="wrap-break-word rounded-2xl bg-blue-600/20 border border-blue-500/20 px-4 py-2.5 text-foreground empty:hidden">
|
|
<MessagePrimitive.Parts />
|
|
</div>
|
|
</div>
|
|
<BranchPicker className="col-span-full col-start-1 row-start-3 -mr-1 justify-end" />
|
|
</MessagePrimitive.Root>
|
|
);
|
|
}; |