@papyrus-sdk/ui-react 0.2.9 → 0.2.11

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/index.mjs CHANGED
@@ -1,10 +1,11 @@
1
1
  // components/Topbar.tsx
2
- import { useRef, useState, useEffect } from "react";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { createPortal } from "react-dom";
3
4
  import { useViewerStore } from "@papyrus-sdk/core";
4
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
5
6
  var Topbar = ({
6
7
  engine,
7
- showBrand = true,
8
+ showBrand = false,
8
9
  brand,
9
10
  title,
10
11
  showSidebarLeftToggle = true,
@@ -23,6 +24,7 @@ var Topbar = ({
23
24
  pageTheme,
24
25
  setDocumentState,
25
26
  accentColor,
27
+ toolDockOpen,
26
28
  toggleSidebarLeft,
27
29
  toggleSidebarRight,
28
30
  triggerScrollToPage
@@ -31,15 +33,37 @@ var Topbar = ({
31
33
  const zoomTimerRef = useRef(null);
32
34
  const pendingZoomRef = useRef(null);
33
35
  const [pageInput, setPageInput] = useState(currentPage.toString());
34
- const pageDigits = Math.max(2, String(pageCount || 1).length);
35
36
  const [showPageThemes, setShowPageThemes] = useState(false);
37
+ const [showMobileMenu, setShowMobileMenu] = useState(false);
38
+ const pageDigits = Math.max(2, String(pageCount || 1).length);
36
39
  const isDark = uiTheme === "dark";
40
+ const canUseDOM = typeof document !== "undefined";
41
+ const hasMobileMenu = showZoomControls || showPageThemeSelector || showUIToggle || showUpload;
37
42
  useEffect(() => {
38
43
  setPageInput(currentPage.toString());
39
44
  }, [currentPage]);
40
- useEffect(() => () => {
41
- if (zoomTimerRef.current) clearTimeout(zoomTimerRef.current);
42
- }, []);
45
+ useEffect(
46
+ () => () => {
47
+ if (zoomTimerRef.current) clearTimeout(zoomTimerRef.current);
48
+ },
49
+ []
50
+ );
51
+ useEffect(() => {
52
+ if (!hasMobileMenu) setShowMobileMenu(false);
53
+ }, [hasMobileMenu]);
54
+ useEffect(() => {
55
+ if (!showMobileMenu || !canUseDOM) return;
56
+ const previousOverflow = document.body.style.overflow;
57
+ const handleKeyDown = (event) => {
58
+ if (event.key === "Escape") setShowMobileMenu(false);
59
+ };
60
+ document.body.style.overflow = "hidden";
61
+ window.addEventListener("keydown", handleKeyDown);
62
+ return () => {
63
+ document.body.style.overflow = previousOverflow;
64
+ window.removeEventListener("keydown", handleKeyDown);
65
+ };
66
+ }, [showMobileMenu, canUseDOM]);
43
67
  const handleZoom = (delta) => {
44
68
  const baseZoom = pendingZoomRef.current ?? zoom;
45
69
  const nextZoom = Math.max(0.2, Math.min(5, baseZoom + delta));
@@ -56,10 +80,31 @@ var Topbar = ({
56
80
  };
57
81
  const handlePageChange = (page) => {
58
82
  if (pageCount <= 0) return;
59
- const p = Math.max(1, Math.min(pageCount, isNaN(page) ? 1 : page));
60
- engine.goToPage(p);
61
- setDocumentState({ currentPage: p });
62
- triggerScrollToPage(p - 1);
83
+ const nextPage = Math.max(1, Math.min(pageCount, isNaN(page) ? 1 : page));
84
+ engine.goToPage(nextPage);
85
+ setDocumentState({ currentPage: nextPage });
86
+ triggerScrollToPage(nextPage - 1);
87
+ };
88
+ const handleFileUpload = async (event) => {
89
+ const file = event.target.files?.[0];
90
+ event.target.value = "";
91
+ if (!file) return;
92
+ setDocumentState({ isLoaded: false });
93
+ try {
94
+ await engine.load(file);
95
+ setDocumentState({
96
+ isLoaded: true,
97
+ pageCount: engine.getPageCount(),
98
+ currentPage: 1,
99
+ outline: await engine.getOutline()
100
+ });
101
+ } catch (err) {
102
+ console.error("Upload failed", err);
103
+ setDocumentState({ isLoaded: true });
104
+ }
105
+ };
106
+ const toggleToolDock = () => {
107
+ setDocumentState({ toolDockOpen: !toolDockOpen });
63
108
  };
64
109
  const themes = [
65
110
  { id: "normal", name: "Original", color: "bg-white" },
@@ -67,100 +112,592 @@ var Topbar = ({
67
112
  { id: "dark", name: "Invertido", color: "bg-gray-800" },
68
113
  { id: "high-contrast", name: "Contraste", color: "bg-black" }
69
114
  ];
115
+ const mobileMenuOverlay = canUseDOM && hasMobileMenu && showMobileMenu ? createPortal(
116
+ /* @__PURE__ */ jsx(
117
+ "div",
118
+ {
119
+ className: "sm:hidden fixed inset-0 z-[200] bg-black/45",
120
+ onClick: (event) => {
121
+ if (event.target === event.currentTarget)
122
+ setShowMobileMenu(false);
123
+ },
124
+ children: /* @__PURE__ */ jsxs(
125
+ "div",
126
+ {
127
+ className: `absolute inset-x-0 bottom-0 rounded-t-2xl border-x border-t p-4 pb-6 shadow-2xl ${isDark ? "bg-[#181a1f] border-[#343a46] text-[#e6e9ef]" : "bg-white border-gray-200 text-gray-900"}`,
128
+ children: [
129
+ /* @__PURE__ */ jsx("div", { className: "mx-auto mb-4 h-1.5 w-10 rounded-full bg-gray-400/60" }),
130
+ /* @__PURE__ */ jsxs("div", { className: "mb-4 flex items-center justify-between", children: [
131
+ /* @__PURE__ */ jsx(
132
+ "span",
133
+ {
134
+ className: `text-sm font-semibold ${isDark ? "text-gray-100" : "text-gray-800"}`,
135
+ children: "A\xE7\xF5es r\xE1pidas"
136
+ }
137
+ ),
138
+ /* @__PURE__ */ jsx(
139
+ "button",
140
+ {
141
+ className: `p-2 rounded-md ${isDark ? "text-[#d9deea] hover:bg-white/10" : "text-gray-700 hover:bg-gray-100"}`,
142
+ onClick: () => setShowMobileMenu(false),
143
+ "aria-label": "Fechar menu",
144
+ children: /* @__PURE__ */ jsx(
145
+ "svg",
146
+ {
147
+ className: "w-5 h-5",
148
+ fill: "none",
149
+ stroke: "currentColor",
150
+ viewBox: "0 0 24 24",
151
+ children: /* @__PURE__ */ jsx(
152
+ "path",
153
+ {
154
+ strokeLinecap: "round",
155
+ strokeLinejoin: "round",
156
+ strokeWidth: 2,
157
+ d: "M6 18L18 6M6 6l12 12"
158
+ }
159
+ )
160
+ }
161
+ )
162
+ }
163
+ )
164
+ ] }),
165
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
166
+ showZoomControls && /* @__PURE__ */ jsxs(
167
+ "div",
168
+ {
169
+ className: `rounded-xl border p-3 ${isDark ? "bg-[#20242d] border-[#3a4252] text-[#e6e9ef]" : "bg-gray-50 border-gray-200"}`,
170
+ children: [
171
+ /* @__PURE__ */ jsx(
172
+ "div",
173
+ {
174
+ className: `mb-2 text-xs ${isDark ? "text-[#b7c0d2]" : "text-gray-600"}`,
175
+ children: "Zoom"
176
+ }
177
+ ),
178
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
179
+ /* @__PURE__ */ jsx(
180
+ "button",
181
+ {
182
+ onClick: () => handleZoom(-0.1),
183
+ className: "p-2 rounded-md border",
184
+ style: { color: accentColor, borderColor: accentColor },
185
+ children: /* @__PURE__ */ jsx(
186
+ "svg",
187
+ {
188
+ className: "w-4 h-4",
189
+ fill: "none",
190
+ stroke: "currentColor",
191
+ viewBox: "0 0 24 24",
192
+ children: /* @__PURE__ */ jsx(
193
+ "path",
194
+ {
195
+ strokeLinecap: "round",
196
+ strokeLinejoin: "round",
197
+ strokeWidth: 2,
198
+ d: "M20 12H4"
199
+ }
200
+ )
201
+ }
202
+ )
203
+ }
204
+ ),
205
+ /* @__PURE__ */ jsxs(
206
+ "span",
207
+ {
208
+ className: `text-sm font-semibold ${isDark ? "text-[#e6e9ef]" : "text-gray-800"}`,
209
+ children: [
210
+ Math.round(zoom * 100),
211
+ "%"
212
+ ]
213
+ }
214
+ ),
215
+ /* @__PURE__ */ jsx(
216
+ "button",
217
+ {
218
+ onClick: () => handleZoom(0.1),
219
+ className: "p-2 rounded-md border",
220
+ style: { color: accentColor, borderColor: accentColor },
221
+ children: /* @__PURE__ */ jsx(
222
+ "svg",
223
+ {
224
+ className: "w-4 h-4",
225
+ fill: "none",
226
+ stroke: "currentColor",
227
+ viewBox: "0 0 24 24",
228
+ children: /* @__PURE__ */ jsx(
229
+ "path",
230
+ {
231
+ strokeLinecap: "round",
232
+ strokeLinejoin: "round",
233
+ strokeWidth: 2,
234
+ d: "M12 4v16m8-8H4"
235
+ }
236
+ )
237
+ }
238
+ )
239
+ }
240
+ )
241
+ ] })
242
+ ]
243
+ }
244
+ ),
245
+ showPageThemeSelector && /* @__PURE__ */ jsxs(
246
+ "div",
247
+ {
248
+ className: `rounded-xl border p-3 ${isDark ? "bg-[#20242d] border-[#3a4252] text-[#e6e9ef]" : "bg-gray-50 border-gray-200"}`,
249
+ children: [
250
+ /* @__PURE__ */ jsx(
251
+ "div",
252
+ {
253
+ className: `mb-2 text-xs ${isDark ? "text-[#b7c0d2]" : "text-gray-600"}`,
254
+ children: "Tema da p\xE1gina"
255
+ }
256
+ ),
257
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2", children: themes.map((theme) => /* @__PURE__ */ jsx(
258
+ "button",
259
+ {
260
+ onClick: () => {
261
+ setDocumentState({ pageTheme: theme.id });
262
+ },
263
+ className: `rounded-lg border px-2 py-2 text-xs font-semibold ${pageTheme === theme.id ? "text-white" : isDark ? "text-[#dbe1ed] border-[#49556a]" : "text-gray-700 border-gray-300"}`,
264
+ style: pageTheme === theme.id ? {
265
+ backgroundColor: accentColor,
266
+ borderColor: accentColor
267
+ } : void 0,
268
+ children: theme.name
269
+ },
270
+ theme.id
271
+ )) })
272
+ ]
273
+ }
274
+ ),
275
+ showUIToggle && /* @__PURE__ */ jsxs(
276
+ "button",
277
+ {
278
+ onClick: () => {
279
+ setDocumentState({ uiTheme: isDark ? "light" : "dark" });
280
+ },
281
+ className: `w-full rounded-xl border px-3 py-3 text-left text-sm font-medium flex items-center gap-2 ${isDark ? "bg-[#20242d] border-[#3a4252] text-[#e6e9ef]" : "bg-gray-50 border-gray-200 text-gray-800"}`,
282
+ children: [
283
+ /* @__PURE__ */ jsx(
284
+ "svg",
285
+ {
286
+ className: "w-4 h-4 shrink-0",
287
+ fill: "none",
288
+ stroke: "currentColor",
289
+ viewBox: "0 0 24 24",
290
+ children: isDark ? /* @__PURE__ */ jsx(
291
+ "path",
292
+ {
293
+ strokeLinecap: "round",
294
+ strokeLinejoin: "round",
295
+ strokeWidth: 2,
296
+ d: "M12 3v1m0 16v1m8-9h1M3 12H2m15.364 6.364l.707.707M5.93 5.93l-.707-.707m12.141 0l-.707.707M5.93 18.07l-.707.707M12 17a5 5 0 100-10 5 5 0 000 10z"
297
+ }
298
+ ) : /* @__PURE__ */ jsx(
299
+ "path",
300
+ {
301
+ strokeLinecap: "round",
302
+ strokeLinejoin: "round",
303
+ strokeWidth: 2,
304
+ d: "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"
305
+ }
306
+ )
307
+ }
308
+ ),
309
+ isDark ? "Mudar para tema claro" : "Mudar para tema escuro"
310
+ ]
311
+ }
312
+ ),
313
+ showUpload && /* @__PURE__ */ jsxs(
314
+ "button",
315
+ {
316
+ onClick: () => {
317
+ setShowMobileMenu(false);
318
+ fileInputRef.current?.click();
319
+ },
320
+ className: "w-full rounded-xl px-3 py-3 text-left text-sm font-semibold text-white flex items-center gap-2",
321
+ style: { backgroundColor: accentColor },
322
+ children: [
323
+ /* @__PURE__ */ jsx(
324
+ "svg",
325
+ {
326
+ className: "w-4 h-4 shrink-0",
327
+ fill: "none",
328
+ stroke: "currentColor",
329
+ viewBox: "0 0 24 24",
330
+ children: /* @__PURE__ */ jsx(
331
+ "path",
332
+ {
333
+ strokeLinecap: "round",
334
+ strokeLinejoin: "round",
335
+ strokeWidth: 2,
336
+ d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
337
+ }
338
+ )
339
+ }
340
+ ),
341
+ "Upload de arquivo"
342
+ ]
343
+ }
344
+ )
345
+ ] })
346
+ ]
347
+ }
348
+ )
349
+ }
350
+ ),
351
+ document.body
352
+ ) : null;
70
353
  return /* @__PURE__ */ jsxs(
71
354
  "div",
72
355
  {
73
356
  "data-papyrus-theme": uiTheme,
74
- className: `papyrus-topbar papyrus-theme h-14 border-b flex items-center justify-between px-4 z-50 transition-colors duration-200 ${isDark ? "bg-[#1a1a1a] border-[#333] text-white" : "bg-white border-gray-200 text-gray-800"}`,
357
+ className: `papyrus-topbar papyrus-theme relative h-14 border-b flex items-center px-3 sm:px-4 z-50 transition-colors duration-200 ${isDark ? "bg-[#1a1a1a] border-[#333] text-white" : "bg-white border-gray-200 text-gray-800"}`,
75
358
  children: [
76
- /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3", children: [
77
- showSidebarLeftToggle && /* @__PURE__ */ jsx("button", { onClick: toggleSidebarLeft, className: `p-2 rounded-md ${isDark ? "hover:bg-white/10" : "hover:bg-gray-100"}`, children: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16M4 18h16" }) }) }),
78
- showBrand && (brand ?? /* @__PURE__ */ jsxs("span", { className: "font-bold text-lg tracking-tight", style: { color: accentColor }, children: [
79
- "Papyrus",
80
- /* @__PURE__ */ jsx("span", { className: isDark ? "text-white" : "text-gray-900", children: "Core" })
81
- ] })),
82
- title && /* @__PURE__ */ jsx("span", { className: `text-sm font-semibold truncate max-w-[220px] ${isDark ? "text-gray-200" : "text-gray-700"}`, title: typeof title === "string" ? title : void 0, children: title })
359
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0 z-10", children: [
360
+ showSidebarLeftToggle && /* @__PURE__ */ jsx(
361
+ "button",
362
+ {
363
+ onClick: toggleSidebarLeft,
364
+ className: `p-2 rounded-md ${isDark ? "hover:bg-white/10" : "hover:bg-gray-100"}`,
365
+ children: /* @__PURE__ */ jsx(
366
+ "svg",
367
+ {
368
+ className: "w-5 h-5",
369
+ fill: "none",
370
+ stroke: "currentColor",
371
+ viewBox: "0 0 24 24",
372
+ children: /* @__PURE__ */ jsx(
373
+ "path",
374
+ {
375
+ strokeLinecap: "round",
376
+ strokeLinejoin: "round",
377
+ strokeWidth: 2,
378
+ d: "M4 6h16M4 12h16M4 18h16"
379
+ }
380
+ )
381
+ }
382
+ )
383
+ }
384
+ ),
385
+ /* @__PURE__ */ jsx(
386
+ "button",
387
+ {
388
+ onClick: toggleToolDock,
389
+ className: `p-2 rounded-md border transition-colors ${toolDockOpen ? isDark ? "border-[#335ea8] bg-[#1b2f55] text-[#8fb6ff]" : "border-blue-300 bg-blue-50 text-blue-700" : isDark ? "border-[#444] bg-[#2a2a2a] hover:bg-[#333]" : "border-gray-300 bg-white hover:bg-gray-100"}`,
390
+ "aria-label": toolDockOpen ? "Fechar ferramentas" : "Abrir ferramentas",
391
+ title: toolDockOpen ? "Fechar ferramentas" : "Abrir ferramentas",
392
+ children: /* @__PURE__ */ jsx(
393
+ "svg",
394
+ {
395
+ className: "w-5 h-5",
396
+ fill: "none",
397
+ stroke: "currentColor",
398
+ viewBox: "0 0 24 24",
399
+ children: /* @__PURE__ */ jsx(
400
+ "path",
401
+ {
402
+ strokeLinecap: "round",
403
+ strokeLinejoin: "round",
404
+ strokeWidth: 2,
405
+ d: "M16.862 3.487a2.25 2.25 0 013.182 3.182L8.22 18.492a4.5 4.5 0 01-1.897 1.12l-2.692.898.898-2.692a4.5 4.5 0 011.12-1.897L16.862 3.487z"
406
+ }
407
+ )
408
+ }
409
+ )
410
+ }
411
+ ),
412
+ showBrand && (brand ?? /* @__PURE__ */ jsxs(
413
+ "span",
414
+ {
415
+ className: "font-bold text-base tracking-tight",
416
+ style: { color: accentColor },
417
+ children: [
418
+ "Papyrus",
419
+ /* @__PURE__ */ jsx("span", { className: isDark ? "text-white" : "text-gray-900", children: "Core" })
420
+ ]
421
+ }
422
+ )),
423
+ title && /* @__PURE__ */ jsx(
424
+ "span",
425
+ {
426
+ className: `text-sm font-semibold truncate min-w-0 max-w-[35vw] sm:max-w-[260px] ${isDark ? "text-gray-200" : "text-gray-700"}`,
427
+ title: typeof title === "string" ? title : void 0,
428
+ children: title
429
+ }
430
+ )
83
431
  ] }),
84
- (showPageControls || showZoomControls) && /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-4", children: [
85
- showPageControls && /* @__PURE__ */ jsxs("div", { className: `papyrus-control flex items-center rounded-lg p-1 space-x-1 border ${isDark ? "bg-[#2a2a2a] border-[#444]" : "bg-gray-50 border-gray-200"}`, children: [
86
- /* @__PURE__ */ jsx("button", { onClick: () => handlePageChange(currentPage - 1), className: "p-1.5 rounded transition-all hover:brightness-110", style: { color: accentColor }, children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }) }),
87
- /* @__PURE__ */ jsx(
88
- "input",
89
- {
90
- type: "text",
91
- className: "papyrus-input text-center bg-transparent focus:outline-none font-bold text-sm shrink-0",
92
- style: { width: `${pageDigits + 1.75}ch` },
93
- value: pageInput,
94
- onChange: (e) => setPageInput(e.target.value),
95
- onKeyDown: (e) => e.key === "Enter" && handlePageChange(parseInt(pageInput)),
96
- onBlur: () => handlePageChange(parseInt(pageInput))
97
- }
98
- ),
99
- /* @__PURE__ */ jsx("span", { className: "opacity-40 px-1", children: "/" }),
100
- /* @__PURE__ */ jsx("span", { className: "opacity-80 text-sm", children: pageCount > 0 ? pageCount : "\u2014" }),
101
- /* @__PURE__ */ jsx("button", { onClick: () => handlePageChange(currentPage + 1), className: "p-1.5 rounded transition-all hover:brightness-110", style: { color: accentColor }, children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) }) })
102
- ] }),
103
- showZoomControls && /* @__PURE__ */ jsxs("div", { className: `papyrus-control flex items-center rounded-lg p-1 border ${isDark ? "bg-[#2a2a2a] border-[#444]" : "bg-gray-50 border-gray-200"}`, children: [
104
- /* @__PURE__ */ jsx("button", { onClick: () => handleZoom(-0.1), className: "p-1.5 rounded hover:brightness-110", style: { color: accentColor }, children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M20 12H4" }) }) }),
105
- /* @__PURE__ */ jsxs("span", { className: "px-3 text-xs font-bold min-w-[50px] text-center", children: [
106
- Math.round(zoom * 100),
107
- "%"
108
- ] }),
109
- /* @__PURE__ */ jsx("button", { onClick: () => handleZoom(0.1), className: "p-1.5 rounded hover:brightness-110", style: { color: accentColor }, children: /* @__PURE__ */ jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 4v16m8-8H4" }) }) })
110
- ] })
432
+ (showPageControls || showZoomControls) && /* @__PURE__ */ jsxs("div", { className: "absolute left-1/2 -translate-x-1/2 flex items-center gap-3", children: [
433
+ showPageControls && /* @__PURE__ */ jsxs(
434
+ "div",
435
+ {
436
+ className: `papyrus-control flex items-center rounded-lg p-1 space-x-1 border ${isDark ? "bg-[#2a2a2a] border-[#444]" : "bg-gray-50 border-gray-200"}`,
437
+ children: [
438
+ /* @__PURE__ */ jsx(
439
+ "button",
440
+ {
441
+ onClick: () => handlePageChange(currentPage - 1),
442
+ className: "p-1.5 rounded transition-all hover:brightness-110",
443
+ style: { color: accentColor },
444
+ children: /* @__PURE__ */ jsx(
445
+ "svg",
446
+ {
447
+ className: "w-4 h-4",
448
+ fill: "none",
449
+ stroke: "currentColor",
450
+ viewBox: "0 0 24 24",
451
+ children: /* @__PURE__ */ jsx(
452
+ "path",
453
+ {
454
+ strokeLinecap: "round",
455
+ strokeLinejoin: "round",
456
+ strokeWidth: 2,
457
+ d: "M15 19l-7-7 7-7"
458
+ }
459
+ )
460
+ }
461
+ )
462
+ }
463
+ ),
464
+ /* @__PURE__ */ jsx(
465
+ "input",
466
+ {
467
+ type: "text",
468
+ className: "papyrus-input text-center bg-transparent focus:outline-none font-bold text-sm shrink-0",
469
+ style: { width: `${pageDigits + 1.75}ch` },
470
+ value: pageInput,
471
+ onChange: (e) => setPageInput(e.target.value),
472
+ onKeyDown: (e) => e.key === "Enter" && handlePageChange(parseInt(pageInput)),
473
+ onBlur: () => handlePageChange(parseInt(pageInput))
474
+ }
475
+ ),
476
+ /* @__PURE__ */ jsx("span", { className: "opacity-40 px-1", children: "/" }),
477
+ /* @__PURE__ */ jsx("span", { className: "opacity-80 text-sm", children: pageCount > 0 ? pageCount : "\u2014" }),
478
+ /* @__PURE__ */ jsx(
479
+ "button",
480
+ {
481
+ onClick: () => handlePageChange(currentPage + 1),
482
+ className: "p-1.5 rounded transition-all hover:brightness-110",
483
+ style: { color: accentColor },
484
+ children: /* @__PURE__ */ jsx(
485
+ "svg",
486
+ {
487
+ className: "w-4 h-4",
488
+ fill: "none",
489
+ stroke: "currentColor",
490
+ viewBox: "0 0 24 24",
491
+ children: /* @__PURE__ */ jsx(
492
+ "path",
493
+ {
494
+ strokeLinecap: "round",
495
+ strokeLinejoin: "round",
496
+ strokeWidth: 2,
497
+ d: "M9 5l7 7-7 7"
498
+ }
499
+ )
500
+ }
501
+ )
502
+ }
503
+ )
504
+ ]
505
+ }
506
+ ),
507
+ showZoomControls && /* @__PURE__ */ jsxs(
508
+ "div",
509
+ {
510
+ className: `papyrus-control hidden sm:flex items-center rounded-lg p-1 border ${isDark ? "bg-[#2a2a2a] border-[#444]" : "bg-gray-50 border-gray-200"}`,
511
+ children: [
512
+ /* @__PURE__ */ jsx(
513
+ "button",
514
+ {
515
+ onClick: () => handleZoom(-0.1),
516
+ className: "p-1.5 rounded hover:brightness-110",
517
+ style: { color: accentColor },
518
+ children: /* @__PURE__ */ jsx(
519
+ "svg",
520
+ {
521
+ className: "w-4 h-4",
522
+ fill: "none",
523
+ stroke: "currentColor",
524
+ viewBox: "0 0 24 24",
525
+ children: /* @__PURE__ */ jsx(
526
+ "path",
527
+ {
528
+ strokeLinecap: "round",
529
+ strokeLinejoin: "round",
530
+ strokeWidth: 2,
531
+ d: "M20 12H4"
532
+ }
533
+ )
534
+ }
535
+ )
536
+ }
537
+ ),
538
+ /* @__PURE__ */ jsxs("span", { className: "px-3 text-xs font-bold min-w-[50px] text-center", children: [
539
+ Math.round(zoom * 100),
540
+ "%"
541
+ ] }),
542
+ /* @__PURE__ */ jsx(
543
+ "button",
544
+ {
545
+ onClick: () => handleZoom(0.1),
546
+ className: "p-1.5 rounded hover:brightness-110",
547
+ style: { color: accentColor },
548
+ children: /* @__PURE__ */ jsx(
549
+ "svg",
550
+ {
551
+ className: "w-4 h-4",
552
+ fill: "none",
553
+ stroke: "currentColor",
554
+ viewBox: "0 0 24 24",
555
+ children: /* @__PURE__ */ jsx(
556
+ "path",
557
+ {
558
+ strokeLinecap: "round",
559
+ strokeLinejoin: "round",
560
+ strokeWidth: 2,
561
+ d: "M12 4v16m8-8H4"
562
+ }
563
+ )
564
+ }
565
+ )
566
+ }
567
+ )
568
+ ]
569
+ }
570
+ )
111
571
  ] }),
112
- /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3", children: [
113
- showPageThemeSelector && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
572
+ /* @__PURE__ */ jsxs("div", { className: "ml-auto flex items-center gap-2 sm:gap-3 z-10", children: [
573
+ showPageThemeSelector && /* @__PURE__ */ jsxs("div", { className: "relative hidden sm:block", children: [
114
574
  /* @__PURE__ */ jsxs(
115
575
  "button",
116
576
  {
117
577
  onClick: () => setShowPageThemes(!showPageThemes),
118
578
  className: `papyrus-control flex items-center space-x-2 px-3 py-1.5 rounded-md text-xs font-bold border transition-all ${isDark ? "bg-[#2a2a2a] border-[#444]" : "bg-gray-50 border-gray-200"}`,
119
579
  children: [
120
- /* @__PURE__ */ jsx("div", { className: `w-3 h-3 rounded-full border ${themes.find((t) => t.id === pageTheme)?.color}` }),
580
+ /* @__PURE__ */ jsx(
581
+ "div",
582
+ {
583
+ className: `w-3 h-3 rounded-full border ${themes.find((t) => t.id === pageTheme)?.color}`
584
+ }
585
+ ),
121
586
  /* @__PURE__ */ jsx("span", { children: "TEMA" })
122
587
  ]
123
588
  }
124
589
  ),
125
- showPageThemes && /* @__PURE__ */ jsx("div", { className: `papyrus-popover absolute top-full right-0 mt-2 w-48 rounded-lg shadow-xl border p-2 z-[60] ${isDark ? "bg-[#2a2a2a] border-[#444]" : "bg-white border-gray-200"}`, children: themes.map((t) => /* @__PURE__ */ jsxs(
126
- "button",
127
- {
128
- onClick: () => {
129
- setDocumentState({ pageTheme: t.id });
130
- setShowPageThemes(false);
131
- },
132
- className: `w-full flex items-center space-x-3 px-3 py-2 rounded-md text-sm ${pageTheme === t.id ? "text-white" : isDark ? "hover:bg-white/10 text-gray-300" : "hover:bg-gray-50 text-gray-700"}`,
133
- style: pageTheme === t.id ? { backgroundColor: accentColor } : void 0,
134
- children: [
135
- /* @__PURE__ */ jsx("div", { className: `w-3 h-3 rounded-full border ${t.color}` }),
136
- /* @__PURE__ */ jsx("span", { children: t.name })
137
- ]
138
- },
139
- t.id
140
- )) })
141
- ] }),
142
- showUIToggle && /* @__PURE__ */ jsx("button", { onClick: () => setDocumentState({ uiTheme: isDark ? "light" : "dark" }), className: `p-2 rounded-full ${isDark ? "bg-yellow-500/10 text-yellow-500" : "bg-gray-100 text-gray-500"}`, children: isDark ? /* @__PURE__ */ jsx("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx("path", { d: "M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414z" }) }) : /* @__PURE__ */ jsx("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx("path", { d: "M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" }) }) }),
143
- showUpload && /* @__PURE__ */ jsxs(Fragment, { children: [
144
- /* @__PURE__ */ jsx(
145
- "button",
590
+ showPageThemes && /* @__PURE__ */ jsx(
591
+ "div",
146
592
  {
147
- onClick: () => fileInputRef.current?.click(),
148
- className: "px-4 py-1.5 text-white rounded-md text-sm font-bold shadow-md active:scale-95",
149
- style: { backgroundColor: accentColor },
150
- children: "UPLOAD"
151
- }
152
- ),
153
- /* @__PURE__ */ jsx("input", { type: "file", ref: fileInputRef, className: "hidden", accept: ".pdf,.epub,.txt", onChange: async (e) => {
154
- const file = e.target.files?.[0];
155
- if (file) {
156
- setDocumentState({ isLoaded: false });
157
- await engine.load(file);
158
- setDocumentState({ isLoaded: true, pageCount: engine.getPageCount(), currentPage: 1, outline: await engine.getOutline() });
593
+ className: `papyrus-popover absolute top-full right-0 mt-2 w-48 rounded-lg shadow-xl border p-2 z-[60] ${isDark ? "bg-[#2a2a2a] border-[#444]" : "bg-white border-gray-200"}`,
594
+ children: themes.map((theme) => /* @__PURE__ */ jsxs(
595
+ "button",
596
+ {
597
+ onClick: () => {
598
+ setDocumentState({ pageTheme: theme.id });
599
+ setShowPageThemes(false);
600
+ },
601
+ className: `w-full flex items-center space-x-3 px-3 py-2 rounded-md text-sm ${pageTheme === theme.id ? "text-white" : isDark ? "hover:bg-white/10 text-gray-300" : "hover:bg-gray-50 text-gray-700"}`,
602
+ style: pageTheme === theme.id ? { backgroundColor: accentColor } : void 0,
603
+ children: [
604
+ /* @__PURE__ */ jsx(
605
+ "div",
606
+ {
607
+ className: `w-3 h-3 rounded-full border ${theme.color}`
608
+ }
609
+ ),
610
+ /* @__PURE__ */ jsx("span", { children: theme.name })
611
+ ]
612
+ },
613
+ theme.id
614
+ ))
159
615
  }
160
- } })
616
+ )
161
617
  ] }),
162
- showSearch && /* @__PURE__ */ jsx("button", { onClick: () => toggleSidebarRight("search"), className: `p-2 rounded-md ${isDark ? "hover:bg-white/10" : "hover:bg-gray-100"}`, children: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }) })
163
- ] })
618
+ showUIToggle && /* @__PURE__ */ jsx(
619
+ "button",
620
+ {
621
+ onClick: () => setDocumentState({ uiTheme: isDark ? "light" : "dark" }),
622
+ className: `hidden sm:inline-flex p-2 rounded-full ${isDark ? "bg-yellow-500/10 text-yellow-500" : "bg-gray-100 text-gray-500"}`,
623
+ children: isDark ? /* @__PURE__ */ jsx("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx("path", { d: "M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414z" }) }) : /* @__PURE__ */ jsx("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx("path", { d: "M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" }) })
624
+ }
625
+ ),
626
+ showUpload && /* @__PURE__ */ jsx(
627
+ "button",
628
+ {
629
+ onClick: () => fileInputRef.current?.click(),
630
+ className: "hidden sm:inline-flex px-4 py-1.5 text-white rounded-md text-sm font-bold shadow-md active:scale-95",
631
+ style: { backgroundColor: accentColor },
632
+ children: "UPLOAD"
633
+ }
634
+ ),
635
+ showSearch && /* @__PURE__ */ jsx(
636
+ "button",
637
+ {
638
+ onClick: () => toggleSidebarRight("search"),
639
+ className: `inline-flex p-2 rounded-md ${isDark ? "hover:bg-white/10" : "hover:bg-gray-100"}`,
640
+ "aria-label": "Abrir busca",
641
+ title: "Buscar",
642
+ children: /* @__PURE__ */ jsx(
643
+ "svg",
644
+ {
645
+ className: "w-5 h-5",
646
+ fill: "none",
647
+ stroke: "currentColor",
648
+ viewBox: "0 0 24 24",
649
+ children: /* @__PURE__ */ jsx(
650
+ "path",
651
+ {
652
+ strokeLinecap: "round",
653
+ strokeLinejoin: "round",
654
+ strokeWidth: 2,
655
+ d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
656
+ }
657
+ )
658
+ }
659
+ )
660
+ }
661
+ ),
662
+ hasMobileMenu && /* @__PURE__ */ jsx(
663
+ "button",
664
+ {
665
+ onClick: () => setShowMobileMenu(true),
666
+ className: `sm:hidden p-2 rounded-md border ${isDark ? "border-[#444] bg-[#2a2a2a] hover:bg-[#333]" : "border-gray-300 bg-white hover:bg-gray-100"}`,
667
+ "aria-label": "Abrir menu",
668
+ title: "Mais op\xE7\xF5es",
669
+ children: /* @__PURE__ */ jsx(
670
+ "svg",
671
+ {
672
+ className: "w-5 h-5",
673
+ fill: "none",
674
+ stroke: "currentColor",
675
+ viewBox: "0 0 24 24",
676
+ children: /* @__PURE__ */ jsx(
677
+ "path",
678
+ {
679
+ strokeLinecap: "round",
680
+ strokeLinejoin: "round",
681
+ strokeWidth: 2,
682
+ d: "M5 12h.01M12 12h.01M19 12h.01"
683
+ }
684
+ )
685
+ }
686
+ )
687
+ }
688
+ ),
689
+ showUpload && /* @__PURE__ */ jsx(
690
+ "input",
691
+ {
692
+ type: "file",
693
+ ref: fileInputRef,
694
+ className: "hidden",
695
+ accept: ".pdf,.epub,.txt",
696
+ onChange: handleFileUpload
697
+ }
698
+ )
699
+ ] }),
700
+ mobileMenuOverlay
164
701
  ]
165
702
  }
166
703
  );
@@ -195,14 +732,17 @@ var Thumbnail = ({ engine, pageIndex, active, isDark, accentColor, onClick }) =>
195
732
  return;
196
733
  }
197
734
  const root = target.closest(".custom-scrollbar");
198
- const observer = new IntersectionObserver((entries) => {
199
- entries.forEach((entry) => {
200
- if (entry.isIntersecting) {
201
- setIsVisible(true);
202
- observer.disconnect();
203
- }
204
- });
205
- }, { root: root ?? null, rootMargin: "200px" });
735
+ const observer = new IntersectionObserver(
736
+ (entries) => {
737
+ entries.forEach((entry) => {
738
+ if (entry.isIntersecting) {
739
+ setIsVisible(true);
740
+ observer.disconnect();
741
+ }
742
+ });
743
+ },
744
+ { root: root ?? null, rootMargin: "200px" }
745
+ );
206
746
  observer.observe(target);
207
747
  return () => observer.disconnect();
208
748
  }, []);
@@ -223,31 +763,46 @@ var Thumbnail = ({ engine, pageIndex, active, isDark, accentColor, onClick }) =>
223
763
  className: `p-3 cursor-pointer transition-all rounded-lg border-2 ${active ? "shadow-sm" : "border-transparent"}`,
224
764
  style: active ? { borderColor: accentColor, backgroundColor: accentSoft } : void 0,
225
765
  children: /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center", children: [
226
- /* @__PURE__ */ jsxs2("div", { className: `shadow-lg rounded overflow-hidden mb-2 border ${isDark ? "border-[#333]" : "border-gray-200"}`, children: [
227
- /* @__PURE__ */ jsx2(
228
- "canvas",
229
- {
230
- ref: canvasRef,
231
- className: "max-w-full h-auto bg-white",
232
- style: { display: renderTargetType === "element" ? "none" : "block" }
233
- }
234
- ),
235
- /* @__PURE__ */ jsx2(
236
- "div",
237
- {
238
- ref: htmlRef,
239
- className: "bg-white",
240
- style: {
241
- width: 90,
242
- height: 120,
243
- display: renderTargetType === "element" ? "block" : "none",
244
- overflow: "hidden"
245
- },
246
- children: renderTargetType === "element" && /* @__PURE__ */ jsx2("div", { className: "w-full h-full flex items-center justify-center text-[10px] font-semibold text-gray-500", children: "HTML" })
247
- }
248
- )
249
- ] }),
250
- /* @__PURE__ */ jsx2("span", { className: `text-[11px] font-bold ${active ? "" : isDark ? "text-gray-500" : "text-gray-400"}`, style: active ? { color: accentColor } : void 0, children: pageIndex + 1 })
766
+ /* @__PURE__ */ jsxs2(
767
+ "div",
768
+ {
769
+ className: `shadow-lg rounded overflow-hidden mb-2 border ${isDark ? "border-[#333]" : "border-gray-200"}`,
770
+ children: [
771
+ /* @__PURE__ */ jsx2(
772
+ "canvas",
773
+ {
774
+ ref: canvasRef,
775
+ className: "max-w-full h-auto bg-white",
776
+ style: {
777
+ display: renderTargetType === "element" ? "none" : "block"
778
+ }
779
+ }
780
+ ),
781
+ /* @__PURE__ */ jsx2(
782
+ "div",
783
+ {
784
+ ref: htmlRef,
785
+ className: "bg-white",
786
+ style: {
787
+ width: 90,
788
+ height: 120,
789
+ display: renderTargetType === "element" ? "block" : "none",
790
+ overflow: "hidden"
791
+ },
792
+ children: renderTargetType === "element" && /* @__PURE__ */ jsx2("div", { className: "w-full h-full flex items-center justify-center text-[10px] font-semibold text-gray-500", children: "HTML" })
793
+ }
794
+ )
795
+ ]
796
+ }
797
+ ),
798
+ /* @__PURE__ */ jsx2(
799
+ "span",
800
+ {
801
+ className: `text-[11px] font-bold ${active ? "" : isDark ? "text-gray-500" : "text-gray-400"}`,
802
+ style: active ? { color: accentColor } : void 0,
803
+ children: pageIndex + 1
804
+ }
805
+ )
251
806
  ] })
252
807
  }
253
808
  );
@@ -257,8 +812,11 @@ var OutlineNode = ({ item, engine, isDark, accentColor, depth = 0 }) => {
257
812
  const [expanded, setExpanded] = useState2(true);
258
813
  const accentSoft = withAlpha(accentColor, 0.2);
259
814
  const matchesSearch = outlineSearchQuery === "" || item.title.toLowerCase().includes(outlineSearchQuery.toLowerCase());
260
- const hasMatchingChildren = item.children?.some((child) => child.title.toLowerCase().includes(outlineSearchQuery.toLowerCase()));
261
- if (!matchesSearch && !hasMatchingChildren && outlineSearchQuery !== "") return null;
815
+ const hasMatchingChildren = item.children?.some(
816
+ (child) => child.title.toLowerCase().includes(outlineSearchQuery.toLowerCase())
817
+ );
818
+ if (!matchesSearch && !hasMatchingChildren && outlineSearchQuery !== "")
819
+ return null;
262
820
  const handleClick = () => {
263
821
  if (item.pageIndex >= 0) {
264
822
  engine.goToPage(item.pageIndex + 1);
@@ -277,12 +835,32 @@ var OutlineNode = ({ item, engine, isDark, accentColor, depth = 0 }) => {
277
835
  "button",
278
836
  {
279
837
  className: `mr-1 text-gray-400 transition-transform p-1`,
280
- style: { color: accentColor, transform: expanded ? "rotate(90deg)" : "rotate(0deg)" },
838
+ style: {
839
+ color: accentColor,
840
+ transform: expanded ? "rotate(90deg)" : "rotate(0deg)"
841
+ },
281
842
  onClick: (e) => {
282
843
  e.stopPropagation();
283
844
  setExpanded(!expanded);
284
845
  },
285
- children: /* @__PURE__ */ jsx2("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M9 5l7 7-7 7" }) })
846
+ children: /* @__PURE__ */ jsx2(
847
+ "svg",
848
+ {
849
+ className: "w-3 h-3",
850
+ fill: "none",
851
+ stroke: "currentColor",
852
+ viewBox: "0 0 24 24",
853
+ children: /* @__PURE__ */ jsx2(
854
+ "path",
855
+ {
856
+ strokeLinecap: "round",
857
+ strokeLinejoin: "round",
858
+ strokeWidth: 3,
859
+ d: "M9 5l7 7-7 7"
860
+ }
861
+ )
862
+ }
863
+ )
286
864
  }
287
865
  ) : /* @__PURE__ */ jsx2("div", { className: "w-5" }),
288
866
  /* @__PURE__ */ jsx2(
@@ -296,7 +874,17 @@ var OutlineNode = ({ item, engine, isDark, accentColor, depth = 0 }) => {
296
874
  ]
297
875
  }
298
876
  ),
299
- expanded && item.children && item.children.length > 0 && /* @__PURE__ */ jsx2("div", { className: "flex flex-col", children: item.children.map((child, i) => /* @__PURE__ */ jsx2(OutlineNode, { item: child, engine, isDark, accentColor, depth: depth + 1 }, i)) })
877
+ expanded && item.children && item.children.length > 0 && /* @__PURE__ */ jsx2("div", { className: "flex flex-col", children: item.children.map((child, i) => /* @__PURE__ */ jsx2(
878
+ OutlineNode,
879
+ {
880
+ item: child,
881
+ engine,
882
+ isDark,
883
+ accentColor,
884
+ depth: depth + 1
885
+ },
886
+ i
887
+ )) })
300
888
  ] });
301
889
  };
302
890
  var SidebarLeft = ({ engine }) => {
@@ -320,39 +908,129 @@ var SidebarLeft = ({ engine }) => {
320
908
  "div",
321
909
  {
322
910
  "data-papyrus-theme": uiTheme,
323
- className: `papyrus-sidebar-left papyrus-theme w-72 border-r flex flex-col h-full shrink-0 overflow-hidden transition-colors duration-200 ${isDark ? "bg-[#2a2a2a] border-[#3a3a3a]" : "bg-[#fcfcfc] border-gray-200"}`,
911
+ className: `papyrus-sidebar-left papyrus-theme absolute left-0 top-0 bottom-0 z-[120] w-[85vw] max-w-72 border-r flex flex-col h-full overflow-hidden transition-colors duration-200 ${isDark ? "bg-[#2a2a2a] border-[#3a3a3a]" : "bg-[#fcfcfc] border-gray-200"}`,
324
912
  children: [
325
- /* @__PURE__ */ jsxs2("div", { className: `p-4 border-b flex flex-col space-y-4 ${isDark ? "border-[#3a3a3a]" : "border-gray-100"}`, children: [
326
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between", children: [
327
- /* @__PURE__ */ jsx2("h3", { className: `text-sm font-bold uppercase tracking-widest ${isDark ? "text-gray-100" : "text-gray-800"}`, children: sidebarLeftTab === "thumbnails" ? "Thumbnails" : "Sum\xE1rio" }),
328
- /* @__PURE__ */ jsx2("button", { onClick: () => setDocumentState({ sidebarLeftOpen: false }), className: "text-gray-400 hover:text-gray-600", children: /* @__PURE__ */ jsx2("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
329
- ] }),
330
- /* @__PURE__ */ jsxs2("div", { className: "flex gap-1", children: [
331
- /* @__PURE__ */ jsx2(
332
- "button",
333
- {
334
- onClick: () => setSidebarLeftTab("thumbnails"),
335
- className: `p-2 rounded-md ${sidebarLeftTab === "thumbnails" ? isDark ? "bg-white/10 text-white" : "bg-white shadow-sm border border-gray-200" : "text-gray-400"}`,
336
- style: sidebarLeftTab === "thumbnails" && !isDark ? { color: accentColor } : void 0,
337
- children: /* @__PURE__ */ jsx2("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2 2V6z" }) })
338
- }
339
- ),
340
- /* @__PURE__ */ jsx2(
341
- "button",
342
- {
343
- onClick: () => setSidebarLeftTab("summary"),
344
- className: `p-2 rounded-md ${sidebarLeftTab === "summary" ? isDark ? "bg-white/10 text-white" : "bg-white shadow-sm border border-gray-200" : "text-gray-400"}`,
345
- style: sidebarLeftTab === "summary" && !isDark ? { color: accentColor } : void 0,
346
- children: /* @__PURE__ */ jsx2("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16M4 18h7" }) })
347
- }
348
- )
349
- ] })
350
- ] }),
351
- /* @__PURE__ */ jsx2("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3", children: sidebarLeftTab === "thumbnails" ? /* @__PURE__ */ jsx2("div", { className: "space-y-1", children: Array.from({ length: pageCount }).map((_, idx) => /* @__PURE__ */ jsx2(Thumbnail, { engine, pageIndex: idx, isDark, accentColor, active: currentPage === idx + 1, onClick: () => {
352
- engine.goToPage(idx + 1);
353
- setDocumentState({ currentPage: idx + 1 });
354
- triggerScrollToPage(idx);
355
- } }, idx)) }) : /* @__PURE__ */ jsx2("div", { className: "flex flex-col space-y-0.5", children: outline.map((item, i) => /* @__PURE__ */ jsx2(OutlineNode, { item, engine, isDark, accentColor }, i)) }) })
913
+ /* @__PURE__ */ jsxs2(
914
+ "div",
915
+ {
916
+ className: `p-4 border-b flex flex-col space-y-4 ${isDark ? "border-[#3a3a3a]" : "border-gray-100"}`,
917
+ children: [
918
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between", children: [
919
+ /* @__PURE__ */ jsx2(
920
+ "h3",
921
+ {
922
+ className: `text-sm font-bold uppercase tracking-widest ${isDark ? "text-gray-100" : "text-gray-800"}`,
923
+ children: sidebarLeftTab === "thumbnails" ? "Thumbnails" : "Sum\xE1rio"
924
+ }
925
+ ),
926
+ /* @__PURE__ */ jsx2(
927
+ "button",
928
+ {
929
+ onClick: () => setDocumentState({ sidebarLeftOpen: false }),
930
+ className: "text-gray-400 hover:text-gray-600",
931
+ children: /* @__PURE__ */ jsx2(
932
+ "svg",
933
+ {
934
+ className: "w-4 h-4",
935
+ fill: "none",
936
+ stroke: "currentColor",
937
+ viewBox: "0 0 24 24",
938
+ children: /* @__PURE__ */ jsx2(
939
+ "path",
940
+ {
941
+ strokeLinecap: "round",
942
+ strokeLinejoin: "round",
943
+ strokeWidth: 2,
944
+ d: "M6 18L18 6M6 6l12 12"
945
+ }
946
+ )
947
+ }
948
+ )
949
+ }
950
+ )
951
+ ] }),
952
+ /* @__PURE__ */ jsxs2("div", { className: "flex gap-1", children: [
953
+ /* @__PURE__ */ jsx2(
954
+ "button",
955
+ {
956
+ onClick: () => setSidebarLeftTab("thumbnails"),
957
+ className: `p-2 rounded-md ${sidebarLeftTab === "thumbnails" ? isDark ? "bg-white/10 text-white" : "bg-white shadow-sm border border-gray-200" : "text-gray-400"}`,
958
+ style: sidebarLeftTab === "thumbnails" && !isDark ? { color: accentColor } : void 0,
959
+ children: /* @__PURE__ */ jsx2(
960
+ "svg",
961
+ {
962
+ className: "w-5 h-5",
963
+ fill: "none",
964
+ stroke: "currentColor",
965
+ viewBox: "0 0 24 24",
966
+ children: /* @__PURE__ */ jsx2(
967
+ "path",
968
+ {
969
+ strokeLinecap: "round",
970
+ strokeLinejoin: "round",
971
+ strokeWidth: 2,
972
+ d: "M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2 2V6z"
973
+ }
974
+ )
975
+ }
976
+ )
977
+ }
978
+ ),
979
+ /* @__PURE__ */ jsx2(
980
+ "button",
981
+ {
982
+ onClick: () => setSidebarLeftTab("summary"),
983
+ className: `p-2 rounded-md ${sidebarLeftTab === "summary" ? isDark ? "bg-white/10 text-white" : "bg-white shadow-sm border border-gray-200" : "text-gray-400"}`,
984
+ style: sidebarLeftTab === "summary" && !isDark ? { color: accentColor } : void 0,
985
+ children: /* @__PURE__ */ jsx2(
986
+ "svg",
987
+ {
988
+ className: "w-5 h-5",
989
+ fill: "none",
990
+ stroke: "currentColor",
991
+ viewBox: "0 0 24 24",
992
+ children: /* @__PURE__ */ jsx2(
993
+ "path",
994
+ {
995
+ strokeLinecap: "round",
996
+ strokeLinejoin: "round",
997
+ strokeWidth: 2,
998
+ d: "M4 6h16M4 12h16M4 18h7"
999
+ }
1000
+ )
1001
+ }
1002
+ )
1003
+ }
1004
+ )
1005
+ ] })
1006
+ ]
1007
+ }
1008
+ ),
1009
+ /* @__PURE__ */ jsx2("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-3", children: sidebarLeftTab === "thumbnails" ? /* @__PURE__ */ jsx2("div", { className: "space-y-1", children: Array.from({ length: pageCount }).map((_, idx) => /* @__PURE__ */ jsx2(
1010
+ Thumbnail,
1011
+ {
1012
+ engine,
1013
+ pageIndex: idx,
1014
+ isDark,
1015
+ accentColor,
1016
+ active: currentPage === idx + 1,
1017
+ onClick: () => {
1018
+ engine.goToPage(idx + 1);
1019
+ setDocumentState({ currentPage: idx + 1 });
1020
+ triggerScrollToPage(idx);
1021
+ }
1022
+ },
1023
+ idx
1024
+ )) }) : /* @__PURE__ */ jsx2("div", { className: "flex flex-col space-y-0.5", children: outline.map((item, i) => /* @__PURE__ */ jsx2(
1025
+ OutlineNode,
1026
+ {
1027
+ item,
1028
+ engine,
1029
+ isDark,
1030
+ accentColor
1031
+ },
1032
+ i
1033
+ )) }) })
356
1034
  ]
357
1035
  }
358
1036
  );
@@ -408,31 +1086,61 @@ var SidebarRight = ({ engine }) => {
408
1086
  "div",
409
1087
  {
410
1088
  "data-papyrus-theme": uiTheme,
411
- className: `papyrus-sidebar-right papyrus-theme w-80 border-l flex flex-col h-full shrink-0 transition-colors duration-200 shadow-2xl z-40 ${isDark ? "bg-[#1a1a1a] border-[#333]" : "bg-white border-gray-200"}`,
1089
+ className: `papyrus-sidebar-right papyrus-theme absolute right-0 top-0 bottom-0 z-[120] w-[88vw] max-w-80 border-l flex flex-col h-full transition-colors duration-200 shadow-2xl ${isDark ? "bg-[#1a1a1a] border-[#333]" : "bg-white border-gray-200"}`,
412
1090
  children: [
413
- /* @__PURE__ */ jsxs3("div", { className: `p-4 border-b flex items-center justify-between shrink-0 ${isDark ? "border-[#333]" : "border-gray-100"}`, children: [
414
- /* @__PURE__ */ jsxs3("div", { className: "flex space-x-6", children: [
415
- /* @__PURE__ */ jsx3(
416
- "button",
417
- {
418
- onClick: () => toggleSidebarRight("search"),
419
- className: `text-[10px] font-black uppercase tracking-widest pb-1 transition-all ${sidebarRightTab === "search" ? "border-b-2" : "text-gray-400"}`,
420
- style: sidebarRightTab === "search" ? { color: accentColor, borderColor: accentColor } : void 0,
421
- children: "Busca"
422
- }
423
- ),
424
- /* @__PURE__ */ jsx3(
425
- "button",
426
- {
427
- onClick: () => toggleSidebarRight("annotations"),
428
- className: `text-[10px] font-black uppercase tracking-widest pb-1 transition-all ${sidebarRightTab === "annotations" ? "border-b-2" : "text-gray-400"}`,
429
- style: sidebarRightTab === "annotations" ? { color: accentColor, borderColor: accentColor } : void 0,
430
- children: "Notas"
431
- }
432
- )
433
- ] }),
434
- /* @__PURE__ */ jsx3("button", { onClick: () => toggleSidebarRight(), className: "papyrus-unstyled-button text-gray-400 hover:text-red-500 transition-colors", children: /* @__PURE__ */ jsx3("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })
435
- ] }),
1091
+ /* @__PURE__ */ jsxs3(
1092
+ "div",
1093
+ {
1094
+ className: `p-4 border-b flex items-center justify-between shrink-0 ${isDark ? "border-[#333]" : "border-gray-100"}`,
1095
+ children: [
1096
+ /* @__PURE__ */ jsxs3("div", { className: "flex space-x-6", children: [
1097
+ /* @__PURE__ */ jsx3(
1098
+ "button",
1099
+ {
1100
+ onClick: () => toggleSidebarRight("search"),
1101
+ className: `text-[10px] font-black uppercase tracking-widest pb-1 transition-all ${sidebarRightTab === "search" ? "border-b-2" : "text-gray-400"}`,
1102
+ style: sidebarRightTab === "search" ? { color: accentColor, borderColor: accentColor } : void 0,
1103
+ children: "Busca"
1104
+ }
1105
+ ),
1106
+ /* @__PURE__ */ jsx3(
1107
+ "button",
1108
+ {
1109
+ onClick: () => toggleSidebarRight("annotations"),
1110
+ className: `text-[10px] font-black uppercase tracking-widest pb-1 transition-all ${sidebarRightTab === "annotations" ? "border-b-2" : "text-gray-400"}`,
1111
+ style: sidebarRightTab === "annotations" ? { color: accentColor, borderColor: accentColor } : void 0,
1112
+ children: "Notas"
1113
+ }
1114
+ )
1115
+ ] }),
1116
+ /* @__PURE__ */ jsx3(
1117
+ "button",
1118
+ {
1119
+ onClick: () => toggleSidebarRight(),
1120
+ className: "papyrus-unstyled-button text-gray-400 hover:text-red-500 transition-colors",
1121
+ children: /* @__PURE__ */ jsx3(
1122
+ "svg",
1123
+ {
1124
+ className: "w-4 h-4",
1125
+ fill: "none",
1126
+ stroke: "currentColor",
1127
+ viewBox: "0 0 24 24",
1128
+ children: /* @__PURE__ */ jsx3(
1129
+ "path",
1130
+ {
1131
+ strokeLinecap: "round",
1132
+ strokeLinejoin: "round",
1133
+ strokeWidth: 2,
1134
+ d: "M6 18L18 6M6 6l12 12"
1135
+ }
1136
+ )
1137
+ }
1138
+ )
1139
+ }
1140
+ )
1141
+ ]
1142
+ }
1143
+ ),
436
1144
  /* @__PURE__ */ jsx3("div", { className: "flex-1 overflow-y-auto p-4 custom-scrollbar bg-opacity-50", children: sidebarRightTab === "search" ? /* @__PURE__ */ jsxs3("div", { className: "space-y-4", children: [
437
1145
  /* @__PURE__ */ jsxs3("form", { onSubmit: handleSearch, className: "relative mb-6", children: [
438
1146
  /* @__PURE__ */ jsx3(
@@ -446,10 +1154,41 @@ var SidebarRight = ({ engine }) => {
446
1154
  }
447
1155
  ),
448
1156
  resultsCount > 0 && /* @__PURE__ */ jsx3("span", { className: "absolute right-9 top-2.5 text-[10px] font-bold text-gray-400", children: resultsCount }),
449
- /* @__PURE__ */ jsx3("button", { type: "submit", className: "papyrus-unstyled-button absolute right-3 top-2.5 text-gray-400 transition-colors", style: { color: accentColor }, children: /* @__PURE__ */ jsx3("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }) })
1157
+ /* @__PURE__ */ jsx3(
1158
+ "button",
1159
+ {
1160
+ type: "submit",
1161
+ className: "papyrus-unstyled-button absolute right-3 top-2.5 text-gray-400 transition-colors",
1162
+ style: { color: accentColor },
1163
+ children: /* @__PURE__ */ jsx3(
1164
+ "svg",
1165
+ {
1166
+ className: "w-4 h-4",
1167
+ fill: "none",
1168
+ stroke: "currentColor",
1169
+ viewBox: "0 0 24 24",
1170
+ children: /* @__PURE__ */ jsx3(
1171
+ "path",
1172
+ {
1173
+ strokeLinecap: "round",
1174
+ strokeLinejoin: "round",
1175
+ strokeWidth: 2.5,
1176
+ d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
1177
+ }
1178
+ )
1179
+ }
1180
+ )
1181
+ }
1182
+ )
450
1183
  ] }),
451
1184
  isSearching && /* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center justify-center py-12 space-y-3", children: [
452
- /* @__PURE__ */ jsx3("div", { className: "w-6 h-6 border-2 border-t-transparent rounded-full animate-spin", style: { borderColor: accentColor } }),
1185
+ /* @__PURE__ */ jsx3(
1186
+ "div",
1187
+ {
1188
+ className: "w-6 h-6 border-2 border-t-transparent rounded-full animate-spin",
1189
+ style: { borderColor: accentColor }
1190
+ }
1191
+ ),
453
1192
  /* @__PURE__ */ jsx3("span", { className: "text-[10px] font-bold text-gray-500 uppercase", children: "Varrendo documento..." })
454
1193
  ] }),
455
1194
  !isSearching && searchResults.map((res, idx) => /* @__PURE__ */ jsxs3(
@@ -458,11 +1197,17 @@ var SidebarRight = ({ engine }) => {
458
1197
  onClick: () => {
459
1198
  const page = res.pageIndex + 1;
460
1199
  engine.goToPage(page);
461
- setDocumentState({ activeSearchIndex: idx, currentPage: page });
1200
+ setDocumentState({
1201
+ activeSearchIndex: idx,
1202
+ currentPage: page
1203
+ });
462
1204
  triggerScrollToPage(res.pageIndex);
463
1205
  },
464
1206
  className: `p-4 rounded-xl border-2 cursor-pointer transition-all group hover:scale-[1.02] ${idx === activeSearchIndex ? "shadow-lg" : isDark ? "border-[#333] hover:border-[#555] bg-[#222]" : "border-gray-50 hover:border-gray-200 bg-gray-50/50 hover:bg-white"}`,
465
- style: idx === activeSearchIndex ? { borderColor: accentColor, backgroundColor: accentSoft } : void 0,
1207
+ style: idx === activeSearchIndex ? {
1208
+ borderColor: accentColor,
1209
+ backgroundColor: accentSoft
1210
+ } : void 0,
466
1211
  children: [
467
1212
  /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between mb-2", children: [
468
1213
  /* @__PURE__ */ jsxs3(
@@ -484,15 +1229,29 @@ var SidebarRight = ({ engine }) => {
484
1229
  fill: "none",
485
1230
  stroke: "currentColor",
486
1231
  viewBox: "0 0 24 24",
487
- children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M9 5l7 7-7 7" })
1232
+ children: /* @__PURE__ */ jsx3(
1233
+ "path",
1234
+ {
1235
+ strokeLinecap: "round",
1236
+ strokeLinejoin: "round",
1237
+ strokeWidth: 3,
1238
+ d: "M9 5l7 7-7 7"
1239
+ }
1240
+ )
488
1241
  }
489
1242
  )
490
1243
  ] }),
491
- /* @__PURE__ */ jsxs3("p", { className: `text-[11px] font-medium leading-relaxed italic ${isDark ? "text-gray-400" : "text-gray-600"}`, children: [
492
- "...",
493
- res.text,
494
- "..."
495
- ] })
1244
+ /* @__PURE__ */ jsxs3(
1245
+ "p",
1246
+ {
1247
+ className: `text-[11px] font-medium leading-relaxed italic ${isDark ? "text-gray-400" : "text-gray-600"}`,
1248
+ children: [
1249
+ "...",
1250
+ res.text,
1251
+ "..."
1252
+ ]
1253
+ }
1254
+ )
496
1255
  ]
497
1256
  },
498
1257
  idx
@@ -503,21 +1262,67 @@ var SidebarRight = ({ engine }) => {
503
1262
  /* @__PURE__ */ jsx3("div", { className: "flex-1 h-px bg-current ml-3 opacity-10" })
504
1263
  ] }),
505
1264
  annotations.length === 0 ? /* @__PURE__ */ jsxs3("div", { className: "text-center py-20", children: [
506
- /* @__PURE__ */ jsx3("div", { className: "w-12 h-12 bg-gray-500/10 rounded-full flex items-center justify-center mx-auto mb-4", children: /* @__PURE__ */ jsx3("svg", { className: "w-6 h-6 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" }) }) }),
1265
+ /* @__PURE__ */ jsx3("div", { className: "w-12 h-12 bg-gray-500/10 rounded-full flex items-center justify-center mx-auto mb-4", children: /* @__PURE__ */ jsx3(
1266
+ "svg",
1267
+ {
1268
+ className: "w-6 h-6 text-gray-400",
1269
+ fill: "none",
1270
+ stroke: "currentColor",
1271
+ viewBox: "0 0 24 24",
1272
+ children: /* @__PURE__ */ jsx3(
1273
+ "path",
1274
+ {
1275
+ strokeLinecap: "round",
1276
+ strokeLinejoin: "round",
1277
+ strokeWidth: 2,
1278
+ d: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
1279
+ }
1280
+ )
1281
+ }
1282
+ ) }),
507
1283
  /* @__PURE__ */ jsx3("p", { className: "text-[10px] font-bold text-gray-400 uppercase tracking-widest", children: "Sem anota\xE7\xF5es" })
508
- ] }) : annotations.map((ann) => /* @__PURE__ */ jsxs3("div", { className: `p-4 rounded-xl border group transition-all cursor-pointer ${isDark ? "bg-[#222] border-[#333] hover:border-[#444]" : "bg-white border-gray-100 shadow-sm hover:shadow-md"}`, children: [
509
- /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between mb-3", children: [
510
- /* @__PURE__ */ jsxs3("div", { className: "flex items-center space-x-2", children: [
511
- /* @__PURE__ */ jsx3("div", { className: "w-2.5 h-2.5 rounded-full", style: { backgroundColor: ann.color } }),
512
- /* @__PURE__ */ jsxs3("span", { className: "text-[10px] font-black", style: { color: accentColor }, children: [
513
- "P",
514
- ann.pageIndex + 1
515
- ] })
516
- ] }),
517
- /* @__PURE__ */ jsx3("span", { className: "text-[9px] text-gray-400 font-bold", children: new Date(ann.createdAt).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" }) })
518
- ] }),
519
- /* @__PURE__ */ jsx3("p", { className: `text-[11px] font-bold uppercase tracking-tight ${isDark ? "text-gray-200" : "text-gray-700"}`, children: ann.type })
520
- ] }, ann.id))
1284
+ ] }) : annotations.map((ann) => /* @__PURE__ */ jsxs3(
1285
+ "div",
1286
+ {
1287
+ className: `p-4 rounded-xl border group transition-all cursor-pointer ${isDark ? "bg-[#222] border-[#333] hover:border-[#444]" : "bg-white border-gray-100 shadow-sm hover:shadow-md"}`,
1288
+ children: [
1289
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between mb-3", children: [
1290
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center space-x-2", children: [
1291
+ /* @__PURE__ */ jsx3(
1292
+ "div",
1293
+ {
1294
+ className: "w-2.5 h-2.5 rounded-full",
1295
+ style: { backgroundColor: ann.color }
1296
+ }
1297
+ ),
1298
+ /* @__PURE__ */ jsxs3(
1299
+ "span",
1300
+ {
1301
+ className: "text-[10px] font-black",
1302
+ style: { color: accentColor },
1303
+ children: [
1304
+ "P",
1305
+ ann.pageIndex + 1
1306
+ ]
1307
+ }
1308
+ )
1309
+ ] }),
1310
+ /* @__PURE__ */ jsx3("span", { className: "text-[9px] text-gray-400 font-bold", children: new Date(ann.createdAt).toLocaleTimeString([], {
1311
+ hour: "2-digit",
1312
+ minute: "2-digit"
1313
+ }) })
1314
+ ] }),
1315
+ /* @__PURE__ */ jsx3(
1316
+ "p",
1317
+ {
1318
+ className: `text-[11px] font-bold uppercase tracking-tight ${isDark ? "text-gray-200" : "text-gray-700"}`,
1319
+ children: ann.type
1320
+ }
1321
+ )
1322
+ ]
1323
+ },
1324
+ ann.id
1325
+ ))
521
1326
  ] }) })
522
1327
  ]
523
1328
  }
@@ -1185,8 +1990,22 @@ var PageRenderer_default = PageRenderer;
1185
1990
  // components/Viewer.tsx
1186
1991
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1187
1992
  var BASE_OVERSCAN = 6;
1993
+ var MIN_ZOOM = 0.2;
1994
+ var MAX_ZOOM = 5;
1188
1995
  var Viewer = ({ engine }) => {
1189
- const { pageCount, currentPage, zoom, activeTool, uiTheme, scrollToPageSignal, setDocumentState, accentColor, annotationColor, setAnnotationColor } = useViewerStore5();
1996
+ const {
1997
+ pageCount,
1998
+ currentPage,
1999
+ zoom,
2000
+ activeTool,
2001
+ uiTheme,
2002
+ scrollToPageSignal,
2003
+ setDocumentState,
2004
+ accentColor,
2005
+ annotationColor,
2006
+ setAnnotationColor,
2007
+ toolDockOpen
2008
+ } = useViewerStore5();
1190
2009
  const isDark = uiTheme === "dark";
1191
2010
  const viewerRef = useRef4(null);
1192
2011
  const colorPickerRef = useRef4(null);
@@ -1195,6 +2014,13 @@ var Viewer = ({ engine }) => {
1195
2014
  const frameRef = useRef4(null);
1196
2015
  const jumpRef = useRef4(false);
1197
2016
  const jumpTimerRef = useRef4(null);
2017
+ const pinchRef = useRef4({
2018
+ active: false,
2019
+ startDistance: 0,
2020
+ startZoom: 1,
2021
+ pendingZoom: null,
2022
+ rafId: null
2023
+ });
1198
2024
  const [availableWidth, setAvailableWidth] = useState5(null);
1199
2025
  const [basePageSize, setBasePageSize] = useState5(null);
1200
2026
  const [pageSizes, setPageSizes] = useState5({});
@@ -1202,7 +2028,16 @@ var Viewer = ({ engine }) => {
1202
2028
  const isCompact = availableWidth !== null && availableWidth < 820;
1203
2029
  const paddingY = isCompact ? "py-10" : "py-16";
1204
2030
  const toolDockPosition = isCompact ? "bottom-4" : "bottom-8";
1205
- const colorPalette = ["#fbbf24", "#f97316", "#ef4444", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#111827"];
2031
+ const colorPalette = [
2032
+ "#fbbf24",
2033
+ "#f97316",
2034
+ "#ef4444",
2035
+ "#22c55e",
2036
+ "#06b6d4",
2037
+ "#3b82f6",
2038
+ "#8b5cf6",
2039
+ "#111827"
2040
+ ];
1206
2041
  useEffect4(() => {
1207
2042
  if (!colorPickerOpen) return;
1208
2043
  const handleClick = (event) => {
@@ -1214,6 +2049,17 @@ var Viewer = ({ engine }) => {
1214
2049
  document.addEventListener("mousedown", handleClick);
1215
2050
  return () => document.removeEventListener("mousedown", handleClick);
1216
2051
  }, [colorPickerOpen]);
2052
+ useEffect4(() => {
2053
+ if (!toolDockOpen && colorPickerOpen) setColorPickerOpen(false);
2054
+ }, [toolDockOpen, colorPickerOpen]);
2055
+ useEffect4(
2056
+ () => () => {
2057
+ if (pinchRef.current.rafId != null) {
2058
+ cancelAnimationFrame(pinchRef.current.rafId);
2059
+ }
2060
+ },
2061
+ []
2062
+ );
1217
2063
  useEffect4(() => {
1218
2064
  const element = viewerRef.current;
1219
2065
  if (!element) return;
@@ -1260,7 +2106,10 @@ var Viewer = ({ engine }) => {
1260
2106
  if (target) {
1261
2107
  targetTop = target.offsetTop;
1262
2108
  } else if (basePageSize && availableWidth) {
1263
- const fitScale = Math.min(1, Math.max(0, availableWidth - 48) / basePageSize.width);
2109
+ const fitScale = Math.min(
2110
+ 1,
2111
+ Math.max(0, availableWidth - 48) / basePageSize.width
2112
+ );
1264
2113
  const estimatedPageHeight = basePageSize.height * fitScale * zoom + 64;
1265
2114
  targetTop = Math.max(0, estimatedPageHeight * scrollToPageSignal);
1266
2115
  } else if (pageCount > 1) {
@@ -1279,7 +2128,14 @@ var Viewer = ({ engine }) => {
1279
2128
  }, 250);
1280
2129
  }
1281
2130
  setDocumentState({ scrollToPageSignal: null });
1282
- }, [scrollToPageSignal, setDocumentState, basePageSize, availableWidth, zoom, pageCount]);
2131
+ }, [
2132
+ scrollToPageSignal,
2133
+ setDocumentState,
2134
+ basePageSize,
2135
+ availableWidth,
2136
+ zoom,
2137
+ pageCount
2138
+ ]);
1283
2139
  useEffect4(() => {
1284
2140
  setPageSizes({});
1285
2141
  }, [zoom]);
@@ -1302,18 +2158,23 @@ var Viewer = ({ engine }) => {
1302
2158
  const shouldSwitch = bestPage !== currentPage && (currentRatio <= 0 || bestRatio >= currentRatio + 0.1 || bestRatio >= 0.75);
1303
2159
  if (shouldSwitch) setDocumentState({ currentPage: bestPage });
1304
2160
  };
1305
- const observer = new IntersectionObserver((entries) => {
1306
- entries.forEach((entry) => {
1307
- const pageIndex = parseInt(entry.target.getAttribute("data-page-index") || "0");
1308
- if (!Number.isFinite(pageIndex)) return;
1309
- intersectionRatiosRef.current[pageIndex] = entry.isIntersecting ? entry.intersectionRatio : 0;
1310
- });
1311
- if (frameRef.current != null) cancelAnimationFrame(frameRef.current);
1312
- frameRef.current = requestAnimationFrame(() => {
1313
- frameRef.current = null;
1314
- flushCurrentPage();
1315
- });
1316
- }, { root, threshold: [0.25, 0.5, 0.75] });
2161
+ const observer = new IntersectionObserver(
2162
+ (entries) => {
2163
+ entries.forEach((entry) => {
2164
+ const pageIndex = parseInt(
2165
+ entry.target.getAttribute("data-page-index") || "0"
2166
+ );
2167
+ if (!Number.isFinite(pageIndex)) return;
2168
+ intersectionRatiosRef.current[pageIndex] = entry.isIntersecting ? entry.intersectionRatio : 0;
2169
+ });
2170
+ if (frameRef.current != null) cancelAnimationFrame(frameRef.current);
2171
+ frameRef.current = requestAnimationFrame(() => {
2172
+ frameRef.current = null;
2173
+ flushCurrentPage();
2174
+ });
2175
+ },
2176
+ { root, threshold: [0.25, 0.5, 0.75] }
2177
+ );
1317
2178
  const pageElements = root.querySelectorAll(".page-container");
1318
2179
  pageElements.forEach((el) => observer.observe(el));
1319
2180
  return () => {
@@ -1331,7 +2192,10 @@ var Viewer = ({ engine }) => {
1331
2192
  const virtualEnd = Math.min(pageCount - 1, virtualAnchor + virtualOverscan);
1332
2193
  const fallbackSize = useMemo2(() => {
1333
2194
  if (basePageSize && availableWidth) {
1334
- const fitScale = Math.min(1, Math.max(0, availableWidth - 48) / basePageSize.width);
2195
+ const fitScale = Math.min(
2196
+ 1,
2197
+ Math.max(0, availableWidth - 48) / basePageSize.width
2198
+ );
1335
2199
  return {
1336
2200
  width: Math.round(basePageSize.width * fitScale * zoom),
1337
2201
  height: Math.round(basePageSize.height * fitScale * zoom)
@@ -1345,31 +2209,103 @@ var Viewer = ({ engine }) => {
1345
2209
  }, [basePageSize, availableWidth, zoom]);
1346
2210
  const averagePageHeight = useMemo2(() => {
1347
2211
  const heights = Object.values(pageSizes).map((size) => size.height);
1348
- if (!heights.length) return availableWidth ? Math.max(680, availableWidth * 1.3) : 1100;
2212
+ if (!heights.length)
2213
+ return availableWidth ? Math.max(680, availableWidth * 1.3) : 1100;
1349
2214
  return Math.round(heights.reduce((sum, h) => sum + h, 0) / heights.length);
1350
2215
  }, [pageSizes, availableWidth]);
1351
2216
  const pages = Array.from({ length: pageCount }).map((_, i) => i);
1352
2217
  const handlePageMeasured = (pageIndex, size) => {
1353
2218
  setPageSizes((prev) => {
1354
2219
  const current = prev[pageIndex];
1355
- if (current && current.width === size.width && current.height === size.height) return prev;
2220
+ if (current && current.width === size.width && current.height === size.height)
2221
+ return prev;
1356
2222
  return { ...prev, [pageIndex]: size };
1357
2223
  });
1358
2224
  };
1359
2225
  const tools = [
1360
2226
  { id: "select", name: "Select", icon: "M15 15l-2 5L9 9l11 4-5 2zm0 0l5 5" },
1361
- { id: "highlight", name: "Highlight", icon: "M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" },
1362
- { id: "underline", name: "Underline", icon: "M6 3v6a6 6 0 0012 0V3M4 21h16" },
1363
- { id: "squiggly", name: "Squiggly", icon: "M3 17c2-4 4-4 6 0s4 4 6 0 4-4 6 0" },
2227
+ {
2228
+ id: "highlight",
2229
+ name: "Highlight",
2230
+ icon: "M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"
2231
+ },
2232
+ {
2233
+ id: "underline",
2234
+ name: "Underline",
2235
+ icon: "M6 3v6a6 6 0 0012 0V3M4 21h16"
2236
+ },
2237
+ {
2238
+ id: "squiggly",
2239
+ name: "Squiggly",
2240
+ icon: "M3 17c2-4 4-4 6 0s4 4 6 0 4-4 6 0"
2241
+ },
1364
2242
  { id: "strikeout", name: "Strike", icon: "M4 12h16M8 6h8M8 18h8" },
1365
2243
  { id: "ink", name: "Freehand", icon: "M4 19c4-6 7-9 10-9 3 0 5 2 6 5" },
1366
- { id: "comment", name: "Note", icon: "M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z" }
2244
+ {
2245
+ id: "comment",
2246
+ name: "Note",
2247
+ icon: "M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"
2248
+ }
1367
2249
  ];
2250
+ const getTouchDistance = (touchA, touchB) => {
2251
+ const dx = touchA.clientX - touchB.clientX;
2252
+ const dy = touchA.clientY - touchB.clientY;
2253
+ return Math.sqrt(dx * dx + dy * dy);
2254
+ };
2255
+ const flushPinchZoom = () => {
2256
+ const nextZoom = pinchRef.current.pendingZoom;
2257
+ pinchRef.current.pendingZoom = null;
2258
+ pinchRef.current.rafId = null;
2259
+ if (nextZoom == null) return;
2260
+ engine.setZoom(nextZoom);
2261
+ setDocumentState({ zoom: nextZoom });
2262
+ };
2263
+ const handleTouchStart = (event) => {
2264
+ if (event.touches.length < 2) return;
2265
+ const touchA = event.touches[0];
2266
+ const touchB = event.touches[1];
2267
+ pinchRef.current.active = true;
2268
+ pinchRef.current.startDistance = getTouchDistance(touchA, touchB);
2269
+ pinchRef.current.startZoom = zoom;
2270
+ event.preventDefault();
2271
+ };
2272
+ const handleTouchMove = (event) => {
2273
+ if (!pinchRef.current.active || event.touches.length < 2) return;
2274
+ const touchA = event.touches[0];
2275
+ const touchB = event.touches[1];
2276
+ const nextDistance = getTouchDistance(touchA, touchB);
2277
+ if (!pinchRef.current.startDistance) return;
2278
+ const scale = nextDistance / pinchRef.current.startDistance;
2279
+ const nextZoom = Math.max(
2280
+ MIN_ZOOM,
2281
+ Math.min(MAX_ZOOM, pinchRef.current.startZoom * scale)
2282
+ );
2283
+ pinchRef.current.pendingZoom = nextZoom;
2284
+ if (pinchRef.current.rafId == null) {
2285
+ pinchRef.current.rafId = requestAnimationFrame(flushPinchZoom);
2286
+ }
2287
+ event.preventDefault();
2288
+ };
2289
+ const handleTouchEnd = (event) => {
2290
+ if (event.touches.length >= 2) return;
2291
+ pinchRef.current.active = false;
2292
+ pinchRef.current.startDistance = 0;
2293
+ pinchRef.current.startZoom = zoom;
2294
+ if (pinchRef.current.pendingZoom != null && pinchRef.current.rafId == null) {
2295
+ engine.setZoom(pinchRef.current.pendingZoom);
2296
+ setDocumentState({ zoom: pinchRef.current.pendingZoom });
2297
+ pinchRef.current.pendingZoom = null;
2298
+ }
2299
+ };
1368
2300
  return /* @__PURE__ */ jsxs5(
1369
2301
  "div",
1370
2302
  {
1371
2303
  ref: viewerRef,
1372
2304
  "data-papyrus-theme": uiTheme,
2305
+ onTouchStart: handleTouchStart,
2306
+ onTouchMove: handleTouchMove,
2307
+ onTouchEnd: handleTouchEnd,
2308
+ onTouchCancel: handleTouchEnd,
1373
2309
  className: `papyrus-viewer papyrus-theme min-w-0 w-full flex-1 overflow-y-scroll overflow-x-hidden flex flex-col items-center ${paddingY} relative custom-scrollbar scroll-smooth ${isDark ? "bg-[#121212]" : "bg-[#e9ecef]"}`,
1374
2310
  children: [
1375
2311
  /* @__PURE__ */ jsx5("div", { className: "flex flex-col items-center gap-6 w-full min-w-0", children: pages.map((idx) => /* @__PURE__ */ jsx5(
@@ -1401,65 +2337,109 @@ var Viewer = ({ engine }) => {
1401
2337
  },
1402
2338
  idx
1403
2339
  )) }),
1404
- /* @__PURE__ */ jsx5("div", { className: `papyrus-tool-dock sticky ${toolDockPosition} w-full flex justify-center pointer-events-none z-[70]`, children: /* @__PURE__ */ jsxs5("div", { className: `pointer-events-auto shadow-2xl rounded-2xl p-2 flex items-center border z-[80] ${isDark ? "bg-[#2a2a2a]/90 border-[#3a3a3a] backdrop-blur-xl" : "bg-white/95 border-gray-100 backdrop-blur-md"}`, children: [
1405
- tools.map((tool) => /* @__PURE__ */ jsx5(
1406
- "button",
1407
- {
1408
- title: tool.name,
1409
- "aria-label": tool.name,
1410
- onClick: () => setDocumentState({ activeTool: tool.id }),
1411
- className: `w-10 h-10 rounded-xl flex items-center justify-center transition-all ${activeTool === tool.id ? "text-white shadow-lg" : "text-gray-400"}`,
1412
- style: activeTool === tool.id ? { backgroundColor: accentColor } : void 0,
1413
- children: /* @__PURE__ */ jsx5("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: tool.icon }) })
1414
- },
1415
- tool.id
1416
- )),
1417
- /* @__PURE__ */ jsx5("div", { className: "w-px h-7 mx-2 bg-white/10" }),
1418
- /* @__PURE__ */ jsxs5("div", { ref: colorPickerRef, className: "relative", children: [
1419
- /* @__PURE__ */ jsx5(
1420
- "button",
2340
+ toolDockOpen && /* @__PURE__ */ jsx5(
2341
+ "div",
2342
+ {
2343
+ className: `papyrus-tool-dock sticky ${toolDockPosition} w-full flex justify-center pointer-events-none z-[70]`,
2344
+ children: /* @__PURE__ */ jsxs5(
2345
+ "div",
1421
2346
  {
1422
- title: "Cor do marcador",
1423
- "aria-label": "Cor do marcador",
1424
- onClick: () => setColorPickerOpen((prev) => !prev),
1425
- className: "w-9 h-9 rounded-full flex items-center justify-center border transition-all cursor-pointer relative",
1426
- style: { borderColor: annotationColor },
1427
- children: /* @__PURE__ */ jsx5("span", { className: "w-5 h-5 rounded-full", style: { backgroundColor: annotationColor } })
1428
- }
1429
- ),
1430
- colorPickerOpen && /* @__PURE__ */ jsxs5("div", { className: `absolute bottom-full left-1/2 -translate-x-1/2 mb-3 w-48 rounded-xl border p-3 shadow-2xl overflow-hidden ${isDark ? "bg-[#1f1f1f] border-[#333]" : "bg-white border-gray-200"}`, children: [
1431
- /* @__PURE__ */ jsx5("div", { className: "grid grid-cols-4 gap-2 mb-3", children: colorPalette.map((color) => /* @__PURE__ */ jsx5(
1432
- "button",
1433
- {
1434
- onClick: () => {
1435
- setAnnotationColor(color);
1436
- setColorPickerOpen(false);
1437
- },
1438
- className: "w-7 h-7 rounded-full border transition-all",
1439
- style: { backgroundColor: color, borderColor: color === annotationColor ? "#fff" : "transparent" }
1440
- },
1441
- color
1442
- )) }),
1443
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 w-full", children: [
1444
- /* @__PURE__ */ jsx5("span", { className: "text-[10px] uppercase tracking-widest text-gray-400 shrink-0", children: "Hex" }),
1445
- /* @__PURE__ */ jsx5(
1446
- "input",
1447
- {
1448
- type: "text",
1449
- value: annotationColor.toUpperCase(),
1450
- onChange: (e) => {
1451
- const next = e.target.value.trim();
1452
- if (next.startsWith("#") && (next.length === 4 || next.length === 7)) {
1453
- setAnnotationColor(next);
1454
- }
2347
+ className: `pointer-events-auto shadow-2xl rounded-2xl p-2 flex items-center border z-[80] ${isDark ? "bg-[#2a2a2a]/90 border-[#3a3a3a] backdrop-blur-xl" : "bg-white/95 border-gray-100 backdrop-blur-md"}`,
2348
+ children: [
2349
+ tools.map((tool) => /* @__PURE__ */ jsx5(
2350
+ "button",
2351
+ {
2352
+ title: tool.name,
2353
+ "aria-label": tool.name,
2354
+ onClick: () => setDocumentState({ activeTool: tool.id }),
2355
+ className: `w-10 h-10 rounded-xl flex items-center justify-center transition-all ${activeTool === tool.id ? "text-white shadow-lg" : "text-gray-400"}`,
2356
+ style: activeTool === tool.id ? { backgroundColor: accentColor } : void 0,
2357
+ children: /* @__PURE__ */ jsx5(
2358
+ "svg",
2359
+ {
2360
+ className: "w-5 h-5",
2361
+ fill: "none",
2362
+ stroke: "currentColor",
2363
+ viewBox: "0 0 24 24",
2364
+ children: /* @__PURE__ */ jsx5(
2365
+ "path",
2366
+ {
2367
+ strokeLinecap: "round",
2368
+ strokeLinejoin: "round",
2369
+ strokeWidth: 2,
2370
+ d: tool.icon
2371
+ }
2372
+ )
2373
+ }
2374
+ )
1455
2375
  },
1456
- className: `flex-1 min-w-0 w-full text-xs rounded-md px-2 py-1 border ${isDark ? "bg-[#2a2a2a] border-[#444] text-white" : "bg-gray-100 border-gray-200 text-gray-700"}`
1457
- }
1458
- )
1459
- ] })
1460
- ] })
1461
- ] })
1462
- ] }) })
2376
+ tool.id
2377
+ )),
2378
+ /* @__PURE__ */ jsx5("div", { className: "w-px h-7 mx-2 bg-white/10" }),
2379
+ /* @__PURE__ */ jsxs5("div", { ref: colorPickerRef, className: "relative", children: [
2380
+ /* @__PURE__ */ jsx5(
2381
+ "button",
2382
+ {
2383
+ title: "Cor do marcador",
2384
+ "aria-label": "Cor do marcador",
2385
+ onClick: () => setColorPickerOpen((prev) => !prev),
2386
+ className: "w-9 h-9 rounded-full flex items-center justify-center border transition-all cursor-pointer relative",
2387
+ style: { borderColor: annotationColor },
2388
+ children: /* @__PURE__ */ jsx5(
2389
+ "span",
2390
+ {
2391
+ className: "w-5 h-5 rounded-full",
2392
+ style: { backgroundColor: annotationColor }
2393
+ }
2394
+ )
2395
+ }
2396
+ ),
2397
+ colorPickerOpen && /* @__PURE__ */ jsxs5(
2398
+ "div",
2399
+ {
2400
+ className: `absolute bottom-full left-1/2 -translate-x-1/2 mb-3 w-48 rounded-xl border p-3 shadow-2xl overflow-hidden ${isDark ? "bg-[#1f1f1f] border-[#333]" : "bg-white border-gray-200"}`,
2401
+ children: [
2402
+ /* @__PURE__ */ jsx5("div", { className: "grid grid-cols-4 gap-2 mb-3", children: colorPalette.map((color) => /* @__PURE__ */ jsx5(
2403
+ "button",
2404
+ {
2405
+ onClick: () => {
2406
+ setAnnotationColor(color);
2407
+ setColorPickerOpen(false);
2408
+ },
2409
+ className: "w-7 h-7 rounded-full border transition-all",
2410
+ style: {
2411
+ backgroundColor: color,
2412
+ borderColor: color === annotationColor ? "#fff" : "transparent"
2413
+ }
2414
+ },
2415
+ color
2416
+ )) }),
2417
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2 w-full", children: [
2418
+ /* @__PURE__ */ jsx5("span", { className: "text-[10px] uppercase tracking-widest text-gray-400 shrink-0", children: "Hex" }),
2419
+ /* @__PURE__ */ jsx5(
2420
+ "input",
2421
+ {
2422
+ type: "text",
2423
+ value: annotationColor.toUpperCase(),
2424
+ onChange: (e) => {
2425
+ const next = e.target.value.trim();
2426
+ if (next.startsWith("#") && (next.length === 4 || next.length === 7)) {
2427
+ setAnnotationColor(next);
2428
+ }
2429
+ },
2430
+ className: `flex-1 min-w-0 w-full text-xs rounded-md px-2 py-1 border ${isDark ? "bg-[#2a2a2a] border-[#444] text-white" : "bg-gray-100 border-gray-200 text-gray-700"}`
2431
+ }
2432
+ )
2433
+ ] })
2434
+ ]
2435
+ }
2436
+ )
2437
+ ] })
2438
+ ]
2439
+ }
2440
+ )
2441
+ }
2442
+ )
1463
2443
  ]
1464
2444
  }
1465
2445
  );