Files
papercrate/frontend/src/desktop/DesktopPreviewCard.tsx
T
2025-11-20 02:36:32 +01:00

123 lines
3.1 KiB
TypeScript

import { useEffect } from 'react';
import type { JSX } from 'react';
import { useAssetNavigator } from '../hooks/useAssetNavigator';
type Identifier = string | number;
interface DocumentLike {
id?: Identifier;
title?: string;
[key: string]: unknown;
}
interface AssetLike {
id?: Identifier;
url?: string | null;
expires_at?: number | null;
metadata?: Record<string, unknown> | null;
[key: string]: unknown;
}
type EnsureAssetUrl = (
documentId: Identifier,
asset: AssetLike,
options?: { force?: boolean; [key: string]: unknown },
) => Promise<unknown>;
type GetDocumentAsset = (document: DocumentLike | null, assetType: string) => AssetLike | null;
interface NavigatorSnapshot {
url: string | null;
alt?: string;
width: number | null;
height: number | null;
}
interface DesktopPreviewCardProps {
doc: DocumentLike | null;
title?: string;
ensureAssetUrl?: EnsureAssetUrl | null;
getDocumentAsset: GetDocumentAsset;
onNavigatorSnapshot?: (docId: Identifier, snapshot: NavigatorSnapshot | null) => void;
shouldLoad?: boolean;
}
const DesktopPreviewCard = ({
doc,
title,
ensureAssetUrl,
getDocumentAsset,
onNavigatorSnapshot,
shouldLoad = true,
}: DesktopPreviewCardProps): JSX.Element => {
const navigator = useAssetNavigator({
document: doc,
assetType: 'thumbnail',
ensureAssetUrl: shouldLoad ? ensureAssetUrl : null,
getAsset: getDocumentAsset,
});
const { currentUrl, currentMetadata } = navigator;
const docId = doc?.id ?? null;
const metadataWidth = Number((currentMetadata as { width?: number } | null)?.width);
const metadataHeight = Number((currentMetadata as { height?: number } | null)?.height);
useEffect(() => {
if (!onNavigatorSnapshot || !docId) {
return undefined;
}
if (!currentUrl) {
onNavigatorSnapshot(docId, null);
return undefined;
}
const snapshot = {
url: currentUrl,
alt: title,
width: Number.isFinite(metadataWidth) && metadataWidth > 0 ? metadataWidth : null,
height: Number.isFinite(metadataHeight) && metadataHeight > 0 ? metadataHeight : null,
};
onNavigatorSnapshot(docId, snapshot);
return () => onNavigatorSnapshot(docId, null);
}, [
docId,
currentUrl,
title,
metadataWidth,
metadataHeight,
onNavigatorSnapshot,
]);
const hasPreview = Boolean(currentUrl);
const cardClasses = ['desk-item__card'];
if (!hasPreview) cardClasses.push('desk-item__card--empty');
return (
<div
className={cardClasses.join(' ')}
onDragStart={(event) => {
if (event instanceof DragEvent) {
event.preventDefault();
}
}}
>
{hasPreview ? (
<img
src={currentUrl}
alt={title}
draggable={false}
onDragStart={(event) => event.preventDefault()}
/>
) : (
<div className="desk-item__empty">
<div className="desk-item__placeholder">DOC</div>
<div className="desk-item__title" title={title}>
{title}
</div>
</div>
)}
</div>
);
};
export default DesktopPreviewCard;