"use client";
import React, { useState, useMemo, useEffect } from 'react';
import {
Search, Download, Trash2, Share, Star,
MoreVertical, Home, ChevronRight, ChevronLeft,
Folder, File, Image, Video, Music, FileText, Code, Database,
Clock, Users, Eye, Edit3, Copy, Scissors,
FolderPlus, Info, Lock, Menu,
ExternalLink, History, X
} from 'lucide-react';
import { cn } from "@/lib/utils";
import Footer from '../footer';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { Button } from '@/components/ui/button';
import { Separator } from '@/components/ui/separator';
import { ScrollArea } from '@/components/ui/scroll-area';
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger } from '@/components/ui/context-menu';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable";
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Input } from '@/components/ui/input';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet';
// Simple date formatting functions
const formatDate = (dateString) => {
const date = new Date(dateString);
return date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric'
});
};
const formatDateTime = (dateString) => {
const date = new Date(dateString);
return date.toLocaleString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: '2-digit',
hour12: true
});
};
const formatDistanceToNow = (date) => {
const now = new Date();
const diffMs = now.getTime() - new Date(date).getTime();
const diffMinutes = Math.floor(diffMs / (1000 * 60));
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
if (diffMinutes < 1) return 'now';
if (diffMinutes < 60) return `${diffMinutes}m ago`;
if (diffHours < 24) return `${diffHours}h ago`;
if (diffDays < 7) return `${diffDays}d ago`;
return formatDate(date);
};
// File system data
const fileSystemData = {
"": {
id: "root",
name: "My Drive",
path: "",
is_dir: true,
children: ["projects", "documents", "media", "shared"]
},
"projects": {
id: "projects",
name: "Projects",
path: "projects",
is_dir: true,
modified: "2025-01-15T10:30:00Z",
starred: true,
shared: false,
children: ["web-apps", "mobile-apps", "ai-research"]
},
"projects/web-apps": {
id: "web-apps",
name: "Web Applications",
path: "projects/web-apps",
is_dir: true,
modified: "2025-01-14T16:45:00Z",
starred: false,
shared: true,
children: ["dashboard-pro", "package.json", "README.md"]
},
"projects/web-apps/package.json": {
id: "package-json",
name: "package.json",
path: "projects/web-apps/package.json",
is_dir: false,
size: 2048,
type: "json",
modified: "2025-01-13T14:20:00Z",
starred: false,
shared: false
},
"projects/web-apps/README.md": {
id: "readme-md",
name: "README.md",
path: "projects/web-apps/README.md",
is_dir: false,
size: 5120,
type: "markdown",
modified: "2025-01-12T09:30:00Z",
starred: false,
shared: true
},
"documents": {
id: "documents",
name: "Documents",
path: "documents",
is_dir: true,
modified: "2025-01-14T12:00:00Z",
starred: false,
shared: false,
children: ["proposals", "Q1-Strategy.pdf", "Budget-2025.xlsx"]
},
"documents/Q1-Strategy.pdf": {
id: "q1-strategy",
name: "Q1 Strategy.pdf",
path: "documents/Q1-Strategy.pdf",
is_dir: false,
size: 1048576,
type: "pdf",
modified: "2025-01-10T15:30:00Z",
starred: true,
shared: true
},
"media": {
id: "media",
name: "Media",
path: "media",
is_dir: true,
modified: "2025-01-13T18:45:00Z",
starred: false,
shared: false,
children: ["photos", "videos", "vacation-2024.jpg"]
},
"media/vacation-2024.jpg": {
id: "vacation-photo",
name: "vacation-2024.jpg",
path: "media/vacation-2024.jpg",
is_dir: false,
size: 3145728,
type: "image",
modified: "2024-12-25T20:00:00Z",
starred: true,
shared: false
},
"shared": {
id: "shared",
name: "Shared",
path: "shared",
is_dir: true,
modified: "2025-01-12T11:20:00Z",
starred: false,
shared: true,
children: ["team-resources", "client-files"]
}
};
const getFileIcon = (item) => {
if (item.is_dir) {
return ;
}
const iconMap = {
pdf: ,
xlsx: ,
json:
,
markdown: ,
md: ,
jpg: ,
jpeg: ,
png: ,
mp4: ,
mp3:
};
return iconMap[item.type] || ;
};
const formatFileSize = (bytes) => {
if (!bytes) return '';
const sizes = ['B', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return `${(bytes / Math.pow(1024, i)).toFixed(1)} ${sizes[i]}`;
};
const FileContextMenu = ({ file, children, onAction }) => {
const contextMenuItems = [
{ icon: Eye, label: "Open", action: "open" },
{ icon: Download, label: "Download", action: "download" },
{ separator: true },
{
icon: Share, label: "Share", action: "share", submenu: [
{ icon: Users, label: "Share with team", action: "share-team" },
{ icon: ExternalLink, label: "Get link", action: "get-link" },
{ icon: Lock, label: "Restrict access", action: "restrict" },
]
},
{ icon: Star, label: file?.starred ? "Remove from starred" : "Add to starred", action: "star" },
{ separator: true },
{ icon: Copy, label: "Copy", action: "copy" },
{ icon: Scissors, label: "Cut", action: "cut" },
{ icon: Edit3, label: "Rename", action: "rename" },
{ separator: true },
{
icon: FolderPlus, label: "Move to", action: "move", submenu: [
{ icon: Folder, label: "Documents", action: "move-documents" },
{ icon: Folder, label: "Projects", action: "move-projects" },
{ icon: Folder, label: "Choose folder...", action: "move-choose" },
]
},
{ icon: Copy, label: "Make a copy", action: "duplicate" },
{ separator: true },
{ icon: History, label: "Version history", action: "history" },
{ icon: Info, label: "Details", action: "details" },
{ separator: true },
{ icon: Trash2, label: "Move to trash", action: "trash", destructive: true },
];
const renderContextMenuItem = (item, index) => {
if (item.separator) {
return ;
}
if (item.submenu) {
return (
{item.label}
{item.submenu.map((subItem, subIndex) => (
onAction(subItem.action, file)}
className="flex items-center gap-2"
>
{subItem.label}
))}
);
}
return (
onAction(item.action, file)}
className={cn(
"flex items-center gap-2",
item.destructive && "text-destructive focus:text-destructive"
)}
>
{item.label}
);
};
return (
{children}
{contextMenuItems.map(renderContextMenuItem)}
);
};
const FolderTree = ({ onSelect, selectedPath = undefined, isCollapsed = undefined, isMobile = undefined }) => {
const [expanded, setExpanded] = useState({ "": true, "projects": true });
const toggleExpand = (path) => {
setExpanded(prev => ({ ...prev, [path]: !prev[path] }));
onSelect(path);
};
const navLinks = [
{ title: "My Drive", path: "", icon: Home },
{ title: "Shared", path: "shared", icon: Users },
{ title: "Starred", path: "starred", icon: Star },
{ title: "Recent", path: "recent", icon: Clock },
{ title: "Trash", path: "trash", icon: Trash2 },
];
const renderTreeItem = (path, level = 0) => {
const item = fileSystemData[path];
if (!item || !item.is_dir) return null;
const isExpanded = expanded[path];
const isSelected = selectedPath === path;
return (
{!isCollapsed && isExpanded && item.children && (
{item.children.map(childPath => {
const fullPath = path ? `${path}/${childPath}` : childPath;
return renderTreeItem(fullPath, level + 1);
})}
)}
);
};
return (
{!isCollapsed && (
<>
{renderTreeItem("")}
>
)}
);
};
const FileList = ({ path, searchTerm, filterType, selectedFile, setSelectedFile, onContextAction, isMobile }) => {
const files = useMemo(() => {
const currentItem = fileSystemData[path];
if (!currentItem || !currentItem.is_dir || !currentItem.children) return [];
let items = currentItem.children.map(childName => {
const childPath = path ? `${path}/${childName}` : childName;
return fileSystemData[childPath];
}).filter(Boolean);
if (searchTerm) {
items = items.filter(item =>
item.name.toLowerCase().includes(searchTerm.toLowerCase())
);
}
if (filterType && filterType !== 'all') {
items = items.filter(item => {
if (filterType === 'folders') return item.is_dir;
if (filterType === 'files') return !item.is_dir;
if (filterType === 'starred') return item.starred;
return true;
});
}
return items.sort((a, b) => {
if (a.is_dir && !b.is_dir) return -1;
if (!a.is_dir && b.is_dir) return 1;
return a.name.localeCompare(b.name);
});
}, [path, searchTerm, filterType]);
return (
{files.map((item) => (
))}
);
};
const FileDisplay = ({ file, isMobile }) => {
if (!file) {
return (
No file selected
Select a file to view details
);
}
return (
Download
Share
Star
Rename
Make a copy
Move to trash
{getFileIcon(file)}
{file.name}
{file.is_dir ? 'Folder' : `${file.type?.toUpperCase() || 'File'} • ${formatFileSize(file.size)}`}
{file.modified && (
{formatDate(file.modified)}
)}
Location
/{file.path || ''}
Modified
{formatDateTime(file.modified)}
{!file.is_dir && (
Size
{formatFileSize(file.size)}
)}
);
};
export default function FileManager() {
const [isCollapsed, setIsCollapsed] = useState(false);
const [currentPath, setCurrentPath] = useState('');
const [searchTerm, setSearchTerm] = useState('');
const [filterType, setFilterType] = useState('all');
const [selectedFile, setSelectedFile] = useState(null);
const [isMobile, setIsMobile] = useState(false);
const [showMobileMenu, setShowMobileMenu] = useState(false);
const [activePanel, setActivePanel] = useState('files'); // 'tree', 'files', 'preview'
const currentItem = fileSystemData[currentPath];
const shortcuts = [
[
{ key: 'Q', label: 'Rename', action: () => console.log('Rename') },
{ key: 'W', label: 'View', action: () => console.log('View') },
{ key: 'E', label: 'Edit', action: () => console.log('Edit') },
{ key: 'R', label: 'Move', action: () => console.log('Move') },
{ key: 'T', label: 'MkDir', action: () => console.log('Make Directory') },
{ key: 'Y', label: 'Delete', action: () => console.log('Delete') },
{ key: 'U', label: 'Copy', action: () => console.log('Copy') },
{ key: 'I', label: 'Cut', action: () => console.log('Cut') },
{ key: 'O', label: 'Paste', action: () => console.log('Paste') },
{ key: 'P', label: 'Duplicate', action: () => console.log('Duplicate') },
],
[
{ key: 'A', label: 'Select', action: () => console.log('Select') },
{ key: 'S', label: 'Select All', action: () => console.log('Select All') },
{ key: 'D', label: 'Deselect', action: () => console.log('Deselect') },
{ key: 'G', label: 'Details', action: () => console.log('Details') },
{ key: 'H', label: 'History', action: () => console.log('History') },
{ key: 'J', label: 'Share', action: () => console.log('Share') },
{ key: 'K', label: 'Star', action: () => console.log('Star') },
{ key: 'L', label: 'Download', action: () => console.log('Download') },
{ key: 'Z', label: 'Upload', action: () => console.log('Upload') },
{ key: 'X', label: 'Refresh', action: () => console.log('Refresh') },
]
];
const handleContextAction = (action, file) => {
console.log(`Context action: ${action}`, file);
switch (action) {
case 'star':
console.log('Toggle star for', file.name);
break;
case 'share':
console.log('Share', file.name);
break;
case 'download':
console.log('Download', file.name);
break;
case 'trash':
console.log('Move to trash', file.name);
break;
case 'copy':
console.log('Copy', file.name);
break;
case 'cut':
console.log('Cut', file.name);
break;
case 'rename':
console.log('Rename', file.name);
break;
case 'duplicate':
console.log('Duplicate', file.name);
break;
case 'details':
console.log('Show details for', file.name);
setSelectedFile(file);
if (isMobile) setActivePanel('preview');
break;
default:
console.log('Unknown action:', action);
}
};
useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth < 768);
};
handleResize();
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
useEffect(() => {
const handleKeyDown = (e) => {
const isCtrl = e.ctrlKey || e.metaKey;
const isShift = e.shiftKey;
if (isCtrl && e.key === 'n' && isShift) {
e.preventDefault();
console.log('New folder shortcut');
} else if (isCtrl && e.key === 'n') {
e.preventDefault();
console.log('New file shortcut');
} else if (isCtrl && e.key === 'u') {
e.preventDefault();
console.log('Upload shortcut');
} else if (isCtrl && e.key === 'f') {
e.preventDefault();
document.querySelector('input[placeholder="Search files"]').focus();
} else if (e.key === 'Delete' && selectedFile) {
e.preventDefault();
console.log('Delete shortcut');
} else if (e.key === 'F2' && selectedFile) {
e.preventDefault();
console.log('Rename shortcut');
}
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, [selectedFile]);
if (isMobile) {
return (
{
setCurrentPath(path);
setShowMobileMenu(false);
setActivePanel('files');
}}
selectedPath={currentPath}
isMobile={true}
/>
{currentItem?.name || 'My Drive'}
{activePanel !== 'preview' && (
)}
{activePanel === 'preview' && (
)}
{activePanel === 'files' && (
{
setSelectedFile(file);
setActivePanel('preview');
}}
onContextAction={handleContextAction}
isMobile={true}
/>
)}
{activePanel === 'preview' && (
)}
);
}
return (
setIsCollapsed(true)}
onResize={() => setIsCollapsed(false)}
className={cn(isCollapsed && "min-w-[50px] transition-all duration-300")}
>
{currentItem?.name || 'My Drive'}
All
Starred
);
}