refactor: Reorganize frontend by moving UI components, hooks, and utilities to new components, logic, features, and lib directories

This commit is contained in:
2025-12-04 23:05:35 +01:00
parent 128714a1e0
commit 8aa1872ea5
114 changed files with 199 additions and 199 deletions
@@ -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);