refactor: unify document panel empty state rendering and view mode logic, adjust related styles

This commit is contained in:
2025-11-25 10:13:46 +01:00
parent ccc22beda2
commit fe80ccc046
4 changed files with 94 additions and 146 deletions
+1 -5
View File
@@ -1023,13 +1023,9 @@ function DesktopWorkspaceView({
}}
>
{!allSizesReady ? (
<div className="desk-empty">
<div className="empty-state">
<p>Loading previews</p>
</div>
) : items.length === 0 ? (
<div className="desk-empty">
<p>No documents to show here yet. Drop files to make this space come alive.</p>
</div>
) : (
items.map((doc, index) => {
const sizeInfo = ensureDocumentSize(doc);
+79 -95
View File
@@ -40,6 +40,37 @@ const defaultGetDocumentAsset = (_doc?: unknown, _type?: string) => null;
export type DocumentLinkLike = { url?: string | null; mimeType?: string | null };
export interface DocumentsListProps {
entries: Array<{ type: string; id: Identifier; key: string; folder?: any; document?: any }>;
draggingDocumentIdsSet: Set<Identifier>;
draggedFolderId: Identifier | 'root' | null;
onFolderClick: (folder: any, event: React.MouseEvent) => void;
onFolderSelect?: (id: Identifier) => void;
onFolderDragOver?: (event: React.DragEvent, folder: any) => void;
onFolderDragLeave?: (event: React.DragEvent) => void;
onFolderDrop?: (event: React.DragEvent, folder: any) => void;
onFolderDragStart?: (event: React.DragEvent, folder: any) => void;
onFolderDragEnd?: (event: React.DragEvent) => void;
onDocumentClick: (doc: any, event: React.MouseEvent) => void;
onDocumentActivate: (doc: any, event?: React.MouseEvent | KeyboardEvent) => void;
onDocumentDragStart?: (event: React.DragEvent, doc: any) => void;
onDocumentDragEnd?: (event: React.DragEvent) => void;
onDocumentTagDragOver?: (event: React.DragEvent) => void;
onDocumentTagDragLeave?: (event: React.DragEvent) => void;
onDocumentTagDrop?: (event: React.DragEvent, docId: Identifier) => void;
ensureAssetUrl?: any;
getDocumentAsset?: any;
tagLookupById?: any;
onTagClick?: (tagId: Identifier) => void;
scrollRef?: React.RefObject<HTMLElement>;
onCorrespondentClick?: (correspondentId: Identifier) => void;
activeCorrespondentIdSet?: Set<Identifier>;
onDocumentRename?: (id: Identifier, name: string) => void;
onFolderRename?: (id: Identifier, name: string) => void;
focusedRowKey?: string | null;
gridIconSize?: number;
}
const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
headerLeading = null,
onBreadcrumbNavigate,
@@ -706,116 +737,69 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
() => entries.some((entry) => entry.type === EntryType.document),
[entries],
);
const showTableRows = entries.length > 0;
const showDefaultEmptyState = !showingSearchResults && !isFilterActive && entries.length === 0;
const showListSearchEmptyState = showingSearchResults && !hasDocumentEntries && !isGridView && !isSearchLoading;
const showGridSearchEmptyState = isGridView && showingSearchResults && !hasDocumentEntries && !isSearchLoading;
const renderBody = () => {
if (isDeskView) {
return deskWorkspaceProps ? (
<DesktopWorkspace {...deskWorkspaceProps} />
) : (
<div className="empty-state empty-state--global">
Desk view is unavailable.
</div>
);
}
if (showDefaultEmptyState) {
const renderBody = () => {
const hasEntries = entries.length > 0;
const isSearchEmpty = (showingSearchResults || isFilterActive) && !hasDocumentEntries && !isSearchLoading;
if (isSearchEmpty) {
return (
<div className="empty-state">
Drop files anywhere or onto a folder to upload documents.
</div>
);
}
if (showGridSearchEmptyState) {
return (
<div className="empty-state empty-state--global">
No documents match the current filters.
</div>
);
}
if (showListSearchEmptyState) {
return (
<div className="empty-state">No documents match the current filters.</div>
);
if (!hasEntries) {
<div className="empty-state">
No documents to show here yet. Drop files to make this space come alive.
</div>
}
if (!showTableRows) {
return null;
}
const listProps: DocumentsListProps = {
entries,
draggingDocumentIdsSet: draggingSet,
draggedFolderId,
onFolderClick: handleFolderClick,
onFolderSelect,
onFolderDragOver,
onFolderDragLeave,
onFolderDrop,
onFolderDragStart,
onFolderDragEnd,
onDocumentClick: handleDocumentClick,
onDocumentActivate: handleDocumentActivate,
onDocumentDragStart: handleDocumentDragStartLocal,
onDocumentDragEnd: handleDocumentDragEndLocal,
onDocumentTagDragOver: handleDocumentTagDragOver,
onDocumentTagDragLeave: handleDocumentTagDragLeave,
onDocumentTagDrop: handleDocumentTagDrop,
onDocumentRename,
onFolderRename,
ensureAssetUrl,
getDocumentAsset,
tagLookupById,
onTagClick: toggleTagFilter,
onCorrespondentClick: toggleCorrespondentFilter,
activeCorrespondentIdSet: activeCorrespondentIdSet,
scrollRef,
focusedRowKey,
gridIconSize,
};
if (isGridView) {
return (
<DocumentsGrid
entries={entries}
draggingDocumentIdsSet={draggingSet}
draggedFolderId={draggedFolderId}
onFolderClick={handleFolderClick}
onFolderSelect={onFolderSelect}
onFolderDragOver={onFolderDragOver}
onFolderDragLeave={onFolderDragLeave}
onFolderDrop={onFolderDrop}
onFolderDragStart={onFolderDragStart}
onFolderDragEnd={onFolderDragEnd}
onDocumentClick={handleDocumentClick}
onDocumentActivate={handleDocumentActivate}
onDocumentDragStart={handleDocumentDragStartLocal}
onDocumentDragEnd={handleDocumentDragEndLocal}
onDocumentTagDragOver={handleDocumentTagDragOver}
onDocumentTagDragLeave={handleDocumentTagDragLeave}
onDocumentTagDrop={onDocumentTagDrop}
ensureAssetUrl={ensureAssetUrl}
getDocumentAsset={getDocumentAsset}
gridIconSize={gridIconSize}
tagLookupById={tagLookupById}
onTagClick={toggleTagFilter}
scrollRef={scrollRef}
onCorrespondentClick={toggleCorrespondentFilter}
activeCorrespondentIdSet={activeCorrespondentIdSet}
onDocumentRename={onDocumentRename}
onFolderRename={onFolderRename}
/>
);
switch (viewMode) {
case 'desk':
return <DesktopWorkspace {...deskWorkspaceProps} />;
case 'grid':
return <DocumentsGrid {...listProps} />;
case 'list':
default:
return <DocumentsList {...listProps} />;
}
return (
<DocumentsList
entries={entries}
focusedRowKey={focusedRowKey}
draggingDocumentIdsSet={draggingSet}
draggedFolderId={draggedFolderId}
ensureAssetUrl={ensureAssetUrl}
getDocumentAsset={getDocumentAsset}
onFolderClick={handleFolderClick}
onFolderSelect={onFolderSelect}
onFolderDragOver={onFolderDragOver}
onFolderDragLeave={onFolderDragLeave}
onFolderDrop={onFolderDrop}
onFolderDragStart={onFolderDragStart}
onFolderDragEnd={onFolderDragEnd}
onFolderRename={onFolderRename}
onDocumentClick={handleDocumentClick}
onDocumentActivate={handleDocumentActivate}
onDocumentDragStart={handleDocumentDragStartLocal}
onDocumentDragEnd={handleDocumentDragEndLocal}
onDocumentTagDragOver={handleDocumentTagDragOver}
onDocumentTagDragLeave={handleDocumentTagDragLeave}
onDocumentTagDrop={handleDocumentTagDrop}
onDocumentRename={onDocumentRename}
tagLookupById={tagLookupById}
onTagClick={toggleTagFilter}
onCorrespondentClick={toggleCorrespondentFilter}
activeCorrespondentIdSet={activeCorrespondentIdSet}
scrollRef={scrollRef}
/>
);
};
const panelVariant = isDeskView ? 'desk' : isGridView ? 'grid' : 'list';
const shouldHandlePanelInteractions = !isDeskView && showTableRows;
const shouldHandlePanelInteractions = !isDeskView && entries.length > 0;
const handleSectionFocus = useCallback((event: React.FocusEvent<HTMLElement>) => {
if (!shouldHandlePanelInteractions || event.target !== event.currentTarget) {
+13 -34
View File
@@ -467,8 +467,8 @@
cursor: pointer;
}
.documents-panel tbody tr.document > *,
.documents-panel tbody tr.folder > * {
.documents-panel tbody tr.document>*,
.documents-panel tbody tr.folder>* {
height: var(--documents-list-row-height);
}
@@ -762,28 +762,11 @@
padding: 0.2rem 0.4rem;
font-weight: 600;
border: none;
background: oklch(
min(1, calc(var(--tag-chip-resolved-l) + (1 - var(--tag-chip-resolved-l)) * var(--tag-chip-bg-lighten)))
calc(var(--tag-chip-resolved-c) * var(--tag-chip-bg-chroma-scale))
var(--tag-chip-resolved-h)
/ 0.9
);
--tag-chip-outline-color: var(
--tag-chip-outline,
oklch(
min(1, calc(var(--tag-chip-resolved-l) + (1 - var(--tag-chip-resolved-l)) * var(--tag-chip-outline-lighten)))
min(1, calc(var(--tag-chip-resolved-c) * var(--tag-chip-outline-chroma-scale)))
var(--tag-chip-resolved-h)
)
);
--tag-chip-text-color: var(
--tag-chip-text,
oklch(
clamp(0, calc(var(--tag-chip-resolved-l) + var(--tag-chip-text-lighten)), 1)
clamp(0, calc(var(--tag-chip-resolved-c) * var(--tag-chip-text-chroma-scale)), 1)
var(--tag-chip-resolved-h)
)
);
background: oklch(min(1, calc(var(--tag-chip-resolved-l) + (1 - var(--tag-chip-resolved-l)) * var(--tag-chip-bg-lighten))) calc(var(--tag-chip-resolved-c) * var(--tag-chip-bg-chroma-scale)) var(--tag-chip-resolved-h) / 0.9);
--tag-chip-outline-color: var(--tag-chip-outline,
oklch(min(1, calc(var(--tag-chip-resolved-l) + (1 - var(--tag-chip-resolved-l)) * var(--tag-chip-outline-lighten))) min(1, calc(var(--tag-chip-resolved-c) * var(--tag-chip-outline-chroma-scale))) var(--tag-chip-resolved-h)));
--tag-chip-text-color: var(--tag-chip-text,
oklch(clamp(0, calc(var(--tag-chip-resolved-l) + var(--tag-chip-text-lighten)), 1) clamp(0, calc(var(--tag-chip-resolved-c) * var(--tag-chip-text-chroma-scale)), 1) var(--tag-chip-resolved-h)));
color: var(--tag-chip-text-color, currentColor);
}
@@ -822,15 +805,11 @@
}
.empty-state {
border: 1px dashed var(--border);
border-radius: 0;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 1rem;
text-align: center;
padding: 1.1rem 0.9rem;
color: var(--muted);
margin-top: 0.75rem;
background: var(--surface-subtle);
}
.empty-state--global {
border-style: solid;
}
}
@@ -28,18 +28,7 @@
outline: none;
}
.desk-empty {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 3rem;
text-align: center;
color: var(--muted);
font-size: 0.95rem;
}
body.desk-cursor-remove,
body.desk-cursor-remove * {
cursor: not-allowed !important;
}
}