@w100n/documents 0.2.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
@@ -74,6 +74,7 @@ function matches(doc, query, kind) {
74
74
  // src/text.ts
75
75
  var en = {
76
76
  documents: "Documents",
77
+ loose: "Without a folder",
77
78
  search: "Search documents",
78
79
  all: "All",
79
80
  empty: "No documents here yet",
@@ -102,10 +103,17 @@ var en = {
102
103
  unsupported: "This file cannot be shown yet",
103
104
  restore: "Restore this version",
104
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",
105
112
  kinds: { docx: "DOCX", markdown: "Markdown", pdf: "PDF", sheet: "Sheets", slides: "Slides" }
106
113
  };
107
114
  var pl = {
108
115
  documents: "Dokumenty",
116
+ loose: "Bez folderu",
109
117
  search: "Szukaj dokument\xF3w",
110
118
  all: "Wszystkie",
111
119
  empty: "Nie ma tu jeszcze dokument\xF3w",
@@ -134,10 +142,17 @@ var pl = {
134
142
  unsupported: "Tego pliku nie da si\u0119 jeszcze pokaza\u0107",
135
143
  restore: "Przywr\xF3\u0107 t\u0119 wersj\u0119",
136
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",
137
151
  kinds: { docx: "DOCX", markdown: "Markdown", pdf: "PDF", sheet: "Arkusze", slides: "Slajdy" }
138
152
  };
139
153
  var uk = {
140
154
  documents: "\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438",
155
+ loose: "\u0411\u0435\u0437 \u0442\u0435\u043A\u0438",
141
156
  search: "\u041F\u043E\u0448\u0443\u043A \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432",
142
157
  all: "\u0423\u0441\u0456",
143
158
  empty: "\u0422\u0443\u0442 \u0449\u0435 \u043D\u0435\u043C\u0430\u0454 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432",
@@ -166,16 +181,117 @@ var uk = {
166
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",
167
182
  restore: "\u0412\u0456\u0434\u043D\u043E\u0432\u0438\u0442\u0438 \u0446\u044E \u0432\u0435\u0440\u0441\u0456\u044E",
168
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",
169
190
  kinds: { docx: "DOCX", markdown: "Markdown", pdf: "PDF", sheet: "\u0422\u0430\u0431\u043B\u0438\u0446\u0456", slides: "\u0421\u043B\u0430\u0439\u0434\u0438" }
170
191
  };
171
192
  var texts = { en, pl, uk };
172
193
 
173
- // src/useLoad.ts
194
+ // src/Thumb.tsx
174
195
  var import_react = require("react");
175
- function useLoad(load, key) {
176
- const [state, setState] = (0, import_react.useState)({ data: null, error: null, loading: true });
177
- 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]);
178
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)(() => {
179
295
  const controller = new AbortController();
180
296
  setState((current) => ({ ...current, loading: true, error: null }));
181
297
  load(controller.signal).then(
@@ -192,7 +308,7 @@ function useLoad(load, key) {
192
308
  }
193
309
 
194
310
  // src/viewers/DocxView.tsx
195
- var import_react2 = require("react");
311
+ var import_react3 = require("react");
196
312
 
197
313
  // src/viewers/headings.ts
198
314
  var last = 0;
@@ -206,11 +322,11 @@ function collect(root, selector, level = (el) => Number(el.tagName.slice(1))) {
206
322
  }
207
323
 
208
324
  // src/viewers/DocxView.tsx
209
- var import_jsx_runtime = require("react/jsx-runtime");
325
+ var import_jsx_runtime2 = require("react/jsx-runtime");
210
326
  function DocxView({ bytes, onOutline, failed }) {
211
- const box = (0, import_react2.useRef)(null);
212
- const [error, setError] = (0, import_react2.useState)(false);
213
- (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)(() => {
214
330
  let live = true;
215
331
  let width = 0;
216
332
  const root = box.current;
@@ -235,35 +351,35 @@ function DocxView({ bytes, onOutline, failed }) {
235
351
  watch.disconnect();
236
352
  };
237
353
  }, [bytes, onOutline]);
238
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
239
- error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "w100n-docs-note", children: failed }),
240
- /* @__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" })
241
357
  ] });
242
358
  }
243
359
 
244
360
  // src/viewers/MarkdownView.tsx
245
361
  var import_dompurify = __toESM(require("dompurify"), 1);
246
362
  var import_marked = require("marked");
247
- var import_react3 = require("react");
248
- var import_jsx_runtime2 = require("react/jsx-runtime");
363
+ var import_react4 = require("react");
364
+ var import_jsx_runtime3 = require("react/jsx-runtime");
249
365
  function MarkdownView({ bytes, onOutline }) {
250
- const box = (0, import_react3.useRef)(null);
251
- (0, import_react3.useLayoutEffect)(() => {
366
+ const box = (0, import_react4.useRef)(null);
367
+ (0, import_react4.useLayoutEffect)(() => {
252
368
  const root = box.current;
253
369
  root.innerHTML = import_dompurify.default.sanitize(import_marked.marked.parse(new TextDecoder().decode(bytes), { async: false }));
254
370
  onOutline(collect(root, "h1, h2, h3"));
255
371
  }, [bytes, onOutline]);
256
- 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" });
257
373
  }
258
374
 
259
375
  // src/viewers/PdfView.tsx
260
- var import_react4 = require("react");
261
- var import_jsx_runtime3 = require("react/jsx-runtime");
376
+ var import_react5 = require("react");
377
+ var import_jsx_runtime4 = require("react/jsx-runtime");
262
378
  var last2 = 0;
263
379
  function PdfView({ bytes, worker, onOutline, failed }) {
264
- const box = (0, import_react4.useRef)(null);
265
- const [error, setError] = (0, import_react4.useState)(false);
266
- (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)(() => {
267
383
  const root = box.current;
268
384
  const prefix = `w100n-docs-p${++last2}`;
269
385
  let stop = false;
@@ -310,56 +426,90 @@ function PdfView({ bytes, worker, onOutline, failed }) {
310
426
  close();
311
427
  };
312
428
  }, [bytes, worker, onOutline]);
313
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
314
- error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "w100n-docs-note", children: failed }),
315
- /* @__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" })
316
432
  ] });
317
433
  }
318
434
 
319
435
  // src/viewers/SlidesView.tsx
320
- var import_jsx_runtime4 = require("react/jsx-runtime");
436
+ var import_jsx_runtime5 = require("react/jsx-runtime");
321
437
  function SlidesView({ bytes, title }) {
322
- 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) });
323
439
  }
324
440
 
325
441
  // src/DocumentsWorkspace.tsx
326
- var import_jsx_runtime5 = require("react/jsx-runtime");
442
+ var import_jsx_runtime6 = require("react/jsx-runtime");
327
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 };
328
- function DocumentsWorkspace({ host, language = "en", theme = "light", place, onPlace, start, end }) {
444
+ function DocumentsWorkspace({ host, language = "en", theme = "light", place, onPlace, start, end, aside, actions }) {
329
445
  const t = texts[language];
330
- const [own, setOwn] = (0, import_react5.useState)({ spaceId: null, documentId: null });
446
+ const [own, setOwn] = (0, import_react6.useState)({ spaceId: null, documentId: null });
331
447
  const here = place ?? own;
332
448
  const go = (next) => {
333
449
  setOwn(next);
334
450
  onPlace?.(next);
335
451
  };
336
- const [query, setQuery] = (0, import_react5.useState)("");
337
- const [kind, setKind] = (0, import_react5.useState)("all");
338
- const [listOpen, setListOpen] = (0, import_react5.useState)(true);
339
- const [picking, setPicking] = (0, import_react5.useState)(false);
340
- const [tab, setTab] = (0, import_react5.useState)("outline");
341
- const [outline, setOutline] = (0, import_react5.useState)([]);
342
- const [version, setVersion] = (0, import_react5.useState)({ documentId: null, id: null });
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);
460
+ }, []);
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 });
343
466
  const versionId = version.documentId === here.documentId ? version.id : null;
344
- const [restoring, setRestoring] = (0, import_react5.useState)("idle");
467
+ const [restoring, setRestoring] = (0, import_react6.useState)("idle");
345
468
  const spaces = useLoad((signal) => host.spaces({ signal }), [host]);
346
- 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;
347
471
  const space = spaces.data?.find((item) => item.id === spaceId);
348
- 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]);
349
478
  const doc = useLoad((signal) => here.documentId ? host.document(here.documentId, { signal }) : Promise.resolve(null), [host, here.documentId]);
350
479
  const versions = useLoad((signal) => here.documentId ? host.versions(here.documentId, { signal }) : Promise.resolve([]), [host, here.documentId]);
351
480
  const content = useLoad((signal) => here.documentId ? host.content(here.documentId, versionId, { signal }) : Promise.resolve(null), [host, here.documentId, versionId]);
352
- const shown = (list.data ?? []).filter((item) => matches(item, query, kind));
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 ?? ""))];
353
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
+ };
354
498
  const size = (bytes) => bytes < 1024 ? `${bytes} B` : bytes < 1048576 ? `${(bytes / 1024).toFixed(0)} KB` : `${(bytes / 1048576).toFixed(1)} MB`;
355
- 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: [
356
500
  t.failed,
357
- /* @__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 })
358
502
  ] });
359
- const open = (documentId) => {
503
+ const open = (item) => {
360
504
  setOutline([]);
361
505
  setTab("outline");
362
- go({ spaceId, documentId });
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 });
363
513
  };
364
514
  const restore = async (documentId, versionId2) => {
365
515
  setRestoring("busy");
@@ -375,8 +525,8 @@ function DocumentsWorkspace({ host, language = "en", theme = "light", place, onP
375
525
  doc.retry();
376
526
  list.retry();
377
527
  };
378
- let stage = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w100n-docs-empty", children: [
379
- /* @__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 }),
380
530
  t.pick
381
531
  ] });
382
532
  if (here.documentId) {
@@ -384,111 +534,157 @@ function DocumentsWorkspace({ host, language = "en", theme = "light", place, onP
384
534
  doc.retry();
385
535
  content.retry();
386
536
  });
387
- else if (!doc.data || !content.data) stage = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w100n-docs-empty", children: t.loading });
388
- else if (doc.data.kind === "markdown") stage = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MarkdownView, { bytes: content.data, onOutline: setOutline });
389
- else if (doc.data.kind === "docx") stage = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DocxView, { bytes: content.data, onOutline: setOutline, failed: t.failed });
390
- 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 });
391
- else if (doc.data.kind === "slides") stage = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SlidesView, { bytes: content.data, title: doc.data.name });
392
- 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 });
393
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] : [];
394
546
  const panelTabs = [["outline", import_lucide_react.ListTree, t.outline], ["versions", import_lucide_react.History, t.versions], ["details", import_lucide_react.Info, t.details]];
395
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w100n-docs", "data-theme": theme, children: [
396
- /* @__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: [
397
549
  start,
398
- /* @__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, {}) }),
399
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { className: "w100n-docs-title", children: doc.data?.name ?? t.documents }),
400
- doc.data && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w100n-docs-badge", "data-kind": doc.data.kind, children: t.kinds[doc.data.kind] }),
401
- 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) }),
402
- 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: [
403
- /* @__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 }),
404
562
  t.restore
405
563
  ] }),
406
- restoring === "failed" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w100n-docs-muted", children: t.restoreFailed }),
407
- 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 })
408
567
  ] }),
409
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w100n-docs-body", children: [
410
- listOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("aside", { className: "w100n-docs-list w100n-docs-island", "aria-label": t.documents, children: [
411
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w100n-docs-picker", children: [
412
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", className: "w100n-docs-field", "aria-haspopup": "listbox", "aria-expanded": picking, onClick: () => setPicking(!picking), children: [
413
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w100n-docs-dot", style: { background: space?.color ?? void 0 } }),
414
- space?.name ?? t.space,
415
- /* @__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 }) })
416
578
  ] }),
417
- 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: () => {
418
- setPicking(false);
419
- go({ spaceId: item.id, documentId: null });
420
- }, children: [
421
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w100n-docs-dot", style: { background: item.color ?? void 0 } }),
422
- item.name
423
- ] }) }, item.id)) })
424
- ] }),
425
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { className: "w100n-docs-field w100n-docs-search", children: [
426
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react.Search, { "aria-hidden": true }),
427
- /* @__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)) })
428
611
  ] }),
429
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w100n-docs-chips", role: "group", children: ["all", ...kinds].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)) }),
430
- /* @__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: [
431
613
  list.error && failed(list.retry),
432
- list.loading && !list.data && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "w100n-docs-muted", children: t.loading }),
433
- list.data && !shown.length && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "w100n-docs-muted", children: list.data.length ? t.nothing : t.empty }),
434
- shown.map((item) => {
435
- const Icon = icons[item.kind];
436
- 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: [
437
- 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 }) }),
438
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "w100n-docs-card-text", children: [
439
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("b", { children: item.name }),
440
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("small", { children: [
441
- t.kinds[item.kind],
442
- " \xB7 ",
443
- date(item.updatedAt)
444
- ] })
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 ") })
445
623
  ] })
446
- ] }, item.id);
447
- })
624
+ ] }, item.id)) })
625
+ ] }, folder))
448
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 }) })
449
640
  ] }),
450
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("main", { className: "w100n-docs-stage", children: stage }),
451
- doc.data && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("aside", { className: "w100n-docs-panel w100n-docs-island", children: [
452
- /* @__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: [
453
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { "aria-hidden": true }),
454
- label
455
- ] }, key)) }),
456
- 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 })),
457
- tab === "versions" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "w100n-docs-versions", children: [
458
- versions.error && failed(versions.retry),
459
- (versions.data ?? []).map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
460
- "button",
461
- {
462
- type: "button",
463
- "aria-pressed": (versionId ?? "current") === item.id || !versionId && item.current,
464
- onClick: () => {
465
- setRestoring("idle");
466
- 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
+ ]
467
669
  },
468
- children: [
469
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("b", { children: [
470
- date(item.createdAt),
471
- item.current && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w100n-docs-badge", children: t.current })
472
- ] }),
473
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("small", { children: [item.author?.name, size(item.size), item.note].filter(Boolean).join(" \xB7 ") })
474
- ]
475
- },
476
- item.id
477
- ))
478
- ] }),
479
- tab === "details" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "w100n-docs-details", children: [
480
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: t.kind }),
481
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: t.kinds[doc.data.kind] }),
482
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: t.size }),
483
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: size(doc.data.size) }),
484
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: t.updated }),
485
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: date(doc.data.updatedAt) }),
486
- doc.data.updatedBy && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
487
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: t.by }),
488
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: doc.data.updatedBy.name })
670
+ item.id
671
+ ))
672
+ ] }),
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(", ") })
489
686
  ] }),
490
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: t.rights }),
491
- /* @__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(", ") })
687
+ aside?.(doc.data)
492
688
  ] })
493
689
  ] })
494
690
  ] })