import React, { useEffect, useState } from "react"; import { getCollections, createCollection, deleteCollection, } from "../../api/client"; import { Plus, Folder, Trash2, X } from "lucide-react"; import CollectionIcon from "../../components/common/CollectionIcon"; import { ICON_MAP } from "../../components/common/iconMap"; import { useStore } from "@nanostores/react"; import { $user } from "../../store/auth"; import EmojiPicker, { Theme } from "emoji-picker-react"; import { $theme } from "../../store/theme"; import type { Collection } from "../../types"; import { formatDistanceToNow } from "date-fns"; import { clsx } from "clsx"; import { Button, Input, EmptyState, Skeleton } from "../../components/ui"; export default function Collections() { const user = useStore($user); const theme = useStore($theme); const [collections, setCollections] = useState([]); const [loading, setLoading] = useState(true); const [showCreateModal, setShowCreateModal] = useState(false); const [newItemName, setNewItemName] = useState(""); const [newItemDesc, setNewItemDesc] = useState(""); const [newItemIcon, setNewItemIcon] = useState("folder"); const [activeTab, setActiveTab] = useState<"icon" | "emoji">("icon"); const [creating, setCreating] = useState(false); const fetchCollections = async () => { try { setLoading(true); const data = await getCollections(); setCollections(data); } catch (error) { console.error("Failed to load collections:", error); } finally { setLoading(false); } }; useEffect(() => { fetchCollections(); }, []); const handleCreate = async (e: React.FormEvent) => { e.preventDefault(); if (!newItemName.trim()) return; setCreating(true); const finalIcon = ICON_MAP[newItemIcon] ? `icon:${newItemIcon}` : newItemIcon; const res = await createCollection(newItemName, newItemDesc, finalIcon); if (res) { setCollections([res, ...collections]); setShowCreateModal(false); setNewItemName(""); setNewItemDesc(""); setNewItemIcon("folder"); setActiveTab("icon"); fetchCollections(); } setCreating(false); }; const handleDelete = async (id: string, e: React.MouseEvent) => { e.preventDefault(); if (window.confirm("Delete this collection?")) { const success = await deleteCollection(id); if (success) { setCollections((prev) => prev.filter((c) => c.id !== id)); } } }; if (loading) { return (
{[1, 2, 3].map((i) => (
))}
); } return (

Collections

Organize your annotations and highlights

{collections.length === 0 ? ( } title="No collections yet" message="Create a collection to organize your highlights and annotations." action={{ label: "Create collection", onClick: () => setShowCreateModal(true), }} /> ) : (
{collections .filter((c) => c && c.id && c.name) .map((collection) => (

{collection.name}

{collection.itemCount}{" "} {collection.itemCount === 1 ? "item" : "items"} {collection.createdAt && ` ยท ${formatDistanceToNow(new Date(collection.createdAt), { addSuffix: true })}`}

{!collection.uri.includes("network.cosmik") && ( )}
))}
)} {showCreateModal && (

New Collection

setNewItemName(e.target.value)} placeholder="e.g. Design Inspiration" autoFocus required />
{activeTab === "icon" ? (
{Object.keys(ICON_MAP).map((key) => { const Icon = ICON_MAP[key]; return ( ); })}
) : (
setNewItemIcon(emojiData.emoji) } autoFocusSearch={false} width="100%" height={300} previewConfig={{ showPreview: false }} skinTonesDisabled lazyLoadEmojis theme={ theme === "dark" || (theme === "system" && window.matchMedia("(prefers-color-scheme: dark)") .matches) ? (Theme.DARK as Theme) : (Theme.LIGHT as Theme) } />
)}