From 548d6f5c40a2e1d0bc665a6b3eaff79ce31f47f7 Mon Sep 17 00:00:00 2001 From: Puja-Rachchh Date: Tue, 16 Sep 2025 08:12:11 +0530 Subject: [PATCH 1/2] Made the sidebar more responsive --- .../src/components/FileExplorer.css | 441 ++++++++++++++++-- .../src/components/FileExplorer.jsx | 291 +++++++----- .../vite-project/src/components/FileTab.css | 134 ------ .../vite-project/src/components/FileTab.jsx | 63 +-- 4 files changed, 616 insertions(+), 313 deletions(-) diff --git a/frontend/vite-project/src/components/FileExplorer.css b/frontend/vite-project/src/components/FileExplorer.css index f6a1603..9ec0776 100644 --- a/frontend/vite-project/src/components/FileExplorer.css +++ b/frontend/vite-project/src/components/FileExplorer.css @@ -1,54 +1,200 @@ .file-explorer { background: var(--explorer-bg, #252526); border: 1px solid var(--explorer-border, #404040); - border-radius: 4px; - margin-bottom: 20px; + border-radius: 0.25rem; + margin-bottom: 1.25rem; + width: 100%; + max-width: 20rem; + min-width: 3rem; + position: relative; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + display: flex; + flex-direction: column; + height: 100%; +} + +.file-explorer.collapsed { + max-width: 3.5rem; + min-width: 3.5rem; +} + +.file-explorer.mobile-open .file-explorer-content { + transform: translateX(0); +} + +/* Mobile and responsive controls */ +.mobile-toggle-btn { + display: none; + position: fixed; + top: 1rem; + left: 1rem; + z-index: 1001; + background: var(--btn-primary-bg, #007acc); + border: none; + border-radius: 0.375rem; + width: 2.5rem; + height: 2.5rem; + cursor: pointer; + transition: all 0.2s ease; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); +} + +.mobile-toggle-btn:hover { + background: var(--btn-primary-hover, #0086d1); + transform: scale(1.05); +} + +.hamburger { + width: 1.25rem; + height: 1rem; + position: relative; + display: inline-block; +} + +.hamburger::before, +.hamburger::after, +.hamburger { + border-top: 2px solid white; +} + +.hamburger::before, +.hamburger::after { + content: ''; + position: absolute; + width: 100%; +} + +.hamburger::before { + top: 0.25rem; +} + +.hamburger::after { + top: 0.5rem; +} + +.sidebar-toggle-btn { + position: absolute; + top: 0.5rem; + right: -0.75rem; + z-index: 10; + background: var(--btn-primary-bg, #007acc); + border: none; + border-radius: 50%; + width: 1.5rem; + height: 1.5rem; + cursor: pointer; + transition: all 0.2s ease; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.75rem; + color: white; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.sidebar-toggle-btn:hover { + background: var(--btn-primary-hover, #0086d1); + transform: scale(1.1); +} + +.toggle-icon { + transition: transform 0.2s ease; +} + +.toggle-icon.collapsed { + transform: rotate(180deg); +} + +.file-explorer-content { + display: flex; + flex-direction: column; + height: 100%; + width: 100%; + transition: transform 0.3s ease; +} + +.mobile-overlay { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + z-index: 999; } .file-explorer-header { display: flex; justify-content: space-between; align-items: center; - padding: 8px 12px; + padding: 0.5rem 0.75rem; background: var(--explorer-header-bg, #2d2d2d); border-bottom: 1px solid var(--explorer-border, #404040); - border-radius: 4px 4px 0 0; + border-radius: 0.25rem 0.25rem 0 0; + flex-shrink: 0; } /* File Actions Toolbar */ .file-actions-toolbar { display: flex; - flex-wrap: wrap; - gap: 8px; - padding: 8px 12px; + flex-direction: column; + gap: 0.5rem; + padding: 0.5rem 0.75rem; background: var(--explorer-bg, #252526); border-bottom: 1px solid var(--explorer-border, #404040); + flex-shrink: 0; +} + +.file-explorer.collapsed .file-actions-toolbar { + padding: 0.25rem; } .file-actions-toolbar .import-actions, .file-actions-toolbar .export-actions { display: flex; - gap: 8px; + gap: 0.5rem; align-items: center; + flex-wrap: wrap; +} + +.file-explorer.collapsed .file-actions-toolbar .import-actions, +.file-explorer.collapsed .file-actions-toolbar .export-actions { + flex-direction: column; + gap: 0.25rem; } .file-actions-toolbar button { display: flex; align-items: center; - gap: 6px; - padding: 6px 10px; - border-radius: 4px; + gap: 0.375rem; + padding: 0.375rem 0.625rem; + border-radius: 0.25rem; border: 1px solid var(--btn-border, #555); background: var(--btn-bg, #3a3d41); color: var(--btn-text, #e0e0e0); - font-size: 13px; + font-size: 0.8125rem; cursor: pointer; transition: all 0.2s ease; + white-space: nowrap; + min-width: 0; + flex-shrink: 0; +} + +.file-explorer.collapsed .file-actions-toolbar button { + padding: 0.375rem; + min-width: 2rem; + justify-content: center; +} + +.file-explorer.collapsed .file-actions-toolbar button .btn-text { + display: none; } .file-actions-toolbar button:hover { background: var(--btn-hover-bg, #4a4e54); border-color: var(--btn-hover-border, #666); + transform: translateY(-1px); } .file-actions-toolbar .import-files-btn { @@ -94,9 +240,13 @@ .file-explorer-header h3 { margin: 0; - font-size: 14px; + font-size: 0.875rem; font-weight: 600; color: var(--explorer-text, #cccccc); + transition: all 0.2s ease; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .file-actions { @@ -135,42 +285,50 @@ background: var(--btn-primary-bg, #007acc); border: none; color: white; - width: 24px; - height: 24px; - border-radius: 3px; + width: 1.5rem; + height: 1.5rem; + border-radius: 0.1875rem; cursor: pointer; - font-size: 16px; + font-size: 1rem; font-weight: bold; display: flex; align-items: center; justify-content: center; - transition: background-color 0.2s ease; + transition: all 0.2s ease; + flex-shrink: 0; } .new-file-btn:hover { background: var(--btn-primary-hover, #0086d1); + transform: scale(1.05); } .new-file-form-container { - padding: 12px; + padding: 0.75rem; background: var(--form-bg, #1e1e1e); border-bottom: 1px solid var(--explorer-border, #404040); + flex-shrink: 0; +} + +.file-explorer.collapsed .new-file-form-container { + padding: 0.5rem; } .new-file-form { display: flex; flex-direction: column; - gap: 8px; + gap: 0.5rem; } .new-file-input { background: var(--input-bg, #3c3c3c); border: 1px solid var(--input-border, #555555); color: var(--input-text, #ffffff); - padding: 6px 8px; - border-radius: 3px; - font-size: 13px; + padding: 0.375rem 0.5rem; + border-radius: 0.1875rem; + font-size: 0.8125rem; outline: none; + transition: border-color 0.2s ease; } .new-file-input:focus { @@ -179,17 +337,34 @@ .new-file-buttons { display: flex; - gap: 6px; + gap: 0.375rem; justify-content: flex-end; } +.file-explorer.collapsed .new-file-buttons { + justify-content: center; +} + .create-btn, .cancel-btn { - padding: 4px 12px; + padding: 0.25rem 0.75rem; border: none; - border-radius: 3px; - font-size: 12px; + border-radius: 0.1875rem; + font-size: 0.75rem; cursor: pointer; transition: all 0.2s ease; + min-width: 0; + flex-shrink: 0; +} + +.file-explorer.collapsed .create-btn, +.file-explorer.collapsed .cancel-btn { + padding: 0.25rem; + min-width: 1.5rem; + width: 1.5rem; + height: 1.5rem; + display: flex; + align-items: center; + justify-content: center; } .create-btn { @@ -199,6 +374,7 @@ .create-btn:hover { background: var(--btn-success-hover, #218838); + transform: translateY(-1px); } .cancel-btn { @@ -208,23 +384,36 @@ .cancel-btn:hover { background: var(--btn-secondary-hover, #5a6268); + transform: translateY(-1px); } .file-tabs-container { display: flex; flex-direction: column; - gap: 2px; - padding: 8px; - max-height: 300px; + gap: 0.125rem; + padding: 0.5rem; + max-height: 18.75rem; overflow-y: auto; + flex-grow: 1; + min-height: 0; +} + +.file-explorer.collapsed .file-tabs-container { + padding: 0.25rem; } .no-files-message { - padding: 20px; + padding: 1.25rem; text-align: center; color: var(--text-muted, #888888); font-style: italic; - font-size: 13px; + font-size: 0.8125rem; + line-height: 1.4; +} + +.file-explorer.collapsed .no-files-message { + padding: 0.5rem 0.25rem; + font-size: 0.75rem; } .context-menu { @@ -285,7 +474,7 @@ /* Scrollbar styling */ .file-tabs-container::-webkit-scrollbar { - width: 6px; + width: 0.375rem; } .file-tabs-container::-webkit-scrollbar-track { @@ -294,7 +483,7 @@ .file-tabs-container::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb, #404040); - border-radius: 3px; + border-radius: 0.1875rem; } .file-tabs-container::-webkit-scrollbar-thumb:hover { @@ -312,3 +501,187 @@ .light-mode .file-tabs-container::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-thumb-hover, #a8a8a8); } + +/* Responsive Media Queries */ + +/* Tablet and smaller desktop */ +@media (max-width: 1024px) { + .file-explorer { + max-width: 16rem; + } + + .file-actions-toolbar { + gap: 0.25rem; + } + + .file-actions-toolbar button { + font-size: 0.75rem; + padding: 0.25rem 0.5rem; + } + + .sidebar-toggle-btn { + display: flex; + } +} + +/* Mobile landscape and smaller tablets */ +@media (max-width: 768px) { + .sidebar-toggle-btn { + display: none !important; + } + + .mobile-toggle-btn { + display: flex; + } + + .mobile-overlay { + display: block; + } + + .file-explorer { + position: fixed; + top: 0; + left: 0; + height: 100vh; + max-width: 20rem; + min-width: 20rem; + z-index: 1000; + margin: 0; + border-radius: 0; + transform: translateX(-100%); + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); + } + + .file-explorer.mobile-open { + transform: translateX(0); + } + + .file-explorer.collapsed { + max-width: 20rem; + min-width: 20rem; + } + + .file-explorer-content { + height: 100vh; + overflow: hidden; + } + + .file-tabs-container { + max-height: none; + flex-grow: 1; + padding: 0.75rem; + } + + .file-actions-toolbar { + flex-direction: column; + gap: 0.5rem; + padding: 0.75rem; + } + + .file-actions-toolbar .import-actions, + .file-actions-toolbar .export-actions { + justify-content: stretch; + } + + .file-actions-toolbar button { + flex: 1; + justify-content: center; + min-width: auto; + } +} + +/* Mobile portrait */ +@media (max-width: 480px) { + .file-explorer { + max-width: 16rem; + min-width: 16rem; + } + + .file-explorer.mobile-open { + max-width: 16rem; + min-width: 16rem; + } + + .mobile-toggle-btn { + width: 2.25rem; + height: 2.25rem; + } + + .file-actions-toolbar button { + font-size: 0.75rem; + padding: 0.5rem; + } + + .new-file-form-container { + padding: 0.5rem; + } + + .file-tabs-container { + padding: 0.5rem; + } +} + +/* Very small screens */ +@media (max-width: 360px) { + .file-explorer { + max-width: 14rem; + min-width: 14rem; + } + + .file-explorer.mobile-open { + max-width: 14rem; + min-width: 14rem; + } +} + +/* High DPI screens */ +@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { + .mobile-toggle-btn, + .sidebar-toggle-btn, + .new-file-btn { + border: 0.5px solid rgba(255, 255, 255, 0.1); + } +} + +/* Reduced motion preference */ +@media (prefers-reduced-motion: reduce) { + .file-explorer, + .file-explorer-content, + .mobile-toggle-btn, + .sidebar-toggle-btn, + .toggle-icon, + .file-actions-toolbar button, + .create-btn, + .cancel-btn { + transition: none; + } +} + +/* Focus styles for accessibility */ +.mobile-toggle-btn:focus, +.sidebar-toggle-btn:focus, +.new-file-btn:focus, +.file-actions-toolbar button:focus, +.create-btn:focus, +.cancel-btn:focus { + outline: 2px solid var(--focus-outline, #007acc); + outline-offset: 2px; +} + +/* Print styles */ +@media print { + .mobile-toggle-btn, + .sidebar-toggle-btn, + .file-actions-toolbar, + .mobile-overlay { + display: none !important; + } + + .file-explorer { + position: static; + transform: none; + max-width: none; + border: 1px solid #000; + page-break-inside: avoid; + } +} diff --git a/frontend/vite-project/src/components/FileExplorer.jsx b/frontend/vite-project/src/components/FileExplorer.jsx index 01d03ca..1b5e54a 100644 --- a/frontend/vite-project/src/components/FileExplorer.jsx +++ b/frontend/vite-project/src/components/FileExplorer.jsx @@ -15,6 +15,8 @@ const FileExplorer = ({ const [showNewFileForm, setShowNewFileForm] = useState(false); const [newFileName, setNewFileName] = useState(''); const [showContextMenu, setShowContextMenu] = useState(null); + const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false); + const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const fileInputRef = React.useRef(null); const folderInputRef = React.useRef(null); @@ -50,6 +52,14 @@ const FileExplorer = ({ setShowContextMenu(null); }; + const toggleSidebar = () => { + setIsSidebarCollapsed(!isSidebarCollapsed); + }; + + const toggleMobileMenu = () => { + setIsMobileMenuOpen(!isMobileMenuOpen); + }; + // Close context menu when clicking outside React.useEffect(() => { const handleClick = () => closeContextMenu(); @@ -57,6 +67,23 @@ const FileExplorer = ({ return () => document.removeEventListener('click', handleClick); }, []); + // Handle responsive behavior + React.useEffect(() => { + const handleResize = () => { + if (window.innerWidth < 768) { + setIsSidebarCollapsed(true); + } else if (window.innerWidth > 1024) { + setIsSidebarCollapsed(false); + setIsMobileMenuOpen(false); + } + }; + + window.addEventListener('resize', handleResize); + handleResize(); // Call once on mount + + return () => window.removeEventListener('resize', handleResize); + }, []); + // Import: read selected FileList and create files in room const importFileList = async (fileList) => { if (!fileList || fileList.length === 0) return; @@ -144,135 +171,167 @@ const FileExplorer = ({ }; return ( -
-
-

Files

- -
+
+ {/* Mobile hamburger button */} + - {/* File Actions Toolbar */} -
-
- - + +
+
+

{isSidebarCollapsed ? 'F' : 'Files'}

+
-
- - + + {/* File Actions Toolbar */} +
+
+ + +
+
+ + +
+ {/* Hidden inputs for file/folder selection */} + +
- {/* Hidden inputs for file/folder selection */} - - -
- {showNewFileForm && ( -
-
- setNewFileName(e.target.value)} - placeholder="Enter filename (e.g., main.js)" - className="new-file-input" - autoFocus - /> -
- - + {showNewFileForm && ( +
+ + setNewFileName(e.target.value)} + placeholder={isSidebarCollapsed ? "filename.js" : "Enter filename (e.g., main.js)"} + className="new-file-input" + autoFocus + /> +
+ + +
+ +
+ )} + +
+ {files.map((file) => ( +
handleContextMenu(e, file.filename)} + > + onFileSwitch(file.filename, userName)} + onClose={files.length > 1 ? (filename) => handleFileDelete(filename) : null} + onRename={onFileRename} + isRenamable={true} + isCollapsed={isSidebarCollapsed} + />
- + ))}
- )} -
- {files.map((file) => ( + {files.length === 0 && ( +
+ {isSidebarCollapsed ? 'No files' : 'No files in this room. Create a new file to get started.'} +
+ )} + + {/* Context Menu */} + {showContextMenu && (
handleContextMenu(e, file.filename)} + className="context-menu" + style={{ + position: 'fixed', + left: showContextMenu.x, + top: showContextMenu.y, + zIndex: 1000 + }} > - onFileSwitch(file.filename, userName)} - onClose={files.length > 1 ? (filename) => handleFileDelete(filename) : null} - onRename={onFileRename} - isRenamable={true} - /> + +
- ))} + )}
- {files.length === 0 && ( -
- No files in this room. Create a new file to get started. -
- )} - - {/* Context Menu */} - {showContextMenu && ( -
- - -
- )} + {/* Mobile overlay */} + {isMobileMenuOpen &&
}
); }; diff --git a/frontend/vite-project/src/components/FileTab.css b/frontend/vite-project/src/components/FileTab.css index 5ca90c3..e69de29 100644 --- a/frontend/vite-project/src/components/FileTab.css +++ b/frontend/vite-project/src/components/FileTab.css @@ -1,134 +0,0 @@ -.file-tab { - display: flex; - align-items: center; - padding: 8px 12px; - background: var(--tab-bg, #2d2d2d); - border: 1px solid var(--tab-border, #404040); - border-bottom: none; - border-radius: 4px 4px 0 0; - cursor: pointer; - position: relative; - min-width: 120px; - max-width: 200px; - transition: all 0.2s ease; - user-select: none; - gap: 6px; -} -.typing-indicator { - font-size: 0.9rem; - color: #888; - margin-top: 4px; - padding-left: 8px; - font-style: italic; -} - -.file-tab:hover { - background: var(--tab-hover-bg, #3d3d3d); -} - -.file-tab.active { - background: var(--tab-active-bg, #1e1e1e); - border-color: var(--tab-active-border, #007acc); - border-bottom: 1px solid var(--tab-active-bg, #1e1e1e); -} - -.file-icon { - font-size: 14px; - flex-shrink: 0; -} - -.file-name { - flex: 1; - font-size: 13px; - color: var(--tab-text, #cccccc); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.file-tab.active .file-name { - color: var(--tab-active-text, #ffffff); -} - -.file-close-btn { - background: none; - border: none; - color: var(--tab-close, #999999); - font-size: 16px; - font-weight: bold; - cursor: pointer; - padding: 0; - width: 16px; - height: 16px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 2px; - flex-shrink: 0; - opacity: 0; - transition: all 0.2s ease; -} - -.file-tab:hover .file-close-btn { - opacity: 1; -} - -.file-close-btn:hover { - background: var(--tab-close-hover-bg, #ff6b6b); - color: white; -} - -.file-modified-indicator { - color: var(--tab-modified, #ffa500); - font-size: 12px; - flex-shrink: 0; -} - -.file-rename-form { - flex: 1; - margin: 0; -} - -.file-rename-input { - width: 100%; - background: var(--input-bg, #404040); - border: 1px solid var(--input-border, #007acc); - color: var(--input-text, #ffffff); - padding: 2px 4px; - font-size: 13px; - border-radius: 2px; - outline: none; -} - -/* Light mode styles */ -.light-mode .file-tab { - --tab-bg: #f3f3f3; - --tab-border: #d0d0d0; - --tab-hover-bg: #e8e8e8; - --tab-active-bg: #ffffff; - --tab-active-border: #007acc; - --tab-text: #333333; - --tab-active-text: #000000; - --tab-close: #666666; - --tab-close-hover-bg: #ff6b6b; - --tab-modified: #ff8c00; - --input-bg: #ffffff; - --input-border: #007acc; - --input-text: #000000; -} - -/* Animation for new tabs */ -.file-tab { - animation: slideInTab 0.2s ease-out; -} - -@keyframes slideInTab { - from { - opacity: 0; - transform: translateY(-10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} diff --git a/frontend/vite-project/src/components/FileTab.jsx b/frontend/vite-project/src/components/FileTab.jsx index 71fdea9..6fdb83c 100644 --- a/frontend/vite-project/src/components/FileTab.jsx +++ b/frontend/vite-project/src/components/FileTab.jsx @@ -12,6 +12,7 @@ const FileTab = ({ onClose, onRename, isRenamable = true, + isCollapsed = false, roomId, currentUser }) => { @@ -104,40 +105,44 @@ const FileTab = ({ return (
{getFileIcon(file.filename)} - {isEditing ? ( -
- { - setIsEditing(false); - socket.emit('stopTyping', { roomId, user: currentUser }); - }} - className="file-rename-input" - autoFocus - /> -
- ) : ( - {file.filename} - )} - - {onClose && ( - + {!isCollapsed && ( + <> + {isEditing ? ( +
+ { + setIsEditing(false); + socket.emit('stopTyping', { roomId, user: currentUser }); + }} + className="file-rename-input" + autoFocus + /> +
+ ) : ( + {file.filename} + )} + + {onClose && ( + + )} + )} {file.lastModified && !isActive && ( @@ -146,7 +151,7 @@ const FileTab = ({ )} - + {!isCollapsed && }
); }; From ff6a896717672b945ccd3f42dab36b5a0aadd500 Mon Sep 17 00:00:00 2001 From: Puja-Rachchh Date: Tue, 16 Sep 2025 09:46:00 +0530 Subject: [PATCH 2/2] Errors resolved --- .../src/components/FileExplorer.css | 137 ++++++++++++------ .../src/components/FileExplorer.jsx | 35 ++++- .../src/components/ResizableLayout.css | 50 +++---- 3 files changed, 145 insertions(+), 77 deletions(-) diff --git a/frontend/vite-project/src/components/FileExplorer.css b/frontend/vite-project/src/components/FileExplorer.css index 9d3a8e2..d6b0fe5 100644 --- a/frontend/vite-project/src/components/FileExplorer.css +++ b/frontend/vite-project/src/components/FileExplorer.css @@ -153,36 +153,39 @@ .file-actions-toolbar .import-actions, .file-actions-toolbar .export-actions { display: flex; - gap: 0.5rem; + gap: 0.375rem; align-items: center; - flex-wrap: wrap; + flex-wrap: nowrap; + width: 100%; } .file-explorer.collapsed .file-actions-toolbar .import-actions, .file-explorer.collapsed .file-actions-toolbar .export-actions { flex-direction: column; gap: 0.25rem; + width: 100%; } .file-actions-toolbar button { flex: 1; - min-width: 120px; + min-width: 0; + max-width: none; justify-content: center; white-space: nowrap; display: flex; align-items: center; gap: 0.375rem; - padding: 0.375rem 0.625rem; + padding: 0.375rem 0.5rem; border-radius: 0.25rem; border: 1px solid var(--btn-border, #555); background: var(--btn-bg, #3a3d41); color: var(--btn-text, #e0e0e0); - font-size: 0.8125rem; + font-size: 0.75rem; cursor: pointer; transition: all 0.2s ease; - white-space: nowrap; - min-width: 0; - flex-shrink: 0; + flex-shrink: 1; + overflow: hidden; + text-overflow: ellipsis; } .file-explorer.collapsed .file-actions-toolbar button { @@ -517,11 +520,27 @@ .file-actions-toolbar { gap: 0.25rem; + padding: 0.375rem 0.5rem; + } + + .file-actions-toolbar .import-actions, + .file-actions-toolbar .export-actions { + gap: 0.25rem; } .file-actions-toolbar button { - font-size: 0.75rem; - padding: 0.25rem 0.5rem; + font-size: 0.7rem; + padding: 0.25rem 0.375rem; + gap: 0.25rem; + min-width: 0; + flex: 1; + } + + .file-actions-toolbar button .btn-text { + font-size: 0.65rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .sidebar-toggle-btn { @@ -536,75 +555,90 @@ } .mobile-toggle-btn { - display: flex; + display: flex !important; } .mobile-overlay { - display: block; + display: block !important; } .file-explorer { - position: fixed; - top: 0; - left: 0; - height: 100vh; - max-width: 20rem; - min-width: 20rem; - z-index: 1000; - margin: 0; - border-radius: 0; - transform: translateX(-100%); - transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: fixed !important; + top: 0 !important; + left: 0 !important; + height: 100vh !important; + max-width: 20rem !important; + min-width: 20rem !important; + width: 20rem !important; + z-index: 1000 !important; + margin: 0 !important; + border-radius: 0 !important; + transform: translateX(-100%) !important; + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; } .file-explorer.mobile-open { - transform: translateX(0); + transform: translateX(0) !important; } .file-explorer.collapsed { - max-width: 20rem; - min-width: 20rem; + max-width: 20rem !important; + min-width: 20rem !important; + width: 20rem !important; } .file-explorer-content { - height: 100vh; - overflow: hidden; + height: 100vh !important; + overflow: hidden !important; } .file-tabs-container { - max-height: none; - flex-grow: 1; - padding: 0.75rem; + max-height: none !important; + flex-grow: 1 !important; + padding: 0.75rem !important; } .file-actions-toolbar { - flex-direction: column; - gap: 0.5rem; - padding: 0.75rem; + flex-direction: column !important; + gap: 0.5rem !important; + padding: 0.75rem !important; } .file-actions-toolbar .import-actions, .file-actions-toolbar .export-actions { - justify-content: stretch; + justify-content: stretch !important; + flex-direction: row !important; + gap: 0.375rem !important; } .file-actions-toolbar button { - flex: 1; - justify-content: center; - min-width: auto; + flex: 1 !important; + justify-content: center !important; + min-width: 0 !important; + max-width: none !important; + font-size: 0.75rem !important; + padding: 0.5rem 0.375rem !important; + white-space: nowrap !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + } + + .file-actions-toolbar button .btn-text { + display: inline !important; + font-size: 0.7rem !important; } } /* Mobile portrait */ @media (max-width: 480px) { .file-explorer { - max-width: 16rem; - min-width: 16rem; + max-width: 16rem !important; + min-width: 16rem !important; } .file-explorer.mobile-open { - max-width: 16rem; - min-width: 16rem; + max-width: 16rem !important; + min-width: 16rem !important; } .mobile-toggle-btn { @@ -612,9 +646,24 @@ height: 2.25rem; } + .file-actions-toolbar { + padding: 0.5rem !important; + gap: 0.375rem !important; + } + + .file-actions-toolbar .import-actions, + .file-actions-toolbar .export-actions { + gap: 0.25rem !important; + } + .file-actions-toolbar button { - font-size: 0.75rem; - padding: 0.5rem; + font-size: 0.7rem !important; + padding: 0.375rem 0.25rem !important; + gap: 0.125rem !important; + } + + .file-actions-toolbar button .btn-text { + font-size: 0.65rem !important; } .new-file-form-container { diff --git a/frontend/vite-project/src/components/FileExplorer.jsx b/frontend/vite-project/src/components/FileExplorer.jsx index 1b5e54a..16ffb7f 100644 --- a/frontend/vite-project/src/components/FileExplorer.jsx +++ b/frontend/vite-project/src/components/FileExplorer.jsx @@ -70,20 +70,45 @@ const FileExplorer = ({ // Handle responsive behavior React.useEffect(() => { const handleResize = () => { - if (window.innerWidth < 768) { + const width = window.innerWidth; + + if (width <= 768) { + // Mobile: force collapsed state and ensure mobile menu can be used setIsSidebarCollapsed(true); - } else if (window.innerWidth > 1024) { + } else if (width <= 1024) { + // Tablet: allow collapsed/expanded but close mobile menu + setIsMobileMenuOpen(false); + } else { + // Desktop: expand sidebar and close mobile menu setIsSidebarCollapsed(false); setIsMobileMenuOpen(false); } }; + // Add event listener window.addEventListener('resize', handleResize); - handleResize(); // Call once on mount + + // Call immediately to set initial state + handleResize(); + // Cleanup return () => window.removeEventListener('resize', handleResize); }, []); + // Prevent body scroll when mobile menu is open + React.useEffect(() => { + if (isMobileMenuOpen) { + document.body.style.overflow = 'hidden'; + } else { + document.body.style.overflow = ''; + } + + // Cleanup on unmount + return () => { + document.body.style.overflow = ''; + }; + }, [isMobileMenuOpen]); + // Import: read selected FileList and create files in room const importFileList = async (fileList) => { if (!fileList || fileList.length === 0) return; @@ -218,7 +243,7 @@ const FileExplorer = ({