@page-speed/lightbox 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/index.js +204 -60
- package/dist/index.cjs +204 -60
- package/dist/index.js +204 -60
- package/dist/renderers/index.js +157 -59
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -18065,7 +18065,7 @@ var require_pdf = __commonJS({
|
|
|
18065
18065
|
}
|
|
18066
18066
|
});
|
|
18067
18067
|
|
|
18068
|
-
// node_modules/.pnpm/@page-speed+pdf-viewer@0.1.
|
|
18068
|
+
// node_modules/.pnpm/@page-speed+pdf-viewer@0.1.6_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@page-speed/pdf-viewer/dist/index.js
|
|
18069
18069
|
var dist_exports = {};
|
|
18070
18070
|
__export(dist_exports, {
|
|
18071
18071
|
PDFCanvas: () => PDFCanvas,
|
|
@@ -18075,11 +18075,14 @@ __export(dist_exports, {
|
|
|
18075
18075
|
calculateScaleForPageFit: () => calculateScaleForPageFit,
|
|
18076
18076
|
createProgressiveFetchHandler: () => createProgressiveFetchHandler,
|
|
18077
18077
|
downloadPDF: () => downloadPDF,
|
|
18078
|
+
extractPDFFilename: () => extractPDFFilename,
|
|
18078
18079
|
extractPageText: () => extractPageText,
|
|
18079
18080
|
formatFileSize: () => formatFileSize,
|
|
18080
18081
|
getOptimalRangeHeader: () => getOptimalRangeHeader,
|
|
18082
|
+
injectPDFViewerStyles: () => injectPDFViewerStyles,
|
|
18081
18083
|
isLinearizedPDF: () => isLinearizedPDF,
|
|
18082
18084
|
linearizedPDFConfig: () => linearizedPDFConfig,
|
|
18085
|
+
pdfViewerStyles: () => pdfViewerStyles,
|
|
18083
18086
|
usePDFDocument: () => usePDFDocument,
|
|
18084
18087
|
usePageRenderer: () => usePageRenderer,
|
|
18085
18088
|
usePageState: () => usePageState,
|
|
@@ -18320,6 +18323,20 @@ function useSearch(pdfDoc) {
|
|
|
18320
18323
|
prevResult
|
|
18321
18324
|
};
|
|
18322
18325
|
}
|
|
18326
|
+
function injectPDFViewerStyles() {
|
|
18327
|
+
if (typeof document === "undefined") return;
|
|
18328
|
+
if (stylesInjected) return;
|
|
18329
|
+
const styleId = "page-speed-pdf-viewer-styles";
|
|
18330
|
+
if (document.getElementById(styleId)) {
|
|
18331
|
+
stylesInjected = true;
|
|
18332
|
+
return;
|
|
18333
|
+
}
|
|
18334
|
+
const styleElement = document.createElement("style");
|
|
18335
|
+
styleElement.id = styleId;
|
|
18336
|
+
styleElement.textContent = PDF_VIEWER_STYLES;
|
|
18337
|
+
document.head.appendChild(styleElement);
|
|
18338
|
+
stylesInjected = true;
|
|
18339
|
+
}
|
|
18323
18340
|
function PDFCanvas({
|
|
18324
18341
|
pdfDoc,
|
|
18325
18342
|
pageNumber,
|
|
@@ -18343,7 +18360,68 @@ function PDFCanvas({
|
|
|
18343
18360
|
render();
|
|
18344
18361
|
}
|
|
18345
18362
|
}, [pdfDoc, pageNumber, scale, onRender]);
|
|
18346
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: containerRef, className:
|
|
18363
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: containerRef, className: pdfViewerStyles.canvas });
|
|
18364
|
+
}
|
|
18365
|
+
async function isLinearizedPDF(url) {
|
|
18366
|
+
try {
|
|
18367
|
+
const response = await fetch(url, { headers: { Range: "bytes=0-1024" } });
|
|
18368
|
+
const buffer = await response.arrayBuffer();
|
|
18369
|
+
const view = new Uint8Array(buffer);
|
|
18370
|
+
const text = new TextDecoder().decode(view);
|
|
18371
|
+
return text.includes("Linearized");
|
|
18372
|
+
} catch {
|
|
18373
|
+
return false;
|
|
18374
|
+
}
|
|
18375
|
+
}
|
|
18376
|
+
function extractPDFFilename(url, fallbackName) {
|
|
18377
|
+
try {
|
|
18378
|
+
const urlObj = new URL(url, window.location.origin);
|
|
18379
|
+
const pathname = urlObj.pathname;
|
|
18380
|
+
const segments = pathname.split("/").filter(Boolean);
|
|
18381
|
+
const lastSegment = segments[segments.length - 1] || "";
|
|
18382
|
+
if (lastSegment && lastSegment.includes(".")) {
|
|
18383
|
+
if (lastSegment.toLowerCase().endsWith(".pdf")) {
|
|
18384
|
+
return lastSegment;
|
|
18385
|
+
}
|
|
18386
|
+
const nameWithoutExt = lastSegment.substring(0, lastSegment.lastIndexOf("."));
|
|
18387
|
+
return `${nameWithoutExt}.pdf`;
|
|
18388
|
+
}
|
|
18389
|
+
if (lastSegment) {
|
|
18390
|
+
return `${lastSegment}.pdf`;
|
|
18391
|
+
}
|
|
18392
|
+
} catch {
|
|
18393
|
+
}
|
|
18394
|
+
const name = fallbackName || "document";
|
|
18395
|
+
return name.toLowerCase().endsWith(".pdf") ? name : `${name}.pdf`;
|
|
18396
|
+
}
|
|
18397
|
+
function downloadPDF(url, filename) {
|
|
18398
|
+
const link = document.createElement("a");
|
|
18399
|
+
link.href = url;
|
|
18400
|
+
link.download = filename || extractPDFFilename(url);
|
|
18401
|
+
document.body.appendChild(link);
|
|
18402
|
+
link.click();
|
|
18403
|
+
document.body.removeChild(link);
|
|
18404
|
+
}
|
|
18405
|
+
function calculateScaleForPageFit(pageWidth, pageHeight, containerWidth, containerHeight) {
|
|
18406
|
+
const widthRatio = containerWidth / pageWidth;
|
|
18407
|
+
const heightRatio = containerHeight / pageHeight;
|
|
18408
|
+
return Math.min(widthRatio, heightRatio);
|
|
18409
|
+
}
|
|
18410
|
+
function formatFileSize(bytes) {
|
|
18411
|
+
if (bytes === 0) return "0 Bytes";
|
|
18412
|
+
const k = 1024;
|
|
18413
|
+
const sizes = ["Bytes", "KB", "MB", "GB"];
|
|
18414
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
18415
|
+
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
|
|
18416
|
+
}
|
|
18417
|
+
async function extractPageText(pdfDoc, pageNumber) {
|
|
18418
|
+
try {
|
|
18419
|
+
const page = await pdfDoc.getPage(pageNumber);
|
|
18420
|
+
const textContent = await page.getTextContent();
|
|
18421
|
+
return textContent.items.filter((item) => "str" in item).map((item) => item.str).join(" ");
|
|
18422
|
+
} catch {
|
|
18423
|
+
return "";
|
|
18424
|
+
}
|
|
18347
18425
|
}
|
|
18348
18426
|
function PDFControls({
|
|
18349
18427
|
pageState,
|
|
@@ -18356,7 +18434,7 @@ function PDFControls({
|
|
|
18356
18434
|
url
|
|
18357
18435
|
}) {
|
|
18358
18436
|
if (!pdfDocument) return null;
|
|
18359
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className:
|
|
18437
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: pdfViewerStyles.controls, children: [
|
|
18360
18438
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
18361
18439
|
"button",
|
|
18362
18440
|
{
|
|
@@ -18374,10 +18452,10 @@ function PDFControls({
|
|
|
18374
18452
|
max: pdfDocument.numPages,
|
|
18375
18453
|
value: pageState.currentPage,
|
|
18376
18454
|
onChange: (e) => pageState.goToPage(parseInt(e.target.value, 10) || 1),
|
|
18377
|
-
className:
|
|
18455
|
+
className: pdfViewerStyles.pageInput
|
|
18378
18456
|
}
|
|
18379
18457
|
),
|
|
18380
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className:
|
|
18458
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: pdfViewerStyles.pageTotal, children: [
|
|
18381
18459
|
"of ",
|
|
18382
18460
|
pdfDocument.numPages
|
|
18383
18461
|
] }),
|
|
@@ -18399,7 +18477,7 @@ function PDFControls({
|
|
|
18399
18477
|
children: "-"
|
|
18400
18478
|
}
|
|
18401
18479
|
),
|
|
18402
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className:
|
|
18480
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: pdfViewerStyles.zoomLevel, children: [
|
|
18403
18481
|
Math.round(zoom.zoomLevel * 100),
|
|
18404
18482
|
"%"
|
|
18405
18483
|
] }),
|
|
@@ -18419,14 +18497,22 @@ function PDFControls({
|
|
|
18419
18497
|
placeholder: "Search...",
|
|
18420
18498
|
value: search.query,
|
|
18421
18499
|
onChange: (e) => search.search(e.target.value),
|
|
18422
|
-
className:
|
|
18500
|
+
className: pdfViewerStyles.searchInput
|
|
18423
18501
|
}
|
|
18424
18502
|
),
|
|
18425
|
-
search.results.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className:
|
|
18503
|
+
search.results.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: pdfViewerStyles.searchResults, children: [
|
|
18426
18504
|
search.results.length,
|
|
18427
18505
|
" results"
|
|
18428
18506
|
] }),
|
|
18429
|
-
enableDownload && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
18507
|
+
enableDownload && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
18508
|
+
"button",
|
|
18509
|
+
{
|
|
18510
|
+
onClick: () => downloadPDF(url),
|
|
18511
|
+
className: pdfViewerStyles.button,
|
|
18512
|
+
title: "Download",
|
|
18513
|
+
children: "Download"
|
|
18514
|
+
}
|
|
18515
|
+
),
|
|
18430
18516
|
enablePrint && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { onClick: () => window.print(), title: "Print", children: "Print" }),
|
|
18431
18517
|
enableFullscreen && typeof document !== "undefined" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
18432
18518
|
"button",
|
|
@@ -18480,10 +18566,10 @@ function PDFThumbnails({
|
|
|
18480
18566
|
};
|
|
18481
18567
|
generateThumbnails();
|
|
18482
18568
|
}, [pdfDoc, numPages]);
|
|
18483
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className:
|
|
18569
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: pdfViewerStyles.thumbnails, children: thumbnails.map((thumb, idx) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
18484
18570
|
"div",
|
|
18485
18571
|
{
|
|
18486
|
-
className: `${
|
|
18572
|
+
className: `${pdfViewerStyles.thumbnail} ${idx + 1 === currentPage ? pdfViewerStyles.active : ""}`,
|
|
18487
18573
|
onClick: () => onSelectPage(idx + 1),
|
|
18488
18574
|
children: [
|
|
18489
18575
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
@@ -18501,7 +18587,7 @@ function PDFThumbnails({
|
|
|
18501
18587
|
}
|
|
18502
18588
|
}
|
|
18503
18589
|
),
|
|
18504
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className:
|
|
18590
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: pdfViewerStyles.pageNumber, children: idx + 1 })
|
|
18505
18591
|
]
|
|
18506
18592
|
},
|
|
18507
18593
|
idx
|
|
@@ -18531,6 +18617,9 @@ function PDFViewer({
|
|
|
18531
18617
|
initialZoom = "auto",
|
|
18532
18618
|
withCredentials = false
|
|
18533
18619
|
} = config;
|
|
18620
|
+
(0, import_react8.useEffect)(() => {
|
|
18621
|
+
injectPDFViewerStyles();
|
|
18622
|
+
}, []);
|
|
18534
18623
|
const { document: document2, pdfDoc, loading, error } = usePDFDocument(url, onError, withCredentials);
|
|
18535
18624
|
const pageState = usePageState({
|
|
18536
18625
|
totalPages: document2?.numPages || 0,
|
|
@@ -18553,18 +18642,18 @@ function PDFViewer({
|
|
|
18553
18642
|
}
|
|
18554
18643
|
}, [search.results, onSearchResults]);
|
|
18555
18644
|
if (error) {
|
|
18556
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className:
|
|
18645
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: pdfViewerStyles.error, style: { height, width }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { children: [
|
|
18557
18646
|
"Failed to load PDF: ",
|
|
18558
18647
|
error.message
|
|
18559
18648
|
] }) });
|
|
18560
18649
|
}
|
|
18561
18650
|
if (loading) {
|
|
18562
|
-
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className:
|
|
18651
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: pdfViewerStyles.loading, style: { height, width }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "Loading PDF..." }) });
|
|
18563
18652
|
}
|
|
18564
18653
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
18565
18654
|
"div",
|
|
18566
18655
|
{
|
|
18567
|
-
className: `${
|
|
18656
|
+
className: `${pdfViewerStyles.viewer} ${className || ""}`,
|
|
18568
18657
|
style: { height, width, ...style },
|
|
18569
18658
|
children: [
|
|
18570
18659
|
showControls && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
@@ -18580,7 +18669,7 @@ function PDFViewer({
|
|
|
18580
18669
|
url
|
|
18581
18670
|
}
|
|
18582
18671
|
),
|
|
18583
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className:
|
|
18672
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: pdfViewerStyles.content, children: [
|
|
18584
18673
|
showThumbnails && document2 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
18585
18674
|
PDFThumbnails,
|
|
18586
18675
|
{
|
|
@@ -18604,46 +18693,6 @@ function PDFViewer({
|
|
|
18604
18693
|
}
|
|
18605
18694
|
);
|
|
18606
18695
|
}
|
|
18607
|
-
async function isLinearizedPDF(url) {
|
|
18608
|
-
try {
|
|
18609
|
-
const response = await fetch(url, { headers: { Range: "bytes=0-1024" } });
|
|
18610
|
-
const buffer = await response.arrayBuffer();
|
|
18611
|
-
const view = new Uint8Array(buffer);
|
|
18612
|
-
const text = new TextDecoder().decode(view);
|
|
18613
|
-
return text.includes("Linearized");
|
|
18614
|
-
} catch {
|
|
18615
|
-
return false;
|
|
18616
|
-
}
|
|
18617
|
-
}
|
|
18618
|
-
function downloadPDF(url, filename) {
|
|
18619
|
-
const link = document.createElement("a");
|
|
18620
|
-
link.href = url;
|
|
18621
|
-
link.download = filename || "document.pdf";
|
|
18622
|
-
document.body.appendChild(link);
|
|
18623
|
-
link.click();
|
|
18624
|
-
document.body.removeChild(link);
|
|
18625
|
-
}
|
|
18626
|
-
function calculateScaleForPageFit(pageWidth, pageHeight, containerWidth, containerHeight) {
|
|
18627
|
-
const widthRatio = containerWidth / pageWidth;
|
|
18628
|
-
const heightRatio = containerHeight / pageHeight;
|
|
18629
|
-
return Math.min(widthRatio, heightRatio);
|
|
18630
|
-
}
|
|
18631
|
-
function formatFileSize(bytes) {
|
|
18632
|
-
if (bytes === 0) return "0 Bytes";
|
|
18633
|
-
const k = 1024;
|
|
18634
|
-
const sizes = ["Bytes", "KB", "MB", "GB"];
|
|
18635
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
18636
|
-
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i];
|
|
18637
|
-
}
|
|
18638
|
-
async function extractPageText(pdfDoc, pageNumber) {
|
|
18639
|
-
try {
|
|
18640
|
-
const page = await pdfDoc.getPage(pageNumber);
|
|
18641
|
-
const textContent = await page.getTextContent();
|
|
18642
|
-
return textContent.items.filter((item) => "str" in item).map((item) => item.str).join(" ");
|
|
18643
|
-
} catch {
|
|
18644
|
-
return "";
|
|
18645
|
-
}
|
|
18646
|
-
}
|
|
18647
18696
|
function getOptimalRangeHeader(fileSize) {
|
|
18648
18697
|
const chunkSize = Math.min(65536, Math.ceil(fileSize * 0.1));
|
|
18649
18698
|
return {
|
|
@@ -18668,9 +18717,9 @@ function createProgressiveFetchHandler(onProgress) {
|
|
|
18668
18717
|
return response.arrayBuffer();
|
|
18669
18718
|
};
|
|
18670
18719
|
}
|
|
18671
|
-
var import_react8, import_react9, import_react10, import_react11, import_react12, import_react13, import_react14, import_jsx_runtime5, import_jsx_runtime6, import_react15, import_jsx_runtime7, import_jsx_runtime8, DEFAULT_SCALE, CACHE_SIZE, MIN_ZOOM, MAX_ZOOM, ZOOM_STEP,
|
|
18720
|
+
var import_react8, import_react9, import_react10, import_react11, import_react12, import_react13, import_react14, import_jsx_runtime5, import_jsx_runtime6, import_react15, import_jsx_runtime7, import_jsx_runtime8, DEFAULT_SCALE, CACHE_SIZE, MIN_ZOOM, MAX_ZOOM, ZOOM_STEP, PDF_VIEWER_STYLES, stylesInjected, pdfViewerStyles, linearizedPDFConfig;
|
|
18672
18721
|
var init_dist = __esm({
|
|
18673
|
-
"node_modules/.pnpm/@page-speed+pdf-viewer@0.1.
|
|
18722
|
+
"node_modules/.pnpm/@page-speed+pdf-viewer@0.1.6_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@page-speed/pdf-viewer/dist/index.js"() {
|
|
18674
18723
|
"use client";
|
|
18675
18724
|
import_react8 = require("react");
|
|
18676
18725
|
import_react9 = require("react");
|
|
@@ -18689,7 +18738,56 @@ var init_dist = __esm({
|
|
|
18689
18738
|
MIN_ZOOM = 0.5;
|
|
18690
18739
|
MAX_ZOOM = 3;
|
|
18691
18740
|
ZOOM_STEP = 0.25;
|
|
18692
|
-
|
|
18741
|
+
PDF_VIEWER_STYLES = `
|
|
18742
|
+
/* Core viewer layout */
|
|
18743
|
+
.PDFViewer_viewer { display: flex; flex-direction: column; background: #f5f5f5; font-family: system-ui, -apple-system, sans-serif; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1); height: 100%; width: 100%; }
|
|
18744
|
+
|
|
18745
|
+
/* Controls */
|
|
18746
|
+
.PDFViewer_controls { display: flex; align-items: center; gap: 8px; padding: 12px 16px; background: #fff; border-bottom: 1px solid #e0e0e0; overflow-x: auto; flex-wrap: wrap; flex-shrink: 0; z-index: 10; position: relative; }
|
|
18747
|
+
.PDFViewer_controls button { padding: 8px 14px; background: #007bff; color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; font-weight: 500; transition: background 150ms, box-shadow 150ms; white-space: nowrap; }
|
|
18748
|
+
.PDFViewer_controls button:hover:not(:disabled) { background: #0056b3; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
|
18749
|
+
.PDFViewer_controls button:disabled { opacity: 0.5; cursor: not-allowed; background: #6c757d; }
|
|
18750
|
+
|
|
18751
|
+
.PDFViewer_pageInput { width: 60px; padding: 8px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; text-align: center; font-weight: 500; }
|
|
18752
|
+
.PDFViewer_pageInput:focus { outline: none; border-color: #007bff; box-shadow: 0 0 0 2px rgba(0,123,255,0.1); }
|
|
18753
|
+
.PDFViewer_pageTotal { font-size: 14px; color: #666; font-weight: 500; white-space: nowrap; }
|
|
18754
|
+
.PDFViewer_zoomLevel { font-size: 14px; color: #333; min-width: 60px; text-align: center; font-weight: 600; }
|
|
18755
|
+
|
|
18756
|
+
.PDFViewer_searchInput { padding: 6px 12px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; }
|
|
18757
|
+
.PDFViewer_searchResults { font-size: 12px; color: #666; }
|
|
18758
|
+
|
|
18759
|
+
.PDFViewer_button { padding: 6px 12px; background: #28a745; color: #fff; border: none; border-radius: 4px; text-decoration: none; cursor: pointer; transition: background 150ms; font-size: 14px; font-weight: 500; }
|
|
18760
|
+
.PDFViewer_button:hover { background: #218838; }
|
|
18761
|
+
|
|
18762
|
+
/* Main content */
|
|
18763
|
+
.PDFViewer_content { display: flex; flex: 1; overflow: hidden; min-height: 0; }
|
|
18764
|
+
.PDFViewer_canvas { flex: 1; overflow: auto; display: flex; align-items: center; justify-content: center; background: #fff; padding: 20px; }
|
|
18765
|
+
.PDFViewer_canvas canvas { max-width: 100%; height: auto !important; box-shadow: 0 2px 8px rgba(0,0,0,0.15); display: block; }
|
|
18766
|
+
|
|
18767
|
+
/* Thumbnails */
|
|
18768
|
+
.PDFViewer_thumbnails { width: 120px; overflow-y: auto; background: #fff; border-right: 1px solid #e0e0e0; padding: 8px; display: flex; flex-direction: column; gap: 8px; }
|
|
18769
|
+
.PDFViewer_thumbnail { position: relative; cursor: pointer; border: 2px solid transparent; border-radius: 4px; overflow: hidden; transition: border-color 150ms, box-shadow 150ms; }
|
|
18770
|
+
.PDFViewer_thumbnail:hover { border-color: #007bff; box-shadow: 0 2px 4px rgba(0,123,255,0.2); }
|
|
18771
|
+
.PDFViewer_thumbnail.PDFViewer_active { border-color: #007bff; box-shadow: 0 2px 8px rgba(0,123,255,0.4); }
|
|
18772
|
+
.PDFViewer_thumbnail canvas { width: 100%; height: auto; display: block; }
|
|
18773
|
+
.PDFViewer_pageNumber { position: absolute; bottom: 4px; right: 4px; font-size: 11px; background: rgba(0,0,0,0.7); color: #fff; padding: 2px 4px; border-radius: 2px; }
|
|
18774
|
+
|
|
18775
|
+
/* Loading & error */
|
|
18776
|
+
.PDFViewer_loading, .PDFViewer_error { display: flex; align-items: center; justify-content: center; background: #fff; border-radius: 8px; }
|
|
18777
|
+
.PDFViewer_loading p, .PDFViewer_error p { font-size: 16px; color: #666; }
|
|
18778
|
+
.PDFViewer_error p { color: #dc3545; }
|
|
18779
|
+
|
|
18780
|
+
/* Responsive tweaks */
|
|
18781
|
+
@media (max-width: 768px) {
|
|
18782
|
+
.PDFViewer_controls { gap: 6px; padding: 8px 12px; }
|
|
18783
|
+
.PDFViewer_controls button { padding: 4px 8px; font-size: 12px; }
|
|
18784
|
+
.PDFViewer_pageInput { width: 50px; }
|
|
18785
|
+
.PDFViewer_thumbnails { width: 80px; }
|
|
18786
|
+
.PDFViewer_searchInput { padding: 4px 8px; font-size: 12px; }
|
|
18787
|
+
}
|
|
18788
|
+
`;
|
|
18789
|
+
stylesInjected = false;
|
|
18790
|
+
pdfViewerStyles = {
|
|
18693
18791
|
viewer: "PDFViewer_viewer",
|
|
18694
18792
|
controls: "PDFViewer_controls",
|
|
18695
18793
|
pageInput: "PDFViewer_pageInput",
|
|
@@ -22753,10 +22851,56 @@ function LightboxChrome({
|
|
|
22753
22851
|
try {
|
|
22754
22852
|
const response = await fetch(currentItem.src);
|
|
22755
22853
|
const blob = await response.blob();
|
|
22854
|
+
const getFileExtension = () => {
|
|
22855
|
+
const contentType = response.headers.get("Content-Type");
|
|
22856
|
+
if (contentType) {
|
|
22857
|
+
const mimeToExt = {
|
|
22858
|
+
"application/pdf": ".pdf",
|
|
22859
|
+
"image/jpeg": ".jpg",
|
|
22860
|
+
"image/jpg": ".jpg",
|
|
22861
|
+
"image/png": ".png",
|
|
22862
|
+
"image/gif": ".gif",
|
|
22863
|
+
"image/webp": ".webp",
|
|
22864
|
+
"image/svg+xml": ".svg",
|
|
22865
|
+
"video/mp4": ".mp4",
|
|
22866
|
+
"video/webm": ".webm",
|
|
22867
|
+
"video/quicktime": ".mov"
|
|
22868
|
+
};
|
|
22869
|
+
const baseMime = contentType.split(";")[0].trim().toLowerCase();
|
|
22870
|
+
if (mimeToExt[baseMime]) {
|
|
22871
|
+
return mimeToExt[baseMime];
|
|
22872
|
+
}
|
|
22873
|
+
}
|
|
22874
|
+
try {
|
|
22875
|
+
const urlObj = new URL(currentItem.src, window.location.origin);
|
|
22876
|
+
const pathname = urlObj.pathname;
|
|
22877
|
+
const lastDotIndex = pathname.lastIndexOf(".");
|
|
22878
|
+
if (lastDotIndex > pathname.lastIndexOf("/")) {
|
|
22879
|
+
const ext = pathname.substring(lastDotIndex).toLowerCase();
|
|
22880
|
+
if (ext.length >= 2 && ext.length <= 6) {
|
|
22881
|
+
return ext;
|
|
22882
|
+
}
|
|
22883
|
+
}
|
|
22884
|
+
} catch {
|
|
22885
|
+
}
|
|
22886
|
+
const typeToExt = {
|
|
22887
|
+
"pdf": ".pdf",
|
|
22888
|
+
"image": ".jpg",
|
|
22889
|
+
"video": ".mp4"
|
|
22890
|
+
};
|
|
22891
|
+
if (currentItem.type && typeToExt[currentItem.type]) {
|
|
22892
|
+
return typeToExt[currentItem.type];
|
|
22893
|
+
}
|
|
22894
|
+
return "";
|
|
22895
|
+
};
|
|
22896
|
+
const baseName = currentItem.title || "download";
|
|
22897
|
+
const extension = getFileExtension();
|
|
22898
|
+
const hasExtension = baseName.includes(".") && baseName.lastIndexOf(".") > baseName.length - 6;
|
|
22899
|
+
const filename = hasExtension ? baseName : `${baseName}${extension}`;
|
|
22756
22900
|
const url = window.URL.createObjectURL(blob);
|
|
22757
22901
|
const link = document.createElement("a");
|
|
22758
22902
|
link.href = url;
|
|
22759
|
-
link.download =
|
|
22903
|
+
link.download = filename;
|
|
22760
22904
|
document.body.appendChild(link);
|
|
22761
22905
|
link.click();
|
|
22762
22906
|
document.body.removeChild(link);
|