File size: 4,848 Bytes
5335580 1e11ab6 6041155 5335580 356715c 5bbcdcc 1e11ab6 23d7182 fb34a4c 1e11ab6 fb34a4c 5335580 5bbcdcc 5335580 c4c7362 5335580 c4c7362 5335580 c4c7362 5335580 c4c7362 5335580 c4c7362 5335580 c4c7362 b8b25ba 5335580 c4c7362 b8b25ba 5335580 c4c7362 5335580 c4c7362 6041155 b8b25ba 6041155 23d7182 5335580 b8b25ba 5335580 5bbcdcc 5335580 356715c c4c7362 356715c c4c7362 356715c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
import { useParams } from '@remix-run/react';
import { classNames } from '~/utils/classNames';
import * as Dialog from '@radix-ui/react-dialog';
import { type ChatHistoryItem } from '~/lib/persistence';
import WithTooltip from '~/components/ui/Tooltip';
import { useEditChatDescription } from '~/lib/hooks';
import { forwardRef, type ForwardedRef } from 'react';
interface HistoryItemProps {
item: ChatHistoryItem;
onDelete?: (event: React.UIEvent) => void;
onDuplicate?: (id: string) => void;
exportChat: (id?: string) => void;
}
export function HistoryItem({ item, onDelete, onDuplicate, exportChat }: HistoryItemProps) {
const { id: urlId } = useParams();
const isActiveChat = urlId === item.urlId;
const { editing, handleChange, handleBlur, handleSubmit, handleKeyDown, currentDescription, toggleEditMode } =
useEditChatDescription({
initialDescription: item.description,
customChatId: item.id,
syncWithGlobalStore: isActiveChat,
});
return (
<div
className={classNames(
'group rounded-lg text-sm text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white hover:bg-gray-50/80 dark:hover:bg-gray-800/30 overflow-hidden flex justify-between items-center px-3 py-2 transition-colors',
{ 'text-gray-900 dark:text-white bg-gray-50/80 dark:bg-gray-800/30': isActiveChat },
)}
>
{editing ? (
<form onSubmit={handleSubmit} className="flex-1 flex items-center gap-2">
<input
type="text"
className="flex-1 bg-white dark:bg-gray-900 text-gray-900 dark:text-white rounded-md px-3 py-1.5 text-sm border border-gray-200 dark:border-gray-800 focus:outline-none focus:ring-1 focus:ring-purple-500/50"
autoFocus
value={currentDescription}
onChange={handleChange}
onBlur={handleBlur}
onKeyDown={handleKeyDown}
/>
<button
type="submit"
className="i-ph:check h-4 w-4 text-gray-500 hover:text-purple-500 transition-colors"
onMouseDown={handleSubmit}
/>
</form>
) : (
<a href={`/chat/${item.urlId}`} className="flex w-full relative truncate block">
<WithTooltip tooltip={currentDescription}>
<span className="truncate pr-24">{currentDescription}</span>
</WithTooltip>
<div
className={classNames(
'absolute right-0 top-0 bottom-0 flex items-center bg-white dark:bg-gray-950 group-hover:bg-gray-50/80 dark:group-hover:bg-gray-800/30 px-2',
{ 'bg-gray-50/80 dark:bg-gray-800/30': isActiveChat },
)}
>
<div className="flex items-center gap-2.5 text-gray-400 dark:text-gray-500 opacity-0 group-hover:opacity-100 transition-opacity">
<ChatActionButton
toolTipContent="Export"
icon="i-ph:download-simple h-4 w-4"
onClick={(event) => {
event.preventDefault();
exportChat(item.id);
}}
/>
{onDuplicate && (
<ChatActionButton
toolTipContent="Duplicate"
icon="i-ph:copy h-4 w-4"
onClick={() => onDuplicate?.(item.id)}
/>
)}
<ChatActionButton
toolTipContent="Rename"
icon="i-ph:pencil-fill h-4 w-4"
onClick={(event) => {
event.preventDefault();
toggleEditMode();
}}
/>
<Dialog.Trigger asChild>
<ChatActionButton
toolTipContent="Delete"
icon="i-ph:trash h-4 w-4"
className="hover:text-red-500"
onClick={(event) => {
event.preventDefault();
onDelete?.(event);
}}
/>
</Dialog.Trigger>
</div>
</div>
</a>
)}
</div>
);
}
const ChatActionButton = forwardRef(
(
{
toolTipContent,
icon,
className,
onClick,
}: {
toolTipContent: string;
icon: string;
className?: string;
onClick: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
btnTitle?: string;
},
ref: ForwardedRef<HTMLButtonElement>,
) => {
return (
<WithTooltip tooltip={toolTipContent} position="bottom" sideOffset={4}>
<button
ref={ref}
type="button"
className={`text-gray-400 dark:text-gray-500 hover:text-purple-500 dark:hover:text-purple-400 transition-colors ${icon} ${className ? className : ''}`}
onClick={onClick}
/>
</WithTooltip>
);
},
);
|