From aae0059a6f22626496a3be14b224666cce1d6a00 Mon Sep 17 00:00:00 2001 From: Zimeng Xiong Date: Fri, 21 Nov 2025 22:52:32 -0800 Subject: [PATCH] Minor UI, fix dragging to select --- frontend/src/components/ConfirmModal.tsx | 12 +++--- frontend/src/components/Sidebar.tsx | 4 +- frontend/src/pages/Dashboard.tsx | 54 ++++++++++++++++++------ 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/frontend/src/components/ConfirmModal.tsx b/frontend/src/components/ConfirmModal.tsx index 247ee54..04f6431 100644 --- a/frontend/src/components/ConfirmModal.tsx +++ b/frontend/src/components/ConfirmModal.tsx @@ -36,22 +36,22 @@ export const ConfirmModal: React.FC = ({ /> {/* Modal */} -
+
-
+
-

{title}

-

+

{title}

+

{message}

@@ -61,7 +61,7 @@ export const ConfirmModal: React.FC = ({ {showCancel && ( diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 55f257f..c63ce0a 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -87,8 +87,8 @@ const SidebarItem: React.FC = ({ setIsDragOver(false); onDrop?.(e, id); }} - className={clsx( - "w-full flex items-center gap-3 px-3 py-2.5 text-sm font-bold rounded-lg transition-all duration-200 border-2 group cursor-pointer outline-none focus:ring-2 focus:ring-indigo-500", + className={clsx( + "w-full flex items-center gap-3 px-3 py-2.5 text-sm font-bold rounded-lg transition-all duration-200 border-2 group cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:focus-visible:ring-2 dark:focus-visible:ring-neutral-500", isActive || isDragOver ? "bg-indigo-50 dark:bg-neutral-800 text-indigo-900 dark:text-neutral-200 border-black dark:border-neutral-700 shadow-[2px_2px_0px_0px_rgba(0,0,0,1)] dark:shadow-[2px_2px_0px_0px_rgba(255,255,255,0.2)] -translate-y-0.5" : "text-slate-600 dark:text-neutral-400 border-transparent hover:bg-slate-50 dark:hover:bg-neutral-800 hover:border-black dark:hover:border-neutral-700 hover:shadow-[2px_2px_0px_0px_rgba(0,0,0,1)] dark:hover:shadow-[2px_2px_0px_0px_rgba(255,255,255,0.2)] hover:-translate-y-0.5" diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index 46083ef..322c2d8 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -11,6 +11,32 @@ import clsx from 'clsx'; import { ConfirmModal } from '../components/ConfirmModal'; import { importDrawings, importLibrary } from '../utils/importUtils'; +type Point = { x: number; y: number }; + +type SelectionBounds = { + left: number; + top: number; + right: number; + bottom: number; + width: number; + height: number; +}; + +const getSelectionBounds = (start: Point, current: Point): SelectionBounds => { + const left = Math.min(start.x, current.x); + const right = Math.max(start.x, current.x); + const top = Math.min(start.y, current.y); + const bottom = Math.max(start.y, current.y); + return { + left, + top, + right, + bottom, + width: right - left, + height: bottom - top, + }; +}; + const DragOverlayPortal: React.FC<{ children: React.ReactNode }> = ({ children }) => { return createPortal(children, document.body); }; @@ -55,8 +81,8 @@ export const Dashboard: React.FC = () => { // Drag Selection State const [isDragSelecting, setIsDragSelecting] = useState(false); - const [dragStart, setDragStart] = useState<{ x: number; y: number } | null>(null); - const [dragCurrent, setDragCurrent] = useState<{ x: number; y: number } | null>(null); + const [dragStart, setDragStart] = useState(null); + const [dragCurrent, setDragCurrent] = useState(null); const [potentialDragId, setPotentialDragId] = useState(null); const containerRef = useRef(null); @@ -123,6 +149,11 @@ export const Dashboard: React.FC = () => { } }, []); + const selectionBounds = React.useMemo(() => { + if (!dragStart || !dragCurrent) return null; + return getSelectionBounds(dragStart, dragCurrent); + }, [dragStart, dragCurrent]); + useEffect(() => { if (!isDragSelecting) return; @@ -138,14 +169,9 @@ export const Dashboard: React.FC = () => { return; } - // Calculate selection rect - const left = Math.min(dragStart.x, dragCurrent.x); - const top = Math.min(dragStart.y, dragCurrent.y); - const width = Math.abs(dragCurrent.x - dragStart.x); - const height = Math.abs(dragCurrent.y - dragStart.y); - const selectionRect = { left, top, right: left + width, bottom: top + height }; + const selectionRect = getSelectionBounds(dragStart, dragCurrent); - if (width > 5 || height > 5) { + if (selectionRect.width > 5 || selectionRect.height > 5) { const newSelectedIds = new Set(selectedIds); drawings.forEach(drawing => { const card = document.getElementById(`drawing-card-${drawing.id}`); @@ -636,15 +662,15 @@ export const Dashboard: React.FC = () => {
{/* Drag Selection Overlay */} - {isDragSelecting && dragStart && dragCurrent && ( + {isDragSelecting && selectionBounds && (