From daf749e6be13df718428e3491bc5a863c1c6b7ac Mon Sep 17 00:00:00 2001 From: Reece Browne <74901996+reecebrowne@users.noreply.github.com> Date: Tue, 25 Nov 2025 20:28:24 +0000 Subject: [PATCH] File in context indication (#4990) # Description of Changes --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --- .../public/locales/en-GB/translation.json | 2 + frontend/src/core/components/FileManager.tsx | 5 ++ .../components/fileManager/FileListArea.tsx | 3 ++ .../components/fileManager/FileListItem.tsx | 50 ++++++++++++++++--- .../src/core/contexts/FileManagerContext.tsx | 5 ++ frontend/src/core/styles/theme.css | 6 +++ 6 files changed, 65 insertions(+), 6 deletions(-) diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json index 0e72a79c75..2361b5235d 100644 --- a/frontend/public/locales/en-GB/translation.json +++ b/frontend/public/locales/en-GB/translation.json @@ -4686,7 +4686,9 @@ "download": "Download", "delete": "Delete", "unsupported": "Unsupported", + "active": "Active", "addToUpload": "Add to Upload", + "closeFile": "Close File", "deleteAll": "Delete All", "loadingFiles": "Loading files...", "noFiles": "No files available", diff --git a/frontend/src/core/components/FileManager.tsx b/frontend/src/core/components/FileManager.tsx index 440ab4acb4..0afe91d086 100644 --- a/frontend/src/core/components/FileManager.tsx +++ b/frontend/src/core/components/FileManager.tsx @@ -12,6 +12,7 @@ import { FileManagerProvider } from '@app/contexts/FileManagerContext'; import { Z_INDEX_FILE_MANAGER_MODAL } from '@app/styles/zIndex'; import { isGoogleDriveConfigured } from '@app/services/googleDrivePickerService'; import { loadScript } from '@app/utils/scriptLoader'; +import { useAllFiles } from '@app/contexts/FileContext'; interface FileManagerProps { selectedTool?: Tool | null; @@ -25,6 +26,9 @@ const FileManager: React.FC = ({ selectedTool }) => { const { loadRecentFiles, handleRemoveFile, loading } = useFileManager(); + // Get active file IDs from FileContext to show which files are already loaded + const { fileIds: activeFileIds } = useAllFiles(); + // File management handlers const isFileSupported = useCallback((fileName: string) => { if (!selectedTool?.supportedFormats) return true; @@ -175,6 +179,7 @@ const FileManager: React.FC = ({ selectedTool }) => { modalHeight={modalHeight} refreshRecentFiles={refreshRecentFiles} isLoading={loading} + activeFileIds={activeFileIds} > {isMobile ? : } diff --git a/frontend/src/core/components/fileManager/FileListArea.tsx b/frontend/src/core/components/fileManager/FileListArea.tsx index 439af6996d..1964dad542 100644 --- a/frontend/src/core/components/fileManager/FileListArea.tsx +++ b/frontend/src/core/components/fileManager/FileListArea.tsx @@ -30,6 +30,7 @@ const FileListArea: React.FC = ({ onDownloadSingle, isFileSupported, isLoading, + activeFileIds, } = useFileManagerContext(); const { t } = useTranslation(); @@ -55,6 +56,7 @@ const FileListArea: React.FC = ({ // All files in filteredFiles are now leaf files only const historyFiles = loadedHistoryFiles.get(file.id) || []; const isExpanded = expandedFileIds.has(file.id); + const isActive = activeFileIds.includes(file.id); return ( @@ -68,6 +70,7 @@ const FileListArea: React.FC = ({ onDoubleClick={() => onFileDoubleClick(file)} isHistoryFile={false} // All files here are leaf files isLatestVersion={true} // All files here are the latest versions + isActive={isActive} /> = ({ @@ -37,12 +40,14 @@ const FileListItem: React.FC = ({ onDownload, onDoubleClick, isHistoryFile = false, - isLatestVersion = false + isLatestVersion = false, + isActive = false }) => { const [isHovered, setIsHovered] = useState(false); const [isMenuOpen, setIsMenuOpen] = useState(false); const { t } = useTranslation(); const {expandedFileIds, onToggleExpansion, onUnzipFile } = useFileManagerContext(); + const { removeFiles } = useFileManagement(); // Check if this is a ZIP file const isZipFile = zipFileService.isZipFileStub(file); @@ -61,8 +66,10 @@ const FileListItem: React.FC = ({ = ({ paddingLeft: isHistoryFile ? '2rem' : '0.75rem', // Indent history files borderLeft: isHistoryFile ? '3px solid var(--mantine-color-blue-4)' : 'none' // Visual indicator for history }} - onClick={isHistoryFile ? undefined : (e) => onSelect(e.shiftKey)} + onClick={isHistoryFile || isActive ? undefined : (e) => onSelect(e.shiftKey)} onDoubleClick={onDoubleClick} onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} @@ -84,14 +91,16 @@ const FileListItem: React.FC = ({ {/* Checkbox for regular files only */} {}} // Handled by parent onClick size="sm" pl="sm" pr="xs" + disabled={isActive} + color={isActive ? "green" : undefined} styles={{ input: { - cursor: 'pointer' + cursor: isActive ? 'not-allowed' : 'pointer' } }} /> @@ -103,6 +112,19 @@ const FileListItem: React.FC = ({ {file.name} + {isActive && ( + + {t('fileManager.active', 'Active')} + + )} v{currentVersion} @@ -151,6 +173,22 @@ const FileListItem: React.FC = ({ + {/* Close file option for active files */} + {isActive && ( + <> + } + onClick={(e) => { + e.stopPropagation(); + removeFiles([file.id]); + }} + > + {t('fileManager.closeFile', 'Close File')} + + + + )} + {onDownload && ( } diff --git a/frontend/src/core/contexts/FileManagerContext.tsx b/frontend/src/core/contexts/FileManagerContext.tsx index 75c6d9276a..5d6fe3b105 100644 --- a/frontend/src/core/contexts/FileManagerContext.tsx +++ b/frontend/src/core/contexts/FileManagerContext.tsx @@ -20,6 +20,7 @@ interface FileManagerContextValue { fileGroups: Map; loadedHistoryFiles: Map; isLoading: boolean; + activeFileIds: FileId[]; // Handlers onSourceChange: (source: 'recent' | 'local' | 'drive') => void; @@ -63,6 +64,7 @@ interface FileManagerProviderProps { modalHeight: string; refreshRecentFiles: () => Promise; isLoading: boolean; + activeFileIds: FileId[]; } export const FileManagerProvider: React.FC = ({ @@ -77,6 +79,7 @@ export const FileManagerProvider: React.FC = ({ modalHeight, refreshRecentFiles, isLoading, + activeFileIds, }) => { const [activeSource, setActiveSource] = useState<'recent' | 'local' | 'drive'>('recent'); const [selectedFileIds, setSelectedFileIds] = useState([]); @@ -618,6 +621,7 @@ export const FileManagerProvider: React.FC = ({ fileGroups, loadedHistoryFiles, isLoading, + activeFileIds, // Handlers onSourceChange: handleSourceChange, @@ -654,6 +658,7 @@ export const FileManagerProvider: React.FC = ({ fileGroups, loadedHistoryFiles, isLoading, + activeFileIds, handleSourceChange, handleLocalFileClick, handleFileSelect, diff --git a/frontend/src/core/styles/theme.css b/frontend/src/core/styles/theme.css index ddf8c22bf4..30c9d974ae 100644 --- a/frontend/src/core/styles/theme.css +++ b/frontend/src/core/styles/theme.css @@ -12,6 +12,12 @@ /* Inline highlights in summary */ --spdf-compare-inline-removed-bg: rgba(255, 59, 48, 0.25); --spdf-compare-inline-added-bg: rgba(52, 199, 89, 0.25); + + /* File Manager active file colors */ + --file-active-bg: rgba(59, 130, 246, 0.1); /* Transparent blue for active file background */ + --file-active-badge-bg: rgba(34, 197, 94, 0.15); /* Transparent green for active badge */ + --file-active-badge-fg: #15803d; /* Green text for active badge */ + --file-active-badge-border: rgba(34, 197, 94, 0.3); /* Green border for active badge */ } /* CSS variables for Tailwind + Mantine integration */