nexus/ui/src/components/ChatBookmarkList.tsx
Nexus Dev ac6d75ab0d feat(24-02): UI components — ChatSearchDialog, ChatMessageBookmark, ChatBookmarkList, ChatBranchSelector
- ChatSearchDialog: CommandDialog with shouldFilter=false for server-side FTS, term highlighting via React components
- ChatMessageBookmark: ghost icon button with fill-current for bookmarked state, aria-label toggle
- ChatBookmarkList: scrollable list with skeleton loading, empty state, navigation callbacks
- ChatBranchSelector: horizontal branch picker bar with GitBranch icon, active branch highlight
2026-04-04 03:55:48 +00:00

64 lines
2.4 KiB
TypeScript

import { Bookmark } from "lucide-react";
import { useChatBookmarks } from "../hooks/useChatBookmarks";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Skeleton } from "@/components/ui/skeleton";
interface ChatBookmarkListProps {
companyId: string;
onNavigate: (conversationId: string, messageId: string) => void;
}
function formatRelativeTime(dateStr: string): string {
const date = new Date(dateStr);
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffMin = Math.floor(diffMs / 60000);
if (diffMin < 1) return "just now";
if (diffMin < 60) return `${diffMin}m ago`;
const diffHr = Math.floor(diffMin / 60);
if (diffHr < 24) return `${diffHr}h ago`;
const diffDays = Math.floor(diffHr / 24);
if (diffDays < 30) return `${diffDays}d ago`;
return date.toLocaleDateString();
}
export function ChatBookmarkList({ companyId, onNavigate }: ChatBookmarkListProps) {
const { data, isLoading } = useChatBookmarks(companyId);
const bookmarks = data?.items ?? [];
return (
<ScrollArea className="h-full">
<div className="p-1 space-y-0.5">
{isLoading ? (
Array.from({ length: 4 }).map((_, i) => (
<Skeleton key={i} className="h-14 w-full rounded" />
))
) : bookmarks.length === 0 ? (
<div className="flex flex-col items-center justify-center py-10 gap-2 text-muted-foreground">
<Bookmark className="h-8 w-8 opacity-30" />
<p className="text-sm">No bookmarks yet</p>
</div>
) : (
bookmarks.map((bookmark) => (
<button
key={bookmark.id}
type="button"
className="w-full text-left px-2 py-2 rounded hover:bg-accent transition-colors"
onClick={() => onNavigate(bookmark.conversationId, bookmark.message.id)}
>
<p className="text-xs text-muted-foreground truncate mb-0.5">
{bookmark.conversationTitle ?? "Untitled conversation"}
</p>
<p className="text-sm text-foreground line-clamp-2">
{bookmark.message.content.slice(0, 120)}
</p>
<p className="text-xs text-muted-foreground mt-0.5">
{formatRelativeTime(bookmark.createdAt)}
</p>
</button>
))
)}
</div>
</ScrollArea>
);
}