Add clipping provenance status stamps

This commit is contained in:
2026-08-22 23:41:08 +02:00
parent 1d1d082a53
commit 74ccd11d0c
3 changed files with 8 additions and 4 deletions
+2 -2
View File
@@ -971,13 +971,13 @@ function Board({ state, selected, locatorDocumentId, linkFrom, recentlyCreatedEx
<header><span>{definition.heading(ev, widgetContext)}</span><i>{String(i + 1).padStart(3, '0')}</i></header>
<Widget exhibit={ev} context={widgetContext}/>
</article>})}
{documentExhibits(state.exhibits).filter(document => !document.hidden).map(document => { const membership = containmentRelations.find(relation => relation.toExhibitId === document.id); const folder = membership ? byId.get(membership.fromExhibitId) : undefined; const open = folder?.type !== 'folder' || folder.isOpen; const located = open && locatorDocumentId === document.id; const left = open ? document.x : folder.x + folder.width / 2 - document.width / 2, top = open ? document.y : folder.y + 45; const definition = documentWidget(document.fileType); const presentation=documentCapture(document.captureKind); const identification=mugshotIdentification(document,state.exhibits,state.connections); const Preview = definition.Preview; const source = document.assetId ? `/api/assets/${encodeURIComponent(document.assetId)}` : ''; return <article key={document.id} data-document-locator-target={located ? document.id : undefined} data-temporal-id={`widget:${document.id}`} data-capture-kind={document.captureKind} data-identified-party-id={identification?.party.id} className={`source-file-widget ${open ? 'open' : 'closed'} file-type-${document.fileType} capture-kind-${document.captureKind} ${identification ? 'mugshot-identified' : ''} ${selected === document.id ? 'selected' : ''} ${located ? 'document-located' : ''} ${linkFrom === document.id ? 'linking' : ''} ${linkFrom && linkFrom !== document.id ? 'thread-target' : ''} ${arrivingExhibitIds.includes(document.id) ? 'arriving' : ''}`} style={{ left,top,width:document.width,height:document.height,rotate:`${document.rotation}deg`,zIndex:document.zIndex,'--clip-inset-rotation':`${clippingInsetRotation(document.id)}deg` } as React.CSSProperties}
{documentExhibits(state.exhibits).filter(document => !document.hidden).map(document => { const membership = containmentRelations.find(relation => relation.toExhibitId === document.id); const folder = membership ? byId.get(membership.fromExhibitId) : undefined; const open = folder?.type !== 'folder' || folder.isOpen; const located = open && locatorDocumentId === document.id; const left = open ? document.x : folder.x + folder.width / 2 - document.width / 2, top = open ? document.y : folder.y + 45; const definition = documentWidget(document.fileType); const presentation=documentCapture(document.captureKind); const identification=mugshotIdentification(document,state.exhibits,state.connections); const Preview = definition.Preview; const source = document.assetId ? `/api/assets/${encodeURIComponent(document.assetId)}` : ''; const missingProvenance=[!document.publishedAt ? 'DATE' : '',!document.sourceCitation?.trim() ? 'SOURCE' : ''].filter(Boolean); return <article key={document.id} data-document-locator-target={located ? document.id : undefined} data-temporal-id={`widget:${document.id}`} data-capture-kind={document.captureKind} data-identified-party-id={identification?.party.id} className={`source-file-widget ${open ? 'open' : 'closed'} file-type-${document.fileType} capture-kind-${document.captureKind} ${identification ? 'mugshot-identified' : ''} ${selected === document.id ? 'selected' : ''} ${located ? 'document-located' : ''} ${linkFrom === document.id ? 'linking' : ''} ${linkFrom && linkFrom !== document.id ? 'thread-target' : ''} ${arrivingExhibitIds.includes(document.id) ? 'arriving' : ''}`} style={{ left,top,width:document.width,height:document.height,rotate:`${document.rotation}deg`,zIndex:document.zIndex,'--clip-inset-rotation':`${clippingInsetRotation(document.id)}deg` } as React.CSSProperties}
onPointerDown={event => { event.stopPropagation(); if (linkFrom && event.button === 0) return; if (tool === 'hand' || event.button === 1) { event.preventDefault(); pointerDown(event) } else if (open && event.button === 0) pointerDown(event, { kind: 'widget', id: document.id }) }}
onPointerMove={event => { event.stopPropagation(); pointerMove(event) }} onPointerUp={event => { event.stopPropagation(); finishDrag(event) }} onPointerCancel={event => { event.stopPropagation(); finishDrag(event) }} onClick={event => { event.stopPropagation(); if (suppressClick.current) { suppressClick.current = false; return } if (!open) return; if (tool === 'move') onCardClick(document.id) }} onDoubleClick={() => open && !linkFrom && onOpenSource(document.id)}>
<header><span>{(document.captureKind === 'unclassified' ? definition.label : presentation.label).toUpperCase()}</span><i>{String(document.displayNumber || (membership?.sortOrder || 0) + 1).padStart(2, '0')}</i></header>
<div className="source-file-preview"><Preview document={document} source={source} onMemoryCue={cue => onUpdateDocumentCue(document.id, cue)}/></div>
{document.captureKind === 'photo' ? <MugshotCaption name={identification?.party.title || ''}/> : document.captureKind !== 'clipping' ? <strong>{document.title}</strong> : null}
<div className="source-file-footer"><time>{document.publishedAt?.slice(0, 10) || 'UNDATED'}</time>
<div className="source-file-footer">{document.captureKind === 'clipping' && <span className={`clip-provenance ${missingProvenance.length ? 'incomplete' : 'complete'}`}>{missingProvenance.length ? `ADD ${missingProvenance.join(' + ')}` : 'SOURCE RECORDED'}</span>}<time>{document.publishedAt?.slice(0, 10) || 'UNDATED'}</time>
<div className="source-file-actions"><button onClick={event => { event.stopPropagation(); onOpenSource(document.id) }}><BookOpen size={12}/> OPEN</button><button onClick={event => { event.stopPropagation(); onEditFile(document.id) }}><Pencil size={12}/> METADATA</button></div></div>
</article> })}
</div>