mirror of
https://github.com/thegeneralist01/archivr
synced 2026-07-21 18:55:36 +02:00
- PreviewModal: modal overlay with new-tab link (↗) and keyboard close - PreviewPanel: routes by entity_kind + primary_media extension to the correct viewer (tweet/video/audio/pdf/html/image/fallback) - TweetPreview: full X-style tweet, thread, and article renderer with local artifact map for archived media (CDN fallback) - AudioBar: persistent fixed bottom player, triggered via ContextRail Play button; body.has-audio-bar pads content above it - VideoPreview, IframePreview, ImagePreview: inline viewers - PreviewPage: standalone /preview/:archiveId/:entryUid route - ContextRail: Play/Preview buttons; isAudio/isPreviewable detection - App.jsx: preview modal state, currentAudio state, preview route guard, has-audio-bar body class effect - routes.rs: CSP updated (media-src self blob https; frame-ancestors self; Google Fonts + external images/scripts whitelisted) - styles.css: preview modal, tweet-wrap scroll (min-height:0), audio bar body padding, newtab button, preview panel flex layout
32 lines
1.2 KiB
JavaScript
32 lines
1.2 KiB
JavaScript
import { useEffect } from 'react'
|
||
import PreviewPanel from './PreviewPanel'
|
||
|
||
export default function PreviewModal({ archiveId, entry, detail, onClose }) {
|
||
// Close on Escape key
|
||
useEffect(() => {
|
||
const handler = (e) => { if (e.key === 'Escape') onClose() }
|
||
window.addEventListener('keydown', handler)
|
||
return () => window.removeEventListener('keydown', handler)
|
||
}, [onClose])
|
||
|
||
return (
|
||
<div className="preview-modal-backdrop" onClick={onClose}>
|
||
<div className="preview-modal" onClick={e => e.stopPropagation()}>
|
||
<div className="preview-modal-header">
|
||
<span className="preview-modal-title">{entry?.title || entry?.entry_uid || 'Preview'}</span>
|
||
<a
|
||
className="preview-modal-newtab"
|
||
href={`/preview/${archiveId}/${entry?.entry_uid}`}
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
title="Open in new tab"
|
||
>↗</a>
|
||
<button className="preview-modal-close" onClick={onClose} aria-label="Close preview">×</button>
|
||
</div>
|
||
<div className="preview-modal-body">
|
||
<PreviewPanel archiveId={archiveId} entry={entry} detail={detail} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|