feat(22-03): add ChatStopButton and ChatMessageActions components
- ChatStopButton: centered outline button with Square icon and 'Stop generating' label - ChatMessageActions: edit Pencil for user messages (absolute, group-hover) - ChatMessageActions: retry RefreshCw for assistant messages (right-aligned, group-hover) - Both action buttons return null when isStreaming is true - Proper aria-labels and tooltips on all interactive elements
This commit is contained in:
parent
c7887c73ca
commit
d88d846b1e
2 changed files with 81 additions and 0 deletions
58
ui/src/components/ChatMessageActions.tsx
Normal file
58
ui/src/components/ChatMessageActions.tsx
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import { Pencil, RefreshCw } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||||
|
|
||||||
|
interface ChatMessageActionsProps {
|
||||||
|
role: "user" | "assistant" | "system";
|
||||||
|
isStreaming?: boolean;
|
||||||
|
onEdit?: () => void;
|
||||||
|
onRetry?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChatMessageActions({ role, isStreaming, onEdit, onRetry }: ChatMessageActionsProps) {
|
||||||
|
if (isStreaming) return null;
|
||||||
|
|
||||||
|
if (role === "user" && onEdit) {
|
||||||
|
return (
|
||||||
|
<div className="absolute top-1 right-1 hidden group-hover:flex">
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="h-6 w-6"
|
||||||
|
onClick={onEdit}
|
||||||
|
aria-label="Edit message"
|
||||||
|
>
|
||||||
|
<Pencil className="h-3.5 w-3.5" />
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>Edit message</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role === "assistant" && onRetry) {
|
||||||
|
return (
|
||||||
|
<div className="flex justify-end mt-1">
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
className="h-6 w-6 hidden group-hover:inline-flex"
|
||||||
|
onClick={onRetry}
|
||||||
|
aria-label="Retry response"
|
||||||
|
>
|
||||||
|
<RefreshCw className="h-3.5 w-3.5" />
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>Retry response</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
23
ui/src/components/ChatStopButton.tsx
Normal file
23
ui/src/components/ChatStopButton.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { Square } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
|
interface ChatStopButtonProps {
|
||||||
|
onStop: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChatStopButton({ onStop }: ChatStopButtonProps) {
|
||||||
|
return (
|
||||||
|
<div className="flex justify-center py-2 border-t border-border">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={onStop}
|
||||||
|
aria-label="Stop generating response"
|
||||||
|
className="gap-1.5"
|
||||||
|
>
|
||||||
|
<Square className="h-3 w-3 fill-current" />
|
||||||
|
Stop generating
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue