/* Copyright 2026 Marimo. All rights reserved. */ import { useAtomValue } from "jotai"; import { BotMessageSquareIcon, ClockIcon, SearchIcon } from "lucide-react"; import { useMemo, useState } from "react"; import { useLocale } from "react-aria"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Tooltip } from "@/components/ui/tooltip"; import { type ChatId, chatStateAtom } from "@/core/ai/state"; import { cn } from "@/utils/cn"; import { timeAgo } from "@/utils/dates"; import { PanelEmptyState } from "../editor/chrome/panels/empty-state"; import { groupChatsByDate } from "./chat-history-utils"; interface ChatHistoryPopoverProps { activeChatId: ChatId | undefined; setActiveChat: (id: ChatId | null) => void; } export const ChatHistoryPopover: React.FC = ({ activeChatId, setActiveChat, }) => { const chatState = useAtomValue(chatStateAtom); const { locale } = useLocale(); const [searchQuery, setSearchQuery] = useState(""); const chats = useMemo(() => { return [...chatState.chats.values()].toSorted( (a, b) => b.updatedAt - a.updatedAt, ); }, [chatState.chats]); const filteredChats = useMemo(() => { if (!searchQuery.trim()) { return chats; } return chats.filter((chat) => chat.title.toLowerCase().includes(searchQuery.toLowerCase()), ); }, [chats, searchQuery]); const groupedChats = useMemo(() => { return groupChatsByDate(filteredChats); }, [filteredChats]); return (
setSearchQuery(e.target.value)} className="text-xs" />
{chats.length === 0 && ( } /> )} {filteredChats.length === 0 && searchQuery && chats.length > 0 && ( } /> )} {groupedChats.map((group, idx) => (
{group.label}
{group.chats.map((chat) => ( ))}
{/* If last group, don't show a divider */} {idx !== groupedChats.length - 1 &&
}
))}
); };