Better Folder UI
This commit is contained in:
parent
d773f8254c
commit
ebff52d4e6
1 changed files with 69 additions and 48 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import { useState, DragEvent } from 'react';
|
import { useState, DragEvent } from 'react';
|
||||||
import { Button } from '@headlessui/react';
|
import { Button, Transition } from '@headlessui/react';
|
||||||
import { DocumentListItem } from './DocumentListItem';
|
import { DocumentListItem } from './DocumentListItem';
|
||||||
import { Folder, DocumentListDocument } from '@/types/documents';
|
import { Folder, DocumentListDocument } from '@/types/documents';
|
||||||
|
|
||||||
|
|
@ -62,56 +62,77 @@ export function DocumentFolder({
|
||||||
if (!draggedDoc || draggedDoc.folderId) return;
|
if (!draggedDoc || draggedDoc.folderId) return;
|
||||||
onDrop(e, folder.id);
|
onDrop(e, folder.id);
|
||||||
}}
|
}}
|
||||||
className={`rounded-lg p-2 transition-all bg-offbase shadow hover:shadow-md ${
|
className={`overflow-hidden rounded-lg transition-all bg-offbase shadow hover:shadow-md ${isDropTarget ? 'ring-2 ring-accent' : ''}`}
|
||||||
isDropTarget ? 'ring-2 ring-accent bg-primary/10' : ''
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<div className={`flex items-center justify-between ${isCollapsed ? 'mb-0' : 'mb-2'}`}>
|
<div className='flex flex-row justify-between p-2'>
|
||||||
<div className="flex items-center">
|
<div className="w-full">
|
||||||
<h3 className="text-lg px-1 font-semibold">{folder.name}</h3>
|
<div className={`flex items-center justify-between ${isCollapsed ? 'mb-0' : 'mb-2'} transition-all duration-200`}>
|
||||||
<Button
|
<div className="flex items-center">
|
||||||
onClick={onDelete}
|
<h3 className="text-lg px-1 font-semibold">{folder.name}</h3>
|
||||||
className="p-1 text-muted hover:text-red-500 hover:bg-red-50 rounded-lg transition-colors"
|
<Button
|
||||||
aria-label="Delete folder"
|
onClick={() => onToggleCollapse(folder.id)}
|
||||||
>
|
className="transform transition-transform duration-200 ease-in-out hover:scale-[1.09] hover:font-semibold hover:text-accent"
|
||||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
aria-label={isCollapsed ? "Expand folder" : "Collapse folder"}
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
|
>
|
||||||
</svg>
|
<ChevronIcon
|
||||||
</Button>
|
className={`w-5 h-5 transform transition-transform duration-300 ease-in-out ${isCollapsed ? '-rotate-180' : ''}`}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
onClick={onDelete}
|
||||||
|
className="p-1 text-muted hover:text-red-500 hover:bg-red-50 rounded-lg transition-colors"
|
||||||
|
aria-label="Delete folder"
|
||||||
|
>
|
||||||
|
<svg className="w-4 h-4"
|
||||||
|
fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative">
|
||||||
|
<Transition
|
||||||
|
show={!isCollapsed}
|
||||||
|
enter="transition-all duration-300 ease-out"
|
||||||
|
enterFrom="transform scale-y-0 opacity-0 max-h-0"
|
||||||
|
enterTo="transform scale-y-100 opacity-100 max-h-[1000px]"
|
||||||
|
leave="transition-all duration-200 ease-in"
|
||||||
|
leaveFrom="transform scale-y-100 opacity-100 max-h-[1000px]"
|
||||||
|
leaveTo="transform scale-y-0 opacity-0 max-h-0"
|
||||||
|
>
|
||||||
|
<div className="space-y-2 origin-top">
|
||||||
|
{sortedDocuments.map(doc => (
|
||||||
|
<DocumentListItem
|
||||||
|
key={`${doc.type}-${doc.id}`}
|
||||||
|
doc={doc}
|
||||||
|
onDelete={onDocumentDelete}
|
||||||
|
dragEnabled={false} // Documents in folders can't be dragged to other documents
|
||||||
|
onDragStart={onDragStart}
|
||||||
|
onDragEnd={onDragEnd}
|
||||||
|
isDropTarget={false}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
<Transition
|
||||||
|
show={isCollapsed}
|
||||||
|
enter="transition-all duration-200"
|
||||||
|
enterFrom="max-h-0 opacity-0"
|
||||||
|
enterTo="max-h-[50px] opacity-100"
|
||||||
|
leave="transition-all duration-100"
|
||||||
|
leaveFrom="max-h-[50px] opacity-100"
|
||||||
|
leaveTo="max-h-0 opacity-0"
|
||||||
|
>
|
||||||
|
<p className="text-xs px-1 text-left text-muted">
|
||||||
|
{(calculateFolderSize(sortedDocuments) / 1024 / 1024).toFixed(2)} MB
|
||||||
|
{` • ${sortedDocuments.length} ${sortedDocuments.length === 1 ? 'file' : 'files'}`}
|
||||||
|
</p>
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
|
||||||
onClick={() => onToggleCollapse(folder.id)}
|
|
||||||
className="p-1 hover:bg-offbase rounded-lg transition-colors"
|
|
||||||
aria-label={isCollapsed ? "Expand folder" : "Collapse folder"}
|
|
||||||
>
|
|
||||||
<ChevronIcon
|
|
||||||
className={`w-5 h-5 transform transition-transform ${isCollapsed ? 'rotate-180' : ''}`}
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isCollapsed && (
|
|
||||||
<div className="space-y-2">
|
|
||||||
{sortedDocuments.map(doc => (
|
|
||||||
<DocumentListItem
|
|
||||||
key={`${doc.type}-${doc.id}`}
|
|
||||||
doc={doc}
|
|
||||||
onDelete={onDocumentDelete}
|
|
||||||
dragEnabled={false} // Documents in folders can't be dragged to other documents
|
|
||||||
onDragStart={onDragStart}
|
|
||||||
onDragEnd={onDragEnd}
|
|
||||||
isDropTarget={false}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isCollapsed && (
|
|
||||||
<p className="text-xs px-1 text-left text-muted">
|
|
||||||
{(calculateFolderSize(sortedDocuments) / 1024 / 1024).toFixed(2)} MB
|
|
||||||
{` • ${sortedDocuments.length} ${sortedDocuments.length === 1 ? 'file' : 'files'}`}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue