diff --git a/src/app/components/home/FolderRail.tsx b/src/app/components/home/FolderRail.tsx index 43ffba99..9df7e2cc 100644 --- a/src/app/components/home/FolderRail.tsx +++ b/src/app/components/home/FolderRail.tsx @@ -1,11 +1,15 @@ "use client"; import { useState } from "react"; +import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react"; import { MoreVertical, Plus, Star } from "lucide-react"; import type { FolderWire } from "@/app/lib/portfolioHomeView"; export type RailView = "all" | "starred" | { folderId: string }; +// Cards set this dataTransfer type on drag; rail items accept it as a drop. +const PORTFOLIO_DRAG_TYPE = "application/x-portfolio"; + export type FolderRailProps = { folders: FolderWire[]; // already ordered by position view: RailView; @@ -19,6 +23,9 @@ export type FolderRailProps = { onCreate: (name: string) => void; onRename: (folderId: string, name: string) => void; onDelete: (folderId: string) => void; + // Drag-to-file: a card dropped on a folder / Starred / All portfolios. + onDropToFolder: (portfolioId: string, folderId: string | null) => void; + onDropToStarred: (portfolioId: string) => void; }; function AttentionBadge({ count }: { count: number }) { @@ -39,24 +46,25 @@ function railItemClasses(active: boolean) { }`; } +const dropHighlight = "ring-2 ring-inset ring-brandmidblue rounded-lg"; + export default function FolderRail(props: FolderRailProps) { const [dragIndex, setDragIndex] = useState(null); const [dropIndex, setDropIndex] = useState(null); const [creating, setCreating] = useState(false); const [editingId, setEditingId] = useState(null); - // Two-step destructive confirm lives inside the menu panel, not a dialog: + // Two-step destructive confirm lives inside the menu popover, not a dialog: // removal only unfiles portfolios, so OS-modal weight isn't warranted. const [confirmingId, setConfirmingId] = useState(null); + // Which rail target a dragged card is hovering: folder id, "starred", + // "all", or null. + const [cardDropTarget, setCardDropTarget] = useState(null); const isFolderView = (folderId: string) => typeof props.view === "object" && props.view.folderId === folderId; const commitDrop = () => { - if ( - dragIndex !== null && - dropIndex !== null && - dropIndex !== dragIndex - ) { + if (dragIndex !== null && dropIndex !== null && dropIndex !== dragIndex) { const ids = props.folders.map((f) => f.id); const [moved] = ids.splice(dragIndex, 1); ids.splice(dropIndex, 0, moved); @@ -66,6 +74,27 @@ export default function FolderRail(props: FolderRailProps) { setDropIndex(null); }; + const cardDropHandlers = ( + targetKey: string, + onDrop: (portfolioId: string) => void, + ) => ({ + onDragOver: (e: React.DragEvent) => { + if (!e.dataTransfer.types.includes(PORTFOLIO_DRAG_TYPE)) return; + e.preventDefault(); + e.dataTransfer.dropEffect = "move"; + setCardDropTarget(targetKey); + }, + onDragLeave: () => + setCardDropTarget((current) => (current === targetKey ? null : current)), + onDrop: (e: React.DragEvent) => { + const portfolioId = e.dataTransfer.getData(PORTFOLIO_DRAG_TYPE); + if (!portfolioId) return; + e.preventDefault(); + setCardDropTarget(null); + onDrop(portfolioId); + }, + }); + const nameForm = ( defaultValue: string, onSubmit: (name: string) => void, @@ -94,14 +123,26 @@ export default function FolderRail(props: FolderRailProps) { ); return ( -