@papyrus-sdk/ui-react 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/base.css +92 -38
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +909 -274
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +907 -272
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -28,16 +28,31 @@ var Topbar = ({
|
|
|
28
28
|
triggerScrollToPage
|
|
29
29
|
} = useViewerStore();
|
|
30
30
|
const fileInputRef = useRef(null);
|
|
31
|
+
const zoomTimerRef = useRef(null);
|
|
32
|
+
const pendingZoomRef = useRef(null);
|
|
31
33
|
const [pageInput, setPageInput] = useState(currentPage.toString());
|
|
34
|
+
const pageDigits = Math.max(2, String(pageCount || 1).length);
|
|
32
35
|
const [showPageThemes, setShowPageThemes] = useState(false);
|
|
33
36
|
const isDark = uiTheme === "dark";
|
|
34
37
|
useEffect(() => {
|
|
35
38
|
setPageInput(currentPage.toString());
|
|
36
39
|
}, [currentPage]);
|
|
40
|
+
useEffect(() => () => {
|
|
41
|
+
if (zoomTimerRef.current) clearTimeout(zoomTimerRef.current);
|
|
42
|
+
}, []);
|
|
37
43
|
const handleZoom = (delta) => {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
const baseZoom = pendingZoomRef.current ?? zoom;
|
|
45
|
+
const nextZoom = Math.max(0.2, Math.min(5, baseZoom + delta));
|
|
46
|
+
pendingZoomRef.current = nextZoom;
|
|
47
|
+
if (zoomTimerRef.current) return;
|
|
48
|
+
zoomTimerRef.current = setTimeout(() => {
|
|
49
|
+
zoomTimerRef.current = null;
|
|
50
|
+
const targetZoom = pendingZoomRef.current;
|
|
51
|
+
pendingZoomRef.current = null;
|
|
52
|
+
if (targetZoom == null) return;
|
|
53
|
+
engine.setZoom(targetZoom);
|
|
54
|
+
setDocumentState({ zoom: targetZoom });
|
|
55
|
+
}, 80);
|
|
41
56
|
};
|
|
42
57
|
const handlePageChange = (page) => {
|
|
43
58
|
if (pageCount <= 0) return;
|
|
@@ -52,95 +67,103 @@ var Topbar = ({
|
|
|
52
67
|
{ id: "dark", name: "Invertido", color: "bg-gray-800" },
|
|
53
68
|
{ id: "high-contrast", name: "Contraste", color: "bg-black" }
|
|
54
69
|
];
|
|
55
|
-
return /* @__PURE__ */ jsxs(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"input",
|
|
69
|
-
{
|
|
70
|
-
type: "text",
|
|
71
|
-
className: "w-10 text-center bg-transparent focus:outline-none font-bold text-sm",
|
|
72
|
-
value: pageInput,
|
|
73
|
-
onChange: (e) => setPageInput(e.target.value),
|
|
74
|
-
onKeyDown: (e) => e.key === "Enter" && handlePageChange(parseInt(pageInput)),
|
|
75
|
-
onBlur: () => handlePageChange(parseInt(pageInput))
|
|
76
|
-
}
|
|
77
|
-
),
|
|
78
|
-
/* @__PURE__ */ jsx("span", { className: "opacity-40 px-1", children: "/" }),
|
|
79
|
-
/* @__PURE__ */ jsx("span", { className: "opacity-80 text-sm", children: pageCount > 0 ? pageCount : "\u2014" }),
|
|
80
|
-
/* @__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" }) }) })
|
|
81
|
-
] }),
|
|
82
|
-
showZoomControls && /* @__PURE__ */ jsxs("div", { className: `flex items-center rounded-lg p-1 border ${isDark ? "bg-[#2a2a2a] border-[#444]" : "bg-gray-50 border-gray-200"}`, children: [
|
|
83
|
-
/* @__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" }) }) }),
|
|
84
|
-
/* @__PURE__ */ jsxs("span", { className: "px-3 text-xs font-bold min-w-[50px] text-center", children: [
|
|
85
|
-
Math.round(zoom * 100),
|
|
86
|
-
"%"
|
|
70
|
+
return /* @__PURE__ */ jsxs(
|
|
71
|
+
"div",
|
|
72
|
+
{
|
|
73
|
+
"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"}`,
|
|
75
|
+
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 })
|
|
87
83
|
] }),
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
children:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
+
] })
|
|
111
|
+
] }),
|
|
112
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-3", children: [
|
|
113
|
+
showPageThemeSelector && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
114
|
+
/* @__PURE__ */ jsxs(
|
|
115
|
+
"button",
|
|
116
|
+
{
|
|
117
|
+
onClick: () => setShowPageThemes(!showPageThemes),
|
|
118
|
+
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
|
+
children: [
|
|
120
|
+
/* @__PURE__ */ jsx("div", { className: `w-3 h-3 rounded-full border ${themes.find((t) => t.id === pageTheme)?.color}` }),
|
|
121
|
+
/* @__PURE__ */ jsx("span", { children: "TEMA" })
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
),
|
|
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",
|
|
146
|
+
{
|
|
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() });
|
|
159
|
+
}
|
|
160
|
+
} })
|
|
161
|
+
] }),
|
|
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
|
+
] })
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
);
|
|
144
167
|
};
|
|
145
168
|
var Topbar_default = Topbar;
|
|
146
169
|
|
|
@@ -158,22 +181,44 @@ var withAlpha = (hex, alpha) => {
|
|
|
158
181
|
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
159
182
|
};
|
|
160
183
|
var Thumbnail = ({ engine, pageIndex, active, isDark, accentColor, onClick }) => {
|
|
184
|
+
const wrapperRef = useRef2(null);
|
|
161
185
|
const canvasRef = useRef2(null);
|
|
162
186
|
const htmlRef = useRef2(null);
|
|
163
187
|
const accentSoft = withAlpha(accentColor, 0.12);
|
|
164
188
|
const renderTargetType = engine.getRenderTargetType?.() ?? "canvas";
|
|
189
|
+
const [isVisible, setIsVisible] = useState2(false);
|
|
165
190
|
useEffect2(() => {
|
|
166
|
-
|
|
191
|
+
const target = wrapperRef.current;
|
|
192
|
+
if (!target) return;
|
|
193
|
+
if (typeof IntersectionObserver === "undefined") {
|
|
194
|
+
setIsVisible(true);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
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" });
|
|
206
|
+
observer.observe(target);
|
|
207
|
+
return () => observer.disconnect();
|
|
208
|
+
}, []);
|
|
209
|
+
useEffect2(() => {
|
|
210
|
+
if (renderTargetType === "element" || !isVisible) return;
|
|
167
211
|
const target = canvasRef.current;
|
|
168
212
|
if (target) {
|
|
169
213
|
engine.renderPage(pageIndex, target, 0.15).catch((err) => {
|
|
170
214
|
console.error("[Papyrus] Thumbnail render failed:", err);
|
|
171
215
|
});
|
|
172
216
|
}
|
|
173
|
-
}, [engine, pageIndex, renderTargetType]);
|
|
217
|
+
}, [engine, pageIndex, renderTargetType, isVisible]);
|
|
174
218
|
return /* @__PURE__ */ jsx2(
|
|
175
219
|
"div",
|
|
176
220
|
{
|
|
221
|
+
ref: wrapperRef,
|
|
177
222
|
onClick,
|
|
178
223
|
className: `p-3 cursor-pointer transition-all rounded-lg border-2 ${active ? "shadow-sm" : "border-transparent"}`,
|
|
179
224
|
style: active ? { borderColor: accentColor, backgroundColor: accentSoft } : void 0,
|
|
@@ -271,39 +316,46 @@ var SidebarLeft = ({ engine }) => {
|
|
|
271
316
|
} = useViewerStore2();
|
|
272
317
|
const isDark = uiTheme === "dark";
|
|
273
318
|
if (!sidebarLeftOpen) return null;
|
|
274
|
-
return /* @__PURE__ */ jsxs2(
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
319
|
+
return /* @__PURE__ */ jsxs2(
|
|
320
|
+
"div",
|
|
321
|
+
{
|
|
322
|
+
"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"}`,
|
|
324
|
+
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)) }) })
|
|
356
|
+
]
|
|
357
|
+
}
|
|
358
|
+
);
|
|
307
359
|
};
|
|
308
360
|
var SidebarLeft_default = SidebarLeft;
|
|
309
361
|
|
|
@@ -339,6 +391,7 @@ var SidebarRight = ({ engine }) => {
|
|
|
339
391
|
const searchService = new SearchService(engine);
|
|
340
392
|
const isDark = uiTheme === "dark";
|
|
341
393
|
const accentSoft = withAlpha2(accentColor, 0.12);
|
|
394
|
+
const resultsCount = searchResults.length;
|
|
342
395
|
const handleSearch = async (e) => {
|
|
343
396
|
e.preventDefault();
|
|
344
397
|
if (!query.trim()) {
|
|
@@ -351,119 +404,129 @@ var SidebarRight = ({ engine }) => {
|
|
|
351
404
|
setIsSearching(false);
|
|
352
405
|
};
|
|
353
406
|
if (!sidebarRightOpen) return null;
|
|
354
|
-
return /* @__PURE__ */ jsxs3(
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
/* @__PURE__ */ jsx3(
|
|
381
|
-
"input",
|
|
382
|
-
{
|
|
383
|
-
type: "text",
|
|
384
|
-
className: `w-full rounded-lg px-4 py-2.5 text-xs outline-none border transition-all shadow-inner font-medium ${isDark ? "bg-[#2a2a2a] text-white border-[#444] focus:border-blue-500" : "bg-gray-100 border-gray-200 focus:bg-white focus:border-blue-400"}`,
|
|
385
|
-
placeholder: "O que voc\xEA procura?",
|
|
386
|
-
value: query,
|
|
387
|
-
onChange: (e) => setQuery(e.target.value)
|
|
388
|
-
}
|
|
389
|
-
),
|
|
390
|
-
/* @__PURE__ */ jsx3("button", { type: "submit", className: "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" }) }) })
|
|
391
|
-
] }),
|
|
392
|
-
isSearching && /* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center justify-center py-12 space-y-3", children: [
|
|
393
|
-
/* @__PURE__ */ jsx3("div", { className: "w-6 h-6 border-2 border-t-transparent rounded-full animate-spin", style: { borderColor: accentColor } }),
|
|
394
|
-
/* @__PURE__ */ jsx3("span", { className: "text-[10px] font-bold text-gray-500 uppercase", children: "Varrendo documento..." })
|
|
395
|
-
] }),
|
|
396
|
-
!isSearching && searchResults.map((res, idx) => /* @__PURE__ */ jsxs3(
|
|
397
|
-
"div",
|
|
398
|
-
{
|
|
399
|
-
onClick: () => {
|
|
400
|
-
setDocumentState({ activeSearchIndex: idx });
|
|
401
|
-
triggerScrollToPage(res.pageIndex);
|
|
402
|
-
},
|
|
403
|
-
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"}`,
|
|
404
|
-
style: idx === activeSearchIndex ? { borderColor: accentColor, backgroundColor: accentSoft } : void 0,
|
|
405
|
-
children: [
|
|
406
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between mb-2", children: [
|
|
407
|
-
/* @__PURE__ */ jsxs3(
|
|
408
|
-
"span",
|
|
409
|
-
{
|
|
410
|
-
className: `text-[10px] font-black uppercase tracking-tighter ${idx === activeSearchIndex ? "" : "text-gray-400"}`,
|
|
411
|
-
style: idx === activeSearchIndex ? { color: accentColor } : void 0,
|
|
412
|
-
children: [
|
|
413
|
-
"P\xC1GINA ",
|
|
414
|
-
res.pageIndex + 1
|
|
415
|
-
]
|
|
416
|
-
}
|
|
417
|
-
),
|
|
418
|
-
/* @__PURE__ */ jsx3(
|
|
419
|
-
"svg",
|
|
420
|
-
{
|
|
421
|
-
className: `w-3 h-3 transition-transform ${idx === activeSearchIndex ? "" : "text-gray-300"}`,
|
|
422
|
-
style: idx === activeSearchIndex ? { color: accentColor } : void 0,
|
|
423
|
-
fill: "none",
|
|
424
|
-
stroke: "currentColor",
|
|
425
|
-
viewBox: "0 0 24 24",
|
|
426
|
-
children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M9 5l7 7-7 7" })
|
|
427
|
-
}
|
|
428
|
-
)
|
|
429
|
-
] }),
|
|
430
|
-
/* @__PURE__ */ jsxs3("p", { className: `text-[11px] font-medium leading-relaxed italic ${isDark ? "text-gray-400" : "text-gray-600"}`, children: [
|
|
431
|
-
"...",
|
|
432
|
-
res.text,
|
|
433
|
-
"..."
|
|
434
|
-
] })
|
|
435
|
-
]
|
|
436
|
-
},
|
|
437
|
-
idx
|
|
438
|
-
))
|
|
439
|
-
] }) : /* @__PURE__ */ jsxs3("div", { className: "space-y-3", children: [
|
|
440
|
-
/* @__PURE__ */ jsxs3("div", { className: "text-[9px] font-black text-gray-400 uppercase tracking-[0.2em] mb-6 flex items-center", children: [
|
|
441
|
-
/* @__PURE__ */ jsx3("span", { children: "WORKSET" }),
|
|
442
|
-
/* @__PURE__ */ jsx3("div", { className: "flex-1 h-px bg-current ml-3 opacity-10" })
|
|
443
|
-
] }),
|
|
444
|
-
annotations.length === 0 ? /* @__PURE__ */ jsxs3("div", { className: "text-center py-20", children: [
|
|
445
|
-
/* @__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" }) }) }),
|
|
446
|
-
/* @__PURE__ */ jsx3("p", { className: "text-[10px] font-bold text-gray-400 uppercase tracking-widest", children: "Sem anota\xE7\xF5es" })
|
|
447
|
-
] }) : 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: [
|
|
448
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between mb-3", children: [
|
|
449
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex items-center space-x-2", children: [
|
|
450
|
-
/* @__PURE__ */ jsx3("div", { className: "w-2.5 h-2.5 rounded-full", style: { backgroundColor: ann.color } }),
|
|
451
|
-
/* @__PURE__ */ jsxs3("span", { className: "text-[10px] font-black", style: { color: accentColor }, children: [
|
|
452
|
-
"P",
|
|
453
|
-
ann.pageIndex + 1
|
|
454
|
-
] })
|
|
407
|
+
return /* @__PURE__ */ jsxs3(
|
|
408
|
+
"div",
|
|
409
|
+
{
|
|
410
|
+
"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"}`,
|
|
412
|
+
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
|
+
)
|
|
455
433
|
] }),
|
|
456
|
-
/* @__PURE__ */ jsx3("
|
|
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" }) }) })
|
|
457
435
|
] }),
|
|
458
|
-
/* @__PURE__ */ jsx3("
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
436
|
+
/* @__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
|
+
/* @__PURE__ */ jsxs3("form", { onSubmit: handleSearch, className: "relative mb-6", children: [
|
|
438
|
+
/* @__PURE__ */ jsx3(
|
|
439
|
+
"input",
|
|
440
|
+
{
|
|
441
|
+
type: "text",
|
|
442
|
+
className: `papyrus-input w-full rounded-lg px-4 py-2.5 text-xs outline-none border transition-all shadow-inner font-medium ${isDark ? "bg-[#2a2a2a] text-white border-[#444] focus:border-blue-500" : "bg-gray-100 border-gray-200 focus:bg-white focus:border-blue-400"}`,
|
|
443
|
+
placeholder: "O que voc\xEA procura?",
|
|
444
|
+
value: query,
|
|
445
|
+
onChange: (e) => setQuery(e.target.value)
|
|
446
|
+
}
|
|
447
|
+
),
|
|
448
|
+
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" }) }) })
|
|
450
|
+
] }),
|
|
451
|
+
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 } }),
|
|
453
|
+
/* @__PURE__ */ jsx3("span", { className: "text-[10px] font-bold text-gray-500 uppercase", children: "Varrendo documento..." })
|
|
454
|
+
] }),
|
|
455
|
+
!isSearching && searchResults.map((res, idx) => /* @__PURE__ */ jsxs3(
|
|
456
|
+
"div",
|
|
457
|
+
{
|
|
458
|
+
onClick: () => {
|
|
459
|
+
const page = res.pageIndex + 1;
|
|
460
|
+
engine.goToPage(page);
|
|
461
|
+
setDocumentState({ activeSearchIndex: idx, currentPage: page });
|
|
462
|
+
triggerScrollToPage(res.pageIndex);
|
|
463
|
+
},
|
|
464
|
+
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,
|
|
466
|
+
children: [
|
|
467
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center justify-between mb-2", children: [
|
|
468
|
+
/* @__PURE__ */ jsxs3(
|
|
469
|
+
"span",
|
|
470
|
+
{
|
|
471
|
+
className: `text-[10px] font-black uppercase tracking-tighter ${idx === activeSearchIndex ? "" : "text-gray-400"}`,
|
|
472
|
+
style: idx === activeSearchIndex ? { color: accentColor } : void 0,
|
|
473
|
+
children: [
|
|
474
|
+
"P\xC1GINA ",
|
|
475
|
+
res.pageIndex + 1
|
|
476
|
+
]
|
|
477
|
+
}
|
|
478
|
+
),
|
|
479
|
+
/* @__PURE__ */ jsx3(
|
|
480
|
+
"svg",
|
|
481
|
+
{
|
|
482
|
+
className: `w-3 h-3 transition-transform ${idx === activeSearchIndex ? "" : "text-gray-300"}`,
|
|
483
|
+
style: idx === activeSearchIndex ? { color: accentColor } : void 0,
|
|
484
|
+
fill: "none",
|
|
485
|
+
stroke: "currentColor",
|
|
486
|
+
viewBox: "0 0 24 24",
|
|
487
|
+
children: /* @__PURE__ */ jsx3("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 3, d: "M9 5l7 7-7 7" })
|
|
488
|
+
}
|
|
489
|
+
)
|
|
490
|
+
] }),
|
|
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
|
+
] })
|
|
496
|
+
]
|
|
497
|
+
},
|
|
498
|
+
idx
|
|
499
|
+
))
|
|
500
|
+
] }) : /* @__PURE__ */ jsxs3("div", { className: "space-y-3", children: [
|
|
501
|
+
/* @__PURE__ */ jsxs3("div", { className: "text-[9px] font-black text-gray-400 uppercase tracking-[0.2em] mb-6 flex items-center", children: [
|
|
502
|
+
/* @__PURE__ */ jsx3("span", { children: "WORKSET" }),
|
|
503
|
+
/* @__PURE__ */ jsx3("div", { className: "flex-1 h-px bg-current ml-3 opacity-10" })
|
|
504
|
+
] }),
|
|
505
|
+
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" }) }) }),
|
|
507
|
+
/* @__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))
|
|
521
|
+
] }) })
|
|
522
|
+
]
|
|
523
|
+
}
|
|
524
|
+
);
|
|
462
525
|
};
|
|
463
526
|
var SidebarRight_default = SidebarRight;
|
|
464
527
|
|
|
465
528
|
// components/Viewer.tsx
|
|
466
|
-
import { useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
|
|
529
|
+
import { useEffect as useEffect4, useMemo as useMemo2, useRef as useRef4, useState as useState5 } from "react";
|
|
467
530
|
import { useViewerStore as useViewerStore5 } from "@papyrus-sdk/core";
|
|
468
531
|
|
|
469
532
|
// components/PageRenderer.tsx
|
|
@@ -471,7 +534,7 @@ import { useEffect as useEffect3, useMemo, useRef as useRef3, useState as useSta
|
|
|
471
534
|
import { useViewerStore as useViewerStore4, papyrusEvents } from "@papyrus-sdk/core";
|
|
472
535
|
import { PapyrusEventType } from "@papyrus-sdk/types";
|
|
473
536
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
474
|
-
var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
537
|
+
var PageRenderer = ({ engine, pageIndex, availableWidth, onMeasuredSize }) => {
|
|
475
538
|
const containerRef = useRef3(null);
|
|
476
539
|
const canvasRef = useRef3(null);
|
|
477
540
|
const htmlLayerRef = useRef3(null);
|
|
@@ -481,6 +544,10 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
481
544
|
const [isDragging, setIsDragging] = useState4(false);
|
|
482
545
|
const [startPos, setStartPos] = useState4({ x: 0, y: 0 });
|
|
483
546
|
const [currentRect, setCurrentRect] = useState4({ x: 0, y: 0, w: 0, h: 0 });
|
|
547
|
+
const [textLayerVersion, setTextLayerVersion] = useState4(0);
|
|
548
|
+
const [selectionMenu, setSelectionMenu] = useState4(null);
|
|
549
|
+
const [isInkDrawing, setIsInkDrawing] = useState4(false);
|
|
550
|
+
const [inkPoints, setInkPoints] = useState4([]);
|
|
484
551
|
const {
|
|
485
552
|
zoom,
|
|
486
553
|
rotation,
|
|
@@ -493,10 +560,20 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
493
560
|
removeAnnotation,
|
|
494
561
|
selectedAnnotationId,
|
|
495
562
|
setSelectedAnnotation,
|
|
496
|
-
accentColor
|
|
563
|
+
accentColor,
|
|
564
|
+
annotationColor,
|
|
565
|
+
searchQuery,
|
|
566
|
+
searchResults,
|
|
567
|
+
activeSearchIndex
|
|
497
568
|
} = useViewerStore4();
|
|
498
569
|
const renderTargetType = engine.getRenderTargetType?.() ?? "canvas";
|
|
499
570
|
const isElementRender = renderTargetType === "element";
|
|
571
|
+
const textMarkupTools = /* @__PURE__ */ new Set(["highlight", "underline", "squiggly", "strikeout"]);
|
|
572
|
+
const canSelectText = activeTool === "select" || textMarkupTools.has(activeTool);
|
|
573
|
+
const hasSearchHits = useMemo(
|
|
574
|
+
() => Boolean(searchQuery?.trim()) && searchResults.some((res) => res.pageIndex === pageIndex),
|
|
575
|
+
[searchQuery, searchResults, pageIndex]
|
|
576
|
+
);
|
|
500
577
|
useEffect3(() => {
|
|
501
578
|
let active = true;
|
|
502
579
|
const loadSize = async () => {
|
|
@@ -529,8 +606,14 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
529
606
|
};
|
|
530
607
|
}, [pageSize, zoom, fitScale]);
|
|
531
608
|
useEffect3(() => {
|
|
532
|
-
if (
|
|
533
|
-
|
|
609
|
+
if (!displaySize || !onMeasuredSize) return;
|
|
610
|
+
onMeasuredSize(pageIndex, {
|
|
611
|
+
width: Math.round(displaySize.width),
|
|
612
|
+
height: Math.round(displaySize.height)
|
|
613
|
+
});
|
|
614
|
+
}, [displaySize, onMeasuredSize, pageIndex]);
|
|
615
|
+
useEffect3(() => {
|
|
616
|
+
if (scrollToPageSignal === pageIndex) {
|
|
534
617
|
setDocumentState({ scrollToPageSignal: null });
|
|
535
618
|
}
|
|
536
619
|
}, [scrollToPageSignal, pageIndex, setDocumentState]);
|
|
@@ -542,10 +625,15 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
542
625
|
setLoading(true);
|
|
543
626
|
try {
|
|
544
627
|
const RENDER_SCALE = 2;
|
|
545
|
-
const
|
|
546
|
-
|
|
628
|
+
const canvasRenderScale = isElementRender ? 1 : RENDER_SCALE * fitScale;
|
|
629
|
+
const textRenderScale = isElementRender ? 1 : fitScale;
|
|
630
|
+
if (!isElementRender && canvasRef.current && displaySize) {
|
|
631
|
+
canvasRef.current.style.width = `${displaySize.width}px`;
|
|
632
|
+
canvasRef.current.style.height = `${displaySize.height}px`;
|
|
633
|
+
}
|
|
634
|
+
await engine.renderPage(pageIndex, renderTarget, canvasRenderScale);
|
|
547
635
|
if (!isElementRender && !pageSize && canvasRef.current) {
|
|
548
|
-
const denom =
|
|
636
|
+
const denom = canvasRenderScale * Math.max(zoom, 0.01);
|
|
549
637
|
if (denom > 0) {
|
|
550
638
|
setPageSize({
|
|
551
639
|
width: canvasRef.current.width / denom,
|
|
@@ -556,7 +644,7 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
556
644
|
if (!active || !textLayerRef.current) return;
|
|
557
645
|
if (!isElementRender) {
|
|
558
646
|
textLayerRef.current.innerHTML = "";
|
|
559
|
-
await engine.renderTextLayer(pageIndex, textLayerRef.current,
|
|
647
|
+
await engine.renderTextLayer(pageIndex, textLayerRef.current, textRenderScale);
|
|
560
648
|
}
|
|
561
649
|
if (!active || !textLayerRef.current) return;
|
|
562
650
|
if (!isElementRender && displaySize) {
|
|
@@ -567,6 +655,7 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
567
655
|
textLayerRef.current.style.width = `${displaySize.width}px`;
|
|
568
656
|
textLayerRef.current.style.height = `${displaySize.height}px`;
|
|
569
657
|
}
|
|
658
|
+
setTextLayerVersion((v) => v + 1);
|
|
570
659
|
} catch (err) {
|
|
571
660
|
if (!active) return;
|
|
572
661
|
console.error("[Papyrus] Falha na renderiza\xE7\xE3o:", err);
|
|
@@ -579,8 +668,68 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
579
668
|
active = false;
|
|
580
669
|
};
|
|
581
670
|
}, [engine, pageIndex, zoom, rotation, isElementRender, fitScale, displaySize, pageSize]);
|
|
671
|
+
useEffect3(() => {
|
|
672
|
+
if (isElementRender) return;
|
|
673
|
+
const layer = textLayerRef.current;
|
|
674
|
+
if (!layer) return;
|
|
675
|
+
const query = searchQuery?.trim().toLowerCase();
|
|
676
|
+
const existingMarks = Array.from(layer.querySelectorAll("mark.papyrus-search-hit"));
|
|
677
|
+
existingMarks.forEach((mark) => {
|
|
678
|
+
const parent = mark.parentNode;
|
|
679
|
+
if (!parent) return;
|
|
680
|
+
while (mark.firstChild) parent.insertBefore(mark.firstChild, mark);
|
|
681
|
+
parent.removeChild(mark);
|
|
682
|
+
parent.normalize();
|
|
683
|
+
});
|
|
684
|
+
if (!query || !hasSearchHits) return;
|
|
685
|
+
const nodes = [];
|
|
686
|
+
const walker = document.createTreeWalker(layer, NodeFilter.SHOW_TEXT, {
|
|
687
|
+
acceptNode(node) {
|
|
688
|
+
const text = node.nodeValue ?? "";
|
|
689
|
+
if (!text.trim()) return NodeFilter.FILTER_REJECT;
|
|
690
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
while (walker.nextNode()) {
|
|
694
|
+
nodes.push(walker.currentNode);
|
|
695
|
+
}
|
|
696
|
+
nodes.forEach((textNode) => {
|
|
697
|
+
const text = textNode.nodeValue ?? "";
|
|
698
|
+
const lower = text.toLowerCase();
|
|
699
|
+
if (!lower.includes(query)) return;
|
|
700
|
+
const fragment = document.createDocumentFragment();
|
|
701
|
+
let cursor = 0;
|
|
702
|
+
let index = lower.indexOf(query, cursor);
|
|
703
|
+
while (index !== -1) {
|
|
704
|
+
if (index > cursor) {
|
|
705
|
+
fragment.appendChild(document.createTextNode(text.slice(cursor, index)));
|
|
706
|
+
}
|
|
707
|
+
const mark = document.createElement("mark");
|
|
708
|
+
mark.className = "papyrus-search-hit";
|
|
709
|
+
mark.textContent = text.slice(index, index + query.length);
|
|
710
|
+
fragment.appendChild(mark);
|
|
711
|
+
cursor = index + query.length;
|
|
712
|
+
index = lower.indexOf(query, cursor);
|
|
713
|
+
}
|
|
714
|
+
if (cursor < text.length) {
|
|
715
|
+
fragment.appendChild(document.createTextNode(text.slice(cursor)));
|
|
716
|
+
}
|
|
717
|
+
const parent = textNode.parentNode;
|
|
718
|
+
if (parent) parent.replaceChild(fragment, textNode);
|
|
719
|
+
});
|
|
720
|
+
}, [searchQuery, hasSearchHits, pageIndex, isElementRender, activeSearchIndex, textLayerVersion]);
|
|
582
721
|
const handleMouseDown = (e) => {
|
|
583
|
-
|
|
722
|
+
setSelectionMenu(null);
|
|
723
|
+
if (activeTool === "ink") {
|
|
724
|
+
const rect2 = containerRef.current?.getBoundingClientRect();
|
|
725
|
+
if (!rect2) return;
|
|
726
|
+
const x2 = (e.clientX - rect2.left) / rect2.width;
|
|
727
|
+
const y2 = (e.clientY - rect2.top) / rect2.height;
|
|
728
|
+
setIsInkDrawing(true);
|
|
729
|
+
setInkPoints([{ x: x2, y: y2 }]);
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
if (canSelectText) return;
|
|
584
733
|
const rect = containerRef.current?.getBoundingClientRect();
|
|
585
734
|
if (!rect) return;
|
|
586
735
|
setIsDragging(true);
|
|
@@ -590,6 +739,14 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
590
739
|
setCurrentRect({ x, y, w: 0, h: 0 });
|
|
591
740
|
};
|
|
592
741
|
const handleMouseMove = (e) => {
|
|
742
|
+
if (isInkDrawing) {
|
|
743
|
+
const rect2 = containerRef.current?.getBoundingClientRect();
|
|
744
|
+
if (!rect2) return;
|
|
745
|
+
const x = (e.clientX - rect2.left) / rect2.width;
|
|
746
|
+
const y = (e.clientY - rect2.top) / rect2.height;
|
|
747
|
+
setInkPoints((prev) => [...prev, { x, y }]);
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
593
750
|
if (!isDragging) return;
|
|
594
751
|
const rect = containerRef.current?.getBoundingClientRect();
|
|
595
752
|
if (!rect) return;
|
|
@@ -603,6 +760,115 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
603
760
|
});
|
|
604
761
|
};
|
|
605
762
|
const handleMouseUp = (e) => {
|
|
763
|
+
if (isInkDrawing) {
|
|
764
|
+
setIsInkDrawing(false);
|
|
765
|
+
if (inkPoints.length > 1) {
|
|
766
|
+
const xs = inkPoints.map((p) => p.x);
|
|
767
|
+
const ys = inkPoints.map((p) => p.y);
|
|
768
|
+
const minX = Math.min(...xs);
|
|
769
|
+
const maxX = Math.max(...xs);
|
|
770
|
+
const minY = Math.min(...ys);
|
|
771
|
+
const maxY = Math.max(...ys);
|
|
772
|
+
const width = Math.max(maxX - minX, 5e-4);
|
|
773
|
+
const height = Math.max(maxY - minY, 5e-4);
|
|
774
|
+
const path = inkPoints.map((p) => ({
|
|
775
|
+
x: Math.max(0, Math.min(1, p.x)),
|
|
776
|
+
y: Math.max(0, Math.min(1, p.y))
|
|
777
|
+
}));
|
|
778
|
+
addAnnotation({
|
|
779
|
+
id: Math.random().toString(36).substr(2, 9),
|
|
780
|
+
pageIndex,
|
|
781
|
+
type: "ink",
|
|
782
|
+
rect: { x: minX, y: minY, width, height },
|
|
783
|
+
path,
|
|
784
|
+
color: annotationColor,
|
|
785
|
+
createdAt: Date.now()
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
setInkPoints([]);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
const selection = window.getSelection();
|
|
792
|
+
const selectionText = selection?.toString().trim() ?? "";
|
|
793
|
+
if (selectionText && textLayerRef.current && containerRef.current && selection && selection.rangeCount > 0) {
|
|
794
|
+
const range = selection.getRangeAt(0);
|
|
795
|
+
if (textLayerRef.current.contains(range.commonAncestorContainer)) {
|
|
796
|
+
const containerRect = containerRef.current.getBoundingClientRect();
|
|
797
|
+
const clientRects = Array.from(range.getClientRects());
|
|
798
|
+
const rects = clientRects.filter((r) => r.width > 1 && r.height > 1).map((r) => {
|
|
799
|
+
const x = (r.left - containerRect.left) / containerRect.width;
|
|
800
|
+
const y = (r.top - containerRect.top) / containerRect.height;
|
|
801
|
+
const width = r.width / containerRect.width;
|
|
802
|
+
const height = r.height / containerRect.height;
|
|
803
|
+
return {
|
|
804
|
+
x: Math.max(0, Math.min(1, x)),
|
|
805
|
+
y: Math.max(0, Math.min(1, y)),
|
|
806
|
+
width: Math.max(0, Math.min(1, width)),
|
|
807
|
+
height: Math.max(0, Math.min(1, height))
|
|
808
|
+
};
|
|
809
|
+
});
|
|
810
|
+
const uniqueRects = rects.filter((rect, index, list) => {
|
|
811
|
+
const key = `${Math.round(rect.x * 1e4)}-${Math.round(rect.y * 1e4)}-${Math.round(rect.width * 1e4)}-${Math.round(rect.height * 1e4)}`;
|
|
812
|
+
return list.findIndex((r) => `${Math.round(r.x * 1e4)}-${Math.round(r.y * 1e4)}-${Math.round(r.width * 1e4)}-${Math.round(r.height * 1e4)}` === key) === index;
|
|
813
|
+
});
|
|
814
|
+
const mergedRects = uniqueRects.reduce((acc, rect) => {
|
|
815
|
+
const target = acc.find((r) => {
|
|
816
|
+
const closeY = Math.abs(r.y - rect.y) < 2e-3 && Math.abs(r.height - rect.height) < 2e-3;
|
|
817
|
+
const overlaps = rect.x <= r.x + r.width + 2e-3 && rect.x + rect.width >= r.x - 2e-3;
|
|
818
|
+
return closeY && overlaps;
|
|
819
|
+
});
|
|
820
|
+
if (!target) {
|
|
821
|
+
acc.push({ ...rect });
|
|
822
|
+
return acc;
|
|
823
|
+
}
|
|
824
|
+
const left = Math.min(target.x, rect.x);
|
|
825
|
+
const right = Math.max(target.x + target.width, rect.x + rect.width);
|
|
826
|
+
target.x = left;
|
|
827
|
+
target.width = right - left;
|
|
828
|
+
return acc;
|
|
829
|
+
}, []);
|
|
830
|
+
if (mergedRects.length) {
|
|
831
|
+
const xs = mergedRects.map((r) => r.x);
|
|
832
|
+
const ys = mergedRects.map((r) => r.y);
|
|
833
|
+
const xe = mergedRects.map((r) => r.x + r.width);
|
|
834
|
+
const ye = mergedRects.map((r) => r.y + r.height);
|
|
835
|
+
const rect = {
|
|
836
|
+
x: Math.min(...xs),
|
|
837
|
+
y: Math.min(...ys),
|
|
838
|
+
width: Math.max(...xe) - Math.min(...xs),
|
|
839
|
+
height: Math.max(...ye) - Math.min(...ys)
|
|
840
|
+
};
|
|
841
|
+
if (textMarkupTools.has(activeTool)) {
|
|
842
|
+
addAnnotation({
|
|
843
|
+
id: Math.random().toString(36).substr(2, 9),
|
|
844
|
+
pageIndex,
|
|
845
|
+
type: activeTool,
|
|
846
|
+
rect,
|
|
847
|
+
rects: mergedRects,
|
|
848
|
+
color: annotationColor,
|
|
849
|
+
content: selectionText,
|
|
850
|
+
createdAt: Date.now()
|
|
851
|
+
});
|
|
852
|
+
selection.removeAllRanges();
|
|
853
|
+
setSelectionMenu(null);
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
if (activeTool === "select") {
|
|
857
|
+
const anchorX = (rect.x + rect.width) * containerRect.width;
|
|
858
|
+
const anchorY = rect.y * containerRect.height;
|
|
859
|
+
setSelectionMenu({
|
|
860
|
+
rects: mergedRects,
|
|
861
|
+
rect,
|
|
862
|
+
text: selectionText,
|
|
863
|
+
anchor: {
|
|
864
|
+
x: Math.max(12, Math.min(containerRect.width - 12, anchorX)),
|
|
865
|
+
y: Math.max(12, anchorY - 32)
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
606
872
|
if (isDragging) {
|
|
607
873
|
setIsDragging(false);
|
|
608
874
|
if (currentRect.w > 5 && currentRect.h > 5) {
|
|
@@ -618,7 +884,7 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
618
884
|
width: currentRect.w / rect.width,
|
|
619
885
|
height: currentRect.h / rect.height
|
|
620
886
|
},
|
|
621
|
-
color: activeTool === "highlight" ?
|
|
887
|
+
color: activeTool === "highlight" ? annotationColor : accentColor,
|
|
622
888
|
content: activeTool === "text" || activeTool === "comment" ? "" : void 0,
|
|
623
889
|
createdAt: Date.now()
|
|
624
890
|
});
|
|
@@ -628,7 +894,6 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
628
894
|
return;
|
|
629
895
|
}
|
|
630
896
|
if (activeTool === "select") {
|
|
631
|
-
const selection = window.getSelection();
|
|
632
897
|
const selectedText = selection?.toString().trim();
|
|
633
898
|
if (selectedText) {
|
|
634
899
|
papyrusEvents.emit(PapyrusEventType.TEXT_SELECTED, {
|
|
@@ -654,7 +919,7 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
654
919
|
"div",
|
|
655
920
|
{
|
|
656
921
|
ref: containerRef,
|
|
657
|
-
className: `relative inline-block shadow-2xl bg-white mb-10 transition-all ${
|
|
922
|
+
className: `relative inline-block shadow-2xl bg-white mb-10 transition-all ${canSelectText ? "" : "no-select cursor-crosshair"}`,
|
|
658
923
|
style: { scrollMarginTop: "20px", minHeight: "100px" },
|
|
659
924
|
onMouseDown: handleMouseDown,
|
|
660
925
|
onMouseMove: handleMouseMove,
|
|
@@ -683,7 +948,7 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
683
948
|
ref: textLayerRef,
|
|
684
949
|
className: "textLayer",
|
|
685
950
|
style: {
|
|
686
|
-
pointerEvents: isElementRender ? "none" :
|
|
951
|
+
pointerEvents: isElementRender ? "none" : canSelectText ? "auto" : "none",
|
|
687
952
|
display: isElementRender ? "none" : "block"
|
|
688
953
|
}
|
|
689
954
|
}
|
|
@@ -693,8 +958,9 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
693
958
|
{
|
|
694
959
|
className: "absolute border-2 z-[40] pointer-events-none",
|
|
695
960
|
style: {
|
|
696
|
-
borderColor: accentColor,
|
|
697
|
-
backgroundColor: `${accentColor}33`,
|
|
961
|
+
borderColor: activeTool === "highlight" ? annotationColor : accentColor,
|
|
962
|
+
backgroundColor: activeTool === "highlight" ? `${annotationColor}66` : `${accentColor}33`,
|
|
963
|
+
mixBlendMode: activeTool === "highlight" ? "multiply" : void 0,
|
|
698
964
|
left: currentRect.x,
|
|
699
965
|
top: currentRect.y,
|
|
700
966
|
width: currentRect.w,
|
|
@@ -702,6 +968,60 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
702
968
|
}
|
|
703
969
|
}
|
|
704
970
|
),
|
|
971
|
+
isInkDrawing && inkPoints.length > 1 && /* @__PURE__ */ jsx4(
|
|
972
|
+
"svg",
|
|
973
|
+
{
|
|
974
|
+
className: "absolute inset-0 pointer-events-none z-[45]",
|
|
975
|
+
viewBox: "0 0 1 1",
|
|
976
|
+
preserveAspectRatio: "none",
|
|
977
|
+
style: { width: "100%", height: "100%" },
|
|
978
|
+
children: /* @__PURE__ */ jsx4(
|
|
979
|
+
"path",
|
|
980
|
+
{
|
|
981
|
+
d: inkPoints.map((p, idx) => `${idx === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" "),
|
|
982
|
+
fill: "none",
|
|
983
|
+
stroke: annotationColor,
|
|
984
|
+
strokeWidth: 8e-3,
|
|
985
|
+
strokeLinecap: "round",
|
|
986
|
+
strokeLinejoin: "round"
|
|
987
|
+
}
|
|
988
|
+
)
|
|
989
|
+
}
|
|
990
|
+
),
|
|
991
|
+
selectionMenu && /* @__PURE__ */ jsx4(
|
|
992
|
+
"div",
|
|
993
|
+
{
|
|
994
|
+
className: "absolute z-[60] flex items-center gap-1 rounded-full border px-2 py-1 shadow-xl bg-white/95 backdrop-blur-md text-gray-700",
|
|
995
|
+
style: { left: selectionMenu.anchor.x, top: selectionMenu.anchor.y },
|
|
996
|
+
children: [
|
|
997
|
+
{ id: "highlight", label: "Marcar" },
|
|
998
|
+
{ id: "underline", label: "Sublinhar" },
|
|
999
|
+
{ id: "squiggly", label: "Onda" },
|
|
1000
|
+
{ id: "strikeout", label: "Risco" }
|
|
1001
|
+
].map((action) => /* @__PURE__ */ jsx4(
|
|
1002
|
+
"button",
|
|
1003
|
+
{
|
|
1004
|
+
className: "text-[10px] font-bold px-2 py-1 rounded-full hover:bg-gray-100",
|
|
1005
|
+
onClick: () => {
|
|
1006
|
+
addAnnotation({
|
|
1007
|
+
id: Math.random().toString(36).substr(2, 9),
|
|
1008
|
+
pageIndex,
|
|
1009
|
+
type: action.id,
|
|
1010
|
+
rect: selectionMenu.rect,
|
|
1011
|
+
rects: selectionMenu.rects,
|
|
1012
|
+
content: selectionMenu.text,
|
|
1013
|
+
color: annotationColor,
|
|
1014
|
+
createdAt: Date.now()
|
|
1015
|
+
});
|
|
1016
|
+
window.getSelection()?.removeAllRanges();
|
|
1017
|
+
setSelectionMenu(null);
|
|
1018
|
+
},
|
|
1019
|
+
children: action.label
|
|
1020
|
+
},
|
|
1021
|
+
action.id
|
|
1022
|
+
))
|
|
1023
|
+
}
|
|
1024
|
+
),
|
|
705
1025
|
/* @__PURE__ */ jsx4("div", { className: "absolute inset-0 pointer-events-none z-20", children: annotations.filter((a) => a.pageIndex === pageIndex).map((ann) => /* @__PURE__ */ jsx4(
|
|
706
1026
|
AnnotationItem,
|
|
707
1027
|
{
|
|
@@ -719,6 +1039,101 @@ var PageRenderer = ({ engine, pageIndex, availableWidth }) => {
|
|
|
719
1039
|
};
|
|
720
1040
|
var AnnotationItem = ({ ann, isSelected, accentColor, onDelete, onSelect }) => {
|
|
721
1041
|
const isText = ann.type === "text" || ann.type === "comment";
|
|
1042
|
+
const isHighlight = ann.type === "highlight";
|
|
1043
|
+
const isMarkup = ann.type === "highlight" || ann.type === "underline" || ann.type === "squiggly" || ann.type === "strikeout";
|
|
1044
|
+
const rects = ann.rects && ann.rects.length > 0 ? ann.rects : [ann.rect];
|
|
1045
|
+
const isInk = ann.type === "ink" && ann.path && ann.path.length > 1;
|
|
1046
|
+
const renderMarkupRects = () => {
|
|
1047
|
+
if (!isMarkup) return null;
|
|
1048
|
+
return rects.map((r, idx) => {
|
|
1049
|
+
const left = ann.rect.width ? (r.x - ann.rect.x) / ann.rect.width * 100 : 0;
|
|
1050
|
+
const top = ann.rect.height ? (r.y - ann.rect.y) / ann.rect.height * 100 : 0;
|
|
1051
|
+
const width = ann.rect.width ? r.width / ann.rect.width * 100 : 100;
|
|
1052
|
+
const height = ann.rect.height ? r.height / ann.rect.height * 100 : 100;
|
|
1053
|
+
if (ann.type === "highlight") {
|
|
1054
|
+
return /* @__PURE__ */ jsx4(
|
|
1055
|
+
"div",
|
|
1056
|
+
{
|
|
1057
|
+
className: "absolute rounded-sm",
|
|
1058
|
+
style: {
|
|
1059
|
+
left: `${left}%`,
|
|
1060
|
+
top: `${top}%`,
|
|
1061
|
+
width: `${width}%`,
|
|
1062
|
+
height: `${height}%`,
|
|
1063
|
+
backgroundColor: `${ann.color}88`,
|
|
1064
|
+
mixBlendMode: "multiply"
|
|
1065
|
+
}
|
|
1066
|
+
},
|
|
1067
|
+
idx
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
const lineStyle = {
|
|
1071
|
+
left: `${left}%`,
|
|
1072
|
+
width: `${width}%`
|
|
1073
|
+
};
|
|
1074
|
+
if (ann.type === "underline") {
|
|
1075
|
+
return /* @__PURE__ */ jsx4(
|
|
1076
|
+
"div",
|
|
1077
|
+
{
|
|
1078
|
+
className: "absolute",
|
|
1079
|
+
style: {
|
|
1080
|
+
...lineStyle,
|
|
1081
|
+
top: `calc(${top}% + ${height}% - 2px)`,
|
|
1082
|
+
height: "2px",
|
|
1083
|
+
backgroundColor: ann.color
|
|
1084
|
+
}
|
|
1085
|
+
},
|
|
1086
|
+
idx
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
if (ann.type === "strikeout") {
|
|
1090
|
+
return /* @__PURE__ */ jsx4(
|
|
1091
|
+
"div",
|
|
1092
|
+
{
|
|
1093
|
+
className: "absolute",
|
|
1094
|
+
style: {
|
|
1095
|
+
...lineStyle,
|
|
1096
|
+
top: `calc(${top}% + ${height * 0.5}% - 1px)`,
|
|
1097
|
+
height: "2px",
|
|
1098
|
+
backgroundColor: ann.color
|
|
1099
|
+
}
|
|
1100
|
+
},
|
|
1101
|
+
idx
|
|
1102
|
+
);
|
|
1103
|
+
}
|
|
1104
|
+
if (ann.type === "squiggly") {
|
|
1105
|
+
return /* @__PURE__ */ jsx4(
|
|
1106
|
+
"div",
|
|
1107
|
+
{
|
|
1108
|
+
className: "absolute",
|
|
1109
|
+
style: {
|
|
1110
|
+
...lineStyle,
|
|
1111
|
+
top: `calc(${top}% + ${height}% - 4px)`,
|
|
1112
|
+
height: "4px",
|
|
1113
|
+
backgroundImage: `linear-gradient(135deg, transparent 75%, ${ann.color} 0), linear-gradient(225deg, transparent 75%, ${ann.color} 0)`,
|
|
1114
|
+
backgroundSize: "6px 6px",
|
|
1115
|
+
backgroundPosition: "0 0, 3px 3px"
|
|
1116
|
+
}
|
|
1117
|
+
},
|
|
1118
|
+
idx
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1121
|
+
return null;
|
|
1122
|
+
});
|
|
1123
|
+
};
|
|
1124
|
+
const renderInk = () => {
|
|
1125
|
+
if (!isInk || !ann.path) return null;
|
|
1126
|
+
const d = ann.path.map((p, idx) => `${idx === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ");
|
|
1127
|
+
return /* @__PURE__ */ jsx4(
|
|
1128
|
+
"svg",
|
|
1129
|
+
{
|
|
1130
|
+
className: "absolute inset-0",
|
|
1131
|
+
viewBox: `${ann.rect.x} ${ann.rect.y} ${ann.rect.width} ${ann.rect.height}`,
|
|
1132
|
+
preserveAspectRatio: "none",
|
|
1133
|
+
children: /* @__PURE__ */ jsx4("path", { d, fill: "none", stroke: ann.color, strokeWidth: 8e-3, strokeLinecap: "round", strokeLinejoin: "round" })
|
|
1134
|
+
}
|
|
1135
|
+
);
|
|
1136
|
+
};
|
|
722
1137
|
return /* @__PURE__ */ jsxs4(
|
|
723
1138
|
"div",
|
|
724
1139
|
{
|
|
@@ -728,8 +1143,9 @@ var AnnotationItem = ({ ann, isSelected, accentColor, onDelete, onSelect }) => {
|
|
|
728
1143
|
top: `${ann.rect.y * 100}%`,
|
|
729
1144
|
width: `${ann.rect.width * 100}%`,
|
|
730
1145
|
height: `${ann.rect.height * 100}%`,
|
|
731
|
-
backgroundColor:
|
|
732
|
-
|
|
1146
|
+
backgroundColor: !isMarkup && isHighlight ? `${ann.color}88` : "transparent",
|
|
1147
|
+
mixBlendMode: !isMarkup && isHighlight ? "multiply" : void 0,
|
|
1148
|
+
borderBottom: ann.type === "strikeout" && !isMarkup ? `2px solid ${ann.color}` : "none",
|
|
733
1149
|
outline: isSelected ? `2px solid ${accentColor}` : void 0
|
|
734
1150
|
},
|
|
735
1151
|
onClick: (e) => {
|
|
@@ -737,6 +1153,8 @@ var AnnotationItem = ({ ann, isSelected, accentColor, onDelete, onSelect }) => {
|
|
|
737
1153
|
onSelect();
|
|
738
1154
|
},
|
|
739
1155
|
children: [
|
|
1156
|
+
renderMarkupRects(),
|
|
1157
|
+
renderInk(),
|
|
740
1158
|
isText && isSelected && /* @__PURE__ */ jsx4("div", { className: "absolute top-full mt-2 w-64 bg-white shadow-2xl rounded-xl p-4 border border-gray-100 z-50", children: /* @__PURE__ */ jsx4(
|
|
741
1159
|
"textarea",
|
|
742
1160
|
{
|
|
@@ -766,14 +1184,36 @@ var PageRenderer_default = PageRenderer;
|
|
|
766
1184
|
|
|
767
1185
|
// components/Viewer.tsx
|
|
768
1186
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1187
|
+
var BASE_OVERSCAN = 6;
|
|
769
1188
|
var Viewer = ({ engine }) => {
|
|
770
|
-
const {
|
|
1189
|
+
const { pageCount, currentPage, zoom, activeTool, uiTheme, scrollToPageSignal, setDocumentState, accentColor, annotationColor, setAnnotationColor } = useViewerStore5();
|
|
771
1190
|
const isDark = uiTheme === "dark";
|
|
772
1191
|
const viewerRef = useRef4(null);
|
|
1192
|
+
const colorPickerRef = useRef4(null);
|
|
1193
|
+
const pageRefs = useRef4([]);
|
|
1194
|
+
const intersectionRatiosRef = useRef4({});
|
|
1195
|
+
const frameRef = useRef4(null);
|
|
1196
|
+
const jumpRef = useRef4(false);
|
|
1197
|
+
const jumpTimerRef = useRef4(null);
|
|
773
1198
|
const [availableWidth, setAvailableWidth] = useState5(null);
|
|
1199
|
+
const [basePageSize, setBasePageSize] = useState5(null);
|
|
1200
|
+
const [pageSizes, setPageSizes] = useState5({});
|
|
1201
|
+
const [colorPickerOpen, setColorPickerOpen] = useState5(false);
|
|
774
1202
|
const isCompact = availableWidth !== null && availableWidth < 820;
|
|
775
1203
|
const paddingY = isCompact ? "py-10" : "py-16";
|
|
776
|
-
const toolDockPosition = isCompact ? "bottom-
|
|
1204
|
+
const toolDockPosition = isCompact ? "bottom-4" : "bottom-8";
|
|
1205
|
+
const colorPalette = ["#fbbf24", "#f97316", "#ef4444", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#111827"];
|
|
1206
|
+
useEffect4(() => {
|
|
1207
|
+
if (!colorPickerOpen) return;
|
|
1208
|
+
const handleClick = (event) => {
|
|
1209
|
+
if (!colorPickerRef.current) return;
|
|
1210
|
+
if (!colorPickerRef.current.contains(event.target)) {
|
|
1211
|
+
setColorPickerOpen(false);
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1214
|
+
document.addEventListener("mousedown", handleClick);
|
|
1215
|
+
return () => document.removeEventListener("mousedown", handleClick);
|
|
1216
|
+
}, [colorPickerOpen]);
|
|
777
1217
|
useEffect4(() => {
|
|
778
1218
|
const element = viewerRef.current;
|
|
779
1219
|
if (!element) return;
|
|
@@ -790,44 +1230,239 @@ var Viewer = ({ engine }) => {
|
|
|
790
1230
|
observer.observe(element);
|
|
791
1231
|
return () => observer.disconnect();
|
|
792
1232
|
}, []);
|
|
1233
|
+
useEffect4(() => {
|
|
1234
|
+
let active = true;
|
|
1235
|
+
if (!pageCount) return;
|
|
1236
|
+
const loadBaseSize = async () => {
|
|
1237
|
+
try {
|
|
1238
|
+
const size = await engine.getPageDimensions(0);
|
|
1239
|
+
if (!active || !size.width || !size.height) return;
|
|
1240
|
+
setBasePageSize(size);
|
|
1241
|
+
} catch {
|
|
1242
|
+
}
|
|
1243
|
+
};
|
|
1244
|
+
loadBaseSize();
|
|
1245
|
+
return () => {
|
|
1246
|
+
active = false;
|
|
1247
|
+
};
|
|
1248
|
+
}, [engine, pageCount]);
|
|
1249
|
+
useEffect4(() => {
|
|
1250
|
+
if (scrollToPageSignal == null) return;
|
|
1251
|
+
const root = viewerRef.current;
|
|
1252
|
+
const target = pageRefs.current[scrollToPageSignal];
|
|
1253
|
+
if (root) {
|
|
1254
|
+
setDocumentState({ currentPage: scrollToPageSignal + 1 });
|
|
1255
|
+
jumpRef.current = true;
|
|
1256
|
+
if (jumpTimerRef.current) clearTimeout(jumpTimerRef.current);
|
|
1257
|
+
const previousBehavior = root.style.scrollBehavior;
|
|
1258
|
+
root.style.scrollBehavior = "auto";
|
|
1259
|
+
let targetTop = null;
|
|
1260
|
+
if (target) {
|
|
1261
|
+
targetTop = target.offsetTop;
|
|
1262
|
+
} else if (basePageSize && availableWidth) {
|
|
1263
|
+
const fitScale = Math.min(1, Math.max(0, availableWidth - 48) / basePageSize.width);
|
|
1264
|
+
const estimatedPageHeight = basePageSize.height * fitScale * zoom + 64;
|
|
1265
|
+
targetTop = Math.max(0, estimatedPageHeight * scrollToPageSignal);
|
|
1266
|
+
} else if (pageCount > 1) {
|
|
1267
|
+
const maxScroll = Math.max(0, root.scrollHeight - root.clientHeight);
|
|
1268
|
+
const ratio = scrollToPageSignal / Math.max(1, pageCount - 1);
|
|
1269
|
+
targetTop = Math.max(0, maxScroll * ratio);
|
|
1270
|
+
}
|
|
1271
|
+
if (targetTop != null) {
|
|
1272
|
+
root.scrollTop = Math.max(0, targetTop - 12);
|
|
1273
|
+
}
|
|
1274
|
+
requestAnimationFrame(() => {
|
|
1275
|
+
root.style.scrollBehavior = previousBehavior;
|
|
1276
|
+
});
|
|
1277
|
+
jumpTimerRef.current = setTimeout(() => {
|
|
1278
|
+
jumpRef.current = false;
|
|
1279
|
+
}, 250);
|
|
1280
|
+
}
|
|
1281
|
+
setDocumentState({ scrollToPageSignal: null });
|
|
1282
|
+
}, [scrollToPageSignal, setDocumentState, basePageSize, availableWidth, zoom, pageCount]);
|
|
1283
|
+
useEffect4(() => {
|
|
1284
|
+
setPageSizes({});
|
|
1285
|
+
}, [zoom]);
|
|
793
1286
|
useEffect4(() => {
|
|
794
1287
|
const root = viewerRef.current;
|
|
795
1288
|
if (!root) return;
|
|
1289
|
+
const flushCurrentPage = () => {
|
|
1290
|
+
if (jumpRef.current) return;
|
|
1291
|
+
const ratios = intersectionRatiosRef.current;
|
|
1292
|
+
const entries = Object.entries(ratios).filter(([, ratio]) => ratio > 0);
|
|
1293
|
+
if (!entries.length) return;
|
|
1294
|
+
const currentIndex = currentPage - 1;
|
|
1295
|
+
const currentRatio = ratios[currentIndex] ?? 0;
|
|
1296
|
+
const [bestIndexText, bestRatio] = entries.reduce(
|
|
1297
|
+
(best, candidate) => Number(candidate[1]) > Number(best[1]) ? candidate : best
|
|
1298
|
+
);
|
|
1299
|
+
const bestIndex = Number(bestIndexText);
|
|
1300
|
+
if (!Number.isFinite(bestIndex)) return;
|
|
1301
|
+
const bestPage = bestIndex + 1;
|
|
1302
|
+
const shouldSwitch = bestPage !== currentPage && (currentRatio <= 0 || bestRatio >= currentRatio + 0.1 || bestRatio >= 0.75);
|
|
1303
|
+
if (shouldSwitch) setDocumentState({ currentPage: bestPage });
|
|
1304
|
+
};
|
|
796
1305
|
const observer = new IntersectionObserver((entries) => {
|
|
797
1306
|
entries.forEach((entry) => {
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
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();
|
|
802
1315
|
});
|
|
803
|
-
}, { root, threshold: 0.5 });
|
|
1316
|
+
}, { root, threshold: [0.25, 0.5, 0.75] });
|
|
804
1317
|
const pageElements = root.querySelectorAll(".page-container");
|
|
805
1318
|
pageElements.forEach((el) => observer.observe(el));
|
|
806
1319
|
return () => {
|
|
1320
|
+
if (frameRef.current != null) {
|
|
1321
|
+
cancelAnimationFrame(frameRef.current);
|
|
1322
|
+
frameRef.current = null;
|
|
1323
|
+
}
|
|
807
1324
|
pageElements.forEach((el) => observer.unobserve(el));
|
|
808
1325
|
observer.disconnect();
|
|
809
1326
|
};
|
|
810
1327
|
}, [pageCount, setDocumentState, currentPage]);
|
|
1328
|
+
const virtualOverscan = zoom > 1.35 ? 4 : BASE_OVERSCAN;
|
|
1329
|
+
const virtualAnchor = currentPage - 1;
|
|
1330
|
+
const virtualStart = Math.max(0, virtualAnchor - virtualOverscan);
|
|
1331
|
+
const virtualEnd = Math.min(pageCount - 1, virtualAnchor + virtualOverscan);
|
|
1332
|
+
const fallbackSize = useMemo2(() => {
|
|
1333
|
+
if (basePageSize && availableWidth) {
|
|
1334
|
+
const fitScale = Math.min(1, Math.max(0, availableWidth - 48) / basePageSize.width);
|
|
1335
|
+
return {
|
|
1336
|
+
width: Math.round(basePageSize.width * fitScale * zoom),
|
|
1337
|
+
height: Math.round(basePageSize.height * fitScale * zoom)
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
const base = availableWidth ? Math.max(680, availableWidth * 1.3) : 1100;
|
|
1341
|
+
return {
|
|
1342
|
+
width: Math.round((availableWidth ?? 860) - 48),
|
|
1343
|
+
height: Math.round(base * zoom)
|
|
1344
|
+
};
|
|
1345
|
+
}, [basePageSize, availableWidth, zoom]);
|
|
1346
|
+
const averagePageHeight = useMemo2(() => {
|
|
1347
|
+
const heights = Object.values(pageSizes).map((size) => size.height);
|
|
1348
|
+
if (!heights.length) return availableWidth ? Math.max(680, availableWidth * 1.3) : 1100;
|
|
1349
|
+
return Math.round(heights.reduce((sum, h) => sum + h, 0) / heights.length);
|
|
1350
|
+
}, [pageSizes, availableWidth]);
|
|
811
1351
|
const pages = Array.from({ length: pageCount }).map((_, i) => i);
|
|
1352
|
+
const handlePageMeasured = (pageIndex, size) => {
|
|
1353
|
+
setPageSizes((prev) => {
|
|
1354
|
+
const current = prev[pageIndex];
|
|
1355
|
+
if (current && current.width === size.width && current.height === size.height) return prev;
|
|
1356
|
+
return { ...prev, [pageIndex]: size };
|
|
1357
|
+
});
|
|
1358
|
+
};
|
|
812
1359
|
const tools = [
|
|
813
1360
|
{ id: "select", name: "Select", icon: "M15 15l-2 5L9 9l11 4-5 2zm0 0l5 5" },
|
|
814
|
-
{ id: "highlight", name: "
|
|
815
|
-
{ id: "
|
|
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" },
|
|
1364
|
+
{ id: "strikeout", name: "Strike", icon: "M4 12h16M8 6h8M8 18h8" },
|
|
1365
|
+
{ id: "ink", name: "Freehand", icon: "M4 19c4-6 7-9 10-9 3 0 5 2 6 5" },
|
|
816
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" }
|
|
817
1367
|
];
|
|
818
|
-
return /* @__PURE__ */ jsxs5(
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
1368
|
+
return /* @__PURE__ */ jsxs5(
|
|
1369
|
+
"div",
|
|
1370
|
+
{
|
|
1371
|
+
ref: viewerRef,
|
|
1372
|
+
"data-papyrus-theme": uiTheme,
|
|
1373
|
+
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
|
+
children: [
|
|
1375
|
+
/* @__PURE__ */ jsx5("div", { className: "flex flex-col items-center gap-6 w-full min-w-0", children: pages.map((idx) => /* @__PURE__ */ jsx5(
|
|
1376
|
+
"div",
|
|
1377
|
+
{
|
|
1378
|
+
ref: (element) => {
|
|
1379
|
+
pageRefs.current[idx] = element;
|
|
1380
|
+
},
|
|
1381
|
+
"data-page-index": idx,
|
|
1382
|
+
className: "page-container",
|
|
1383
|
+
children: idx >= virtualStart && idx <= virtualEnd ? /* @__PURE__ */ jsx5(
|
|
1384
|
+
PageRenderer_default,
|
|
1385
|
+
{
|
|
1386
|
+
engine,
|
|
1387
|
+
pageIndex: idx,
|
|
1388
|
+
availableWidth: availableWidth ?? void 0,
|
|
1389
|
+
onMeasuredSize: handlePageMeasured
|
|
1390
|
+
}
|
|
1391
|
+
) : /* @__PURE__ */ jsx5(
|
|
1392
|
+
"div",
|
|
1393
|
+
{
|
|
1394
|
+
className: `inline-block mb-10 shadow-2xl border ${isDark ? "bg-[#0f0f0f] border-[#2b2b2b]" : "bg-white border-gray-200"}`,
|
|
1395
|
+
style: {
|
|
1396
|
+
width: pageSizes[idx]?.width ?? fallbackSize.width,
|
|
1397
|
+
height: pageSizes[idx]?.height ?? Math.max(fallbackSize.height, averagePageHeight)
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
)
|
|
1401
|
+
},
|
|
1402
|
+
idx
|
|
1403
|
+
)) }),
|
|
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",
|
|
1421
|
+
{
|
|
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
|
+
}
|
|
1455
|
+
},
|
|
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
|
+
] }) })
|
|
1463
|
+
]
|
|
1464
|
+
}
|
|
1465
|
+
);
|
|
831
1466
|
};
|
|
832
1467
|
var Viewer_default = Viewer;
|
|
833
1468
|
export {
|