refactor: Decompose document and folder views into modular components and hooks, replacing monolithic list/grid implementations.

This commit is contained in:
2025-11-26 01:50:53 +01:00
parent 342714528a
commit 0a4a3ae35c
20 changed files with 1074 additions and 917 deletions
@@ -0,0 +1,129 @@
import React from 'react';
import { FolderIcon } from '../../ui/icons';
import DocumentThumbnailImage from '../DocumentThumbnailImage';
import { resolveCorrespondents } from '../correspondents';
import type { DocumentsListEntry } from '../../types/documents';
import type { DocumentsViewProps } from '../panel/DocumentsPanel';
import type { DocumentViewLogic } from '../hooks/useDocumentViewLogic';
import EditableEntryTitle from './EditableEntryTitle';
import EntryCorrespondents from './EntryCorrespondents';
import EntryTags from './EntryTags';
import FolderEntry from './FolderEntry';
import DocumentEntry from './DocumentEntry';
interface DocumentsGridCardProps extends DocumentsViewProps {
entry: DocumentsListEntry;
viewLogic: DocumentViewLogic;
gridIconSize?: number;
}
const DocumentsGridCard: React.FC<DocumentsGridCardProps> = (props) => {
const { entry, gridIconSize } = props;
if (entry.type === 'folder') {
const folder = entry.folder;
if (!folder) return null;
return (
<FolderEntry
{...props}
folder={folder}
component="div"
className="document-card folder-card"
role="listitem"
>
{(logic) => (
<>
<div className="folder-card__icon">
<FolderIcon className="folder-card__icon-svg" size={gridIconSize} />
</div>
<div className="folder-card__meta">
<div className="folder-card__label-row">
<EditableEntryTitle
isEditing={logic.isFolderEditing}
draftValue={logic.folderDraftValue}
onChange={logic.handlers.onRenameChange}
onSubmit={logic.handlers.onRenameSubmit}
onCancel={logic.handlers.onRenameCancel}
isSaving={logic.isFolderSaving}
canSubmit={logic.canSubmitFolder}
inputRef={logic.attachFolderInputRef}
allowInlineEdit={logic.allowInlineFolderEdit}
onBeginEditing={logic.handlers.onRenameBegin}
className="folder-card__name"
>
{folder.name}
</EditableEntryTitle>
</div>
</div>
</>
)}
</FolderEntry>
);
}
const doc = entry.document;
if (!doc) return null;
const correspondents = resolveCorrespondents(doc);
return (
<DocumentEntry
{...props}
doc={doc}
component="div"
className="document-card document"
role="listitem"
>
{(logic) => (
<>
<DocumentThumbnailImage
document={doc}
ensureAssetUrl={props.ensureAssetUrl}
getDocumentAsset={props.getDocumentAsset}
alt={`Thumbnail for ${doc.title}`}
maxSize={gridIconSize}
scrollRootRef={props.scrollRef}
/>
<div className="document-card__meta">
<div className="document-card__title" title={doc.title}>
<EntryCorrespondents
correspondents={correspondents}
activeCorrespondentIdSet={props.activeCorrespondentIdSet}
onCorrespondentClick={props.onCorrespondentClick}
/>
<div className="document-card__title-row">
<EditableEntryTitle
isEditing={logic.isEditingDoc}
draftValue={logic.documentDraftValue}
onChange={logic.handlers.onRenameChange}
onSubmit={logic.handlers.onRenameSubmit}
onCancel={logic.handlers.onRenameCancel}
isSaving={logic.isDocumentSaving}
canSubmit={logic.canSubmitDocument}
inputRef={logic.attachDocumentInputRef}
allowInlineEdit={logic.allowInlineDocumentEdit}
onBeginEditing={logic.handlers.onRenameBegin}
className="document-card__title-badge"
>
{doc.title}
</EditableEntryTitle>
</div>
</div>
<div className="document-card__tags">
<EntryTags
tags={doc.tags || []}
tagLookupById={props.tagLookupById}
onTagClick={props.onTagClick}
docId={doc.id}
maxTags={3}
/>
</div>
</div>
</>
)}
</DocumentEntry>
);
};
export default DocumentsGridCard;