playful
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}`,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user