From 8220bfda60bff1055e361bf15e826f3a8b6ca73c Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Tue, 14 Jul 2026 03:25:22 +0530 Subject: [PATCH] feat(documents): enhance DocumentNode and FolderNode components with mobile responsiveness and improved checkbox interactions --- .../components/documents/DocumentNode.tsx | 90 +++++++------- .../components/documents/FolderNode.tsx | 116 +++++++++++------- 2 files changed, 115 insertions(+), 91 deletions(-) diff --git a/surfsense_web/components/documents/DocumentNode.tsx b/surfsense_web/components/documents/DocumentNode.tsx index 256fb4147..423d7562f 100644 --- a/surfsense_web/components/documents/DocumentNode.tsx +++ b/surfsense_web/components/documents/DocumentNode.tsx @@ -37,6 +37,7 @@ import { import { Spinner } from "@/components/ui/spinner"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import type { DocumentTypeEnum } from "@/contracts/types/document.types"; +import { useIsMobile } from "@/hooks/use-mobile"; import { cn } from "@/lib/utils"; import { SidebarListItem } from "../layout/ui/sidebar/SidebarListItem"; import { DND_TYPES } from "./FolderNode"; @@ -92,6 +93,7 @@ export const DocumentNode = React.memo(function DocumentNode({ const isMemoryDocument = doc.document_type === "USER_MEMORY" || doc.document_type === "TEAM_MEMORY"; const isSelectable = canMention && !isUnavailable; + const isMobile = useIsMobile(); const handleCheckChange = useCallback(() => { if (isSelectable) { @@ -164,9 +166,9 @@ export const DocumentNode = React.memo(function DocumentNode({ - {isMemoryDocument ? ( - - - - ) : canMention ? ( + + + {getDocumentTypeIcon( + doc.document_type as DocumentTypeEnum, + "h-3.5 w-3.5 text-muted-foreground" + )} + + {canMention ? ( e.stopPropagation()} - className="h-3.5 w-3.5 shrink-0" - /> - ) : ( - - {getDocumentTypeIcon( - doc.document_type as DocumentTypeEnum, - "h-3.5 w-3.5 text-muted-foreground" + className={cn( + "absolute h-3.5 w-3.5 transition-opacity max-sm:pointer-events-auto max-sm:opacity-100", + isMentioned + ? "opacity-100" + : "pointer-events-none opacity-0 group-hover/item:pointer-events-auto group-hover/item:opacity-100 focus-visible:pointer-events-auto focus-visible:opacity-100" )} - - )} - + /> + ) : null} + ); })()} @@ -260,36 +266,30 @@ export const DocumentNode = React.memo(function DocumentNode({ - - {getDocumentTypeIcon( - doc.document_type as DocumentTypeEnum, - "h-3.5 w-3.5 text-muted-foreground" - ) && ( - - {getDocumentTypeIcon( - doc.document_type as DocumentTypeEnum, - "h-3.5 w-3.5 text-muted-foreground" - )} - +
@@ -341,7 +341,7 @@ export const DocumentNode = React.memo(function DocumentNode({ )} - +
diff --git a/surfsense_web/components/documents/FolderNode.tsx b/surfsense_web/components/documents/FolderNode.tsx index 1cf74f549..bfebf29cd 100644 --- a/surfsense_web/components/documents/FolderNode.tsx +++ b/surfsense_web/components/documents/FolderNode.tsx @@ -34,6 +34,7 @@ import { } from "@/components/ui/dropdown-menu"; import { Spinner } from "@/components/ui/spinner"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; +import { useIsMobile } from "@/hooks/use-mobile"; import { cn } from "@/lib/utils"; import type { FolderSelectionState } from "./FolderTreeView"; @@ -124,6 +125,7 @@ export const FolderNode = React.memo(function FolderNode({ onStopWatching, onExportFolder, }: FolderNodeProps) { + const isMobile = useIsMobile(); const [renameValue, setRenameValue] = useState(folder.name); const inputRef = useRef(null); const rowRef = useRef(null); @@ -261,8 +263,9 @@ export const FolderNode = React.memo(function FolderNode({ tabIndex={0} dragging={isDragging} className={cn( - "relative gap-1 px-1", + "group/item relative gap-1 px-1", isExpanded && "font-medium", + dropdownOpen && "bg-accent text-accent-foreground", isOver && canDrop && dropZone === "middle" && "bg-accent ring-1 ring-primary/40", isOver && canDrop && dropZone === "top" && "border-t-2 border-primary", isOver && canDrop && dropZone === "bottom" && "border-b-2 border-primary", @@ -291,11 +294,11 @@ export const FolderNode = React.memo(function FolderNode({ )} - {processingState !== "idle" && selectionState === "none" ? ( - <> + + {processingState !== "idle" && selectionState === "none" ? ( - + {processingState === "processing" ? ( ) : ( @@ -309,29 +312,37 @@ export const FolderNode = React.memo(function FolderNode({ : "Some files failed to process"} - e.stopPropagation()} - className="h-3.5 w-3.5 shrink-0 hidden group-hover:flex" - /> - - ) : ( - e.stopPropagation()} - className="h-3.5 w-3.5 shrink-0" - /> - )} - - + ) : ( + <> + + e.stopPropagation()} + className={cn( + "absolute h-3.5 w-3.5 transition-opacity max-sm:pointer-events-auto max-sm:opacity-100", + selectionState === "none" + ? "pointer-events-none opacity-0 group-hover/item:pointer-events-auto group-hover/item:opacity-100 focus-visible:pointer-events-auto focus-visible:opacity-100" + : "opacity-100" + )} + /> + + )} + {isRenaming ? ( - - - - +
+ + + + + {isWatched && onRescan && ( { @@ -436,8 +459,9 @@ export const FolderNode = React.memo(function FolderNode({ Delete - - + + +
)}