"use client"; import * as React from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { ArrowLeftRight, FolderKanban, Plus } from "lucide-react"; import { useApp } from "@/components/app/store"; import { useApi } from "@/lib/client/api"; import { Skeleton } from "@/components/ui/misc"; import { Tooltip } from "@/components/ui/tooltip"; import type { PublicProject } from "@/lib/client/types"; import { ProjectIcon } from "./project-icon"; import { ProjectSwitcher } from "./project-switcher"; import { cn } from "@/lib/utils"; const MAX_ROWS = 8; /** * Projects list rendered inside the sidebar / mobile drawer. * - rows link to the project page; the current page's project is highlighted * - the *active* project (used for new chats) shows a coloured dot + "Active" hint * - the ⇄ button opens the quick switcher (ActionSheet on phones, dropdown on desktop) */ export function ProjectsSidebarSection({ onNavigate }: { onNavigate?: () => void }) { const { activeProjectId } = useApp(); const pathname = usePathname(); const { data, isLoading } = useApi<{ projects: PublicProject[] }>("/api/projects"); const all = React.useMemo(() => (data?.projects ?? []).filter((p) => !p.archived), [data]); const list = React.useMemo(() => { // Keep the active project visible even when it is not among the first rows. const head = all.slice(0, MAX_ROWS); const active = activeProjectId ? all.find((p) => p.id === activeProjectId) : undefined; if (active && !head.some((p) => p.id === active.id)) return [active, ...head.slice(0, MAX_ROWS - 1)]; return head; }, [all, activeProjectId]); const currentId = pathname.match(/^\/app\/projects\/([^/]+)/)?.[1]; const overflow = all.length - list.length; return (
Projects {all.length ? {all.length} : null}
{all.length ? ( ) : null}
{isLoading && !data ? (
) : list.length === 0 ? ( Group chats, files and instructions into a project. ) : (
{list.map((p) => { const isActive = p.id === activeProjectId; const isCurrent = p.id === currentId; return ( {p.name} {isActive ? ( Active ) : null} ); })} {overflow > 0 ? ( +{overflow} more… ) : null}
)}
); }