import VideoPreview from './VideoPreview';
import IframePreview from './IframePreview';
import ImagePreview from './ImagePreview';
import TweetPreview from './TweetPreview';
const VIDEO_EXTS = new Set(['mp4', 'webm', 'mov', 'mkv', 'avi', 'm4v', 'ogv']);
const AUDIO_EXTS = new Set(['mp3', 'ogg', 'm4a', 'opus', 'wav', 'flac', 'aac']);
const IMAGE_EXTS = new Set(['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', 'svg', 'bmp']);
export default function PreviewPanel({ archiveId, entry, detail }) {
if (!entry) {
return (
Select an entry to preview
);
}
if (!detail) {
return (
Loading…
);
}
const { summary, artifacts } = detail;
const entryUid = summary.entry_uid;
const entityKind = summary.entity_kind;
// 1. Tweet / tweet thread
if (entityKind === 'tweet' || entityKind === 'tweet_thread') {
return (
);
}
// 2. Find primary_media artifact
const primaryMediaIndex = artifacts.findIndex(a => a.artifact_role === 'primary_media');
if (primaryMediaIndex === -1) {
return (
No preview available
{artifacts.length > 0 && (
{artifacts.map((a, i) => (
- {a.artifact_role}: {a.relpath}
))}
)}
);
}
const primaryArtifact = artifacts[primaryMediaIndex];
const primaryMediaUrl = `/api/archives/${archiveId}/entries/${entryUid}/artifacts/${primaryMediaIndex}`;
const ext = primaryArtifact.relpath.split('.').pop().toLowerCase();
// 3. Video
if (VIDEO_EXTS.has(ext)) {
return (
);
}
// 4. Audio — inline player (AudioBar handles persistent playback via rail Play button)
if (AUDIO_EXTS.has(ext)) {
return (
🎵
{summary.title || entryUid}
);
}
// 5. PDF
if (ext === 'pdf') {
return (
);
}
// 6. HTML page
if (ext === 'html' || ext === 'htm') {
return (
);
}
// 7. Image
if (IMAGE_EXTS.has(ext)) {
return (
);
}
// 8. Fallback
return (
No preview available
{artifacts.map((a, i) => (
- {a.artifact_role}: {a.relpath}
))}
);
}