Feature/v2/filemanager (#4121)

FileManager Component Overview

Purpose: Modal component for selecting and managing PDF files with
preview capabilities

  Architecture:
- Responsive Layouts: MobileLayout.tsx (stacked) vs DesktopLayout.tsx
(3-column)
- Central State: FileManagerContext handles file operations, selection,
and modal state
  - File Storage: IndexedDB persistence with thumbnail caching

  Key Components:
  - FileSourceButtons: Switch between Recent/Local/Drive sources
  - FileListArea: Scrollable file grid with search functionality
- FilePreview: PDF thumbnails with dynamic shadow stacking (1-2 shadow
pages based on file count)
  - FileDetails: File info card with metadata
  - CompactFileDetails: Mobile-optimized file info layout

  File Flow:
1. Users select source → browse/search files → select multiple files →
preview with navigation → open in
  tools
  2. Files persist across tool switches via FileContext integration
  3. Memory management handles large PDFs (up to 100GB+)

 ```mermaid
 graph TD
      FM[FileManager] --> ML[MobileLayout]
      FM --> DL[DesktopLayout]

      ML --> FSB[FileSourceButtons<br/>Recent/Local/Drive]
      ML --> FLA[FileListArea]
      ML --> FD[FileDetails]

      DL --> FSB
      DL --> FLA
      DL --> FD

      FLA --> FLI[FileListItem]
      FD --> FP[FilePreview]
      FD --> CFD[CompactFileDetails]

  ```

---------

Co-authored-by: Connor Yoh <[email protected]>
This commit is contained in:
ConnorYoh
2025-08-08 15:15:09 +01:00
committed by GitHub
co-authored by Connor Yoh
parent 9861332040
commit 7e3321ee16
33 changed files with 1818 additions and 506 deletions
+46 -9
View File
@@ -1,21 +1,58 @@
import React, { createContext, useContext } from 'react';
import { useFilesModal, UseFilesModalReturn } from '../hooks/useFilesModal';
import React, { createContext, useContext, useState, useCallback } from 'react';
import { useFileHandler } from '../hooks/useFileHandler';
interface FilesModalContextType extends UseFilesModalReturn {}
interface FilesModalContextType {
isFilesModalOpen: boolean;
openFilesModal: () => void;
closeFilesModal: () => void;
onFileSelect: (file: File) => void;
onFilesSelect: (files: File[]) => void;
onModalClose: () => void;
setOnModalClose: (callback: () => void) => void;
}
const FilesModalContext = createContext<FilesModalContextType | null>(null);
export const FilesModalProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const { addToActiveFiles, addMultipleFiles } = useFileHandler();
const filesModal = useFilesModal({
onFileSelect: addToActiveFiles,
onFilesSelect: addMultipleFiles,
});
const [isFilesModalOpen, setIsFilesModalOpen] = useState(false);
const [onModalClose, setOnModalClose] = useState<(() => void) | undefined>();
const openFilesModal = useCallback(() => {
setIsFilesModalOpen(true);
}, []);
const closeFilesModal = useCallback(() => {
setIsFilesModalOpen(false);
onModalClose?.();
}, [onModalClose]);
const handleFileSelect = useCallback((file: File) => {
addToActiveFiles(file);
closeFilesModal();
}, [addToActiveFiles, closeFilesModal]);
const handleFilesSelect = useCallback((files: File[]) => {
addMultipleFiles(files);
closeFilesModal();
}, [addMultipleFiles, closeFilesModal]);
const setModalCloseCallback = useCallback((callback: () => void) => {
setOnModalClose(() => callback);
}, []);
const contextValue: FilesModalContextType = {
isFilesModalOpen,
openFilesModal,
closeFilesModal,
onFileSelect: handleFileSelect,
onFilesSelect: handleFilesSelect,
onModalClose,
setOnModalClose: setModalCloseCallback,
};
return (
<FilesModalContext.Provider value={filesModal}>
<FilesModalContext.Provider value={contextValue}>
{children}
</FilesModalContext.Provider>
);