refactor: unify document panel empty state rendering and view mode logic, adjust related styles
This commit is contained in:
@@ -1023,13 +1023,9 @@ function DesktopWorkspaceView({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!allSizesReady ? (
|
{!allSizesReady ? (
|
||||||
<div className="desk-empty">
|
<div className="empty-state">
|
||||||
<p>Loading previews…</p>
|
<p>Loading previews…</p>
|
||||||
</div>
|
</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) => {
|
items.map((doc, index) => {
|
||||||
const sizeInfo = ensureDocumentSize(doc);
|
const sizeInfo = ensureDocumentSize(doc);
|
||||||
|
|||||||
@@ -40,6 +40,37 @@ const defaultGetDocumentAsset = (_doc?: unknown, _type?: string) => null;
|
|||||||
|
|
||||||
export type DocumentLinkLike = { url?: string | null; mimeType?: 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> = ({
|
const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
|
||||||
headerLeading = null,
|
headerLeading = null,
|
||||||
onBreadcrumbNavigate,
|
onBreadcrumbNavigate,
|
||||||
@@ -706,116 +737,69 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
|
|||||||
() => entries.some((entry) => entry.type === EntryType.document),
|
() => entries.some((entry) => entry.type === EntryType.document),
|
||||||
[entries],
|
[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 (
|
return (
|
||||||
<div className="empty-state">
|
<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.
|
No documents match the current filters.
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showListSearchEmptyState) {
|
if (!hasEntries) {
|
||||||
return (
|
<div className="empty-state">
|
||||||
<div className="empty-state">No documents match the current filters.</div>
|
No documents to show here yet. Drop files to make this space come alive.
|
||||||
);
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!showTableRows) {
|
const listProps: DocumentsListProps = {
|
||||||
return null;
|
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) {
|
switch (viewMode) {
|
||||||
return (
|
case 'desk':
|
||||||
<DocumentsGrid
|
return <DesktopWorkspace {...deskWorkspaceProps} />;
|
||||||
entries={entries}
|
case 'grid':
|
||||||
draggingDocumentIdsSet={draggingSet}
|
return <DocumentsGrid {...listProps} />;
|
||||||
draggedFolderId={draggedFolderId}
|
case 'list':
|
||||||
onFolderClick={handleFolderClick}
|
default:
|
||||||
onFolderSelect={onFolderSelect}
|
return <DocumentsList {...listProps} />;
|
||||||
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}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 panelVariant = isDeskView ? 'desk' : isGridView ? 'grid' : 'list';
|
||||||
const shouldHandlePanelInteractions = !isDeskView && showTableRows;
|
const shouldHandlePanelInteractions = !isDeskView && entries.length > 0;
|
||||||
|
|
||||||
const handleSectionFocus = useCallback((event: React.FocusEvent<HTMLElement>) => {
|
const handleSectionFocus = useCallback((event: React.FocusEvent<HTMLElement>) => {
|
||||||
if (!shouldHandlePanelInteractions || event.target !== event.currentTarget) {
|
if (!shouldHandlePanelInteractions || event.target !== event.currentTarget) {
|
||||||
|
|||||||
@@ -467,8 +467,8 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.documents-panel tbody tr.document > *,
|
.documents-panel tbody tr.document>*,
|
||||||
.documents-panel tbody tr.folder > * {
|
.documents-panel tbody tr.folder>* {
|
||||||
height: var(--documents-list-row-height);
|
height: var(--documents-list-row-height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,28 +762,11 @@
|
|||||||
padding: 0.2rem 0.4rem;
|
padding: 0.2rem 0.4rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
border: none;
|
border: none;
|
||||||
background: oklch(
|
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);
|
||||||
min(1, calc(var(--tag-chip-resolved-l) + (1 - var(--tag-chip-resolved-l)) * var(--tag-chip-bg-lighten)))
|
--tag-chip-outline-color: var(--tag-chip-outline,
|
||||||
calc(var(--tag-chip-resolved-c) * var(--tag-chip-bg-chroma-scale))
|
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)));
|
||||||
var(--tag-chip-resolved-h)
|
--tag-chip-text-color: var(--tag-chip-text,
|
||||||
/ 0.9
|
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)));
|
||||||
);
|
|
||||||
--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);
|
color: var(--tag-chip-text-color, currentColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -822,15 +805,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.empty-state {
|
.empty-state {
|
||||||
border: 1px dashed var(--border);
|
height: 100%;
|
||||||
border-radius: 0;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 1rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 1.1rem 0.9rem;
|
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
margin-top: 0.75rem;
|
}
|
||||||
background: var(--surface-subtle);
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-state--global {
|
|
||||||
border-style: solid;
|
|
||||||
}
|
|
||||||
@@ -28,18 +28,7 @@
|
|||||||
outline: none;
|
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,
|
||||||
body.desk-cursor-remove * {
|
body.desk-cursor-remove * {
|
||||||
cursor: not-allowed !important;
|
cursor: not-allowed !important;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user