1
Fork 0
mirror of https://github.com/thegeneralist01/archivr synced 2026-07-21 18:55:36 +02:00
archivr/frontend/src/components/PreviewModal.jsx
TheGeneralist 8755e2c503
feat: entry previews — tweet/thread/article/video/audio/image/iframe/pdf
- 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
2026-07-11 19:45:13 +02:00

32 lines
1.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
)
}