Spaces:
Running
Running
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, | |
}); | |
const renderDescriptionForm = ( | |
<form onSubmit={handleSubmit} className="flex-1 flex items-center"> | |
<input | |
type="text" | |
className="flex-1 bg-bolt-elements-background-depth-1 text-bolt-elements-textPrimary rounded px-2 mr-2" | |
autoFocus | |
value={currentDescription} | |
onChange={handleChange} | |
onBlur={handleBlur} | |
onKeyDown={handleKeyDown} | |
/> | |
<button | |
type="submit" | |
className="i-ph:check scale-110 hover:text-bolt-elements-item-contentAccent" | |
onMouseDown={handleSubmit} | |
/> | |
</form> | |
); | |
return ( | |
<div | |
className={classNames( | |
'group rounded-md text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary hover:bg-bolt-elements-background-depth-3 overflow-hidden flex justify-between items-center px-2 py-1', | |
{ '[&&]:text-bolt-elements-textPrimary bg-bolt-elements-background-depth-3': isActiveChat }, | |
)} | |
> | |
{editing ? ( | |
renderDescriptionForm | |
) : ( | |
<a href={`/chat/${item.urlId}`} className="flex w-full relative truncate block"> | |
{currentDescription} | |
<div | |
className={classNames( | |
'absolute right-0 z-1 top-0 bottom-0 bg-gradient-to-l from-bolt-elements-background-depth-2 group-hover:from-bolt-elements-background-depth-3 box-content pl-3 to-transparent w-10 flex justify-end group-hover:w-22 group-hover:from-99%', | |
{ 'from-bolt-elements-background-depth-3 w-10 ': isActiveChat }, | |
)} | |
> | |
<div className="flex items-center p-1 text-bolt-elements-textSecondary opacity-0 group-hover:opacity-100 transition-opacity"> | |
<ChatActionButton | |
toolTipContent="Export chat" | |
icon="i-ph:download-simple" | |
onClick={(event) => { | |
event.preventDefault(); | |
exportChat(item.id); | |
}} | |
/> | |
{onDuplicate && ( | |
<ChatActionButton | |
toolTipContent="Duplicate chat" | |
icon="i-ph:copy" | |
onClick={() => onDuplicate?.(item.id)} | |
/> | |
)} | |
<ChatActionButton | |
toolTipContent="Rename chat" | |
icon="i-ph:pencil-fill" | |
onClick={(event) => { | |
event.preventDefault(); | |
toggleEditMode(); | |
}} | |
/> | |
<Dialog.Trigger asChild> | |
<ChatActionButton | |
toolTipContent="Delete chat" | |
icon="i-ph:trash" | |
className="[&&]:hover:text-bolt-elements-button-danger-text" | |
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}> | |
<button | |
ref={ref} | |
type="button" | |
className={`scale-110 mr-2 hover:text-bolt-elements-item-contentAccent ${icon} ${className ? className : ''}`} | |
onClick={onClick} | |
/> | |
</WithTooltip> | |
); | |
}, | |
); | |