@zerohive/hive-viewer 0.2.0 → 0.2.2
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/README.md +123 -6
- package/dist/index.cjs +257 -112
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +261 -113
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +261 -113
- package/dist/styles.css +75 -0
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { useEffect as useEffect6, useMemo as useMemo6, useRef as useRef3, useSta
|
|
|
3
3
|
|
|
4
4
|
// src/utils/locale.ts
|
|
5
5
|
var defaultLocale = {
|
|
6
|
-
|
|
6
|
+
loading: "Loading\u2026",
|
|
7
7
|
"error.title": "Error",
|
|
8
8
|
"toolbar.layout.single": "Single page",
|
|
9
9
|
"toolbar.layout.two": "Side-by-side",
|
|
@@ -26,7 +26,17 @@ var defaultLocale = {
|
|
|
26
26
|
function guessFileType(name, explicit) {
|
|
27
27
|
if (explicit) return explicit;
|
|
28
28
|
const ext = (name?.split(".").pop() || "").toLowerCase();
|
|
29
|
-
const allowed = [
|
|
29
|
+
const allowed = [
|
|
30
|
+
"pdf",
|
|
31
|
+
"md",
|
|
32
|
+
"docx",
|
|
33
|
+
"xlsx",
|
|
34
|
+
"pptx",
|
|
35
|
+
"txt",
|
|
36
|
+
"png",
|
|
37
|
+
"jpg",
|
|
38
|
+
"svg"
|
|
39
|
+
];
|
|
30
40
|
return allowed.includes(ext) ? ext : "txt";
|
|
31
41
|
}
|
|
32
42
|
function arrayBufferToBase64(buf) {
|
|
@@ -57,7 +67,8 @@ async function resolveSource(args) {
|
|
|
57
67
|
const ab = await base64ToArrayBuffer(args.base64);
|
|
58
68
|
return { fileType, fileName, arrayBuffer: ab };
|
|
59
69
|
}
|
|
60
|
-
if (!args.fileUrl)
|
|
70
|
+
if (!args.fileUrl)
|
|
71
|
+
throw new Error("No file source provided. Use fileUrl, blob, or base64.");
|
|
61
72
|
const res = await fetch(args.fileUrl);
|
|
62
73
|
if (!res.ok) throw new Error(`Failed to fetch file (${res.status})`);
|
|
63
74
|
const total = Number(res.headers.get("content-length") || "") || void 0;
|
|
@@ -173,44 +184,69 @@ function SignaturePanel(props) {
|
|
|
173
184
|
|
|
174
185
|
// src/renderers/PdfRenderer.tsx
|
|
175
186
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
176
|
-
import {
|
|
187
|
+
import {
|
|
188
|
+
GlobalWorkerOptions,
|
|
189
|
+
getDocument
|
|
190
|
+
} from "pdfjs-dist";
|
|
177
191
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
178
192
|
function PdfRenderer(props) {
|
|
179
193
|
const { url, arrayBuffer } = props;
|
|
180
194
|
const [doc, setDoc] = useState(null);
|
|
181
195
|
const [pageCount, setPageCount] = useState(0);
|
|
182
|
-
const [rendered, setRendered] = useState(
|
|
196
|
+
const [rendered, setRendered] = useState(
|
|
197
|
+
/* @__PURE__ */ new Map()
|
|
198
|
+
);
|
|
183
199
|
const [thumbs, setThumbs] = useState([]);
|
|
184
200
|
const [size, setSize] = useState({ w: 840, h: 1188 });
|
|
201
|
+
const [error, setError] = useState(null);
|
|
202
|
+
const [loading, setLoading] = useState(false);
|
|
185
203
|
const containerRef = useRef(null);
|
|
186
204
|
useEffect(() => {
|
|
187
205
|
try {
|
|
188
|
-
GlobalWorkerOptions.workerSrc = new URL(
|
|
206
|
+
GlobalWorkerOptions.workerSrc = new URL(
|
|
207
|
+
"pdfjs-dist/build/pdf.worker.min.mjs",
|
|
208
|
+
import.meta.url
|
|
209
|
+
).toString();
|
|
189
210
|
} catch {
|
|
190
211
|
}
|
|
191
212
|
}, []);
|
|
192
213
|
useEffect(() => {
|
|
193
214
|
let cancel = false;
|
|
215
|
+
setError(null);
|
|
216
|
+
setLoading(true);
|
|
194
217
|
(async () => {
|
|
195
218
|
setDoc(null);
|
|
196
219
|
setRendered(/* @__PURE__ */ new Map());
|
|
197
220
|
setThumbs([]);
|
|
198
|
-
if (!url && !arrayBuffer)
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
221
|
+
if (!url && !arrayBuffer) {
|
|
222
|
+
setError("No PDF source provided.");
|
|
223
|
+
setLoading(false);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
const task = getDocument(
|
|
228
|
+
url ? { url, rangeChunkSize: 512 * 1024 } : { data: arrayBuffer }
|
|
229
|
+
);
|
|
230
|
+
const pdf = await task.promise;
|
|
231
|
+
if (cancel) return;
|
|
232
|
+
setDoc(pdf);
|
|
233
|
+
setPageCount(pdf.numPages);
|
|
234
|
+
props.onPageCount(pdf.numPages);
|
|
235
|
+
setThumbs(Array.from({ length: pdf.numPages }));
|
|
236
|
+
const p1 = await pdf.getPage(1);
|
|
237
|
+
const base = p1.getViewport({ scale: 1 });
|
|
238
|
+
const w = Math.min(980, Math.max(640, base.width));
|
|
239
|
+
const s = w / base.width;
|
|
240
|
+
const vp = p1.getViewport({ scale: s });
|
|
241
|
+
setSize({ w: Math.round(vp.width), h: Math.round(vp.height) });
|
|
242
|
+
} catch (e) {
|
|
243
|
+
setError(
|
|
244
|
+
"Failed to load PDF. " + (e instanceof Error ? e.message : "")
|
|
245
|
+
);
|
|
246
|
+
} finally {
|
|
247
|
+
setLoading(false);
|
|
248
|
+
}
|
|
249
|
+
})();
|
|
214
250
|
return () => {
|
|
215
251
|
cancel = true;
|
|
216
252
|
};
|
|
@@ -232,37 +268,43 @@ function PdfRenderer(props) {
|
|
|
232
268
|
(async () => {
|
|
233
269
|
for (const p of pagesToShow) {
|
|
234
270
|
if (rendered.has(p)) continue;
|
|
235
|
-
const page = await doc.getPage(p);
|
|
236
|
-
if (cancel) return;
|
|
237
|
-
const base = page.getViewport({ scale: 1 });
|
|
238
|
-
const vp = page.getViewport({ scale: size.w / base.width });
|
|
239
|
-
const canvas = document.createElement("canvas");
|
|
240
|
-
canvas.width = Math.round(vp.width);
|
|
241
|
-
canvas.height = Math.round(vp.height);
|
|
242
|
-
const ctx = canvas.getContext("2d", { alpha: false });
|
|
243
|
-
if (!ctx) continue;
|
|
244
|
-
await page.render({ canvasContext: ctx, viewport: vp }).promise;
|
|
245
|
-
if (cancel) return;
|
|
246
|
-
setRendered((prev) => {
|
|
247
|
-
const next = new Map(prev);
|
|
248
|
-
next.set(p, canvas);
|
|
249
|
-
return next;
|
|
250
|
-
});
|
|
251
271
|
try {
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
272
|
+
const page = await doc.getPage(p);
|
|
273
|
+
if (cancel) return;
|
|
274
|
+
const base = page.getViewport({ scale: 1 });
|
|
275
|
+
const vp = page.getViewport({ scale: size.w / base.width });
|
|
276
|
+
const canvas = document.createElement("canvas");
|
|
277
|
+
canvas.width = Math.round(vp.width);
|
|
278
|
+
canvas.height = Math.round(vp.height);
|
|
279
|
+
const ctx = canvas.getContext("2d", { alpha: false });
|
|
280
|
+
if (!ctx) continue;
|
|
281
|
+
await page.render({ canvasContext: ctx, viewport: vp }).promise;
|
|
282
|
+
if (cancel) return;
|
|
283
|
+
setRendered((prev) => {
|
|
284
|
+
const next = new Map(prev);
|
|
285
|
+
next.set(p, canvas);
|
|
286
|
+
return next;
|
|
287
|
+
});
|
|
288
|
+
if (!thumbs[p - 1]) {
|
|
289
|
+
const thumbCanvas = document.createElement("canvas");
|
|
290
|
+
const thumbScale = 120 / vp.width;
|
|
291
|
+
thumbCanvas.width = Math.round(vp.width * thumbScale);
|
|
292
|
+
thumbCanvas.height = Math.round(vp.height * thumbScale);
|
|
293
|
+
const thumbCtx = thumbCanvas.getContext("2d", { alpha: false });
|
|
294
|
+
if (thumbCtx) {
|
|
295
|
+
thumbCtx.drawImage(
|
|
296
|
+
canvas,
|
|
297
|
+
0,
|
|
298
|
+
0,
|
|
299
|
+
thumbCanvas.width,
|
|
300
|
+
thumbCanvas.height
|
|
301
|
+
);
|
|
302
|
+
setThumbs((prev) => {
|
|
303
|
+
const arr = prev.slice();
|
|
304
|
+
arr[p - 1] = thumbCanvas.toDataURL("image/png");
|
|
305
|
+
return arr;
|
|
306
|
+
});
|
|
307
|
+
}
|
|
266
308
|
}
|
|
267
309
|
} catch {
|
|
268
310
|
}
|
|
@@ -271,13 +313,16 @@ function PdfRenderer(props) {
|
|
|
271
313
|
return () => {
|
|
272
314
|
cancel = true;
|
|
273
315
|
};
|
|
274
|
-
}, [doc, pagesToShow, size.w, rendered]);
|
|
316
|
+
}, [doc, pagesToShow, size.w, rendered, thumbs]);
|
|
275
317
|
function onWheel(e) {
|
|
276
318
|
if (!pageCount) return;
|
|
277
319
|
if (Math.abs(e.deltaY) < 10) return;
|
|
278
320
|
const dir = e.deltaY > 0 ? 1 : -1;
|
|
279
321
|
const step = props.layout === "side-by-side" ? 2 : 1;
|
|
280
|
-
const next = Math.max(
|
|
322
|
+
const next = Math.max(
|
|
323
|
+
1,
|
|
324
|
+
Math.min(pageCount, props.currentPage + dir * step)
|
|
325
|
+
);
|
|
281
326
|
props.onCurrentPageChange(next);
|
|
282
327
|
}
|
|
283
328
|
function clickPlace(e, page) {
|
|
@@ -290,22 +335,37 @@ function PdfRenderer(props) {
|
|
|
290
335
|
}
|
|
291
336
|
return /* @__PURE__ */ jsxs4("div", { className: "hv-doc", ref: containerRef, onWheel, children: [
|
|
292
337
|
!doc ? /* @__PURE__ */ jsx4("div", { className: "hv-loading", children: "Loading PDF\u2026" }) : null,
|
|
293
|
-
doc ? /* @__PURE__ */ jsx4(
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
"
|
|
297
|
-
{
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
338
|
+
doc ? /* @__PURE__ */ jsx4(
|
|
339
|
+
"div",
|
|
340
|
+
{
|
|
341
|
+
className: props.layout === "side-by-side" ? "hv-pages hv-pages--two" : "hv-pages",
|
|
342
|
+
children: pagesToShow.map((p) => {
|
|
343
|
+
const c = rendered.get(p);
|
|
344
|
+
return /* @__PURE__ */ jsx4(
|
|
345
|
+
"div",
|
|
346
|
+
{
|
|
347
|
+
className: "hv-page",
|
|
348
|
+
style: { width: size.w, height: size.h },
|
|
349
|
+
onClick: (e) => clickPlace(e, p),
|
|
350
|
+
children: c ? /* @__PURE__ */ jsx4(
|
|
351
|
+
"canvas",
|
|
352
|
+
{
|
|
353
|
+
className: "hv-canvas",
|
|
354
|
+
width: c.width,
|
|
355
|
+
height: c.height,
|
|
356
|
+
ref: (node) => {
|
|
357
|
+
if (!node) return;
|
|
358
|
+
const ctx = node.getContext("2d");
|
|
359
|
+
if (ctx) ctx.drawImage(c, 0, 0);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
) : /* @__PURE__ */ jsx4("div", { className: "hv-loading", children: "Rendering\u2026" })
|
|
363
|
+
},
|
|
364
|
+
p
|
|
365
|
+
);
|
|
366
|
+
})
|
|
367
|
+
}
|
|
368
|
+
) : null
|
|
309
369
|
] });
|
|
310
370
|
}
|
|
311
371
|
|
|
@@ -427,17 +487,29 @@ var RichTextEditor = forwardRef((props, ref) => {
|
|
|
427
487
|
}
|
|
428
488
|
if (props.fileType === "docx") {
|
|
429
489
|
try {
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
490
|
+
const response = await fetch("/api/export-docx", {
|
|
491
|
+
method: "POST",
|
|
492
|
+
headers: { "Content-Type": "application/json" },
|
|
493
|
+
body: JSON.stringify({
|
|
494
|
+
html: stitched,
|
|
495
|
+
fileName: replaceExt(props.fileName, "docx")
|
|
496
|
+
})
|
|
437
497
|
});
|
|
498
|
+
if (!response.ok) throw new Error("Failed to generate DOCX");
|
|
499
|
+
const blob = await response.blob();
|
|
500
|
+
const url = window.URL.createObjectURL(blob);
|
|
501
|
+
const a = document.createElement("a");
|
|
502
|
+
a.href = url;
|
|
503
|
+
a.download = replaceExt(props.fileName, "docx");
|
|
504
|
+
document.body.appendChild(a);
|
|
505
|
+
a.click();
|
|
506
|
+
setTimeout(() => {
|
|
507
|
+
window.URL.revokeObjectURL(url);
|
|
508
|
+
a.remove();
|
|
509
|
+
}, 100);
|
|
438
510
|
} catch (err) {
|
|
439
511
|
alert(
|
|
440
|
-
"DOCX export
|
|
512
|
+
"DOCX export failed: " + (err instanceof Error ? err.message : String(err))
|
|
441
513
|
);
|
|
442
514
|
}
|
|
443
515
|
return;
|
|
@@ -601,7 +673,11 @@ function ensureExt(name, ext) {
|
|
|
601
673
|
// src/renderers/ImageRenderer.tsx
|
|
602
674
|
import { useEffect as useEffect4, useMemo as useMemo4, useState as useState4 } from "react";
|
|
603
675
|
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
604
|
-
function ImageRenderer({
|
|
676
|
+
function ImageRenderer({
|
|
677
|
+
arrayBuffer,
|
|
678
|
+
fileType,
|
|
679
|
+
fileName
|
|
680
|
+
}) {
|
|
605
681
|
const [zoom, setZoom] = useState4(1);
|
|
606
682
|
const url = useMemo4(() => {
|
|
607
683
|
if (!arrayBuffer) return void 0;
|
|
@@ -617,14 +693,42 @@ function ImageRenderer({ arrayBuffer, fileType, fileName }) {
|
|
|
617
693
|
/* @__PURE__ */ jsxs7("div", { className: "hv-mini-toolbar", children: [
|
|
618
694
|
/* @__PURE__ */ jsx7("div", { className: "hv-title", children: fileName }),
|
|
619
695
|
/* @__PURE__ */ jsx7("div", { className: "hv-spacer" }),
|
|
620
|
-
/* @__PURE__ */ jsx7(
|
|
696
|
+
/* @__PURE__ */ jsx7(
|
|
697
|
+
"button",
|
|
698
|
+
{
|
|
699
|
+
type: "button",
|
|
700
|
+
className: "hv-btn",
|
|
701
|
+
onClick: () => setZoom((z) => Math.max(0.25, z - 0.25)),
|
|
702
|
+
children: "-"
|
|
703
|
+
}
|
|
704
|
+
),
|
|
621
705
|
/* @__PURE__ */ jsxs7("div", { className: "hv-zoom", children: [
|
|
622
706
|
Math.round(zoom * 100),
|
|
623
707
|
"%"
|
|
624
708
|
] }),
|
|
625
|
-
/* @__PURE__ */ jsx7(
|
|
709
|
+
/* @__PURE__ */ jsx7(
|
|
710
|
+
"button",
|
|
711
|
+
{
|
|
712
|
+
type: "button",
|
|
713
|
+
className: "hv-btn",
|
|
714
|
+
onClick: () => setZoom((z) => Math.min(4, z + 0.25)),
|
|
715
|
+
children: "+"
|
|
716
|
+
}
|
|
717
|
+
)
|
|
626
718
|
] }),
|
|
627
|
-
/* @__PURE__ */
|
|
719
|
+
/* @__PURE__ */ jsxs7("div", { className: "hv-center", children: [
|
|
720
|
+
!arrayBuffer && /* @__PURE__ */ jsx7("div", { className: "hv-error", children: "No image data provided." }),
|
|
721
|
+
arrayBuffer && !url && /* @__PURE__ */ jsx7("div", { className: "hv-error", children: "Failed to load image." }),
|
|
722
|
+
url && /* @__PURE__ */ jsx7(
|
|
723
|
+
"img",
|
|
724
|
+
{
|
|
725
|
+
src: url,
|
|
726
|
+
alt: fileName,
|
|
727
|
+
style: { transform: `scale(${zoom})` },
|
|
728
|
+
className: "hv-image"
|
|
729
|
+
}
|
|
730
|
+
)
|
|
731
|
+
] })
|
|
628
732
|
] });
|
|
629
733
|
}
|
|
630
734
|
|
|
@@ -641,37 +745,57 @@ function extractText(xml) {
|
|
|
641
745
|
function PptxRenderer(props) {
|
|
642
746
|
const [slides, setSlides] = useState5([]);
|
|
643
747
|
const [thumbs, setThumbs] = useState5([]);
|
|
748
|
+
const [error, setError] = useState5(null);
|
|
749
|
+
const [loading, setLoading] = useState5(false);
|
|
644
750
|
useEffect5(() => {
|
|
645
751
|
let cancelled = false;
|
|
752
|
+
setError(null);
|
|
753
|
+
setLoading(true);
|
|
646
754
|
(async () => {
|
|
647
755
|
setSlides([]);
|
|
648
756
|
setThumbs([]);
|
|
649
757
|
if (!props.arrayBuffer) {
|
|
650
758
|
props.onSlideCount(1);
|
|
651
759
|
setSlides([{ index: 1, text: "No content" }]);
|
|
760
|
+
setError("No PPTX data provided.");
|
|
761
|
+
setLoading(false);
|
|
652
762
|
return;
|
|
653
763
|
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
764
|
+
try {
|
|
765
|
+
const zip = await JSZip.loadAsync(props.arrayBuffer);
|
|
766
|
+
const files = Object.keys(zip.files).filter((p) => /^ppt\/slides\/slide\d+\.xml$/.test(p)).sort((a, b) => {
|
|
767
|
+
const na = Number(a.match(/slide(\d+)\.xml/)?.[1] || 0);
|
|
768
|
+
const nb = Number(b.match(/slide(\d+)\.xml/)?.[1] || 0);
|
|
769
|
+
return na - nb;
|
|
770
|
+
});
|
|
771
|
+
const out = [];
|
|
772
|
+
for (let i = 0; i < files.length; i++) {
|
|
773
|
+
const xml = await zip.file(files[i]).async("string");
|
|
774
|
+
out.push({ index: i + 1, text: extractText(xml) });
|
|
775
|
+
}
|
|
776
|
+
if (cancelled) return;
|
|
777
|
+
const count = Math.max(1, out.length);
|
|
778
|
+
props.onSlideCount(count);
|
|
779
|
+
setSlides(out.length ? out : [{ index: 1, text: "(empty)" }]);
|
|
780
|
+
setThumbs(
|
|
781
|
+
Array.from(
|
|
782
|
+
{ length: count },
|
|
783
|
+
(_, i) => `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgThumb(i + 1))}`
|
|
784
|
+
)
|
|
785
|
+
);
|
|
786
|
+
} catch (e) {
|
|
787
|
+
props.onSlideCount(1);
|
|
788
|
+
setSlides([
|
|
789
|
+
{ index: 1, text: "Unable to render this .pptx in-browser." }
|
|
790
|
+
]);
|
|
791
|
+
setThumbs([void 0]);
|
|
792
|
+
setError(
|
|
793
|
+
"Failed to load PPTX. " + (e instanceof Error ? e.message : "")
|
|
794
|
+
);
|
|
795
|
+
} finally {
|
|
796
|
+
setLoading(false);
|
|
664
797
|
}
|
|
665
|
-
|
|
666
|
-
const count = Math.max(1, out.length);
|
|
667
|
-
props.onSlideCount(count);
|
|
668
|
-
setSlides(out.length ? out : [{ index: 1, text: "(empty)" }]);
|
|
669
|
-
setThumbs(Array.from({ length: count }, (_, i) => `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgThumb(i + 1))}`));
|
|
670
|
-
})().catch(() => {
|
|
671
|
-
props.onSlideCount(1);
|
|
672
|
-
setSlides([{ index: 1, text: "Unable to render this .pptx in-browser." }]);
|
|
673
|
-
setThumbs([void 0]);
|
|
674
|
-
});
|
|
798
|
+
})();
|
|
675
799
|
return () => {
|
|
676
800
|
cancelled = true;
|
|
677
801
|
};
|
|
@@ -680,19 +804,43 @@ function PptxRenderer(props) {
|
|
|
680
804
|
props.onThumbs(thumbs);
|
|
681
805
|
}, [thumbs]);
|
|
682
806
|
const pagesToShow = useMemo5(() => {
|
|
683
|
-
if (props.layout === "side-by-side")
|
|
807
|
+
if (props.layout === "side-by-side")
|
|
808
|
+
return [
|
|
809
|
+
props.currentPage,
|
|
810
|
+
Math.min(slides.length || props.currentPage + 1, props.currentPage + 1)
|
|
811
|
+
];
|
|
684
812
|
return [props.currentPage];
|
|
685
813
|
}, [props.currentPage, props.layout, slides.length]);
|
|
686
|
-
return /* @__PURE__ */
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
814
|
+
return /* @__PURE__ */ jsxs8("div", { className: "hv-doc", children: [
|
|
815
|
+
loading && /* @__PURE__ */ jsx8("div", { className: "hv-loading", children: "Loading PPTX\u2026" }),
|
|
816
|
+
error && /* @__PURE__ */ jsx8("div", { className: "hv-error", children: error }),
|
|
817
|
+
!loading && !error && (!slides || slides.length === 0) && /* @__PURE__ */ jsx8("div", { className: "hv-error", children: "No slides to display." }),
|
|
818
|
+
!error && slides && slides.length > 0 && /* @__PURE__ */ jsx8(
|
|
819
|
+
"div",
|
|
820
|
+
{
|
|
821
|
+
className: props.layout === "side-by-side" ? "hv-pages hv-pages--two" : "hv-pages",
|
|
822
|
+
children: pagesToShow.map((p) => {
|
|
823
|
+
const s = slides[p - 1];
|
|
824
|
+
return /* @__PURE__ */ jsxs8(
|
|
825
|
+
"div",
|
|
826
|
+
{
|
|
827
|
+
className: "hv-slide",
|
|
828
|
+
tabIndex: 0,
|
|
829
|
+
onFocus: () => props.onCurrentPageChange(p),
|
|
830
|
+
children: [
|
|
831
|
+
/* @__PURE__ */ jsxs8("div", { className: "hv-slide-title", children: [
|
|
832
|
+
"Slide ",
|
|
833
|
+
p
|
|
834
|
+
] }),
|
|
835
|
+
/* @__PURE__ */ jsx8("div", { className: "hv-slide-text", children: s?.text || "" })
|
|
836
|
+
]
|
|
837
|
+
},
|
|
838
|
+
p
|
|
839
|
+
);
|
|
840
|
+
})
|
|
841
|
+
}
|
|
842
|
+
)
|
|
843
|
+
] });
|
|
696
844
|
}
|
|
697
845
|
function svgThumb(n) {
|
|
698
846
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="180" height="100"><rect width="100%" height="100%" rx="12" fill="#111827"/><text x="50%" y="54%" font-size="18" fill="#e5e7eb" text-anchor="middle">${n}</text></svg>`;
|