Mobile UI scrolling fix and top bar redesign
All checks were successful
Automated Container Build / build-and-push (push) Successful in 40s

This commit is contained in:
Elijah 2026-05-24 09:03:27 -07:00
parent 7997ccb293
commit 14289b741f

View file

@ -208,6 +208,8 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const [sidebarOpen, setSidebarOpen] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(false);
const [mobileSearchOpen, setMobileSearchOpen] = useState(false); const [mobileSearchOpen, setMobileSearchOpen] = useState(false);
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const [mobileFabOpen, setMobileFabOpen] = useState(false);
const [currentPath, setCurrentPath] = useState(() => { const [currentPath, setCurrentPath] = useState(() => {
@ -1278,7 +1280,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
}, [displayFiles, activeSection, trashAutoPurgeDays]); }, [displayFiles, activeSection, trashAutoPurgeDays]);
return ( return (
<div className="flex h-screen w-full overflow-hidden" style={{ backgroundColor: 'var(--color-bg-primary)' }}> <div className={`flex ${isMobile ? 'h-[100dvh]' : 'h-screen'} w-full overflow-hidden`} style={{ backgroundColor: 'var(--color-bg-primary)' }}>
{isMobile && sidebarOpen && ( {isMobile && sidebarOpen && (
<div <div
className="fixed inset-0 bg-black/50 backdrop-blur-sm z-40" className="fixed inset-0 bg-black/50 backdrop-blur-sm z-40"
@ -1525,14 +1527,140 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
{(!isMobile || !mobileSearchOpen) && ( {(!isMobile || !mobileSearchOpen) && (
<div className="flex items-center gap-1 sm:gap-2"> <div className="flex items-center gap-1 sm:gap-2">
{isMobile ? (
<>
<div className="relative">
<button
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
className="p-2 rounded-lg transition-colors hover:bg-black/5 dark:hover:bg-white/5"
style={{ color: 'var(--color-text-secondary)' }}
>
<MoreVertical className="w-5 h-5" />
</button>
<AnimatePresence>
{mobileMenuOpen && (
<>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-40"
onClick={() => setMobileMenuOpen(false)}
/>
<motion.div
initial={{ opacity: 0, scale: 0.95, y: -10 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: -10 }}
className="absolute right-0 top-full mt-2 w-48 py-2 rounded-xl shadow-2xl border z-50 flex flex-col"
style={{ backgroundColor: 'var(--color-bg-elevated)', borderColor: 'var(--color-border)' }}
>
<button
onClick={() => { setMobileMenuOpen(false); toggleTheme(); }}
className="flex items-center gap-3 px-4 py-3 text-sm transition-colors hover:bg-black/5 dark:hover:bg-white/5"
style={{ color: 'var(--color-text-primary)' }}
>
{theme === 'dark' ? <Sun className="w-4.5 h-4.5" /> : <Moon className="w-4.5 h-4.5" />}
Theme: {theme === 'dark' ? 'Dark' : 'Light'}
</button>
<button
onClick={() => { setMobileMenuOpen(false); setViewMode(viewMode === 'grid' ? 'list' : 'grid'); }}
className="flex items-center gap-3 px-4 py-3 text-sm transition-colors hover:bg-black/5 dark:hover:bg-white/5"
style={{ color: 'var(--color-text-primary)' }}
>
{viewMode === 'grid' ? <List className="w-4.5 h-4.5" /> : <Grid3X3 className="w-4.5 h-4.5" />}
View: {viewMode === 'grid' ? 'Grid' : 'List'}
</button>
<div className="w-full h-px my-1" style={{ backgroundColor: 'var(--color-border-subtle)' }} />
<div className="px-4 py-2 text-xs font-semibold uppercase tracking-wider" style={{ color: 'var(--color-text-tertiary)' }}>Sort By</div>
{['name', 'size', 'date', 'type'].map(opt => (
<button
key={opt}
onClick={() => { setMobileMenuOpen(false); if (sortBy === opt) setSortAsc(!sortAsc); else setSortBy(opt as any); }}
className="flex items-center gap-3 px-4 py-2.5 text-sm transition-colors hover:bg-black/5 dark:hover:bg-white/5 capitalize"
style={{ color: sortBy === opt ? 'var(--color-accent)' : 'var(--color-text-primary)' }}
>
{opt}
{sortBy === opt && <ArrowUp className={`w-3.5 h-3.5 ml-auto ${sortAsc ? '' : 'rotate-180 transition-transform'}`} />}
</button>
))}
{activeSection === 'trash' && (
<>
<div className="w-full h-px my-1" style={{ backgroundColor: 'var(--color-border-subtle)' }} />
<button
onClick={() => { setMobileMenuOpen(false); setShowTrashModal(true); }}
className="flex items-center gap-3 px-4 py-3 text-sm transition-colors hover:bg-black/5 dark:hover:bg-white/5"
style={{ color: 'var(--color-danger)' }}
>
<Trash2 className="w-4.5 h-4.5" />
Empty Trash
</button>
</>
)}
</motion.div>
</>
)}
</AnimatePresence>
</div>
{activeSection === 'files' && (
<div className="relative">
<button
onClick={() => setMobileFabOpen(!mobileFabOpen)}
className="p-2 rounded-lg text-white transition-all hover:opacity-90 ml-1"
style={{ background: 'linear-gradient(135deg, var(--color-accent), #8b5cf6)' }}
>
<Plus className={`w-5 h-5 transition-transform ${mobileFabOpen ? 'rotate-45' : ''}`} />
</button>
<AnimatePresence>
{mobileFabOpen && (
<>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-40"
onClick={() => setMobileFabOpen(false)}
/>
<motion.div
initial={{ opacity: 0, scale: 0.95, y: -10 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.95, y: -10 }}
className="absolute right-0 top-full mt-2 w-48 py-2 rounded-xl shadow-2xl border z-50 flex flex-col"
style={{ backgroundColor: 'var(--color-bg-elevated)', borderColor: 'var(--color-border)' }}
>
<button
onClick={() => { setMobileFabOpen(false); setShowNewFolder(true); }}
className="flex items-center gap-3 px-4 py-3 text-sm transition-colors hover:bg-black/5 dark:hover:bg-white/5"
style={{ color: 'var(--color-text-primary)' }}
>
<FolderPlus className="w-4.5 h-4.5" />
New Folder
</button>
<button
onClick={() => { setMobileFabOpen(false); fileInputRef.current?.click(); }}
className="flex items-center gap-3 px-4 py-3 text-sm transition-colors hover:bg-black/5 dark:hover:bg-white/5"
style={{ color: 'var(--color-text-primary)' }}
>
<Upload className="w-4.5 h-4.5" />
Upload File
</button>
<input ref={fileInputRef} type="file" multiple className="hidden" onChange={handleFileUpload} />
</motion.div>
</>
)}
</AnimatePresence>
</div>
)}
</>
) : (
<>
{activeSection === 'trash' && ( {activeSection === 'trash' && (
<button <button
onClick={() => setShowTrashModal(true)} onClick={() => setShowTrashModal(true)}
className={`flex items-center gap-2 ${isMobile ? 'p-2' : 'px-4 py-2'} rounded-lg text-sm font-medium transition-all hover:opacity-90`} className={`flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-all hover:opacity-90`}
style={{ backgroundColor: 'rgba(239, 68, 68, 0.1)', color: 'var(--color-danger)' }} style={{ backgroundColor: 'rgba(239, 68, 68, 0.1)', color: 'var(--color-danger)' }}
> >
<Trash2 className="w-4 h-4" /> <Trash2 className="w-4 h-4" />
{!isMobile && "Empty Trash"} Empty Trash
</button> </button>
)} )}
@ -1551,14 +1679,8 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
<div className="relative group"> <div className="relative group">
<button className="flex items-center gap-1.5 p-2 rounded-lg transition-colors text-sm font-medium" style={{ color: 'var(--color-text-secondary)' }} title="Sort"> <button className="flex items-center gap-1.5 p-2 rounded-lg transition-colors text-sm font-medium" style={{ color: 'var(--color-text-secondary)' }} title="Sort">
{isMobile ? (
<ArrowUp className={`w-4.5 h-4.5 ${sortAsc ? '' : 'rotate-180 transition-transform'}`} />
) : (
<>
Sort by: <span className="capitalize">{sortBy}</span> Sort by: <span className="capitalize">{sortBy}</span>
{sortAsc ? <ArrowUp className="w-3 h-3" /> : <ArrowUp className="w-3 h-3 rotate-180 transition-transform" />} {sortAsc ? <ArrowUp className="w-3 h-3" /> : <ArrowUp className="w-3 h-3 rotate-180 transition-transform" />}
</>
)}
</button> </button>
<div className="absolute right-0 top-full pt-1 w-40 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto transition-all z-50"> <div className="absolute right-0 top-full pt-1 w-40 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto transition-all z-50">
<div className="w-full rounded-xl shadow-lg border overflow-hidden" style={{ backgroundColor: 'var(--color-bg-elevated)', borderColor: 'var(--color-border)' }}> <div className="w-full rounded-xl shadow-lg border overflow-hidden" style={{ backgroundColor: 'var(--color-bg-elevated)', borderColor: 'var(--color-border)' }}>
@ -1598,14 +1720,14 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
<button <button
id="upload-button" id="upload-button"
onClick={() => fileInputRef.current?.click()} onClick={() => fileInputRef.current?.click()}
className={`flex items-center gap-2 ${isMobile ? 'p-2' : 'px-4 py-2'} rounded-lg text-sm font-medium text-white transition-all hover:opacity-90`} className={`flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium text-white transition-all hover:opacity-90`}
style={{ style={{
background: 'linear-gradient(135deg, var(--color-accent), #8b5cf6)', background: 'linear-gradient(135deg, var(--color-accent), #8b5cf6)',
}} }}
title="Upload" title="Upload"
> >
<Upload className="w-4 h-4" /> <Upload className="w-4 h-4" />
{!isMobile && "Upload"} Upload
</button> </button>
<input <input
ref={fileInputRef} ref={fileInputRef}
@ -1618,6 +1740,8 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
)} )}
</> </>
)} )}
</>
)}
</div> </div>
)} )}
</header> </header>