feat: ai elements (#1143)

This commit is contained in:
josh 2025-08-28 14:15:36 +01:00 committed by GitHub
parent 66e8227655
commit f09be3f286
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 3558 additions and 500 deletions

View file

@ -4,13 +4,7 @@ import { useCopyToClipboard } from 'usehooks-ts';
import type { Vote } from '@/lib/db/schema';
import { CopyIcon, ThumbDownIcon, ThumbUpIcon } from './icons';
import { Button } from './ui/button';
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from './ui/tooltip';
import { Actions, Action } from './elements/actions';
import { memo } from 'react';
import equal from 'fast-deep-equal';
import { toast } from 'sonner';
@ -34,42 +28,32 @@ export function PureMessageActions({
if (message.role === 'user') return null;
return (
<TooltipProvider delayDuration={0}>
<div className="flex flex-row gap-2">
<Tooltip>
<TooltipTrigger asChild>
<Button
className="py-1 px-2 h-fit text-muted-foreground"
variant="outline"
onClick={async () => {
const textFromParts = message.parts
?.filter((part) => part.type === 'text')
.map((part) => part.text)
.join('\n')
.trim();
<Actions>
<Action
tooltip="Copy"
onClick={async () => {
const textFromParts = message.parts
?.filter((part) => part.type === 'text')
.map((part) => part.text)
.join('\n')
.trim();
if (!textFromParts) {
toast.error("There's no text to copy!");
return;
}
if (!textFromParts) {
toast.error("There's no text to copy!");
return;
}
await copyToClipboard(textFromParts);
toast.success('Copied to clipboard!');
}}
>
<CopyIcon />
</Button>
</TooltipTrigger>
<TooltipContent>Copy</TooltipContent>
</Tooltip>
await copyToClipboard(textFromParts);
toast.success('Copied to clipboard!');
}}
>
<CopyIcon />
</Action>
<Tooltip>
<TooltipTrigger asChild>
<Button
data-testid="message-upvote"
className="py-1 px-2 h-fit text-muted-foreground !pointer-events-auto"
disabled={vote?.isUpvoted}
variant="outline"
<Action
tooltip="Upvote Response"
data-testid="message-upvote"
disabled={vote?.isUpvoted}
onClick={async () => {
const upvote = fetch('/api/vote', {
method: 'PATCH',
@ -109,20 +93,14 @@ export function PureMessageActions({
error: 'Failed to upvote response.',
});
}}
>
<ThumbUpIcon />
</Button>
</TooltipTrigger>
<TooltipContent>Upvote Response</TooltipContent>
</Tooltip>
>
<ThumbUpIcon />
</Action>
<Tooltip>
<TooltipTrigger asChild>
<Button
data-testid="message-downvote"
className="py-1 px-2 h-fit text-muted-foreground !pointer-events-auto"
variant="outline"
disabled={vote && !vote.isUpvoted}
<Action
tooltip="Downvote Response"
data-testid="message-downvote"
disabled={vote && !vote.isUpvoted}
onClick={async () => {
const downvote = fetch('/api/vote', {
method: 'PATCH',
@ -162,14 +140,10 @@ export function PureMessageActions({
error: 'Failed to downvote response.',
});
}}
>
<ThumbDownIcon />
</Button>
</TooltipTrigger>
<TooltipContent>Downvote Response</TooltipContent>
</Tooltip>
</div>
</TooltipProvider>
>
<ThumbDownIcon />
</Action>
</Actions>
);
}