mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-08-10 15:21:22 +02:00
pdf-viewer: various visual and usability changes
- fix page nav buttons, smaller default pages, violet bg
- Build toolbar after renderAllPages so it queries existing canvases;
query canvases fresh in the scroll handler so page tracking works
after re-render (zoom in/out).
- Default data-pdf-scale 0.85 (JS fallback 0.8) so pages are a bit
smaller by default.
- Add dark transparent violet background (accent-secondary 22%) to
.pdf-expanded, behind the pages.
- expand to fill column top-to-bottom via CSS flex
Use a flex chain (.tfe-files flex:1, .tfe-file-item:has(.pdf-expanded)
flex:1) so the expanded PDF wrapper fills the right column from under
the header to the bottom of the viewport, instead of viewport-based
clamp math that didn't account for the header height.
- fill right column, center pages, freeze column on expand
The expanded viewer now stays inside the right column instead of
growing the page: the column switches to overflow:hidden while the
PDF panel scrolls internally. Pages are centered horizontally via
flexbox align-items: center.
- fix toolbar not full-width, hide sibling file items
The toolbar was constrained by the parent's align-items:center; fixed
with align-self:stretch. Hiding sibling .tfe-file-item elements when
a PDF is expanded prevents them from rendering above the overlay.
- disable overscroll on expanded view
- use overscroll-behavior-y on container, none on toolbar
- disable body overscroll via .pdf-viewer-open class
- mobile full-viewport, iframe matches pdf height
- mobile overlay above everything via position:fixed
- opaque dark-violet bg on mobile overlay
- tfe: add 'Open in new tab' link above website iframes
- trim column padding when expanded for more vertical space
- 5% zoom increments, subtle padding on expanded column
- prevent horizontal overflow/overscroll
This commit is contained in:
@@ -57,6 +57,8 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-m);
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.tfe-file-item {
|
||||
@@ -70,6 +72,30 @@
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.tfe-file-item:has(.pdf-expanded) {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.tfe-file-item:has(.tfe-file-iframe) {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* When a PDF is expanded, freeze the right column and hide
|
||||
sibling file items so they can't render above the expanded view.
|
||||
Also trim column padding so the PDF fills more vertical space. */
|
||||
.tfe-right-column:has(.pdf-expanded) {
|
||||
overflow: hidden;
|
||||
padding-top: var(--space-xs);
|
||||
padding-bottom: var(--space-xs);
|
||||
}
|
||||
.tfe-right-column:has(.pdf-expanded) .tfe-file-item:not(:has(.pdf-expanded)) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tfe-file-item img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
@@ -95,11 +121,29 @@
|
||||
.tfe-file-iframe {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: clamp(300px, 80vh, 700px);
|
||||
height: 100%;
|
||||
min-height: 400px;
|
||||
display: block;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tfe-website-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-3xs);
|
||||
padding: var(--space-2xs) var(--space-xs);
|
||||
font-size: var(--step--1);
|
||||
color: var(--accent-primary);
|
||||
text-decoration: none;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
margin-bottom: var(--space-2xs);
|
||||
}
|
||||
|
||||
.tfe-website-link:hover {
|
||||
background: color-mix(in srgb, var(--accent-primary) 10%, var(--bg-primary));
|
||||
}
|
||||
|
||||
.tfe-file-item figcaption {
|
||||
font-size: var(--step--2);
|
||||
color: var(--text-secondary);
|
||||
@@ -312,8 +356,8 @@
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
outline: none;
|
||||
transition: height 0.35s ease, border-color 0.35s ease;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* ── Collapsed state: thumbnail tile ────────── */
|
||||
@@ -395,19 +439,30 @@
|
||||
|
||||
/* ── Expanded state: wrapper becomes scroll panel ── */
|
||||
|
||||
/* Disable root-level overscroll (rubberbanding) while a PDF is open. */
|
||||
body.pdf-viewer-open {
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
.pdf-expanded {
|
||||
/* Fill viewport minus the column's vertical padding */
|
||||
max-height: calc(100vh - var(--space-xl) * 2);
|
||||
height: clamp(400px, 80vh, calc(100vh - var(--space-xl) * 2));
|
||||
/* Fill the right column from top to bottom (under the header). */
|
||||
height: 100%;
|
||||
min-height: 400px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
overscroll-behavior-y: contain;
|
||||
border: 2px solid var(--accent-primary);
|
||||
display: block;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background: color-mix(in srgb, var(--accent-secondary) 22%, transparent);
|
||||
}
|
||||
|
||||
/* ── Toolbar ────────────────────────────────── */
|
||||
|
||||
.pdf-toolbar {
|
||||
position: sticky;
|
||||
align-self: stretch;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
@@ -420,6 +475,7 @@
|
||||
flex-shrink: 0;
|
||||
font-size: var(--step--1);
|
||||
user-select: none;
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
.pdf-toolbar-btn {
|
||||
@@ -505,6 +561,19 @@
|
||||
.tfe-title {
|
||||
font-size: var(--step-2);
|
||||
}
|
||||
|
||||
/* PDF expands to full viewport height on mobile, above everything */
|
||||
.pdf-expanded {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 100;
|
||||
height: auto;
|
||||
min-height: unset;
|
||||
background: color-mix(in srgb, var(--accent-secondary) 92%, #000 8%);
|
||||
}
|
||||
.tfe-file-iframe {
|
||||
height: 100dvh;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
|
||||
@@ -116,6 +116,7 @@
|
||||
async function expand(container, pdfDoc) {
|
||||
container.classList.remove("pdf-collapsed");
|
||||
container.classList.add("pdf-expanded");
|
||||
document.body.classList.add("pdf-viewer-open");
|
||||
|
||||
container.addEventListener("contextmenu", (e) => e.preventDefault());
|
||||
container.addEventListener("keydown", (e) => {
|
||||
@@ -132,10 +133,10 @@
|
||||
if (oldThumb) oldThumb.remove();
|
||||
|
||||
// Build toolbar
|
||||
buildToolbar(container, pdfDoc);
|
||||
|
||||
// Render pages directly into the wrapper
|
||||
// Render pages directly into the wrapper, then build the toolbar
|
||||
// (toolbar queries canvases, so it must run after they exist).
|
||||
await renderAllPages(container, pdfDoc);
|
||||
buildToolbar(container, pdfDoc);
|
||||
|
||||
container.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
||||
}
|
||||
@@ -143,6 +144,7 @@
|
||||
function collapse(container) {
|
||||
container.classList.remove("pdf-expanded");
|
||||
container.classList.add("pdf-collapsed");
|
||||
document.body.classList.remove("pdf-viewer-open");
|
||||
|
||||
const oldToolbar = container.querySelector(".pdf-toolbar");
|
||||
if (oldToolbar) oldToolbar.remove();
|
||||
@@ -178,7 +180,7 @@
|
||||
const rendering = new Set();
|
||||
|
||||
const resolveScale = () => {
|
||||
const userScale = parseFloat(container.dataset.pdfScale ?? "1");
|
||||
const userScale = parseFloat(container.dataset.pdfScale ?? "0.8");
|
||||
const containerWidth = container.clientWidth - 16;
|
||||
if (containerWidth <= 0) return userScale;
|
||||
return (containerWidth / firstViewport.width) * userScale;
|
||||
@@ -236,7 +238,7 @@
|
||||
toolbar.className = "pdf-toolbar";
|
||||
|
||||
let currentPage = 1;
|
||||
let currentScale = parseFloat(container.dataset.pdfScale ?? "1");
|
||||
let currentScale = parseFloat(container.dataset.pdfScale ?? "0.8");
|
||||
const numPages = pdfDoc.numPages;
|
||||
|
||||
const updateUI = () => {
|
||||
@@ -261,14 +263,14 @@
|
||||
const pageLabel = mkLabel("");
|
||||
|
||||
const zoomOutBtn = mkBtn("−", "Zoom arrière", () => {
|
||||
currentScale = Math.max(0.5, currentScale - 0.2);
|
||||
currentScale = Math.max(0.5, currentScale - 0.05);
|
||||
container.dataset.pdfScale = String(currentScale);
|
||||
reRender(container, pdfDoc);
|
||||
updateUI();
|
||||
});
|
||||
|
||||
const zoomInBtn = mkBtn("+", "Zoom avant", () => {
|
||||
currentScale = Math.min(3.0, currentScale + 0.2);
|
||||
currentScale = Math.min(3.0, currentScale + 0.05);
|
||||
container.dataset.pdfScale = String(currentScale);
|
||||
reRender(container, pdfDoc);
|
||||
updateUI();
|
||||
@@ -296,9 +298,8 @@
|
||||
|
||||
updateUI();
|
||||
|
||||
const canvases = container.querySelectorAll(".pdf-canvas");
|
||||
|
||||
const onScroll = () => {
|
||||
const canvases = container.querySelectorAll(".pdf-canvas");
|
||||
const mid = container.scrollTop + container.clientHeight * 0.4;
|
||||
let best = 1;
|
||||
let bestDist = Infinity;
|
||||
@@ -352,14 +353,14 @@
|
||||
function reRender(container, pdfDoc) {
|
||||
if (container._onScroll) {
|
||||
container.removeEventListener("scroll", container._onScroll);
|
||||
container._onScroll = null;
|
||||
}
|
||||
container.querySelectorAll(".pdf-canvas").forEach((c) => {
|
||||
c.remove();
|
||||
});
|
||||
const oldToolbar = container.querySelector(".pdf-toolbar");
|
||||
if (oldToolbar) oldToolbar.remove();
|
||||
buildToolbar(container, pdfDoc);
|
||||
renderAllPages(container, pdfDoc);
|
||||
renderAllPages(container, pdfDoc).then(() => buildToolbar(container, pdfDoc));
|
||||
}
|
||||
|
||||
// ── Bootstrap ──────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user