mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-28 14:09:22 +02:00
Extract <ProjectIcon> with sm/md/lg sizes and a single 📁 fallback, replacing 9 inline render sites that had drifted into 6 different sizes and a mixed FolderKanban/emoji fallback. Two visible fixes fall out of the centralization: - ProjectPicker trigger now shows the selected project's icon (most visibly in the issue detail right Properties panel, where it had always been a generic FolderKanban). - Sidebar parent nav (Projects, Issues, Settings, ...) now stays highlighted on child detail routes via a small isNavActive helper. Pinned items keep strict equality. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
67 lines
2.4 KiB
TypeScript
67 lines
2.4 KiB
TypeScript
"use client";
|
|
|
|
import { Check, FolderKanban, X } from "lucide-react";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { projectListOptions } from "@multica/core/projects/queries";
|
|
import { useWorkspaceId } from "@multica/core/hooks";
|
|
import type { UpdateIssueRequest } from "@multica/core/types";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
DropdownMenuSeparator,
|
|
} from "@multica/ui/components/ui/dropdown-menu";
|
|
import { ProjectIcon } from "./project-icon";
|
|
|
|
export function ProjectPicker({
|
|
projectId,
|
|
onUpdate,
|
|
triggerRender,
|
|
align = "start",
|
|
}: {
|
|
projectId: string | null;
|
|
onUpdate: (updates: Partial<UpdateIssueRequest>) => void;
|
|
triggerRender?: React.ReactElement;
|
|
align?: "start" | "center" | "end";
|
|
}) {
|
|
const wsId = useWorkspaceId();
|
|
const { data: projects = [] } = useQuery(projectListOptions(wsId));
|
|
const current = projects.find((p) => p.id === projectId);
|
|
|
|
return (
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger
|
|
className={triggerRender ? undefined : "flex items-center gap-1.5 cursor-pointer rounded px-1 -mx-1 hover:bg-accent/30 transition-colors overflow-hidden"}
|
|
render={triggerRender}
|
|
>
|
|
{current ? (
|
|
<ProjectIcon project={current} size="sm" />
|
|
) : (
|
|
<FolderKanban className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
|
)}
|
|
<span className="truncate">{current ? current.title : "No project"}</span>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align={align} className="w-52">
|
|
{projects.map((p) => (
|
|
<DropdownMenuItem key={p.id} onClick={() => onUpdate({ project_id: p.id })}>
|
|
<ProjectIcon project={p} size="md" className="mr-1" />
|
|
<span className="truncate">{p.title}</span>
|
|
{p.id === projectId && <Check className="ml-auto h-3.5 w-3.5 shrink-0" />}
|
|
</DropdownMenuItem>
|
|
))}
|
|
{projects.length > 0 && projectId && <DropdownMenuSeparator />}
|
|
{projectId && (
|
|
<DropdownMenuItem onClick={() => onUpdate({ project_id: null })}>
|
|
<X className="h-3.5 w-3.5 text-muted-foreground" />
|
|
Remove from project
|
|
</DropdownMenuItem>
|
|
)}
|
|
{projects.length === 0 && (
|
|
<div className="px-2 py-1.5 text-xs text-muted-foreground">No projects yet</div>
|
|
)}
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
);
|
|
}
|