This commit is contained in:
2025-11-02 04:40:07 +01:00
parent f7b274c1ec
commit e7e7881772
13 changed files with 560 additions and 243 deletions
@@ -327,7 +327,7 @@ const DocumentSummarySection = ({
const startTitleEdit = useCallback(() => {
if (!editableTitle || !document) return;
setIsTitleEditing(true);
setTitleDraft(document.title || document.original_name || '');
setTitleDraft(document.title);
setTitleError(null);
}, [document, editableTitle]);
@@ -396,8 +396,6 @@ const DocumentSummarySection = ({
[cancelIssuedEdit, document, editableIssued, issuedDraft, onUpdateIssued],
);
const titleDisplay = summary.title || document?.original_name || 'Untitled document';
if (!document) {
return null;
}
@@ -440,7 +438,7 @@ const DocumentSummarySection = ({
</form>
) : (
<>
<h3 className="doc-title-row__title">{titleDisplay}</h3>
<h3 className="doc-title-row__title">{summary.title}</h3>
{editableTitle ? (
<button
type="button"
+6 -14
View File
@@ -4,6 +4,7 @@ import DocumentThumbnailImage from './DocumentThumbnailImage';
import CorrespondentLinks from './CorrespondentLinks';
import { getTagColorStyle } from '../utils/colors';
import { resolveCorrespondents } from './correspondents';
import { writeTagTransferData } from './tagTransfer';
const DocumentsGrid = ({
entries,
@@ -110,8 +111,6 @@ const DocumentsGrid = ({
const cardClasses = ['document-card', 'document'];
if (isSelected) cardClasses.push('selected');
if (isDraggingDoc) cardClasses.push('is-dragging');
const titleText = doc.title || doc.original_name;
return (
<div
key={entry.key}
@@ -135,12 +134,12 @@ const DocumentsGrid = ({
document={doc}
ensureAssetUrl={ensureAssetUrl}
getDocumentAsset={getDocumentAsset}
alt={`Thumbnail for ${titleText}`}
alt={`Thumbnail for ${doc.title}`}
maxSize={gridIconSize}
scrollRootRef={scrollRef}
/>
<div className="document-card__meta">
<div className="document-card__title" title={titleText}>
<div className="document-card__title" title={doc.title}>
{correspondents.length > 0 ? (
<span className="doc-correspondents">
<CorrespondentLinks
@@ -150,7 +149,7 @@ const DocumentsGrid = ({
/>
</span>
) : null}
<span className="doc-name__primary">{titleText}</span>
<span className="doc-name__primary">{doc.title}</span>
</div>
{visibleTags.length > 0 && (
<div className="document-card__tags">
@@ -175,17 +174,10 @@ const DocumentsGrid = ({
if (event.dataTransfer) {
event.dataTransfer.effectAllowed = 'copyMove';
}
const payload = JSON.stringify({
id: tag.id,
label: tag.label,
sourceDocId: doc.id,
});
event.dataTransfer?.setData('application/x-papercrate-tag', payload);
event.dataTransfer?.setData('text/papercrate-tag', payload);
event.dataTransfer?.setData('text/plain', tag.label || 'Tag');
} catch (error) {
console.warn('[documents] Failed to configure tag drag payload', error);
console.warn('[documents] Failed to configure drag effect', error);
}
writeTagTransferData(event.dataTransfer, tag, doc.id);
}}
onDragEnd={(event) => {
event.stopPropagation();
+6 -14
View File
@@ -9,6 +9,7 @@ import { getTagColorStyle } from '../utils/colors';
import DocumentThumbnailImage from './DocumentThumbnailImage';
import CorrespondentLinks from './CorrespondentLinks';
import { resolveCorrespondents } from './correspondents';
import { writeTagTransferData } from './tagTransfer';
const DocumentsList = ({
entries,
@@ -156,8 +157,6 @@ const DocumentsList = ({
if (isDraggingDoc) rowClasses.push('is-dragging');
const downloadHref = getDownloadHref?.(doc) || null;
const correspondents = resolveCorrespondents(doc);
const titleText = doc.title || doc.original_name;
return (
<tr
key={entry.key}
@@ -178,7 +177,7 @@ const DocumentsList = ({
document={doc}
ensureAssetUrl={ensureAssetUrl}
getDocumentAsset={getDocumentAsset}
alt={`Thumbnail for ${titleText}`}
alt={`Thumbnail for ${doc.title}`}
scrollRootRef={scrollRef}
/>
</td>
@@ -195,7 +194,7 @@ const DocumentsList = ({
/>
</span>
) : null}
<span className="doc-name__primary">{titleText}</span>
<span className="doc-name__primary">{doc.title}</span>
</span>
</div>
{(doc.tags || []).length > 0 && (
@@ -221,17 +220,10 @@ const DocumentsList = ({
if (event.dataTransfer) {
event.dataTransfer.effectAllowed = 'copyMove';
}
const payload = JSON.stringify({
id: tag.id,
label: tag.label,
sourceDocId: doc.id,
});
event.dataTransfer?.setData('application/x-papercrate-tag', payload);
event.dataTransfer?.setData('text/papercrate-tag', payload);
event.dataTransfer?.setData('text/plain', tag.label || 'Tag');
} catch (error) {
console.warn('[documents] Failed to configure tag drag payload', error);
console.warn('[documents] Failed to configure drag effect', error);
}
writeTagTransferData(event.dataTransfer, tag, doc.id);
}}
onDragEnd={(event) => {
event.stopPropagation();
@@ -272,7 +264,7 @@ const DocumentsList = ({
type="button"
className="icon-button"
title="Rename"
aria-label={`Rename document ${titleText}`}
aria-label={`Rename document ${doc.title}`}
onClick={(event) => {
event.stopPropagation();
const nextName = window.prompt('Rename document', doc.title);
+2 -5
View File
@@ -11,8 +11,8 @@ import createWorkspaceSurfaceConfig from './workspaceHeader';
import DetailPanel from '../detail/DetailPanel';
import DocumentsGrid from './DocumentsGrid';
import DocumentsList from './DocumentsList';
import { isTagTransferEvent } from './tagTransfer';
const TAG_MIME_TYPES = ['application/x-papercrate-tag', 'text/papercrate-tag'];
const DEFAULT_GRID_ICON_SIZE = 144;
const EntryType = {
@@ -138,10 +138,7 @@ const DocumentsPanel = ({
scrollRef.current.scrollTop = 0;
}
}, [viewMode]);
const isTagDragEvent = useCallback((event) => {
const types = Array.from(event.dataTransfer?.types || []);
return TAG_MIME_TYPES.some((type) => types.includes(type));
}, []);
const isTagDragEvent = useCallback((event) => isTagTransferEvent(event), []);
const ensureFocusedRowVisible = useCallback(() => {
if (!focusedRowKey) return;
const container = scrollRef.current;
+7 -7
View File
@@ -6,14 +6,14 @@ export const resolveCorrespondents = (doc) => {
const seen = new Set();
const results = [];
doc.correspondents.forEach((entry, index) => {
if (!entry || typeof entry.name !== 'string') {
doc.correspondents.forEach((entry = {}, index) => {
const { id, name } = entry;
if (typeof name !== 'string') {
return;
}
const id = entry.id;
const name = entry.name.trim();
if (!name) {
const trimmedName = name.trim();
if (!trimmedName) {
return;
}
@@ -27,8 +27,8 @@ export const resolveCorrespondents = (doc) => {
results.push({
id,
name,
key: id ?? `${name}-${index}`,
name: trimmedName,
key: id ?? `${trimmedName}-${index}`,
});
});
+5 -6
View File
@@ -29,14 +29,14 @@ const sanitizeTags = (tags) => {
if (!Array.isArray(tags)) {
return [];
}
return tags.filter((tag) => tag && (tag.label || tag.id));
return tags.filter(Boolean);
};
const sanitizeCorrespondents = (entries) => {
if (!Array.isArray(entries)) {
return [];
}
return entries.filter((entry) => entry && (entry.name || entry.id));
return entries.filter(Boolean);
};
export const describeDocumentSummary = (document, options = {}) => {
@@ -64,7 +64,6 @@ export const describeDocumentSummary = (document, options = {}) => {
formatDateTime = defaultFormatDateTime,
} = options;
const title = document.title;
const originalName = document.original_name;
const mimeTypeLabel = document.content_type || 'Unknown';
@@ -79,7 +78,7 @@ export const describeDocumentSummary = (document, options = {}) => {
const issuedLabel = formatDateTime(document.issued_at);
const updatedAtLabel = formatDateTime(document.updated_at);
const folderLabel = document.folder_path || document.folder_name || null;
const folderLabel = document.folder_path;
const tags = sanitizeTags(document.tags);
const correspondents = sanitizeCorrespondents(document.correspondents);
@@ -99,13 +98,13 @@ export const describeDocumentSummary = (document, options = {}) => {
{ key: 'issued', label: 'Issued', value: issuedLabel },
{ key: 'pages', label: 'Pages', value: pageCountLabel },
{ key: 'updated', label: 'Updated', value: updatedAtLabel },
{ key: 'folder', label: 'Folder', value: folderLabel || '—' },
{ key: 'folder', label: 'Folder', value: folderLabel },
{ key: 'tags', label: 'Tags', value: tagsSummary },
{ key: 'correspondents', label: 'Correspondents', value: correspondentsSummary },
];
return {
title,
title: document.title,
originalName,
mimeTypeLabel,
sizeLabel,