@w100n/documents 0.3.0 → 0.4.0

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.cjs CHANGED
@@ -39,7 +39,7 @@ __export(index_exports, {
39
39
  module.exports = __toCommonJS(index_exports);
40
40
 
41
41
  // src/DocumentsWorkspace.tsx
42
- var import_react5 = require("react");
42
+ var import_react6 = require("react");
43
43
  var import_lucide_react = require("lucide-react");
44
44
 
45
45
  // src/kinds.ts
@@ -103,6 +103,12 @@ var en = {
103
103
  unsupported: "This file cannot be shown yet",
104
104
  restore: "Restore this version",
105
105
  restoreFailed: "Could not restore",
106
+ allProjects: "All projects",
107
+ closePanel: "Hide the panel",
108
+ openPanel: "Show the panel",
109
+ zoomIn: "Zoom in",
110
+ zoomOut: "Zoom out",
111
+ fit: "Actual size",
106
112
  kinds: { docx: "DOCX", markdown: "Markdown", pdf: "PDF", sheet: "Sheets", slides: "Slides" }
107
113
  };
108
114
  var pl = {
@@ -136,6 +142,12 @@ var pl = {
136
142
  unsupported: "Tego pliku nie da si\u0119 jeszcze pokaza\u0107",
137
143
  restore: "Przywr\xF3\u0107 t\u0119 wersj\u0119",
138
144
  restoreFailed: "Nie uda\u0142o si\u0119 przywr\xF3ci\u0107",
145
+ allProjects: "Wszystkie projekty",
146
+ closePanel: "Ukryj panel",
147
+ openPanel: "Poka\u017C panel",
148
+ zoomIn: "Powi\u0119ksz",
149
+ zoomOut: "Pomniejsz",
150
+ fit: "Rzeczywisty rozmiar",
139
151
  kinds: { docx: "DOCX", markdown: "Markdown", pdf: "PDF", sheet: "Arkusze", slides: "Slajdy" }
140
152
  };
141
153
  var uk = {
@@ -169,16 +181,117 @@ var uk = {
169
181
  unsupported: "\u0426\u0435\u0439 \u0444\u0430\u0439\u043B \u043F\u043E\u043A\u0438 \u043D\u0435 \u043F\u043E\u043A\u0430\u0437\u0443\u0454\u0442\u044C\u0441\u044F",
170
182
  restore: "\u0412\u0456\u0434\u043D\u043E\u0432\u0438\u0442\u0438 \u0446\u044E \u0432\u0435\u0440\u0441\u0456\u044E",
171
183
  restoreFailed: "\u041D\u0435 \u0432\u0434\u0430\u043B\u043E\u0441\u044F \u0432\u0456\u0434\u043D\u043E\u0432\u0438\u0442\u0438",
184
+ allProjects: "\u0423\u0441\u0456 \u043F\u0440\u043E\u0454\u043A\u0442\u0438",
185
+ closePanel: "\u0421\u0445\u043E\u0432\u0430\u0442\u0438 \u043F\u0430\u043D\u0435\u043B\u044C",
186
+ openPanel: "\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u0438 \u043F\u0430\u043D\u0435\u043B\u044C",
187
+ zoomIn: "\u0417\u0431\u0456\u043B\u044C\u0448\u0438\u0442\u0438",
188
+ zoomOut: "\u0417\u043C\u0435\u043D\u0448\u0438\u0442\u0438",
189
+ fit: "\u0421\u043F\u0440\u0430\u0432\u0436\u043D\u0456\u0439 \u0440\u043E\u0437\u043C\u0456\u0440",
172
190
  kinds: { docx: "DOCX", markdown: "Markdown", pdf: "PDF", sheet: "\u0422\u0430\u0431\u043B\u0438\u0446\u0456", slides: "\u0421\u043B\u0430\u0439\u0434\u0438" }
173
191
  };
174
192
  var texts = { en, pl, uk };
175
193
 
176
- // src/useLoad.ts
194
+ // src/Thumb.tsx
177
195
  var import_react = require("react");
178
- function useLoad(load, key) {
179
- const [state, setState] = (0, import_react.useState)({ data: null, error: null, loading: true });
180
- const [attempt, setAttempt] = (0, import_react.useState)(0);
196
+
197
+ // src/preview.ts
198
+ var cache = /* @__PURE__ */ new Map();
199
+ var waiting = [];
200
+ var running = 0;
201
+ async function turn(work) {
202
+ if (running >= 2) await new Promise((go) => waiting.push(go));
203
+ running++;
204
+ try {
205
+ return await work();
206
+ } finally {
207
+ running--;
208
+ waiting.shift()?.();
209
+ }
210
+ }
211
+ async function make(host, doc) {
212
+ if (doc.size > 3e6 || !["markdown", "docx", "pdf"].includes(doc.kind)) return null;
213
+ return turn(async () => {
214
+ var _a;
215
+ const bytes = await host.content(doc.id, null);
216
+ if (doc.kind === "markdown") return { text: new TextDecoder().decode(bytes.slice(0, 2400)) };
217
+ if (doc.kind === "docx") {
218
+ const { renderAsync } = await import("docx-preview");
219
+ const box = document.createElement("div");
220
+ await renderAsync(bytes, box, void 0, { inWrapper: false, ignoreLastRenderedPageBreak: true });
221
+ return { text: [...box.querySelectorAll("p, h1, h2, h3, li")].map((node) => node.textContent?.trim()).filter(Boolean).join("\n").slice(0, 800) };
222
+ }
223
+ const pdfjs = await import("pdfjs-dist");
224
+ if (host.pdfWorker) (_a = pdfjs.GlobalWorkerOptions).workerPort ?? (_a.workerPort = host.pdfWorker());
225
+ const task = pdfjs.getDocument({ data: new Uint8Array(bytes.slice(0)) });
226
+ const pdf = await task.promise;
227
+ const page = await pdf.getPage(1);
228
+ const viewport = page.getViewport({ scale: 320 / page.getViewport({ scale: 1 }).width });
229
+ const canvas = document.createElement("canvas");
230
+ canvas.width = viewport.width;
231
+ canvas.height = viewport.height;
232
+ await page.render({ canvas, canvasContext: canvas.getContext("2d"), viewport }).promise;
233
+ void task.destroy();
234
+ return { image: canvas.toDataURL("image/png") };
235
+ });
236
+ }
237
+ function preview(host, doc) {
238
+ const key = `${doc.id}:${doc.updatedAt}`;
239
+ let found = cache.get(key);
240
+ if (!found) {
241
+ found = make(host, doc).catch(() => null);
242
+ cache.set(key, found);
243
+ }
244
+ return found;
245
+ }
246
+
247
+ // src/Thumb.tsx
248
+ var import_jsx_runtime = require("react/jsx-runtime");
249
+ function Thumb({ host, item, label }) {
250
+ const box = (0, import_react.useRef)(null);
251
+ const [seen, setSeen] = (0, import_react.useState)(false);
252
+ const [shot, setShot] = (0, import_react.useState)(null);
253
+ (0, import_react.useEffect)(() => {
254
+ if (item.thumbnailUrl || item.excerpt || typeof IntersectionObserver === "undefined") return;
255
+ const watch = new IntersectionObserver((entries) => {
256
+ if (entries.some((entry) => entry.isIntersecting)) setSeen(true);
257
+ }, { rootMargin: "200px" });
258
+ watch.observe(box.current);
259
+ return () => watch.disconnect();
260
+ }, [item.thumbnailUrl, item.excerpt]);
181
261
  (0, import_react.useEffect)(() => {
262
+ if (!seen) return;
263
+ let live = true;
264
+ void preview(host, item).then((found) => {
265
+ if (live) setShot(found);
266
+ });
267
+ return () => {
268
+ live = false;
269
+ };
270
+ }, [seen, host, item.id, item.updatedAt]);
271
+ const text = item.excerpt ?? shot?.text ?? "";
272
+ const lines = text.split("\n").filter((line) => !line.trim().startsWith("```")).map((line) => line.replace(/^#+\s*/, "").replace(/[*_`>|]/g, "").trim()).filter(Boolean);
273
+ const image = item.thumbnailUrl ?? shot?.image;
274
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { ref: box, className: "w100n-docs-thumb", "data-kind": item.kind, children: [
275
+ image ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: image, alt: "" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "w100n-docs-paper", "aria-hidden": true, children: lines.length ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
276
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: lines[0] }),
277
+ lines.slice(1, 14).join(" ")
278
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
279
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("i", {}),
280
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("i", {}),
281
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("i", {}),
282
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("i", {}),
283
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("i", {})
284
+ ] }) }),
285
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "w100n-docs-kind", "data-kind": item.kind, children: label })
286
+ ] });
287
+ }
288
+
289
+ // src/useLoad.ts
290
+ var import_react2 = require("react");
291
+ function useLoad(load, key) {
292
+ const [state, setState] = (0, import_react2.useState)({ data: null, error: null, loading: true });
293
+ const [attempt, setAttempt] = (0, import_react2.useState)(0);
294
+ (0, import_react2.useEffect)(() => {
182
295
  const controller = new AbortController();
183
296
  setState((current) => ({ ...current, loading: true, error: null }));
184
297
  load(controller.signal).then(
@@ -195,7 +308,7 @@ function useLoad(load, key) {
195
308
  }
196
309
 
197
310
  // src/viewers/DocxView.tsx
198
- var import_react2 = require("react");
311
+ var import_react3 = require("react");
199
312
 
200
313
  // src/viewers/headings.ts
201
314
  var last = 0;
@@ -209,11 +322,11 @@ function collect(root, selector, level = (el) => Number(el.tagName.slice(1))) {
209
322
  }
210
323
 
211
324
  // src/viewers/DocxView.tsx
212
- var import_jsx_runtime = require("react/jsx-runtime");
325
+ var import_jsx_runtime2 = require("react/jsx-runtime");
213
326
  function DocxView({ bytes, onOutline, failed }) {
214
- const box = (0, import_react2.useRef)(null);
215
- const [error, setError] = (0, import_react2.useState)(false);
216
- (0, import_react2.useLayoutEffect)(() => {
327
+ const box = (0, import_react3.useRef)(null);
328
+ const [error, setError] = (0, import_react3.useState)(false);
329
+ (0, import_react3.useLayoutEffect)(() => {
217
330
  let live = true;
218
331
  let width = 0;
219
332
  const root = box.current;
@@ -238,35 +351,35 @@ function DocxView({ bytes, onOutline, failed }) {
238
351
  watch.disconnect();
239
352
  };
240
353
  }, [bytes, onOutline]);
241
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
242
- error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "w100n-docs-note", children: failed }),
243
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: box, className: "w100n-docs-docx" })
354
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
355
+ error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "w100n-docs-note", children: failed }),
356
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref: box, className: "w100n-docs-docx" })
244
357
  ] });
245
358
  }
246
359
 
247
360
  // src/viewers/MarkdownView.tsx
248
361
  var import_dompurify = __toESM(require("dompurify"), 1);
249
362
  var import_marked = require("marked");
250
- var import_react3 = require("react");
251
- var import_jsx_runtime2 = require("react/jsx-runtime");
363
+ var import_react4 = require("react");
364
+ var import_jsx_runtime3 = require("react/jsx-runtime");
252
365
  function MarkdownView({ bytes, onOutline }) {
253
- const box = (0, import_react3.useRef)(null);
254
- (0, import_react3.useLayoutEffect)(() => {
366
+ const box = (0, import_react4.useRef)(null);
367
+ (0, import_react4.useLayoutEffect)(() => {
255
368
  const root = box.current;
256
369
  root.innerHTML = import_dompurify.default.sanitize(import_marked.marked.parse(new TextDecoder().decode(bytes), { async: false }));
257
370
  onOutline(collect(root, "h1, h2, h3"));
258
371
  }, [bytes, onOutline]);
259
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("article", { ref: box, className: "w100n-docs-page w100n-docs-prose" });
372
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("article", { ref: box, className: "w100n-docs-page w100n-docs-prose" });
260
373
  }
261
374
 
262
375
  // src/viewers/PdfView.tsx
263
- var import_react4 = require("react");
264
- var import_jsx_runtime3 = require("react/jsx-runtime");
376
+ var import_react5 = require("react");
377
+ var import_jsx_runtime4 = require("react/jsx-runtime");
265
378
  var last2 = 0;
266
379
  function PdfView({ bytes, worker, onOutline, failed }) {
267
- const box = (0, import_react4.useRef)(null);
268
- const [error, setError] = (0, import_react4.useState)(false);
269
- (0, import_react4.useEffect)(() => {
380
+ const box = (0, import_react5.useRef)(null);
381
+ const [error, setError] = (0, import_react5.useState)(false);
382
+ (0, import_react5.useEffect)(() => {
270
383
  const root = box.current;
271
384
  const prefix = `w100n-docs-p${++last2}`;
272
385
  let stop = false;
@@ -313,64 +426,90 @@ function PdfView({ bytes, worker, onOutline, failed }) {
313
426
  close();
314
427
  };
315
428
  }, [bytes, worker, onOutline]);
316
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
317
- error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "w100n-docs-note", children: failed }),
318
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: box, className: "w100n-docs-pdf" })
429
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
430
+ error && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "w100n-docs-note", children: failed }),
431
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref: box, className: "w100n-docs-pdf" })
319
432
  ] });
320
433
  }
321
434
 
322
435
  // src/viewers/SlidesView.tsx
323
- var import_jsx_runtime4 = require("react/jsx-runtime");
436
+ var import_jsx_runtime5 = require("react/jsx-runtime");
324
437
  function SlidesView({ bytes, title }) {
325
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("iframe", { className: "w100n-docs-slides", sandbox: "allow-scripts", title, srcDoc: new TextDecoder().decode(bytes) });
438
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("iframe", { className: "w100n-docs-slides", sandbox: "allow-scripts", title, srcDoc: new TextDecoder().decode(bytes) });
326
439
  }
327
440
 
328
441
  // src/DocumentsWorkspace.tsx
329
- var import_jsx_runtime5 = require("react/jsx-runtime");
442
+ var import_jsx_runtime6 = require("react/jsx-runtime");
330
443
  var icons = { docx: import_lucide_react.FileText, markdown: import_lucide_react.FileType, pdf: import_lucide_react.Files, sheet: import_lucide_react.FileSpreadsheet, slides: import_lucide_react.Presentation };
331
- function DocumentsWorkspace({ host, language = "en", theme = "light", place, onPlace, start, end, aside }) {
444
+ function DocumentsWorkspace({ host, language = "en", theme = "light", place, onPlace, start, end, aside, actions }) {
332
445
  const t = texts[language];
333
- const [own, setOwn] = (0, import_react5.useState)({ spaceId: null, documentId: null });
446
+ const [own, setOwn] = (0, import_react6.useState)({ spaceId: null, documentId: null });
334
447
  const here = place ?? own;
335
448
  const go = (next) => {
336
449
  setOwn(next);
337
450
  onPlace?.(next);
338
451
  };
339
- const [query, setQuery] = (0, import_react5.useState)("");
340
- const [kind, setKind] = (0, import_react5.useState)("all");
341
- const [listOpen, setListOpen] = (0, import_react5.useState)(true);
342
- const listRef = (0, import_react5.useRef)(null);
343
- const overlays = () => listRef.current !== null && getComputedStyle(listRef.current).position === "absolute";
344
- (0, import_react5.useLayoutEffect)(() => {
345
- if (here.documentId && overlays()) setListOpen(false);
452
+ const [query, setQuery] = (0, import_react6.useState)("");
453
+ const [kind, setKind] = (0, import_react6.useState)("all");
454
+ const [listOpen, setListOpen] = (0, import_react6.useState)(true);
455
+ const [panelOpen, setPanelOpen] = (0, import_react6.useState)(true);
456
+ const root = (0, import_react6.useRef)(null);
457
+ const narrow = () => root.current !== null && getComputedStyle(root.current).getPropertyValue("--docs-narrow").trim() === "1";
458
+ (0, import_react6.useLayoutEffect)(() => {
459
+ if (here.documentId && narrow()) setListOpen(false);
346
460
  }, []);
347
- const [picking, setPicking] = (0, import_react5.useState)(false);
348
- const [tab, setTab] = (0, import_react5.useState)("outline");
349
- const [outline, setOutline] = (0, import_react5.useState)([]);
350
- const [version, setVersion] = (0, import_react5.useState)({ documentId: null, id: null });
461
+ const [picking, setPicking] = (0, import_react6.useState)(false);
462
+ const [tab, setTab] = (0, import_react6.useState)("outline");
463
+ const [zoom, setZoom] = (0, import_react6.useState)(100);
464
+ const [outline, setOutline] = (0, import_react6.useState)([]);
465
+ const [version, setVersion] = (0, import_react6.useState)({ documentId: null, id: null });
351
466
  const versionId = version.documentId === here.documentId ? version.id : null;
352
- const [restoring, setRestoring] = (0, import_react5.useState)("idle");
467
+ const [restoring, setRestoring] = (0, import_react6.useState)("idle");
353
468
  const spaces = useLoad((signal) => host.spaces({ signal }), [host]);
354
- const spaceId = here.spaceId ?? spaces.data?.[0]?.id ?? null;
469
+ const single = spaces.data?.length === 1 ? spaces.data[0].id : null;
470
+ const spaceId = here.spaceId ?? single;
355
471
  const space = spaces.data?.find((item) => item.id === spaceId);
356
- const list = useLoad((signal) => spaceId ? host.documents(spaceId, { signal }) : Promise.resolve([]), [host, spaceId]);
472
+ const list = useLoad(async (signal) => {
473
+ if (spaceId) return host.documents(spaceId, { signal });
474
+ if (host.everything) return host.everything({ signal });
475
+ const all2 = await host.spaces({ signal });
476
+ return (await Promise.all(all2.map((item) => host.documents(item.id, { signal })))).flat();
477
+ }, [host, spaceId]);
357
478
  const doc = useLoad((signal) => here.documentId ? host.document(here.documentId, { signal }) : Promise.resolve(null), [host, here.documentId]);
358
479
  const versions = useLoad((signal) => here.documentId ? host.versions(here.documentId, { signal }) : Promise.resolve([]), [host, here.documentId]);
359
480
  const content = useLoad((signal) => here.documentId ? host.content(here.documentId, versionId, { signal }) : Promise.resolve(null), [host, here.documentId, versionId]);
360
- const shown = (list.data ?? []).filter((item) => matches(item, query, kind));
361
- const present = kinds.filter((item) => list.data?.some((doc2) => doc2.kind === item));
362
- const folders = [.../* @__PURE__ */ new Set(["", ...shown.map((item) => item.folder ?? "")])].filter((folder) => shown.some((item) => (item.folder ?? "") === folder));
481
+ const all = list.data ?? [];
482
+ const shown = all.filter((item) => matches(item, query, kind));
483
+ const present = kinds.filter((item) => all.some((doc2) => doc2.kind === item));
484
+ const folders = spaceId ? [.../* @__PURE__ */ new Set(["", ...shown.map((item) => item.folder ?? "")])].filter((folder) => shown.some((item) => (item.folder ?? "") === folder)) : [""];
485
+ const names = new Map((spaces.data ?? []).map((item) => [item.id, item.name]));
486
+ const counts = /* @__PURE__ */ new Map();
487
+ for (const item of all) counts.set(item.spaceId, (counts.get(item.spaceId) ?? 0) + 1);
488
+ const groups = [...new Set((spaces.data ?? []).map((item) => item.group ?? ""))];
363
489
  const date = (iso) => new Intl.DateTimeFormat(language, { day: "numeric", month: "short", year: "numeric", hour: "2-digit", minute: "2-digit" }).format(new Date(iso));
490
+ const ago = (iso) => {
491
+ const minutes = Math.round((Date.parse(iso) - Date.now()) / 6e4);
492
+ const rtf = new Intl.RelativeTimeFormat(language, { numeric: "auto", style: "short" });
493
+ if (Math.abs(minutes) < 60) return rtf.format(minutes, "minute");
494
+ if (Math.abs(minutes) < 1440) return rtf.format(Math.round(minutes / 60), "hour");
495
+ if (Math.abs(minutes) < 43200) return rtf.format(Math.round(minutes / 1440), "day");
496
+ return new Intl.DateTimeFormat(language, { day: "numeric", month: "short", year: "numeric" }).format(new Date(iso));
497
+ };
364
498
  const size = (bytes) => bytes < 1024 ? `${bytes} B` : bytes < 1048576 ? `${(bytes / 1024).toFixed(0)} KB` : `${(bytes / 1048576).toFixed(1)} MB`;
365
- const failed = (retry) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w100n-docs-note", children: [
499
+ const failed = (retry) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w100n-docs-note", children: [
366
500
  t.failed,
367
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", onClick: retry, children: t.retry })
501
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", onClick: retry, children: t.retry })
368
502
  ] });
369
- const open = (documentId) => {
503
+ const open = (item) => {
370
504
  setOutline([]);
371
505
  setTab("outline");
372
- go({ spaceId, documentId });
373
- if (overlays()) setListOpen(false);
506
+ go({ spaceId: here.spaceId, documentId: item.id });
507
+ if (narrow()) setListOpen(false);
508
+ };
509
+ const pick = (next) => {
510
+ setPicking(false);
511
+ setKind("all");
512
+ go({ spaceId: next, documentId: null });
374
513
  };
375
514
  const restore = async (documentId, versionId2) => {
376
515
  setRestoring("busy");
@@ -386,8 +525,8 @@ function DocumentsWorkspace({ host, language = "en", theme = "light", place, onP
386
525
  doc.retry();
387
526
  list.retry();
388
527
  };
389
- let stage = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w100n-docs-empty", children: [
390
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.FileText, { "aria-hidden": true }),
528
+ let stage = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w100n-docs-empty", children: [
529
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.FileText, { "aria-hidden": true }),
391
530
  t.pick
392
531
  ] });
393
532
  if (here.documentId) {
@@ -395,116 +534,158 @@ function DocumentsWorkspace({ host, language = "en", theme = "light", place, onP
395
534
  doc.retry();
396
535
  content.retry();
397
536
  });
398
- else if (!doc.data || !content.data) stage = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w100n-docs-empty", children: t.loading });
399
- else if (doc.data.kind === "markdown") stage = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MarkdownView, { bytes: content.data, onOutline: setOutline });
400
- else if (doc.data.kind === "docx") stage = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DocxView, { bytes: content.data, onOutline: setOutline, failed: t.failed });
401
- else if (doc.data.kind === "pdf") stage = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PdfView, { bytes: content.data, worker: host.pdfWorker, onOutline: setOutline, failed: t.failed });
402
- else if (doc.data.kind === "slides") stage = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SlidesView, { bytes: content.data, title: doc.data.name });
403
- else stage = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w100n-docs-empty", children: t.unsupported });
537
+ else if (!doc.data || !content.data) stage = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w100n-docs-empty", children: t.loading });
538
+ else if (doc.data.kind === "markdown") stage = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarkdownView, { bytes: content.data, onOutline: setOutline });
539
+ else if (doc.data.kind === "docx") stage = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DocxView, { bytes: content.data, onOutline: setOutline, failed: t.failed });
540
+ else if (doc.data.kind === "pdf") stage = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PdfView, { bytes: content.data, worker: host.pdfWorker, onOutline: setOutline, failed: t.failed });
541
+ else if (doc.data.kind === "slides") stage = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SlidesView, { bytes: content.data, title: doc.data.name });
542
+ else stage = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w100n-docs-empty", children: t.unsupported });
404
543
  }
544
+ const Kind = doc.data ? icons[doc.data.kind] : import_lucide_react.FileText;
545
+ const crumbs = doc.data ? [names.get(doc.data.spaceId), doc.data.folder].filter(Boolean) : space ? [space.name] : [];
405
546
  const panelTabs = [["outline", import_lucide_react.ListTree, t.outline], ["versions", import_lucide_react.History, t.versions], ["details", import_lucide_react.Info, t.details]];
406
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w100n-docs", "data-theme": theme, children: [
407
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("header", { className: "w100n-docs-bar w100n-docs-island", children: [
547
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: root, className: "w100n-docs", "data-theme": theme, children: [
548
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("header", { className: "w100n-docs-bar", children: [
408
549
  start,
409
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "w100n-docs-icon", onClick: () => setListOpen(!listOpen), "aria-label": listOpen ? t.closeList : t.openList, title: listOpen ? t.closeList : t.openList, children: listOpen ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.PanelLeftClose, {}) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.PanelLeftOpen, {}) }),
410
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { className: "w100n-docs-title", children: doc.data?.name ?? t.documents }),
411
- doc.data && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w100n-docs-badge", "data-kind": doc.data.kind, children: t.kinds[doc.data.kind] }),
412
- versionId && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w100n-docs-badge", children: versions.data?.find((v) => v.id === versionId) && date(versions.data.find((v) => v.id === versionId).createdAt) }),
413
- versionId && here.documentId && host.restore && doc.data?.rights.edit && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", className: "w100n-docs-action", disabled: restoring === "busy", onClick: () => void restore(here.documentId, versionId), children: [
414
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.RotateCcw, { "aria-hidden": true }),
550
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w100n-docs-tile", "data-kind": doc.data?.kind, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Kind, { "aria-hidden": true }) }),
551
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w100n-docs-heading", children: [
552
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { className: "w100n-docs-title", children: doc.data?.name ?? t.documents }),
553
+ crumbs.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w100n-docs-crumbs", children: crumbs.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
554
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.ChevronRight, { "aria-hidden": true }),
555
+ item
556
+ ] }, i)) })
557
+ ] }),
558
+ doc.data && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w100n-docs-badge", "data-kind": doc.data.kind, children: t.kinds[doc.data.kind] }),
559
+ versionId && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w100n-docs-badge", children: versions.data?.find((v) => v.id === versionId) && date(versions.data.find((v) => v.id === versionId).createdAt) }),
560
+ versionId && here.documentId && host.restore && doc.data?.rights.edit && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("button", { type: "button", className: "w100n-docs-action", disabled: restoring === "busy", onClick: () => void restore(here.documentId, versionId), children: [
561
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.RotateCcw, { "aria-hidden": true }),
415
562
  t.restore
416
563
  ] }),
417
- restoring === "failed" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w100n-docs-muted", children: t.restoreFailed }),
418
- end && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w100n-docs-end", children: end })
564
+ restoring === "failed" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w100n-docs-muted", children: t.restoreFailed }),
565
+ doc.data && !versionId && actions?.(doc.data),
566
+ end && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w100n-docs-end", children: end })
419
567
  ] }),
420
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w100n-docs-body", children: [
421
- listOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("aside", { ref: listRef, className: "w100n-docs-list w100n-docs-island", "aria-label": t.documents, children: [
422
- (spaces.data?.length ?? 0) > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w100n-docs-picker", children: [
423
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", className: "w100n-docs-field", "aria-haspopup": "listbox", "aria-expanded": picking, onClick: () => setPicking(!picking), children: [
424
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w100n-docs-dot", style: { background: space?.color ?? void 0 } }),
425
- space?.name ?? t.space,
426
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.ChevronDown, { "aria-hidden": true })
568
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w100n-docs-body", children: [
569
+ listOpen ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("aside", { className: "w100n-docs-side w100n-docs-list", "aria-label": t.documents, children: [
570
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w100n-docs-head", children: [
571
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w100n-docs-row", children: [
572
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "w100n-docs-caption", children: [
573
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Files, { "aria-hidden": true }),
574
+ t.documents,
575
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: all.length })
576
+ ] }),
577
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "w100n-docs-close", onClick: () => setListOpen(false), "aria-label": t.closeList, title: t.closeList, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.X, { "aria-hidden": true }) })
427
578
  ] }),
428
- picking && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { role: "listbox", className: "w100n-docs-menu", children: (spaces.data ?? []).map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", role: "option", "aria-selected": item.id === spaceId, onClick: () => {
429
- setPicking(false);
430
- go({ spaceId: item.id, documentId: null });
431
- }, children: [
432
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w100n-docs-dot", style: { background: item.color ?? void 0 } }),
433
- item.name
434
- ] }) }, item.id)) })
435
- ] }),
436
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "w100n-docs-field w100n-docs-search", children: [
437
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Search, { "aria-hidden": true }),
438
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { value: query, onChange: (event) => setQuery(event.target.value), placeholder: t.search, "aria-label": t.search })
579
+ (spaces.data?.length ?? 0) > 1 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w100n-docs-picker", children: [
580
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("button", { type: "button", className: "w100n-docs-field", "aria-haspopup": "listbox", "aria-expanded": picking, onClick: () => setPicking(!picking), children: [
581
+ space ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w100n-docs-dot", style: { background: space.color ?? void 0 } }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w100n-docs-all", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.LayoutGrid, { "aria-hidden": true }) }),
582
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("b", { children: space?.name ?? t.allProjects }),
583
+ !space && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w100n-docs-count", children: all.length }),
584
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.ChevronDown, { "aria-hidden": true })
585
+ ] }),
586
+ picking && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { role: "listbox", className: "w100n-docs-menu", children: [
587
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("button", { type: "button", role: "option", "aria-selected": !spaceId, onClick: () => pick(null), children: [
588
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w100n-docs-all", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.LayoutGrid, { "aria-hidden": true }) }),
589
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("b", { children: t.allProjects }),
590
+ !spaceId && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Check, { "aria-hidden": true })
591
+ ] }),
592
+ groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { role: "group", "aria-label": group || void 0, children: [
593
+ group && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "w100n-docs-menu-caption", children: group }),
594
+ (spaces.data ?? []).filter((item) => (item.group ?? "") === group).map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("button", { type: "button", role: "option", "aria-selected": item.id === spaceId, onClick: () => pick(item.id), children: [
595
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w100n-docs-dot", style: { background: item.color ?? void 0 } }),
596
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("b", { children: item.name }),
597
+ !spaceId && counts.get(item.id) ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w100n-docs-count", children: counts.get(item.id) }) : null,
598
+ item.id === spaceId && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Check, { "aria-hidden": true })
599
+ ] }, item.id))
600
+ ] }, group))
601
+ ] })
602
+ ] }),
603
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { className: "w100n-docs-field w100n-docs-search", children: [
604
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Search, { "aria-hidden": true }),
605
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { value: query, onChange: (event) => setQuery(event.target.value), placeholder: t.search, "aria-label": t.search })
606
+ ] }),
607
+ present.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w100n-docs-chips", role: "group", children: ["all", ...present].map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("button", { type: "button", "aria-pressed": kind === item, onClick: () => setKind(item), children: [
608
+ item === "all" ? t.all : t.kinds[item],
609
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { "aria-hidden": true, children: item === "all" ? all.length : all.filter((doc2) => doc2.kind === item).length })
610
+ ] }, item)) })
439
611
  ] }),
440
- present.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w100n-docs-chips", role: "group", children: ["all", ...present].map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", "aria-pressed": kind === item, onClick: () => setKind(item), children: item === "all" ? t.all : t.kinds[item] }, item)) }),
441
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w100n-docs-cards", children: [
612
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w100n-docs-cards", children: [
442
613
  list.error && failed(list.retry),
443
- list.loading && !list.data && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "w100n-docs-muted", children: t.loading }),
444
- list.data && !shown.length && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "w100n-docs-muted", children: list.data.length ? t.nothing : t.empty }),
445
- folders.map((folder) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w100n-docs-folder", role: "group", "aria-label": folder || t.loose, children: [
446
- folders.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "w100n-docs-group", children: folder || t.loose }),
447
- shown.filter((item) => (item.folder ?? "") === folder).map((item) => {
448
- const Icon = icons[item.kind];
449
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", className: "w100n-docs-card", "aria-current": item.id === here.documentId, onClick: () => open(item.id), children: [
450
- item.thumbnailUrl ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { src: item.thumbnailUrl, alt: "", className: "w100n-docs-thumb" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w100n-docs-thumb", "data-kind": item.kind, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { "aria-hidden": true }) }),
451
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "w100n-docs-card-text", children: [
452
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("b", { children: item.name }),
453
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("small", { children: [
454
- t.kinds[item.kind],
455
- " \xB7 ",
456
- date(item.updatedAt)
457
- ] })
458
- ] })
459
- ] }, item.id);
460
- })
614
+ list.loading && !list.data && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "w100n-docs-muted", children: t.loading }),
615
+ list.data && !shown.length && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "w100n-docs-muted", children: all.length ? t.nothing : t.empty }),
616
+ folders.map((folder) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w100n-docs-folder", role: "group", "aria-label": folder || t.loose, children: [
617
+ folders.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "w100n-docs-group", children: folder || t.loose }),
618
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w100n-docs-grid", children: shown.filter((item) => !spaceId || (item.folder ?? "") === folder).map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("button", { type: "button", className: "w100n-docs-card", "aria-current": item.id === here.documentId, onClick: () => open(item), title: item.name, children: [
619
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Thumb, { host, item, label: t.kinds[item.kind] }),
620
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "w100n-docs-card-text", children: [
621
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("b", { children: item.name }),
622
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("small", { children: [!spaceId && names.get(item.spaceId), ago(item.updatedAt)].filter(Boolean).join(" \xB7 ") })
623
+ ] })
624
+ ] }, item.id)) })
461
625
  ] }, folder))
462
626
  ] })
627
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "w100n-docs-reopen", onClick: () => setListOpen(true), "aria-label": t.openList, title: t.openList, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.PanelLeftOpen, { "aria-hidden": true }) }),
628
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("main", { className: "w100n-docs-stage", children: [
629
+ doc.data && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w100n-docs-zoom", role: "group", children: [
630
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", onClick: () => setZoom(Math.max(50, zoom - 10)), "aria-label": t.zoomOut, title: t.zoomOut, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Minus, { "aria-hidden": true }) }),
631
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
632
+ zoom,
633
+ "%"
634
+ ] }),
635
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", onClick: () => setZoom(Math.min(200, zoom + 10)), "aria-label": t.zoomIn, title: t.zoomIn, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Plus, { "aria-hidden": true }) }),
636
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", onClick: () => setZoom(100), "aria-label": t.fit, title: t.fit, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.Maximize2, { "aria-hidden": true }) })
637
+ ] }),
638
+ doc.data && !panelOpen && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "w100n-docs-reopen w100n-docs-reopen-right", onClick: () => setPanelOpen(true), "aria-label": t.openPanel, title: t.openPanel, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.PanelRightOpen, { "aria-hidden": true }) }),
639
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w100n-docs-scroll", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w100n-docs-zoomed", style: { zoom: zoom / 100 }, children: stage }) })
463
640
  ] }),
464
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("main", { className: "w100n-docs-stage", children: stage }),
465
- doc.data && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("aside", { className: "w100n-docs-panel w100n-docs-island", children: [
466
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w100n-docs-tabs", role: "tablist", children: panelTabs.map(([key, Icon, label]) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", role: "tab", "aria-selected": tab === key, onClick: () => setTab(key), children: [
467
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { "aria-hidden": true }),
468
- label
469
- ] }, key)) }),
470
- tab === "outline" && (outline.length ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("nav", { className: "w100n-docs-outline", children: outline.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", "data-level": item.level, onClick: () => document.getElementById(item.id)?.scrollIntoView({ behavior: "smooth", block: "start" }), children: item.text }, item.id)) }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "w100n-docs-muted", children: t.noOutline })),
471
- tab === "versions" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w100n-docs-versions", children: [
472
- versions.error && failed(versions.retry),
473
- (versions.data ?? []).map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
474
- "button",
475
- {
476
- type: "button",
477
- "aria-pressed": (versionId ?? "current") === item.id || !versionId && item.current,
478
- onClick: () => {
479
- setRestoring("idle");
480
- setVersion({ documentId: here.documentId, id: item.current ? null : item.id });
641
+ doc.data && panelOpen && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("aside", { className: "w100n-docs-side w100n-docs-panel", "aria-label": t.details, children: [
642
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w100n-docs-head", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w100n-docs-row", children: [
643
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "w100n-docs-tabs", role: "tablist", children: panelTabs.map(([key, Icon, label]) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("button", { type: "button", role: "tab", "aria-selected": tab === key, onClick: () => setTab(key), children: [
644
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { "aria-hidden": true }),
645
+ label
646
+ ] }, key)) }),
647
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "w100n-docs-close", onClick: () => setPanelOpen(false), "aria-label": t.closePanel, title: t.closePanel, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react.X, { "aria-hidden": true }) })
648
+ ] }) }),
649
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w100n-docs-panel-body", children: [
650
+ tab === "outline" && (outline.length ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("nav", { className: "w100n-docs-outline", children: outline.map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", "data-level": item.level, onClick: () => document.getElementById(item.id)?.scrollIntoView({ behavior: "smooth", block: "start" }), children: item.text }, item.id)) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "w100n-docs-muted", children: t.noOutline })),
651
+ tab === "versions" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w100n-docs-versions", children: [
652
+ versions.error && failed(versions.retry),
653
+ (versions.data ?? []).map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
654
+ "button",
655
+ {
656
+ type: "button",
657
+ "aria-pressed": (versionId ?? "current") === item.id || !versionId && item.current,
658
+ onClick: () => {
659
+ setRestoring("idle");
660
+ setVersion({ documentId: here.documentId, id: item.current ? null : item.id });
661
+ },
662
+ children: [
663
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("b", { children: [
664
+ date(item.createdAt),
665
+ item.current && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "w100n-docs-badge", children: t.current })
666
+ ] }),
667
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("small", { children: [item.author?.name, size(item.size), item.note].filter(Boolean).join(" \xB7 ") })
668
+ ]
481
669
  },
482
- children: [
483
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("b", { children: [
484
- date(item.createdAt),
485
- item.current && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w100n-docs-badge", children: t.current })
486
- ] }),
487
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { children: [item.author?.name, size(item.size), item.note].filter(Boolean).join(" \xB7 ") })
488
- ]
489
- },
490
- item.id
491
- ))
492
- ] }),
493
- tab === "details" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "w100n-docs-details", children: [
494
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: t.kind }),
495
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: t.kinds[doc.data.kind] }),
496
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: t.size }),
497
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: size(doc.data.size) }),
498
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: t.updated }),
499
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: date(doc.data.updatedAt) }),
500
- doc.data.updatedBy && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
501
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: t.by }),
502
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: doc.data.updatedBy.name })
670
+ item.id
671
+ ))
503
672
  ] }),
504
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: t.rights }),
505
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: [doc.data.rights.view && t.view, doc.data.rights.comment && t.comment, doc.data.rights.edit && t.edit].filter(Boolean).join(", ") })
506
- ] }),
507
- aside?.(doc.data)
673
+ tab === "details" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("dl", { className: "w100n-docs-details", children: [
674
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dt", { children: t.kind }),
675
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dd", { children: t.kinds[doc.data.kind] }),
676
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dt", { children: t.size }),
677
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dd", { children: size(doc.data.size) }),
678
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dt", { children: t.updated }),
679
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dd", { children: date(doc.data.updatedAt) }),
680
+ doc.data.updatedBy && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
681
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dt", { children: t.by }),
682
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dd", { children: doc.data.updatedBy.name })
683
+ ] }),
684
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dt", { children: t.rights }),
685
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("dd", { children: [doc.data.rights.view && t.view, doc.data.rights.comment && t.comment, doc.data.rights.edit && t.edit].filter(Boolean).join(", ") })
686
+ ] }),
687
+ aside?.(doc.data)
688
+ ] })
508
689
  ] })
509
690
  ] })
510
691
  ] });