From 5acb700f7100a361146cd6286ed8de88a921220e Mon Sep 17 00:00:00 2001 From: Connor Yoh Date: Tue, 5 Aug 2025 17:52:18 +0100 Subject: [PATCH] Formatting --- .../public/locales/en-GB/translation.json | 11 +- .../src/components/shared/FileManager.tsx | 13 +-- .../shared/fileManager/DesktopLayout.tsx | 67 ++++++++---- .../shared/fileManager/FileDetails.tsx | 25 +++-- .../shared/fileManager/FileListArea.tsx | 6 +- .../shared/fileManager/FileListItem.tsx | 101 ++++++++++-------- .../shared/fileManager/FileManagerContext.tsx | 45 +++++--- .../shared/fileManager/FileSourceButtons.tsx | 12 +-- .../shared/fileManager/MobileLayout.tsx | 62 ++++++++--- .../shared/fileManager/SearchInput.tsx | 9 +- .../components/shared/fileManager/types.ts | 1 + frontend/src/hooks/useFileManager.ts | 9 ++ frontend/src/services/fileStorage.ts | 26 +++++ frontend/src/styles/theme.css | 6 ++ 14 files changed, 269 insertions(+), 124 deletions(-) diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json index 0833a9650..ed3942172 100644 --- a/frontend/public/locales/en-GB/translation.json +++ b/frontend/public/locales/en-GB/translation.json @@ -1738,17 +1738,18 @@ "recent": "Recent", "localFiles": "Local Files", "googleDrive": "Google Drive", + "googleDriveShort": "Drive", "myFiles": "My Files", "noRecentFiles": "No recent files found", "dropFilesHint": "Drop files here to upload", "googleDriveNotAvailable": "Google Drive integration not available", "openFiles": "Open Files", "openFile": "Open File", - "details": "Details", - "fileName": "File Name", - "fileFormat": "File Format", - "fileSize": "File Size", - "fileVersion": "File Version", + "details": "File Details", + "fileName": "Name", + "fileFormat": "Format", + "fileSize": "Size", + "fileVersion": "Version", "totalSelected": "Total Selected", "dropFilesHere": "Drop files here" }, diff --git a/frontend/src/components/shared/FileManager.tsx b/frontend/src/components/shared/FileManager.tsx index cc930dff2..ee2a9df12 100644 --- a/frontend/src/components/shared/FileManager.tsx +++ b/frontend/src/components/shared/FileManager.tsx @@ -22,7 +22,7 @@ const FileManager: React.FC = ({ selectedTool }) => { const [isDragging, setIsDragging] = useState(false); const [isMobile, setIsMobile] = useState(false); - const { loadRecentFiles, handleRemoveFile, storeFile, convertToFile } = useFileManager(); + const { loadRecentFiles, handleRemoveFile, storeFile, convertToFile, touchFile } = useFileManager(); // File management handlers const isFileSupported = useCallback((fileName: string) => { @@ -70,7 +70,7 @@ const FileManager: React.FC = ({ selectedTool }) => { }, [handleRemoveFile, recentFiles]); useEffect(() => { - const checkMobile = () => setIsMobile(window.innerWidth < 768); + const checkMobile = () => setIsMobile(window.innerWidth < 1030); checkMobile(); window.addEventListener('resize', checkMobile); return () => window.removeEventListener('resize', checkMobile); @@ -99,10 +99,10 @@ const FileManager: React.FC = ({ selectedTool }) => { // Modal size constants for consistent scaling const modalHeight = '80vh'; - const modalWidth = isMobile ? '100%' : '60vw'; + const modalWidth = isMobile ? '100%' : '80vw'; const modalMaxWidth = isMobile ? '100%' : '1200px'; const modalMaxHeight = '1200px'; - const modalMinWidth = isMobile ? '320px' : '1030px'; + const modalMinWidth = isMobile ? '320px' : '800px'; return ( = ({ selectedTool }) => { multiple={true} activateOnClick={false} style={{ - padding: '1rem', height: '100%', width: '100%', border: 'none', borderRadius: '30px', - backgroundColor: 'transparent' + backgroundColor: 'var(--bg-file-manager)' }} styles={{ inner: { pointerEvents: 'all' } @@ -159,6 +158,8 @@ const FileManager: React.FC = ({ selectedTool }) => { isOpen={isFilesModalOpen} onFileRemove={handleRemoveFileByIndex} modalHeight={modalHeight} + storeFile={storeFile} + refreshRecentFiles={refreshRecentFiles} > {isMobile ? : } diff --git a/frontend/src/components/shared/fileManager/DesktopLayout.tsx b/frontend/src/components/shared/fileManager/DesktopLayout.tsx index 946164b4b..2cc11e8f8 100644 --- a/frontend/src/components/shared/fileManager/DesktopLayout.tsx +++ b/frontend/src/components/shared/fileManager/DesktopLayout.tsx @@ -15,11 +15,11 @@ const DesktopLayout: React.FC = () => { } = useFileManagerContext(); return ( - + {/* Column 1: File Sources */} - @@ -27,24 +27,55 @@ const DesktopLayout: React.FC = () => { {/* Column 2: File List */} - - {activeSource === 'recent' && ( - - )} - -
- 0 ? `calc(${modalHeight} - 6rem)` : '100%' - }} - /> + +
+ {activeSource === 'recent' && ( +
+ +
+ )} + +
+ 0 ? modalHeight : '100%', + backgroundColor: 'transparent', + border: 'none', + borderRadius: 0 + }} + /> +
{/* Column 3: File Details */} - -
+ +
diff --git a/frontend/src/components/shared/fileManager/FileDetails.tsx b/frontend/src/components/shared/fileManager/FileDetails.tsx index 03d8c38f0..0cdc0f764 100644 --- a/frontend/src/components/shared/fileManager/FileDetails.tsx +++ b/frontend/src/components/shared/fileManager/FileDetails.tsx @@ -62,9 +62,9 @@ const FileDetails: React.FC = ({ return ( {/* Compact mobile layout */} - + {/* Small preview */} - + {currentFile && getCurrentThumbnail() ? ( = ({ onClick={onOpenFiles} disabled={!hasSelection} fullWidth + style={{ + backgroundColor: hasSelection ? 'var(--btn-open-file)' : 'var(--mantine-color-gray-4)', + color: 'white' + }} > {selectedFiles.length > 1 ? t('fileManager.openFiles', `Open ${selectedFiles.length} Files`) @@ -145,7 +149,7 @@ const FileDetails: React.FC = ({ } return ( - + {/* Section 1: Thumbnail Preview */} @@ -182,7 +186,6 @@ const FileDetails: React.FC = ({ width: '100%', height: '100%', backgroundColor: 'var(--mantine-color-gray-2)', - borderRadius: '8px', boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)', transform: 'translate(12px, 12px) rotate(2deg)', zIndex: 1 @@ -197,7 +200,6 @@ const FileDetails: React.FC = ({ width: '100%', height: '100%', backgroundColor: 'var(--mantine-color-gray-1)', - borderRadius: '8px', boxShadow: '0 3px 10px rgba(0, 0, 0, 0.12)', transform: 'translate(6px, 6px) rotate(1deg)', zIndex: 2 @@ -212,14 +214,13 @@ const FileDetails: React.FC = ({ src={getCurrentThumbnail()} alt={currentFile.name} fit="contain" - radius="md" style={{ maxWidth: '100%', maxHeight: '100%', width: 'auto', height: 'auto', boxShadow: '0 6px 16px rgba(0, 0, 0, 0.2)', - borderRadius: '8px', + position: 'relative', zIndex: 3, transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', @@ -232,7 +233,6 @@ const FileDetails: React.FC = ({ width: '80%', height: '80%', backgroundColor: 'var(--mantine-color-gray-1)', - borderRadius: 8, boxShadow: '0 6px 16px rgba(0, 0, 0, 0.2)', position: 'relative', zIndex: 3, @@ -275,7 +275,7 @@ const FileDetails: React.FC = ({ - + {t('fileManager.fileName', 'Name')} @@ -328,10 +328,15 @@ const FileDetails: React.FC = ({ ); if (horizontal) { return ( - + {buttons} ); @@ -92,7 +92,7 @@ const FileSourceButtons: React.FC = ({ return ( - + {t('fileManager.myFiles', 'My Files')} {buttons} diff --git a/frontend/src/components/shared/fileManager/MobileLayout.tsx b/frontend/src/components/shared/fileManager/MobileLayout.tsx index 77cb66174..852b61b1d 100644 --- a/frontend/src/components/shared/fileManager/MobileLayout.tsx +++ b/frontend/src/components/shared/fileManager/MobileLayout.tsx @@ -14,8 +14,22 @@ const MobileLayout: React.FC = () => { modalHeight, } = useFileManagerContext(); + // Calculate the height more accurately based on actual content + const calculateFileListHeight = () => { + // Base modal height minus padding and gaps + const baseHeight = `calc(${modalHeight} - 2rem)`; // Account for Stack padding + + // Estimate heights of fixed components + const fileSourceHeight = '3rem'; // FileSourceButtons height + const fileDetailsHeight = selectedFiles.length > 0 ? '10rem' : '8rem'; // FileDetails compact height + const searchHeight = activeSource === 'recent' ? '3rem' : '0rem'; // SearchInput height + const gapHeight = activeSource === 'recent' ? '3rem' : '2rem'; // Stack gaps + + return `calc(${baseHeight} - ${fileSourceHeight} - ${fileDetailsHeight} - ${searchHeight} - ${gapHeight})`; + }; + return ( - + {/* Section 1: File Sources - Fixed at top */} @@ -25,24 +39,44 @@ const MobileLayout: React.FC = () => { - {/* Section 3: Search Bar - Fixed above file list */} - {activeSource === 'recent' && ( - - + {/* Section 3 & 4: Search Bar + File List - Unified background extending to modal edge */} + + {activeSource === 'recent' && ( + + + + )} + + + - )} - - {/* Section 4: File List - Fixed height scrollable area */} - - 0 ? '300px' : '200px'})`} - scrollAreaStyle={{ maxHeight: '400px', minHeight: '150px' }} - /> {/* Hidden file input for local file selection */} - + ); }; diff --git a/frontend/src/components/shared/fileManager/SearchInput.tsx b/frontend/src/components/shared/fileManager/SearchInput.tsx index b898dcd46..7a86e7300 100644 --- a/frontend/src/components/shared/fileManager/SearchInput.tsx +++ b/frontend/src/components/shared/fileManager/SearchInput.tsx @@ -18,7 +18,14 @@ const SearchInput: React.FC = ({ style }) => { leftSection={} value={searchTerm} onChange={(e) => onSearchChange(e.target.value)} - style={style} + + style={{ padding: '0.5rem', ...style }} + styles={{ + input: { + border: 'none', + backgroundColor: 'transparent' + } + }} /> ); }; diff --git a/frontend/src/components/shared/fileManager/types.ts b/frontend/src/components/shared/fileManager/types.ts index 04ee0012b..36b523295 100644 --- a/frontend/src/components/shared/fileManager/types.ts +++ b/frontend/src/components/shared/fileManager/types.ts @@ -9,5 +9,6 @@ export interface FileListItemProps { onSelect: () => void; onRemove: () => void; onDoubleClick?: () => void; + isLast?: boolean; } diff --git a/frontend/src/hooks/useFileManager.ts b/frontend/src/hooks/useFileManager.ts index d8e776f75..5d1e15b8f 100644 --- a/frontend/src/hooks/useFileManager.ts +++ b/frontend/src/hooks/useFileManager.ts @@ -111,12 +111,21 @@ export const useFileManager = () => { }; }, [convertToFile]); + const touchFile = useCallback(async (id: string) => { + try { + await fileStorage.touchFile(id); + } catch (error) { + console.error('Failed to touch file:', error); + } + }, []); + return { loading, convertToFile, loadRecentFiles, handleRemoveFile, storeFile, + touchFile, createFileSelectionHandlers }; }; \ No newline at end of file diff --git a/frontend/src/services/fileStorage.ts b/frontend/src/services/fileStorage.ts index 9ba2e7def..5fd5739e8 100644 --- a/frontend/src/services/fileStorage.ts +++ b/frontend/src/services/fileStorage.ts @@ -225,6 +225,32 @@ class FileStorageService { }); } + /** + * Update the lastModified timestamp of a file (for most recently used sorting) + */ + async touchFile(id: string): Promise { + if (!this.db) await this.init(); + return new Promise((resolve, reject) => { + const transaction = this.db!.transaction([this.storeName], 'readwrite'); + const store = transaction.objectStore(this.storeName); + + const getRequest = store.get(id); + getRequest.onsuccess = () => { + const file = getRequest.result; + if (file) { + // Update lastModified to current timestamp + file.lastModified = Date.now(); + const updateRequest = store.put(file); + updateRequest.onsuccess = () => resolve(true); + updateRequest.onerror = () => reject(updateRequest.error); + } else { + resolve(false); // File not found + } + }; + getRequest.onerror = () => reject(getRequest.error); + }); + } + /** * Clear all stored files */ diff --git a/frontend/src/styles/theme.css b/frontend/src/styles/theme.css index 7cdb46c55..945ad9935 100644 --- a/frontend/src/styles/theme.css +++ b/frontend/src/styles/theme.css @@ -74,6 +74,9 @@ --bg-muted: #f3f4f6; --bg-background: #f9fafb; --bg-toolbar: #ffffff; + --bg-file-manager: #F5F6F8; + --bg-file-list: #ffffff; + --btn-open-file: #0A8BFF; --text-primary: #111827; --text-secondary: #4b5563; --text-muted: #6b7280; @@ -144,6 +147,9 @@ --bg-muted: #1F2329; --bg-background: #2A2F36; --bg-toolbar: #272A2E; + --bg-file-manager: #1F2329; + --bg-file-list: #2A2F36; + --btn-open-file: #0A8BFF; --text-primary: #f9fafb; --text-secondary: #d1d5db; --text-muted: #9ca3af;