react-os-shell 0.1.55 → 0.1.63

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.
Files changed (46) hide show
  1. package/dist/{Browser-34KKFXNU.js → Browser-DJL2TT56.js} +3 -3
  2. package/dist/{Browser-34KKFXNU.js.map → Browser-DJL2TT56.js.map} +1 -1
  3. package/dist/{Calculator-LJMNOIS6.js → Calculator-CIAX4UDE.js} +4 -4
  4. package/dist/{Calculator-LJMNOIS6.js.map → Calculator-CIAX4UDE.js.map} +1 -1
  5. package/dist/{Calendar-MK27QPLK.js → Calendar-LMKNYJ7J.js} +3 -3
  6. package/dist/{Calendar-MK27QPLK.js.map → Calendar-LMKNYJ7J.js.map} +1 -1
  7. package/dist/{CurrencyConverter-HFPJAIPX.js → CurrencyConverter-QSMM26HX.js} +4 -4
  8. package/dist/{CurrencyConverter-HFPJAIPX.js.map → CurrencyConverter-QSMM26HX.js.map} +1 -1
  9. package/dist/{Documents-3UPQ5QTF.js → Documents-OCP3FEKB.js} +88 -124
  10. package/dist/Documents-OCP3FEKB.js.map +1 -0
  11. package/dist/{Email-ANMJEGEV.js → Email-E7FTMUDO.js} +3 -3
  12. package/dist/{Email-ANMJEGEV.js.map → Email-E7FTMUDO.js.map} +1 -1
  13. package/dist/Files-BYZQMLJJ.js +7 -0
  14. package/dist/{Files-N3QQLSXV.js.map → Files-BYZQMLJJ.js.map} +1 -1
  15. package/dist/{Minesweeper-UUHQCDAC.js → Minesweeper-YUQVBS2S.js} +3 -3
  16. package/dist/{Minesweeper-UUHQCDAC.js.map → Minesweeper-YUQVBS2S.js.map} +1 -1
  17. package/dist/{Notepad-W2PKOGWE.js → Notepad-MJRVAKGR.js} +3 -3
  18. package/dist/{Notepad-W2PKOGWE.js.map → Notepad-MJRVAKGR.js.map} +1 -1
  19. package/dist/{PomodoroTimer-4ZYITLNH.js → PomodoroTimer-P5PLQAO7.js} +4 -4
  20. package/dist/{PomodoroTimer-4ZYITLNH.js.map → PomodoroTimer-P5PLQAO7.js.map} +1 -1
  21. package/dist/Preview-R2V2HL6V.js +6 -0
  22. package/dist/{Preview-IEPHQIJE.js.map → Preview-R2V2HL6V.js.map} +1 -1
  23. package/dist/{Spreadsheet-QIBLYKVF.js → Spreadsheet-KL2TS6GG.js} +3 -3
  24. package/dist/{Spreadsheet-QIBLYKVF.js.map → Spreadsheet-KL2TS6GG.js.map} +1 -1
  25. package/dist/{Weather-ZJE7DNKB.js → Weather-WPMGZ2QY.js} +4 -4
  26. package/dist/{Weather-ZJE7DNKB.js.map → Weather-WPMGZ2QY.js.map} +1 -1
  27. package/dist/apps/index.d.ts +1 -1
  28. package/dist/apps/index.js +22 -22
  29. package/dist/apps/index.js.map +1 -1
  30. package/dist/{chunk-K6COBRQA.js → chunk-7S2XQTV7.js} +155 -122
  31. package/dist/chunk-7S2XQTV7.js.map +1 -0
  32. package/dist/{chunk-OZFHOQYG.js → chunk-AVP2E5H5.js} +3 -3
  33. package/dist/{chunk-OZFHOQYG.js.map → chunk-AVP2E5H5.js.map} +1 -1
  34. package/dist/{chunk-53CE7OVT.js → chunk-GBQOM343.js} +61 -13
  35. package/dist/chunk-GBQOM343.js.map +1 -0
  36. package/dist/{chunk-CEBFLP6R.js → chunk-RZUFEZWB.js} +4 -4
  37. package/dist/{chunk-CEBFLP6R.js.map → chunk-RZUFEZWB.js.map} +1 -1
  38. package/dist/index.d.ts +15 -4
  39. package/dist/index.js +4 -4
  40. package/dist/{types-BKoa7nhP.d.ts → types-D_4ifuf-.d.ts} +14 -1
  41. package/package.json +1 -1
  42. package/dist/Documents-3UPQ5QTF.js.map +0 -1
  43. package/dist/Files-N3QQLSXV.js +0 -7
  44. package/dist/Preview-IEPHQIJE.js +0 -6
  45. package/dist/chunk-53CE7OVT.js.map +0 -1
  46. package/dist/chunk-K6COBRQA.js.map +0 -1
@@ -1,9 +1,15 @@
1
1
  import { toast_default } from './chunk-WIJ45SYD.js';
2
- import { WindowTitle, getActiveModalId } from './chunk-53CE7OVT.js';
3
- import { useState, useEffect, useRef } from 'react';
2
+ import { WindowTitle, getActiveModalId } from './chunk-GBQOM343.js';
3
+ import { createContext, useState, useEffect, useRef, useContext } from 'react';
4
+ import { createPortal } from 'react-dom';
4
5
  import * as pdfjsLib from 'pdfjs-dist';
5
6
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
7
 
8
+ var ToolbarSlotContext = createContext(null);
9
+ function PanelActions({ children }) {
10
+ const slot = useContext(ToolbarSlotContext);
11
+ return slot ? createPortal(children, slot) : null;
12
+ }
7
13
  var _stencilContextPatched = false;
8
14
  function ensureStencilContextAttribute() {
9
15
  if (_stencilContextPatched) return;
@@ -58,6 +64,7 @@ function Preview() {
58
64
  const titleName = data?.filename ? truncateForTitle(data.filename) : "Untitled";
59
65
  const fileRef = useRef(null);
60
66
  const rootRef = useRef(null);
67
+ const [toolbarSlotEl, setToolbarSlotEl] = useState(null);
61
68
  const [isDragging, setIsDragging] = useState(false);
62
69
  const dragDepthRef = useRef(0);
63
70
  const handlePick = () => fileRef.current?.click();
@@ -138,7 +145,8 @@ function Preview() {
138
145
  data?.filename && /* @__PURE__ */ jsxs(Fragment, { children: [
139
146
  /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-gray-300 mx-1" }),
140
147
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-gray-700 truncate max-w-[200px]", title: data.filename, children: data.filename })
141
- ] })
148
+ ] }),
149
+ /* @__PURE__ */ jsx("div", { ref: setToolbarSlotEl, className: "ml-auto flex items-center gap-1 text-xs" })
142
150
  ] });
143
151
  let body;
144
152
  if (!data) {
@@ -218,7 +226,7 @@ function Preview() {
218
226
  children: [
219
227
  /* @__PURE__ */ jsx(WindowTitle, { title: `${titleName} - Preview` }),
220
228
  Toolbar,
221
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0", children: body }),
229
+ /* @__PURE__ */ jsx(ToolbarSlotContext.Provider, { value: toolbarSlotEl, children: /* @__PURE__ */ jsx("div", { className: "flex-1 min-h-0", children: body }) }),
222
230
  isDragging && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-blue-500/15 border-4 border-dashed border-blue-500 pointer-events-none flex items-center justify-center z-20", children: /* @__PURE__ */ jsx("div", { className: "px-4 py-2 rounded-md bg-blue-600 text-white text-sm font-medium shadow-lg", children: "Drop to open" }) })
223
231
  ]
224
232
  }
@@ -238,6 +246,7 @@ function ConvertingPanel({ filename, message }) {
238
246
  /* @__PURE__ */ jsx("style", { children: `@keyframes preview-bar { 0% { transform: translateX(-110%); } 100% { transform: translateX(310%); } }` })
239
247
  ] });
240
248
  }
249
+ var ZOOM_PRESETS = [50, 75, 100, 125, 150, 200, 300, 400];
241
250
  function PdfPanel({ url, filename, onDownload, onEmail }) {
242
251
  const canvasRef = useRef(null);
243
252
  const containerRef = useRef(null);
@@ -282,6 +291,8 @@ function PdfPanel({ url, filename, onDownload, onEmail }) {
282
291
  const canvas = canvasRef.current;
283
292
  canvas.width = viewport.width;
284
293
  canvas.height = viewport.height;
294
+ canvas.style.width = `${viewport.width}px`;
295
+ canvas.style.height = `${viewport.height}px`;
285
296
  const ctx = canvas.getContext("2d");
286
297
  p.render({ canvas, canvasContext: ctx, viewport }).promise.catch(() => {
287
298
  });
@@ -334,41 +345,55 @@ function PdfPanel({ url, filename, onDownload, onEmail }) {
334
345
  };
335
346
  const btn = "px-2 py-1 rounded hover:bg-gray-200 transition-colors text-gray-600 flex items-center gap-1";
336
347
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
337
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-1.5 border-b border-gray-200 bg-gray-50 shrink-0 text-xs", children: [
338
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
339
- /* @__PURE__ */ jsx("button", { onClick: () => setPage((p) => Math.max(1, p - 1)), disabled: page <= 1, className: "px-2 py-1 rounded hover:bg-gray-200 disabled:opacity-30", children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.75 19.5L8.25 12l7.5-7.5" }) }) }),
340
- /* @__PURE__ */ jsxs("span", { className: "text-gray-600 font-medium tabular-nums", children: [
341
- page,
342
- " / ",
343
- totalPages
344
- ] }),
345
- /* @__PURE__ */ jsx("button", { onClick: () => setPage((p) => Math.min(totalPages, p + 1)), disabled: page >= totalPages, className: "px-2 py-1 rounded hover:bg-gray-200 disabled:opacity-30", children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8.25 4.5l7.5 7.5-7.5 7.5" }) }) })
348
+ /* @__PURE__ */ jsxs(PanelActions, { children: [
349
+ /* @__PURE__ */ jsx("button", { onClick: () => setPage((p) => Math.max(1, p - 1)), disabled: page <= 1, className: "px-1 py-1 rounded hover:bg-gray-200 disabled:opacity-30 text-gray-600", children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15.75 19.5L8.25 12l7.5-7.5" }) }) }),
350
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-600 font-medium tabular-nums", children: [
351
+ page,
352
+ " / ",
353
+ totalPages
346
354
  ] }),
347
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
348
- /* @__PURE__ */ jsx("button", { onClick: () => setScale((s) => Math.max(0.3, Math.round((s - 0.25) * 100) / 100)), className: btn, children: "\u2212" }),
349
- /* @__PURE__ */ jsxs("span", { className: "text-gray-500 w-12 text-center tabular-nums", children: [
350
- Math.round(scale * 100),
351
- "%"
352
- ] }),
353
- /* @__PURE__ */ jsx("button", { onClick: () => setScale((s) => Math.min(4, Math.round((s + 0.25) * 100) / 100)), className: btn, children: "+" }),
354
- /* @__PURE__ */ jsx("button", { onClick: fitWidth, className: btn, children: "Fit" })
355
+ /* @__PURE__ */ jsx("button", { onClick: () => setPage((p) => Math.min(totalPages, p + 1)), disabled: page >= totalPages, className: "px-1 py-1 rounded hover:bg-gray-200 disabled:opacity-30 text-gray-600", children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8.25 4.5l7.5 7.5-7.5 7.5" }) }) }),
356
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-gray-300 mx-1" }),
357
+ /* @__PURE__ */ jsx("button", { onClick: () => setScale((s) => Math.max(0.3, Math.round((s - 0.25) * 100) / 100)), className: btn, children: "\u2212" }),
358
+ /* @__PURE__ */ jsxs(
359
+ "select",
360
+ {
361
+ value: ZOOM_PRESETS.includes(Math.round(scale * 100)) ? Math.round(scale * 100) : "custom",
362
+ onChange: (e) => {
363
+ const v = e.target.value;
364
+ if (v !== "custom") setScale(Number(v) / 100);
365
+ },
366
+ className: "bg-transparent hover:bg-gray-200 rounded px-1 py-1 text-gray-600 tabular-nums cursor-pointer focus:outline-none focus:ring-1 focus:ring-blue-400",
367
+ title: "Zoom",
368
+ children: [
369
+ !ZOOM_PRESETS.includes(Math.round(scale * 100)) && /* @__PURE__ */ jsxs("option", { value: "custom", children: [
370
+ Math.round(scale * 100),
371
+ "%"
372
+ ] }),
373
+ ZOOM_PRESETS.map((p) => /* @__PURE__ */ jsxs("option", { value: p, children: [
374
+ p,
375
+ "%"
376
+ ] }, p))
377
+ ]
378
+ }
379
+ ),
380
+ /* @__PURE__ */ jsx("button", { onClick: () => setScale((s) => Math.min(4, Math.round((s + 0.25) * 100) / 100)), className: btn, children: "+" }),
381
+ /* @__PURE__ */ jsx("button", { onClick: fitWidth, className: btn, children: "Fit" }),
382
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-gray-300 mx-1" }),
383
+ /* @__PURE__ */ jsxs("button", { onClick: handlePrint, className: btn, children: [
384
+ /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6.72 13.829c-.24.03-.48.062-.72.096m.72-.096a42.415 42.415 0 0110.56 0m-10.56 0L6.34 18m10.94-4.171c.24.03.48.062.72.096m-.72-.096L17.66 18m0 0l.229 2.523a1.125 1.125 0 01-1.12 1.227H7.231c-.662 0-1.18-.568-1.12-1.227L6.34 18m11.318 0h1.091A2.25 2.25 0 0021 15.75V9.456c0-1.081-.768-2.015-1.837-2.175a48.055 48.055 0 00-1.913-.247M6.34 18H5.25A2.25 2.25 0 013 15.75V9.456c0-1.081.768-2.015 1.837-2.175a48.041 48.041 0 011.913-.247m10.5 0a48.536 48.536 0 00-10.5 0m10.5 0V3.375c0-.621-.504-1.125-1.125-1.125h-8.25c-.621 0-1.125.504-1.125 1.125v3.659M18 10.5h.008v.008H18V10.5zm-3 0h.008v.008H15V10.5z" }) }),
385
+ "Print"
355
386
  ] }),
356
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
357
- /* @__PURE__ */ jsxs("button", { onClick: handlePrint, className: btn, children: [
358
- /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6.72 13.829c-.24.03-.48.062-.72.096m.72-.096a42.415 42.415 0 0110.56 0m-10.56 0L6.34 18m10.94-4.171c.24.03.48.062.72.096m-.72-.096L17.66 18m0 0l.229 2.523a1.125 1.125 0 01-1.12 1.227H7.231c-.662 0-1.18-.568-1.12-1.227L6.34 18m11.318 0h1.091A2.25 2.25 0 0021 15.75V9.456c0-1.081-.768-2.015-1.837-2.175a48.055 48.055 0 00-1.913-.247M6.34 18H5.25A2.25 2.25 0 013 15.75V9.456c0-1.081.768-2.015 1.837-2.175a48.041 48.041 0 011.913-.247m10.5 0a48.536 48.536 0 00-10.5 0m10.5 0V3.375c0-.621-.504-1.125-1.125-1.125h-8.25c-.621 0-1.125.504-1.125 1.125v3.659M18 10.5h.008v.008H18V10.5zm-3 0h.008v.008H15V10.5z" }) }),
359
- "Print"
360
- ] }),
361
- /* @__PURE__ */ jsxs("button", { onClick: onDownload ?? handleDefaultDownload, className: btn, children: [
362
- /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" }) }),
363
- "Download"
364
- ] }),
365
- onEmail && /* @__PURE__ */ jsxs("button", { onClick: onEmail, className: btn, children: [
366
- /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" }) }),
367
- "Email"
368
- ] })
387
+ /* @__PURE__ */ jsxs("button", { onClick: onDownload ?? handleDefaultDownload, className: btn, children: [
388
+ /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" }) }),
389
+ "Download"
390
+ ] }),
391
+ onEmail && /* @__PURE__ */ jsxs("button", { onClick: onEmail, className: btn, children: [
392
+ /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" }) }),
393
+ "Email"
369
394
  ] })
370
395
  ] }),
371
- /* @__PURE__ */ jsx("div", { ref: containerRef, className: "flex-1 overflow-auto bg-gray-100 flex justify-center p-4", children: loading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-20 text-gray-400 text-sm", children: "Loading PDF..." }) : /* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "shadow-lg rounded" }) })
396
+ /* @__PURE__ */ jsx("div", { ref: containerRef, className: "flex-1 overflow-auto bg-gray-100", children: loading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full text-gray-400 text-sm", children: "Loading PDF..." }) : /* @__PURE__ */ jsx("div", { className: "min-h-full flex items-center justify-center p-4", children: /* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "shadow-lg rounded" }) }) })
372
397
  ] });
373
398
  }
374
399
  var DEFAULT_DXF_FONTS = [
@@ -538,42 +563,36 @@ function DxfPanel({ url, filename, onDownload, onEmail }) {
538
563
  return "#" + n.toString(16).padStart(6, "0");
539
564
  };
540
565
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
541
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-1.5 border-b border-gray-200 bg-gray-50 shrink-0 text-xs", children: [
542
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
543
- /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-600", children: "DXF" }),
544
- /* @__PURE__ */ jsx("span", { className: "text-gray-400 truncate max-w-xs", children: filename })
566
+ /* @__PURE__ */ jsxs(PanelActions, { children: [
567
+ /* @__PURE__ */ jsxs(
568
+ "button",
569
+ {
570
+ onClick: () => setShowLayers((s) => !s),
571
+ className: btn + (showLayers ? " bg-gray-200" : ""),
572
+ title: "Toggle layer visibility",
573
+ disabled: layers.length === 0,
574
+ children: [
575
+ /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6.429 9.75L2.25 12l4.179 2.25m0-4.5l5.571 3 5.571-3m-11.142 0L2.25 7.5 12 2.25l9.75 5.25-4.179 2.25m0 0L21.75 12l-4.179 2.25m0 0l4.179 2.25L12 21.75 2.25 16.5l4.179-2.25m11.142 0l-5.571 3-5.571-3" }) }),
576
+ "Layers ",
577
+ layers.length > 0 && /* @__PURE__ */ jsxs("span", { className: "text-gray-400", children: [
578
+ "(",
579
+ layers.filter((l) => l.visible).length,
580
+ "/",
581
+ layers.length,
582
+ ")"
583
+ ] })
584
+ ]
585
+ }
586
+ ),
587
+ /* @__PURE__ */ jsx("button", { onClick: () => setShowHint((s) => !s), className: btn, title: "How to navigate", children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z" }) }) }),
588
+ /* @__PURE__ */ jsx("button", { onClick: handleResetView, className: btn, title: "Fit drawing to view", children: "Fit" }),
589
+ /* @__PURE__ */ jsxs("button", { onClick: onDownload ?? handleDefaultDownload, className: btn, children: [
590
+ /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" }) }),
591
+ "Download"
545
592
  ] }),
546
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 relative", children: [
547
- /* @__PURE__ */ jsxs(
548
- "button",
549
- {
550
- onClick: () => setShowLayers((s) => !s),
551
- className: btn + (showLayers ? " bg-gray-200" : ""),
552
- title: "Toggle layer visibility",
553
- disabled: layers.length === 0,
554
- children: [
555
- /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6.429 9.75L2.25 12l4.179 2.25m0-4.5l5.571 3 5.571-3m-11.142 0L2.25 7.5 12 2.25l9.75 5.25-4.179 2.25m0 0L21.75 12l-4.179 2.25m0 0l4.179 2.25L12 21.75 2.25 16.5l4.179-2.25m11.142 0l-5.571 3-5.571-3" }) }),
556
- "Layers ",
557
- layers.length > 0 && /* @__PURE__ */ jsxs("span", { className: "text-gray-400", children: [
558
- "(",
559
- layers.filter((l) => l.visible).length,
560
- "/",
561
- layers.length,
562
- ")"
563
- ] })
564
- ]
565
- }
566
- ),
567
- /* @__PURE__ */ jsx("button", { onClick: () => setShowHint((s) => !s), className: btn, title: "How to navigate", children: /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z" }) }) }),
568
- /* @__PURE__ */ jsx("button", { onClick: handleResetView, className: btn, title: "Fit drawing to view", children: "Fit" }),
569
- /* @__PURE__ */ jsxs("button", { onClick: onDownload ?? handleDefaultDownload, className: btn, children: [
570
- /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" }) }),
571
- "Download"
572
- ] }),
573
- onEmail && /* @__PURE__ */ jsxs("button", { onClick: onEmail, className: btn, children: [
574
- /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" }) }),
575
- "Email"
576
- ] })
593
+ onEmail && /* @__PURE__ */ jsxs("button", { onClick: onEmail, className: btn, children: [
594
+ /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" }) }),
595
+ "Email"
577
596
  ] })
578
597
  ] }),
579
598
  /* @__PURE__ */ jsxs("div", { className: "relative flex-1 bg-white min-h-0", children: [
@@ -658,8 +677,9 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
658
677
  const [showEdges, setShowEdges] = useState(true);
659
678
  const [edgeColor, setEdgeColor] = useState("#000000");
660
679
  const [edgeThreshold, setEdgeThreshold] = useState(1);
661
- const [showMeshes, setShowMeshes] = useState(true);
662
- const [showSettings, setShowSettings] = useState(true);
680
+ const [showMeshes, setShowMeshes] = useState(false);
681
+ const [showSettings, setShowSettings] = useState(false);
682
+ const [perspective, setPerspective] = useState(true);
663
683
  const [sectionEnabled, setSectionEnabled] = useState(false);
664
684
  const [sectionAxis, setSectionAxis] = useState("z");
665
685
  const [sectionFlip, setSectionFlip] = useState(false);
@@ -1040,6 +1060,15 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1040
1060
  } catch {
1041
1061
  }
1042
1062
  };
1063
+ useEffect(() => {
1064
+ const OV = ovRef.current;
1065
+ const v = viewerRef.current;
1066
+ if (!OV || !v?.viewer || loading) return;
1067
+ try {
1068
+ v.viewer.SetProjectionMode(perspective ? OV.ProjectionMode.Perspective : OV.ProjectionMode.Orthographic);
1069
+ } catch {
1070
+ }
1071
+ }, [perspective, loading]);
1043
1072
  const setCameraPreset = (preset) => {
1044
1073
  const OV = ovRef.current;
1045
1074
  const v = viewerRef.current;
@@ -1163,9 +1192,7 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1163
1192
  const tBtnActive = "h-8 w-8 shrink-0 flex items-center justify-center rounded bg-gray-200 text-gray-900";
1164
1193
  const tBtnSep = "h-5 w-px bg-gray-300 mx-1";
1165
1194
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full bg-white", children: [
1166
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 px-2 py-1.5 bg-gray-50 border-b border-gray-200 shrink-0", children: [
1167
- /* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold tracking-wide text-gray-700 px-2 truncate max-w-xs", title: filename, children: filename }),
1168
- /* @__PURE__ */ jsx("div", { className: tBtnSep }),
1195
+ /* @__PURE__ */ jsxs(PanelActions, { children: [
1169
1196
  /* @__PURE__ */ jsx("button", { onClick: handleFit, className: tBtn, title: "Fit to view", children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" }) }) }),
1170
1197
  /* @__PURE__ */ jsx("div", { className: tBtnSep }),
1171
1198
  /* @__PURE__ */ jsx("button", { onClick: () => setCameraPreset("iso"), className: tBtn, title: "Isometric view", children: /* @__PURE__ */ jsx("span", { className: "text-[10px] font-semibold", children: "ISO" }) }),
@@ -1178,7 +1205,16 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1178
1205
  /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M16.5 12.75a4.5 4.5 0 11-9 0 4.5 4.5 0 019 0zM18.75 10.5h.008v.008h-.008V10.5z" })
1179
1206
  ] }) }),
1180
1207
  /* @__PURE__ */ jsx("button", { onClick: () => setShowHint((s) => !s), className: tBtn, title: "How to navigate", children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z" }) }) }),
1181
- /* @__PURE__ */ jsx("div", { className: "flex-1" }),
1208
+ /* @__PURE__ */ jsx(
1209
+ "button",
1210
+ {
1211
+ onClick: () => setPerspective((p) => !p),
1212
+ className: perspective ? tBtnActive : tBtn,
1213
+ title: perspective ? "Switch to orthographic view" : "Switch to perspective view",
1214
+ children: /* @__PURE__ */ jsx("span", { className: "text-[10px] font-semibold", children: perspective ? "PSP" : "ORT" })
1215
+ }
1216
+ ),
1217
+ /* @__PURE__ */ jsx("div", { className: tBtnSep }),
1182
1218
  /* @__PURE__ */ jsx("button", { onClick: () => setShowMeshes((s) => !s), className: showMeshes ? tBtnActive : tBtn, title: "Toggle meshes panel", children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" }) }) }),
1183
1219
  /* @__PURE__ */ jsx("button", { onClick: () => setShowSettings((s) => !s), className: showSettings ? tBtnActive : tBtn, title: "Toggle display panel", children: /* @__PURE__ */ jsxs("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: [
1184
1220
  /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" }),
@@ -1187,33 +1223,37 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1187
1223
  /* @__PURE__ */ jsx("button", { onClick: onDownload ?? handleDefaultDownload, className: tBtn, title: "Download original file", children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" }) }) }),
1188
1224
  onEmail && /* @__PURE__ */ jsx("button", { onClick: onEmail, className: tBtn, title: "Email", children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" }) }) })
1189
1225
  ] }),
1190
- /* @__PURE__ */ jsxs("div", { className: "flex-1 flex min-h-0", children: [
1191
- showMeshes && /* @__PURE__ */ jsxs("div", { className: "w-60 shrink-0 bg-gray-50 border-r border-gray-200 flex flex-col", children: [
1192
- /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-[11px] font-semibold uppercase tracking-wide text-gray-500 border-b border-gray-200", children: "Meshes" }),
1226
+ /* @__PURE__ */ jsx("div", { className: "flex-1 flex min-h-0", children: /* @__PURE__ */ jsxs("div", { className: "relative flex-1 min-w-0", style: { background: bgColor }, children: [
1227
+ /* @__PURE__ */ jsx("div", { ref: containerRef, style: { width: "100%", height: "100%" } }),
1228
+ showMeshes && /* @__PURE__ */ jsxs("div", { className: "absolute top-2 left-2 w-64 max-h-[80%] flex flex-col bg-white/95 backdrop-blur border border-gray-200 rounded-md shadow-xl z-10 text-xs", children: [
1229
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-2 py-1.5 border-b border-gray-200 bg-gray-50", children: [
1230
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700", children: "Meshes" }),
1231
+ /* @__PURE__ */ jsx("button", { onClick: () => setShowMeshes(false), className: "px-1.5 py-0.5 rounded hover:bg-gray-200 text-gray-600", title: "Close", children: "\xD7" })
1232
+ ] }),
1193
1233
  /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto py-1", children: tree ? renderTreeNode(tree) : /* @__PURE__ */ jsx("div", { className: "px-3 py-3 text-[11px] text-gray-500 italic", children: loading ? "Reading model\u2026" : "No structure available" }) }),
1194
1234
  tree && /* @__PURE__ */ jsx("div", { className: "px-3 py-1.5 text-[10px] text-gray-500 border-t border-gray-200", children: hidden.size === 0 ? "All visible" : `${hidden.size} hidden` })
1195
1235
  ] }),
1196
- /* @__PURE__ */ jsxs("div", { className: "relative flex-1 min-w-0", style: { background: bgColor }, children: [
1197
- /* @__PURE__ */ jsx("div", { ref: containerRef, style: { width: "100%", height: "100%" } }),
1198
- showHint && !loading && !error && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-3 left-1/2 -translate-x-1/2 bg-gray-900/85 text-white text-[11px] px-3 py-1.5 rounded-full shadow-lg flex items-center gap-3 z-10 pointer-events-none", children: [
1199
- /* @__PURE__ */ jsx("span", { children: "Drag to rotate" }),
1200
- /* @__PURE__ */ jsx("span", { className: "text-white/40", children: "\u2022" }),
1201
- /* @__PURE__ */ jsx("span", { children: "Right-click drag to pan" }),
1202
- /* @__PURE__ */ jsx("span", { className: "text-white/40", children: "\u2022" }),
1203
- /* @__PURE__ */ jsx("span", { children: "Scroll to zoom" })
1204
- ] }),
1205
- loading && /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 flex flex-col items-center justify-center bg-white/85 text-sm text-gray-600 gap-2", children: [
1206
- /* @__PURE__ */ jsxs("svg", { className: "h-6 w-6 text-blue-500 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: [
1207
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeOpacity: "0.2" }),
1208
- /* @__PURE__ */ jsx("path", { d: "M22 12a10 10 0 0 1-10 10", strokeLinecap: "round" })
1209
- ] }),
1210
- /* @__PURE__ */ jsx("span", { children: "Loading 3D model\u2026" }),
1211
- ext === "STP" || ext === "STEP" ? /* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-400", children: "STEP files load OpenCascade WASM (~5 MB) on first use." }) : null
1236
+ showHint && !loading && !error && /* @__PURE__ */ jsxs("div", { className: "absolute bottom-3 left-1/2 -translate-x-1/2 bg-gray-900/85 text-white text-[11px] px-3 py-1.5 rounded-full shadow-lg flex items-center gap-3 z-10 pointer-events-none", children: [
1237
+ /* @__PURE__ */ jsx("span", { children: "Drag to rotate" }),
1238
+ /* @__PURE__ */ jsx("span", { className: "text-white/40", children: "\u2022" }),
1239
+ /* @__PURE__ */ jsx("span", { children: "Right-click drag to pan" }),
1240
+ /* @__PURE__ */ jsx("span", { className: "text-white/40", children: "\u2022" }),
1241
+ /* @__PURE__ */ jsx("span", { children: "Scroll to zoom" })
1242
+ ] }),
1243
+ loading && /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 flex flex-col items-center justify-center bg-white/85 text-sm text-gray-600 gap-2", children: [
1244
+ /* @__PURE__ */ jsxs("svg", { className: "h-6 w-6 text-blue-500 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: [
1245
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeOpacity: "0.2" }),
1246
+ /* @__PURE__ */ jsx("path", { d: "M22 12a10 10 0 0 1-10 10", strokeLinecap: "round" })
1212
1247
  ] }),
1213
- error && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-sm text-red-600 px-6 text-center bg-white/85", children: error })
1248
+ /* @__PURE__ */ jsx("span", { children: "Loading 3D model\u2026" }),
1249
+ ext === "STP" || ext === "STEP" ? /* @__PURE__ */ jsx("span", { className: "text-[10px] text-gray-400", children: "STEP files load OpenCascade WASM (~5 MB) on first use." }) : null
1214
1250
  ] }),
1215
- showSettings && /* @__PURE__ */ jsxs("div", { className: "w-60 shrink-0 bg-gray-50 border-l border-gray-200 flex flex-col", children: [
1216
- /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-[11px] font-semibold uppercase tracking-wide text-gray-500 border-b border-gray-200", children: "Model Display" }),
1251
+ error && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-sm text-red-600 px-6 text-center bg-white/85", children: error }),
1252
+ showSettings && /* @__PURE__ */ jsxs("div", { className: "absolute top-2 right-2 w-64 max-h-[80%] flex flex-col bg-white/95 backdrop-blur border border-gray-200 rounded-md shadow-xl z-10 text-xs", children: [
1253
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-2 py-1.5 border-b border-gray-200 bg-gray-50", children: [
1254
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-700", children: "Model Display" }),
1255
+ /* @__PURE__ */ jsx("button", { onClick: () => setShowSettings(false), className: "px-1.5 py-0.5 rounded hover:bg-gray-200 text-gray-600", title: "Close", children: "\xD7" })
1256
+ ] }),
1217
1257
  /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-3 py-3 space-y-3 text-[12px] text-gray-700", children: [
1218
1258
  /* @__PURE__ */ jsxs("label", { className: "flex items-center justify-between gap-2", children: [
1219
1259
  /* @__PURE__ */ jsx("span", { children: "Background Color" }),
@@ -1337,7 +1377,7 @@ function StepPanel({ url, filename, onDownload, onEmail }) {
1337
1377
  }
1338
1378
  ) })
1339
1379
  ] })
1340
- ] })
1380
+ ] }) })
1341
1381
  ] });
1342
1382
  }
1343
1383
  function ImagePanel({ url, filename, onDownload, onEmail }) {
@@ -1351,29 +1391,22 @@ function ImagePanel({ url, filename, onDownload, onEmail }) {
1351
1391
  };
1352
1392
  const btn = "px-2 py-1 rounded hover:bg-gray-200 transition-colors text-gray-600 flex items-center gap-1";
1353
1393
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
1354
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-1.5 border-b border-gray-200 bg-gray-50 shrink-0 text-xs", children: [
1355
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1356
- /* @__PURE__ */ jsx("span", { className: "font-medium text-gray-600", children: "Image" }),
1357
- /* @__PURE__ */ jsx("span", { className: "text-gray-400 truncate max-w-xs", children: filename })
1394
+ /* @__PURE__ */ jsxs(PanelActions, { children: [
1395
+ /* @__PURE__ */ jsx("button", { onClick: () => setZoom((z) => Math.max(0.1, Math.round((z - 0.25) * 100) / 100)), className: btn, children: "\u2212" }),
1396
+ /* @__PURE__ */ jsxs("span", { className: "text-gray-500 w-12 text-center tabular-nums", children: [
1397
+ Math.round(zoom * 100),
1398
+ "%"
1358
1399
  ] }),
1359
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1360
- /* @__PURE__ */ jsx("button", { onClick: () => setZoom((z) => Math.max(0.1, Math.round((z - 0.25) * 100) / 100)), className: btn, children: "\u2212" }),
1361
- /* @__PURE__ */ jsxs("span", { className: "text-gray-500 w-12 text-center tabular-nums", children: [
1362
- Math.round(zoom * 100),
1363
- "%"
1364
- ] }),
1365
- /* @__PURE__ */ jsx("button", { onClick: () => setZoom((z) => Math.min(8, Math.round((z + 0.25) * 100) / 100)), className: btn, children: "+" }),
1366
- /* @__PURE__ */ jsx("button", { onClick: () => setZoom(1), className: btn, children: "1:1" })
1400
+ /* @__PURE__ */ jsx("button", { onClick: () => setZoom((z) => Math.min(8, Math.round((z + 0.25) * 100) / 100)), className: btn, children: "+" }),
1401
+ /* @__PURE__ */ jsx("button", { onClick: () => setZoom(1), className: btn, children: "1:1" }),
1402
+ /* @__PURE__ */ jsx("div", { className: "h-4 w-px bg-gray-300 mx-1" }),
1403
+ /* @__PURE__ */ jsxs("button", { onClick: onDownload ?? handleDefaultDownload, className: btn, children: [
1404
+ /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" }) }),
1405
+ "Download"
1367
1406
  ] }),
1368
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1369
- /* @__PURE__ */ jsxs("button", { onClick: onDownload ?? handleDefaultDownload, className: btn, children: [
1370
- /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" }) }),
1371
- "Download"
1372
- ] }),
1373
- onEmail && /* @__PURE__ */ jsxs("button", { onClick: onEmail, className: btn, children: [
1374
- /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" }) }),
1375
- "Email"
1376
- ] })
1407
+ onEmail && /* @__PURE__ */ jsxs("button", { onClick: onEmail, className: btn, children: [
1408
+ /* @__PURE__ */ jsx("svg", { className: "h-3.5 w-3.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1.5, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" }) }),
1409
+ "Email"
1377
1410
  ] })
1378
1411
  ] }),
1379
1412
  /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto bg-gray-100 flex items-center justify-center p-4", children: error ? /* @__PURE__ */ jsx("div", { className: "text-sm text-red-600", children: "Failed to load image." }) : /* @__PURE__ */ jsx(
@@ -1390,5 +1423,5 @@ function ImagePanel({ url, filename, onDownload, onEmail }) {
1390
1423
  }
1391
1424
 
1392
1425
  export { Preview, setPdfPreview };
1393
- //# sourceMappingURL=chunk-K6COBRQA.js.map
1394
- //# sourceMappingURL=chunk-K6COBRQA.js.map
1426
+ //# sourceMappingURL=chunk-7S2XQTV7.js.map
1427
+ //# sourceMappingURL=chunk-7S2XQTV7.js.map