1
Fork 0
mirror of https://github.com/thegeneralist01/archivr synced 2026-07-22 03:05:32 +02:00

fix: iframe/page preview height chain and toolbar UX

Problem: changing .preview-modal from height to max-height broke iframe
previews - <iframe style='flex:1'> needs a concrete ancestor height, which
max-height alone doesn't supply when content is shorter than the cap.

Fix - CSS:
  .preview-modal--full { height: 88vh } applied to non-tweet modals
  .preview-modal--full .preview-modal-body { max-height: none }
  .preview-iframe-toolbar span: remove text-transform/letter-spacing
    (was uppercasing the URL/title in shouty caps)

Fix - PreviewModal: className adds --full when entity_kind is not
  tweet/tweet_thread; tweet previews keep shrink-to-fit behavior.

Fix - PreviewPanel: pass title + original_url from summary to IframePreview
  for both HTML and PDF; wrappers use flex:1/minHeight:0 not height:100%.

Fix - IframePreview:
  - Accept title + originalUrl props; show originalUrl in toolbar (falls
    back to artifact src only when original_url absent); show title above
    URL when available
  - flex:1 + minHeight:0 instead of height:100% on the wrap div
  - Single unified layout for page + pdf (both just show the iframe)
This commit is contained in:
TheGeneralist 2026-07-12 15:18:38 +02:00
parent 29a99d0713
commit 900e33fa60
Signed by: thegeneralist01
SSH key fingerprint: SHA256:pp9qddbCNmVNoSjevdvQvM5z0DHN7LTa8qBMbcMq/R4
7 changed files with 104 additions and 95 deletions

View file

@ -4,8 +4,8 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Archivr</title>
<script type="module" crossorigin src="/assets/index-CH_nemMw.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CLkuyO9A.css">
<script type="module" crossorigin src="/assets/index-C98W3QeO.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-C89vW3ol.css">
</head>
<body>
<div id="root"></div>

View file

@ -1,83 +1,74 @@
export default function IframePreview({ src, type }) {
export default function IframePreview({ src, type, title, originalUrl }) {
const displayUrl = originalUrl || src;
const displayTitle = title || null;
return (
<div
className="preview-iframe-wrap"
style={{ height: '100%', display: 'flex', flexDirection: 'column' }}
style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}
>
{type === 'page' ? (
<>
<div
className="preview-iframe-toolbar"
style={{
display: 'flex',
alignItems: 'center',
gap: '8px',
padding: '6px 10px',
flexDirection: 'column',
gap: '2px',
padding: '6px 12px',
borderBottom: '1px solid var(--line-soft)',
background: 'var(--paper-2)',
flexShrink: 0,
}}
>
<span
style={{
{displayTitle && (
<span style={{
fontSize: '0.85rem',
fontWeight: 600,
color: 'var(--ink)',
fontFamily: 'var(--sans)',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}>
{displayTitle}
</span>
)}
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
<span style={{
flex: 1,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
fontSize: '0.8rem',
fontSize: '0.78rem',
color: 'var(--muted)',
fontFamily: 'var(--sans)',
}}
>
{src}
}}>
{displayUrl}
</span>
<a
href={src}
target="_blank"
rel="noreferrer noopener"
style={{
fontSize: '0.8rem',
fontSize: '0.78rem',
color: 'var(--accent)',
textDecoration: 'none',
whiteSpace: 'nowrap',
fontFamily: 'var(--sans)',
flexShrink: 0,
}}
>
Open in new tab
{type === 'pdf' ? 'Open PDF ↗' : 'Open in new tab ↗'}
</a>
</div>
</div>
<iframe
src={src}
sandbox="allow-same-origin allow-popups"
allow="autoplay 'none'"
referrerPolicy="no-referrer"
style={{ flex: 1, border: 'none', width: '100%' }}
title="Page preview"
style={{ flex: 1, border: 'none', width: '100%', minHeight: 0 }}
title={displayTitle || (type === 'pdf' ? 'PDF preview' : 'Page preview')}
/>
</>
) : (
<>
<div
style={{
padding: '8px 12px',
borderBottom: '1px solid var(--line-soft)',
background: 'var(--paper-2)',
flexShrink: 0,
fontSize: '0.85rem',
color: 'var(--muted)',
fontFamily: 'var(--sans)',
}}
>
PDF Document
</div>
<iframe
src={src}
allow="autoplay 'none'"
style={{ flex: 1, border: 'none', width: '100%' }}
title="PDF preview"
/>
</>
)}
</div>
);
}

View file

@ -11,7 +11,15 @@ export default function PreviewModal({ archiveId, entry, detail, onClose }) {
return (
<div className="preview-modal-backdrop" onClick={onClose}>
<div className="preview-modal" onClick={e => e.stopPropagation()}>
<div
className={`preview-modal${
detail?.summary?.entity_kind === 'tweet' ||
detail?.summary?.entity_kind === 'tweet_thread'
? ''
: ' preview-modal--full'
}`}
onClick={e => e.stopPropagation()}
>
<div className="preview-modal-header">
<span className="preview-modal-title">{entry?.title || entry?.entry_uid || 'Preview'}</span>
<a

View file

@ -103,8 +103,9 @@ export default function PreviewPanel({ archiveId, entry, detail }) {
// 5. PDF
if (ext === 'pdf') {
return (
<div className="preview-panel" style={{ height: '100%' }}>
<IframePreview src={primaryMediaUrl} type="pdf" />
<div className="preview-panel" style={{ flex: 1, minHeight: 0 }}>
<IframePreview src={primaryMediaUrl} type="pdf"
title={summary.title} originalUrl={summary.original_url} />
</div>
);
}
@ -112,8 +113,9 @@ export default function PreviewPanel({ archiveId, entry, detail }) {
// 6. HTML page
if (ext === 'html' || ext === 'htm') {
return (
<div className="preview-panel" style={{ height: '100%' }}>
<IframePreview src={primaryMediaUrl} type="page" />
<div className="preview-panel" style={{ flex: 1, minHeight: 0 }}>
<IframePreview src={primaryMediaUrl} type="page"
title={summary.title} originalUrl={summary.original_url} />
</div>
);
}

View file

@ -1951,19 +1951,19 @@ select {
}
.preview-iframe-toolbar {
display: flex;
align-items: center;
flex-direction: column;
gap: 2px;
padding: 6px 12px;
background: var(--paper-3);
background: var(--paper-2);
border-bottom: 1px solid var(--line);
gap: 8px;
flex-shrink: 0;
/* never uppercase the toolbar text */
text-transform: none;
letter-spacing: normal;
}
.preview-iframe-toolbar span {
font-size: 11px;
color: var(--muted-2);
text-transform: uppercase;
letter-spacing: 0.07em;
font-weight: 600;
}
.preview-iframe-toolbar a {
margin-left: auto;
@ -2361,6 +2361,14 @@ select {
flex-direction: column;
overflow: hidden;
}
/* Full-height variant for iframe/PDF/video/image (needs explicit height
so flex children like <iframe style="flex:1"> have a concrete container). */
.preview-modal--full {
height: 88vh;
}
.preview-modal--full .preview-modal-body {
max-height: none;
}
.preview-modal-header {
display: flex;
align-items: center;