refactor: Reorganize frontend by moving UI components, hooks, and utilities to new components, logic, features, and lib directories
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import DesktopPreviewCard from './DesktopPreviewCard';
|
||||
import { resolveCorrespondents } from '../../documents/correspondents';
|
||||
import { getTagColorStyle } from '../../utils/colors';
|
||||
import type { DocumentId } from '../../types/identifiers';
|
||||
import type { Document } from '../../types/documents';
|
||||
import { LayoutCard } from '../logic/LayoutSystem';
|
||||
import { useCardPointer } from '../interactions/useCardPointer';
|
||||
|
||||
const preventAll = (event?: React.SyntheticEvent | Event | null) => {
|
||||
if (!event) return;
|
||||
if (typeof event.preventDefault === 'function') event.preventDefault();
|
||||
if (typeof event.stopPropagation === 'function') event.stopPropagation();
|
||||
};
|
||||
|
||||
interface DesktopDocumentCardProps {
|
||||
doc: Document;
|
||||
style?: React.CSSProperties;
|
||||
shouldLoad?: boolean;
|
||||
matchesFilter?: boolean;
|
||||
selected?: boolean;
|
||||
docTagTokens?: string;
|
||||
ensureAssetUrl?: (...args: any[]) => Promise<unknown>;
|
||||
getDocumentAsset?: (...args: any[]) => unknown;
|
||||
onDocumentActivate?: (id: string, event?: any) => void;
|
||||
onSelect: (ids: string[], extend?: boolean) => void;
|
||||
onDeselect: (ids: string[]) => void;
|
||||
selection: string[];
|
||||
requestCanvasFocus?: () => void;
|
||||
onTagDragEnter?: (event: React.DragEvent<HTMLDivElement>, docId: DocumentId) => void;
|
||||
onTagDragOver?: (event: React.DragEvent<HTMLDivElement>, docId: DocumentId) => void;
|
||||
onTagDragLeave?: (event: React.DragEvent<HTMLDivElement>, docId: DocumentId) => void;
|
||||
onTagDrop?: (event: React.DragEvent<HTMLDivElement>, doc: Document) => void;
|
||||
onDocTagDragStart?: (event: React.DragEvent<HTMLElement>, doc: Document, tag: any) => void;
|
||||
onDocTagDragEnd?: (event: React.DragEvent<HTMLElement>) => void;
|
||||
layoutCard: LayoutCard;
|
||||
}
|
||||
|
||||
const DesktopDocumentCard: React.FC<DesktopDocumentCardProps> = ({
|
||||
doc,
|
||||
style,
|
||||
shouldLoad,
|
||||
matchesFilter,
|
||||
selected,
|
||||
docTagTokens,
|
||||
ensureAssetUrl,
|
||||
getDocumentAsset,
|
||||
onDocumentActivate,
|
||||
onSelect,
|
||||
onDeselect,
|
||||
selection,
|
||||
requestCanvasFocus,
|
||||
onTagDragEnter,
|
||||
onTagDragOver,
|
||||
onTagDragLeave,
|
||||
onTagDrop,
|
||||
onDocTagDragStart,
|
||||
onDocTagDragEnd,
|
||||
layoutCard,
|
||||
}) => {
|
||||
const cardPointerHandlers = useCardPointer(
|
||||
layoutCard,
|
||||
!!selected,
|
||||
selection,
|
||||
onSelect,
|
||||
onDeselect,
|
||||
onDocumentActivate,
|
||||
requestCanvasFocus
|
||||
);
|
||||
|
||||
const correspondents = useMemo(() => resolveCorrespondents(doc), [doc]);
|
||||
const tags = Array.isArray(doc?.tags) ? doc.tags : [];
|
||||
|
||||
const itemClasses = ['desk-item'];
|
||||
if (!matchesFilter) itemClasses.push('is-filtered-out');
|
||||
if (selected) itemClasses.push('is-selected');
|
||||
|
||||
const ariaHidden = matchesFilter ? undefined : 'true';
|
||||
const dataTagIds = docTagTokens || undefined;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={doc.id}
|
||||
className={itemClasses.join(' ')}
|
||||
style={style}
|
||||
role="button"
|
||||
data-doc-id={doc.id}
|
||||
data-tag-ids={dataTagIds}
|
||||
aria-hidden={ariaHidden}
|
||||
ref={(node) => layoutCard?.setRef(node)}
|
||||
{...cardPointerHandlers}
|
||||
onDragEnter={(event) => {
|
||||
if (doc?.id == null) {
|
||||
return;
|
||||
}
|
||||
onTagDragEnter?.(event, doc.id);
|
||||
}}
|
||||
onDragOver={(event) => {
|
||||
if (doc?.id == null) {
|
||||
return;
|
||||
}
|
||||
onTagDragOver?.(event, doc.id);
|
||||
}}
|
||||
onDragLeave={(event) => {
|
||||
if (doc?.id == null) {
|
||||
return;
|
||||
}
|
||||
onTagDragLeave?.(event, doc.id);
|
||||
}}
|
||||
onDrop={(event) => {
|
||||
onTagDrop?.(event, doc);
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
preventAll(event);
|
||||
onDocumentActivate?.(doc.id, event);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="desk-item__body">
|
||||
<DesktopPreviewCard
|
||||
doc={doc}
|
||||
title={doc.title}
|
||||
ensureAssetUrl={ensureAssetUrl}
|
||||
getDocumentAsset={getDocumentAsset}
|
||||
shouldLoad={shouldLoad}
|
||||
/>
|
||||
{correspondents.length > 0 && (
|
||||
<div className="desk-item__correspondents" aria-hidden="true">
|
||||
{correspondents.map((correspondent) => (
|
||||
<span
|
||||
key={correspondent.key}
|
||||
className="badge desk-correspondent-chip"
|
||||
title={correspondent.name}
|
||||
>
|
||||
<span className="desk-correspondent-chip__label">{correspondent.name}</span>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{tags.length > 0 && (
|
||||
<div className="desk-item__tags" aria-hidden="true">
|
||||
{tags.map((tag) => {
|
||||
const colorStyle = getTagColorStyle(tag.color);
|
||||
const tagClasses = ['badge', 'tag-chip', 'tag-chip--draggable'];
|
||||
return (
|
||||
<span
|
||||
key={tag.id}
|
||||
className={tagClasses.join(' ')}
|
||||
style={colorStyle || undefined}
|
||||
title={tag.label}
|
||||
draggable
|
||||
data-desk-tag-chip="true"
|
||||
onDragStart={(event) => onDocTagDragStart?.(event, doc, tag)}
|
||||
onDragEnd={(event) => onDocTagDragEnd?.(event)}
|
||||
>
|
||||
<span className="tag-chip__label">{tag.label}</span>
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(DesktopDocumentCard);
|
||||
Reference in New Issue
Block a user