anywork-library-plugin 0.0.0-stage → 0.2.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/lib/client.js ADDED
@@ -0,0 +1,617 @@
1
+ /* Generated by scripts/assemble.mjs. Edit lib/api.js and lib/panel.js, then npm run assemble. */
2
+ window.__ModuleLoader__.load({
3
+ id: "anywork-library-plugin",
4
+ factory: (require) => {
5
+ var module = { exports: {} };
6
+ var exports = module.exports;
7
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
8
+ var React = require("react");
9
+
10
+ // Client for the library shelf. Files and notes stay on this plugin.
11
+
12
+ const MAX_UPLOAD = 50 * 1024 * 1024;
13
+
14
+ function canDeleteNote(role) {
15
+ return role === "admin";
16
+ }
17
+
18
+ function portalErrorText(err) {
19
+ var msg = err && err.message ? String(err.message) : String(err || "");
20
+ var status = err && err.status;
21
+ if (status === 404) return "资料库还没挂到这个工作台。装上插件后重启一次再打开。";
22
+ if (status === 401 || /login required/i.test(msg)) {
23
+ return "读不到资料库。请先登录这个工作台再试。";
24
+ }
25
+ return msg || "读取失败";
26
+ }
27
+
28
+ function readBody(response) {
29
+ return response.text().then(function (text) {
30
+ var data = null;
31
+ if (text) {
32
+ try { data = JSON.parse(text); } catch (e) { data = null; }
33
+ }
34
+ if (!response.ok) {
35
+ var err = new Error((data && data.error) || text || ("HTTP " + response.status));
36
+ err.status = response.status;
37
+ throw err;
38
+ }
39
+ return data == null ? {} : data;
40
+ });
41
+ }
42
+
43
+ function createPortalApi(getFetch) {
44
+ function doFetch(url, options) {
45
+ var fetchImpl = typeof getFetch === "function" ? getFetch() : getFetch;
46
+ if (typeof fetchImpl !== "function") {
47
+ var err = new Error("fetch 不可用");
48
+ err.status = 0;
49
+ return Promise.reject(err);
50
+ }
51
+ var opts = options || {};
52
+ opts.credentials = opts.credentials || "same-origin";
53
+ return Promise.resolve(fetchImpl(url, opts)).then(readBody);
54
+ }
55
+
56
+ return {
57
+ listDrive: function (path) {
58
+ return doFetch("/plugins/anywork-library-plugin/drive/list?path=" + encodeURIComponent(path || ""), {
59
+ headers: { accept: "application/json" },
60
+ });
61
+ },
62
+ upload: function (path, file) {
63
+ return doFetch(
64
+ "/plugins/anywork-library-plugin/drive/upload?path=" + encodeURIComponent(path || "") + "&name=" + encodeURIComponent(file.name),
65
+ { method: "POST", body: file, headers: { accept: "application/json" } }
66
+ );
67
+ },
68
+ mkdir: function (path, name) {
69
+ return doFetch("/plugins/anywork-library-plugin/drive/mkdir", {
70
+ method: "POST",
71
+ headers: { "content-type": "application/json", accept: "application/json" },
72
+ body: JSON.stringify({ path: path || "", name: name }),
73
+ });
74
+ },
75
+ rm: function (path) {
76
+ return doFetch("/plugins/anywork-library-plugin/drive/rm", {
77
+ method: "POST",
78
+ headers: { "content-type": "application/json", accept: "application/json" },
79
+ body: JSON.stringify({ path: path }),
80
+ });
81
+ },
82
+ mv: function (from, to) {
83
+ return doFetch("/plugins/anywork-library-plugin/drive/mv", {
84
+ method: "POST",
85
+ headers: { "content-type": "application/json", accept: "application/json" },
86
+ body: JSON.stringify({ from: from, to: to || "" }),
87
+ });
88
+ },
89
+ downloadUrl: function (path) {
90
+ return "/plugins/anywork-library-plugin/drive/download?path=" + encodeURIComponent(path);
91
+ },
92
+ listNotes: function () {
93
+ return doFetch("/plugins/anywork-library-plugin/kb/list", { headers: { accept: "application/json" } });
94
+ },
95
+ searchNotes: function (q) {
96
+ return doFetch("/plugins/anywork-library-plugin/kb/search?q=" + encodeURIComponent(q), { headers: { accept: "application/json" } });
97
+ },
98
+ readNote: function (name) {
99
+ return doFetch("/plugins/anywork-library-plugin/kb/note?name=" + encodeURIComponent(name), { headers: { accept: "application/json" } });
100
+ },
101
+ saveNote: function (input, lang) {
102
+ return doFetch("/plugins/anywork-library-plugin/kb/save?lang=" + encodeURIComponent(lang || "zh"), {
103
+ method: "POST",
104
+ headers: { "content-type": "application/json", accept: "application/json" },
105
+ body: JSON.stringify({
106
+ title: input.title || "",
107
+ tags: input.tags || "",
108
+ content: input.content || "",
109
+ }),
110
+ });
111
+ },
112
+ removeNote: function (name, lang) {
113
+ return doFetch("/plugins/anywork-library-plugin/kb/rm?lang=" + encodeURIComponent(lang || "zh"), {
114
+ method: "POST",
115
+ headers: { "content-type": "application/json", accept: "application/json" },
116
+ body: JSON.stringify({ name: name }),
117
+ });
118
+ },
119
+ };
120
+ }
121
+
122
+ var inject = ["slots"];
123
+ var ZLK_SEQ = 0;
124
+
125
+ var ZLK_CSS = `
126
+ .zlk-nav { display:flex; align-items:center; gap:10px; width:100%; padding:7px 10px; border:0; border-radius:10px; background:transparent; color:inherit; cursor:pointer; font:400 14px/22px -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Noto Sans SC", "Microsoft YaHei", sans-serif; text-align:left; }
127
+ .zlk-nav:hover { background:rgba(127,127,127,.12); }
128
+ .zlk-nav.on { background:rgba(79,124,247,.13); }
129
+ .zlk-nav .ic { width:16px; height:16px; display:flex; align-items:center; justify-content:center; flex:0 0 auto; }
130
+ .zlk-nav .lbl { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
131
+ .zlk-fv { position:fixed; left:var(--zlk-fv-left, 0px); top:0; right:0; bottom:0; z-index:9999; display:flex; flex-direction:column; background:#e6e6e6; color:#1c1e21; overflow:auto; font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Noto Sans SC", "Microsoft YaHei", sans-serif; }
132
+ .zlk-hd { position:sticky; top:0; z-index:2; display:flex; align-items:center; gap:12px; padding:16px 16px 14px; background:#fff; }
133
+ .zlk-mark { width:44px; height:44px; border-radius:12px; display:flex; align-items:center; justify-content:center; background:#fff; border:1px solid #e4e4e4; color:#4b5563; flex:0 0 auto; }
134
+ .zlk-hd-text { flex:1; min-width:0; }
135
+ .zlk-t1 { font-size:18px; font-weight:700; line-height:1.3; }
136
+ .zlk-t2 { margin-top:3px; font-size:12px; line-height:1.45; color:#8b919a; }
137
+ .zlk-back { margin-left:auto; flex:0 0 auto; height:34px; padding:0 14px; border:1px solid #d5d5d5; border-radius:999px; background:#fff; color:#3a3a3a; font:500 12.5px/1 inherit; cursor:pointer; white-space:nowrap; }
138
+ .zlk-back:hover { background:#f6f6f6; }
139
+ .zlk-bd { padding:14px 16px 72px; }
140
+ .zlk-tabs { display:flex; gap:4px; padding:4px; margin:0 0 14px; background:#fff; border-radius:12px; box-shadow:0 1px 2px rgba(16,24,40,.04); }
141
+ .zlk-tab { flex:1; display:flex; align-items:center; justify-content:center; gap:6px; height:36px; border:0; border-radius:9px; background:transparent; color:#6b7280; font:500 14px/1 inherit; cursor:pointer; }
142
+ .zlk-tab.on { background:#fff; color:#1c1e21; font-weight:650; box-shadow:0 1px 3px rgba(16,24,40,.14); }
143
+ .zlk-hint { margin:0 2px 12px; font-size:13px; line-height:1.65; color:#8b9098; }
144
+ .zlk-row { display:flex; gap:8px; align-items:center; margin-top:12px; flex-wrap:wrap; }
145
+ .zlk-inp { width:100%; min-width:0; height:40px; box-sizing:border-box; border:1px solid #e1e1e1; border-radius:10px; padding:0 12px; background:#fff; color:inherit; font:400 14px/1.4 inherit; outline:none; }
146
+ .zlk-inp::placeholder { color:#c5c8ce; }
147
+ .zlk-inp:focus { border-color:#4f7cf7; box-shadow:0 0 0 3px rgba(79,124,247,.15); }
148
+ .zlk-ta { height:auto; min-height:88px; padding:10px 12px; resize:vertical; }
149
+ .zlk-search { flex:1; }
150
+ .zlk-btn { height:36px; padding:0 16px; border:0; border-radius:10px; background:#3478f6; color:#fff; font:600 14px/1 inherit; cursor:pointer; }
151
+ .zlk-btn:hover { background:#2d6ae0; }
152
+ .zlk-btn.gh { background:#fff; border:1px solid #e1e1e1; color:#3a3a3a; font-weight:500; }
153
+ .zlk-btn.gh:hover { background:#f7f7f7; }
154
+ .zlk-form { display:flex; flex-direction:column; gap:8px; margin-top:12px; }
155
+ .zlk-msg { margin-top:8px; font-size:12.5px; color:#8b9098; }
156
+ .zlk-msg.ok { color:#248a3d; }
157
+ .zlk-msg.err { color:#d64545; }
158
+ .zlk-it { display:flex; gap:10px; align-items:flex-start; padding:8px 2px 14px; }
159
+ .zlk-ico { width:36px; height:36px; border-radius:10px; display:flex; align-items:center; justify-content:center; background:#fff; border:1px solid #ececec; color:#6b7280; flex:0 0 auto; font-size:16px; }
160
+ .zlk-gr { flex:1; min-width:0; }
161
+ .zlk-top { display:flex; align-items:flex-start; gap:10px; }
162
+ .zlk-title { flex:1; min-width:0; font-size:15px; font-weight:650; line-height:1.45; color:#222; word-break:break-word; }
163
+ .zlk-title.link { cursor:pointer; }
164
+ .zlk-meta { margin-top:6px; font-size:13px; line-height:1.4; color:#9aa0a6; }
165
+ .zlk-acts { display:flex; flex-direction:column; gap:8px; flex:0 0 auto; }
166
+ .zlk-acts.row { flex-direction:row; flex-wrap:wrap; justify-content:flex-end; }
167
+ .zlk-mini { min-width:64px; height:32px; padding:0 12px; border:1px solid #d8d8d8; border-radius:8px; background:#fff; color:#3a3a3a; font:400 13px/1 inherit; cursor:pointer; text-decoration:none; display:inline-flex; align-items:center; justify-content:center; box-sizing:border-box; }
168
+ .zlk-mini:hover { background:#f7f7f7; }
169
+ .zlk-body { margin-top:10px; padding:10px 12px; border-radius:10px; background:#fff; border:1px solid #ececec; font-size:13.5px; line-height:1.65; white-space:pre-wrap; word-break:break-word; color:#333; }
170
+ .zlk-empty { margin-top:12px; padding:18px 14px; border:1.5px dashed #cfd3d8; border-radius:12px; background:#f7f8fa; color:#4f7cf7; cursor:pointer; }
171
+ .zlk-empty b { display:block; font-size:14px; }
172
+ .zlk-empty span { display:block; margin-top:4px; font-size:12px; color:#8b9098; font-weight:400; }
173
+ .zlk-file { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); }
174
+ .zlk-bc { font-size:13px; margin:2px 0 4px; color:#4b5563; }
175
+ .zlk-bc .lk { color:#3478f6; cursor:pointer; }
176
+ .zlk-drop { margin-top:12px; border:1.5px dashed #cfd3d8; border-radius:12px; background:#f7f8fa; text-align:center; padding:14px 10px; }
177
+ .zlk-drop.on { border-color:#3478f6; background:#f3f7ff; }
178
+ .zlk-intake {
179
+ position: relative;
180
+ display: flex;
181
+ flex-direction: column;
182
+ justify-content: flex-end;
183
+ gap: 14px;
184
+ min-height: 240px;
185
+ margin: 0 0 22px;
186
+ padding: 28px 26px 22px;
187
+ border-radius: 28px;
188
+ background: #141414;
189
+ color: #f6f1e8;
190
+ box-shadow: 0 24px 60px -36px rgba(0,0,0,.7);
191
+ cursor: pointer;
192
+ }
193
+ .zlk-intake.empty { min-height: 68vh; }
194
+ .zlk-intake.on { outline: 2px solid #f6f1e8; outline-offset: 4px; }
195
+ .zlk-kicker { font-size: 12px; letter-spacing: .16em; text-transform: uppercase; color: #b7aa96; }
196
+ .zlk-headline { font-size: 64px; line-height: .9; font-weight: 720; letter-spacing: -0.04em; }
197
+ .zlk-lead { max-width: 28em; font-size: 16px; line-height: 1.5; color: #d9d0c3; }
198
+ .zlk-drop-hint { font-size: 13px; color: #a89880; }
199
+ .zlk-line { display: flex; gap: 8px; align-items: center; }
200
+ .zlk-line input {
201
+ flex: 1; height: 52px; border: 0; border-radius: 16px; padding: 0 16px;
202
+ background: #f6f1e8; color: #161616; font: 500 16px/1 inherit; outline: none;
203
+ }
204
+ .zlk-line button {
205
+ height: 52px; padding: 0 18px; border: 0; border-radius: 16px;
206
+ background: #f6f1e8; color: #161616; font: 700 15px/1 inherit; cursor: pointer;
207
+ }
208
+ .zlk-shelf-title { margin: 8px 2px 4px; font-size: 13px; letter-spacing: .08em; color: #6b7280; }
209
+ .zlk-pick { margin-top: 12px; padding: 12px; border-radius: 12px; background: #fff; border: 1px solid #e6e6e6; }
210
+ `;
211
+
212
+ function ensureCss() {
213
+ if (typeof document === "undefined") return;
214
+ if (document.getElementById("library-plugin-css")) return;
215
+ var st = document.createElement("style");
216
+ st.id = "library-plugin-css";
217
+ st.textContent = ZLK_CSS;
218
+ (document.head || document.documentElement).appendChild(st);
219
+ }
220
+
221
+ function h(type, props) {
222
+ var args = [type, props];
223
+ for (var i = 2; i < arguments.length; i++) args.push(arguments[i]);
224
+ return React.createElement.apply(React, args);
225
+ }
226
+
227
+ function svg(size) {
228
+ var props = {
229
+ viewBox: "0 0 24 24", width: size, height: size, fill: "none", stroke: "currentColor",
230
+ strokeWidth: 1.7, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true",
231
+ };
232
+ var args = ["svg", props];
233
+ for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
234
+ return h.apply(null, args);
235
+ }
236
+
237
+ function iconFolder(size) {
238
+ return svg(size, h("path", { d: "M3.5 7.5A1.5 1.5 0 0 1 5 6h4l2 2h8a1.5 1.5 0 0 1 1.5 1.5v8A1.5 1.5 0 0 1 19 19H5a1.5 1.5 0 0 1-1.5-1.5v-10z" }));
239
+ }
240
+
241
+ function measureFv() {
242
+ var left = 0;
243
+ try {
244
+ if (!(window.matchMedia && window.matchMedia("(max-width: 820px)").matches)) {
245
+ var sc = document.querySelector('[class*="sidebarCol"]');
246
+ if (sc) {
247
+ var r = sc.getBoundingClientRect();
248
+ if (r && r.right > 40 && r.right < window.innerWidth * 0.6) left = Math.round(r.right);
249
+ }
250
+ }
251
+ document.documentElement.style.setProperty("--zlk-fv-left", left + "px");
252
+ } catch (e) { /* ignore */ }
253
+ }
254
+
255
+ function notifyFv(id) {
256
+ try { window.dispatchEvent(new CustomEvent("desk-fv", { detail: { id: id } })); } catch (e) { /* ignore */ }
257
+ }
258
+
259
+ function deskLang() {
260
+ try {
261
+ var lang = (document.documentElement && document.documentElement.lang) || (navigator.language || "zh");
262
+ return String(lang).toLowerCase().indexOf("en") === 0 ? "en" : "zh";
263
+ } catch (e) { return "zh"; }
264
+ }
265
+
266
+ function formatSize(n) {
267
+ n = Number(n) || 0;
268
+ if (n < 1024) return n + " B";
269
+ if (n < 1048576) return (n / 1024).toFixed(n < 10240 ? 1 : 0) + " KB";
270
+ return (n / 1048576).toFixed(1) + " MB";
271
+ }
272
+
273
+ function formatWhen(value) {
274
+ var m = /^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2})/.exec(String(value || ""));
275
+ if (m) return m[1] + " " + m[2];
276
+ return String(value || "");
277
+ }
278
+
279
+ function joinPath(dir, name) {
280
+ return dir ? dir + "/" + name : name;
281
+ }
282
+
283
+ function LibraryPanel(props) {
284
+ var wide = !!(props && props.wide);
285
+ var openPair = React.useState(false);
286
+ var open = openPair[0];
287
+ var setOpen = openPair[1];
288
+ var tabPair = React.useState("notes");
289
+ var tab = tabPair[0];
290
+ var setTab = tabPair[1];
291
+ var fsPair = React.useState({ phase: "idle", path: "", entries: [], message: "", newFolder: false, pick: null, drag: false });
292
+ var fs = fsPair[0];
293
+ var setFs = fsPair[1];
294
+ var nsPair = React.useState({ phase: "idle", role: "member", notes: [], q: "", hits: [], message: "", expanded: "", content: "", composing: false });
295
+ var ns = nsPair[0];
296
+ var setNs = nsPair[1];
297
+ var apiRef = React.useRef(null);
298
+ var idRef = React.useRef("");
299
+ var openRef = React.useRef(false);
300
+ var fileRef = React.useRef(null);
301
+ var qRef = React.useRef(null);
302
+ var titleRef = React.useRef(null);
303
+ var bodyRef = React.useRef(null);
304
+ var folderRef = React.useRef(null);
305
+ var pathRef = React.useRef("");
306
+ if (!idRef.current) idRef.current = "ziliaoku-" + (++ZLK_SEQ);
307
+ if (!apiRef.current) apiRef.current = createPortalApi(function () { return window.fetch.bind(window); });
308
+ openRef.current = open;
309
+ pathRef.current = fs.path;
310
+
311
+ function patchFs(p) { setFs(function (prev) { return Object.assign({}, prev, p); }); }
312
+ function patchNs(p) { setNs(function (prev) { return Object.assign({}, prev, p); }); }
313
+
314
+ function loadFiles(path) {
315
+ var p = String(path == null ? "" : path);
316
+ patchFs({ phase: "loading", path: p, entries: [], message: "", pick: null, newFolder: false });
317
+ apiRef.current.listDrive(p).then(function (d) {
318
+ patchFs({ phase: "ready", path: d.path != null ? d.path : p, entries: d.entries || [], message: "" });
319
+ }).catch(function (e) {
320
+ patchFs({ phase: "error", message: portalErrorText(e) });
321
+ });
322
+ }
323
+
324
+ function loadNotes() {
325
+ patchNs({ phase: "loading", message: "" });
326
+ apiRef.current.listNotes().then(function (d) {
327
+ patchNs({ phase: "ready", role: d.role || "member", notes: d.notes || [], message: "", tone: "" });
328
+ }).catch(function (e) {
329
+ patchNs({ phase: "error", tone: "err", message: portalErrorText(e) });
330
+ });
331
+ }
332
+
333
+ React.useEffect(function () {
334
+ function onFv(e) {
335
+ var who = e && e.detail ? e.detail.id : null;
336
+ if (who !== idRef.current) setOpen(false);
337
+ }
338
+ function onKey(e) { if (e.key === "Escape" && openRef.current) setOpen(false); }
339
+ function onDown(e) {
340
+ if (!openRef.current) return;
341
+ var t = e.target;
342
+ if (t && t.closest && (t.closest(".zlk-fv") || t.closest(".zlk-nav"))) return;
343
+ setOpen(false);
344
+ }
345
+ window.addEventListener("desk-fv", onFv);
346
+ document.addEventListener("keydown", onKey);
347
+ document.addEventListener("pointerdown", onDown, true);
348
+ return function () {
349
+ window.removeEventListener("desk-fv", onFv);
350
+ document.removeEventListener("keydown", onKey);
351
+ document.removeEventListener("pointerdown", onDown, true);
352
+ };
353
+ }, []);
354
+
355
+ React.useEffect(function () {
356
+ if (!open) return;
357
+ measureFv();
358
+ notifyFv(idRef.current);
359
+ loadFiles("");
360
+ loadNotes();
361
+ }, [open]);
362
+
363
+ function toggle() { setOpen(function (v) { return !v; }); }
364
+ function close() { setOpen(false); }
365
+
366
+ function uploadFiles(list) {
367
+ var files = [];
368
+ if (list) for (var i = 0; i < list.length; i++) files.push(list[i]);
369
+ var cursor = 0;
370
+ function next() {
371
+ if (cursor >= files.length) { loadFiles(pathRef.current); return; }
372
+ var f = files[cursor++];
373
+ if (f.size > MAX_UPLOAD) {
374
+ patchFs({ message: "上传失败:" + f.name + " 超过 50MB" });
375
+ next();
376
+ return;
377
+ }
378
+ patchFs({ message: "上传中:" + f.name + " …" });
379
+ apiRef.current.upload(pathRef.current, f).then(next).catch(function (e) {
380
+ patchFs({ message: "上传失败:" + portalErrorText(e) });
381
+ });
382
+ }
383
+ if (files.length) next();
384
+ }
385
+
386
+ function createFolder() {
387
+ var name = folderRef.current ? String(folderRef.current.value || "").trim() : "";
388
+ if (!name) { if (folderRef.current) folderRef.current.focus(); return; }
389
+ apiRef.current.mkdir(fs.path, name).then(function () { loadFiles(fs.path); }).catch(function (e) {
390
+ patchFs({ message: portalErrorText(e) });
391
+ });
392
+ }
393
+
394
+ function removeEntry(full, isDir) {
395
+ var label = (isDir ? "删除文件夹「" : "删除文件「") + full.split("/").pop() + "」?此操作不可恢复。";
396
+ if (window.confirm && !window.confirm(label)) return;
397
+ apiRef.current.rm(full).then(function () { loadFiles(fs.path); }).catch(function (e) {
398
+ patchFs({ message: portalErrorText(e) });
399
+ });
400
+ }
401
+
402
+ function openPicker(name) {
403
+ patchFs({ pick: { name: name, path: "", entries: [] } });
404
+ apiRef.current.listDrive("").then(function (d) {
405
+ patchFs({ pick: { name: name, path: d.path != null ? d.path : "", entries: d.entries || [] } });
406
+ }).catch(function (e) { patchFs({ message: portalErrorText(e), pick: null }); });
407
+ }
408
+
409
+ function pickerGo(path) {
410
+ apiRef.current.listDrive(path).then(function (d) {
411
+ setFs(function (prev) {
412
+ var pick = prev.pick || { name: "" };
413
+ return Object.assign({}, prev, { pick: { name: pick.name, path: d.path != null ? d.path : path, entries: d.entries || [] } });
414
+ });
415
+ }).catch(function (e) { patchFs({ message: portalErrorText(e) }); });
416
+ }
417
+
418
+ function moveHere() {
419
+ if (!fs.pick) return;
420
+ var from = joinPath(fs.path, fs.pick.name);
421
+ apiRef.current.mv(from, fs.pick.path).then(function () { loadFiles(fs.path); }).catch(function (e) {
422
+ patchFs({ message: portalErrorText(e) });
423
+ });
424
+ }
425
+
426
+ function runSearch() {
427
+ var q = qRef.current ? String(qRef.current.value || "").trim() : "";
428
+ if (!q) { patchNs({ q: "", hits: [] }); return; }
429
+ apiRef.current.searchNotes(q).then(function (d) {
430
+ patchNs({ q: q, hits: (d && d.hits) || [], message: "" });
431
+ }).catch(function (e) { patchNs({ message: portalErrorText(e) }); });
432
+ }
433
+
434
+ function saveNote() {
435
+ var title = titleRef.current ? String(titleRef.current.value || "").trim() : "";
436
+ var body = bodyRef.current ? String(bodyRef.current.value || "").trim() : "";
437
+ if (!body) { if (bodyRef.current) bodyRef.current.focus(); return; }
438
+ if (!title) title = body.split("\n")[0].slice(0, 36);
439
+ apiRef.current.saveNote({ title: title, content: body }, deskLang()).then(function () {
440
+ if (qRef.current) qRef.current.value = "";
441
+ return apiRef.current.listNotes();
442
+ }).then(function (d) {
443
+ patchNs({ phase: "ready", role: (d && d.role) || "member", notes: (d && d.notes) || [], composing: false, q: "", hits: [], message: "已记下 ✓", tone: "ok" });
444
+ }).catch(function (e) { patchNs({ message: portalErrorText(e), tone: "err" }); });
445
+ }
446
+
447
+ function toggleNote(name) {
448
+ if (ns.expanded === name) { patchNs({ expanded: "", content: "" }); return; }
449
+ patchNs({ expanded: name, content: "读取中…" });
450
+ apiRef.current.readNote(name).then(function (d) {
451
+ patchNs({ expanded: name, content: d && d.ok ? d.content : ((d && d.error) || "读取失败") });
452
+ }).catch(function (e) { patchNs({ expanded: name, content: portalErrorText(e) }); });
453
+ }
454
+
455
+ function deleteNote(name) {
456
+ if (window.confirm && !window.confirm("删除笔记:" + name + "?")) return;
457
+ apiRef.current.removeNote(name, deskLang()).then(function () {
458
+ patchNs({ expanded: "", content: "" });
459
+ loadNotes();
460
+ }).catch(function (e) { patchNs({ message: portalErrorText(e) }); });
461
+ }
462
+
463
+ function saveLine() {
464
+ var body = bodyRef.current ? String(bodyRef.current.value || "").trim() : "";
465
+ if (!body) { if (bodyRef.current) bodyRef.current.focus(); return; }
466
+ var title = body.split("\n")[0].slice(0, 36);
467
+ apiRef.current.saveNote({ title: title, content: body }, deskLang()).then(function () {
468
+ if (bodyRef.current) bodyRef.current.value = "";
469
+ return apiRef.current.listNotes();
470
+ }).then(function (d) {
471
+ patchNs({ phase: "ready", role: (d && d.role) || "admin", notes: (d && d.notes) || [], composing: false, q: "", hits: [], message: "已记下", tone: "ok" });
472
+ }).catch(function (e) { patchNs({ message: portalErrorText(e), tone: "err" }); });
473
+ }
474
+
475
+ var trigger = h("button", {
476
+ type: "button", className: "zlk-nav" + (open ? " on" : ""), onClick: toggle, title: "资料库", "data-zlk-open": "1",
477
+ }, h("span", { className: "ic" }, iconFolder(16)), wide ? h("span", { className: "lbl" }, "资料库") : null);
478
+ if (!open) return h("div", { "data-zlk-root": "1" }, trigger);
479
+
480
+ var shelfEmpty = fs.phase !== "error" && ns.phase !== "error" && !fs.path && !(fs.entries && fs.entries.length) && !(ns.notes && ns.notes.length) && !ns.q;
481
+ var bodyKids = [];
482
+ bodyKids.push(h("div", {
483
+ key: "intake",
484
+ className: "zlk-intake" + (shelfEmpty ? " empty" : "") + (fs.drag ? " on" : ""),
485
+ "data-zlk-drop": "1",
486
+ onDragOver: function (e) { e.preventDefault(); if (!fs.drag) patchFs({ drag: true }); },
487
+ onDragLeave: function () { patchFs({ drag: false }); },
488
+ onDrop: function (e) { e.preventDefault(); patchFs({ drag: false }); uploadFiles(e.dataTransfer && e.dataTransfer.files); },
489
+ onClick: function (e) {
490
+ if (e.target.closest("input, button, a")) return;
491
+ if (fileRef.current) fileRef.current.click();
492
+ },
493
+ },
494
+ h("div", { className: "zlk-kicker" }, "SHARED SHELF"),
495
+ h("div", { className: "zlk-headline" }, shelfEmpty ? "丢进来" : "再丢一份"),
496
+ h("div", { className: "zlk-lead" }, "文件,或一句话。放在这块黑板上,用这个工作台的人都能看见。"),
497
+ h("div", { className: "zlk-drop-hint" }, "拖文件到这里 · 点这块黑板也能选文件 · 单个 ≤50MB"),
498
+ h("div", { className: "zlk-line", onClick: function (e) { e.stopPropagation(); } },
499
+ h("input", { ref: bodyRef, "data-zlk-body": "1", "data-zlk-line": "1", placeholder: "或写一句,回车记下", onKeyDown: function (e) { if (e.key === "Enter") saveLine(); } }),
500
+ h("button", { type: "button", "data-zlk-save": "1", onClick: saveLine }, "记下")
501
+ ),
502
+ h("input", { ref: fileRef, className: "zlk-file", type: "file", multiple: true, "data-zlk-file-input": "1", onChange: function (e) { uploadFiles(e.target.files); e.target.value = ""; } })
503
+ ));
504
+ if (fs.message) bodyKids.push(h("div", { key: "fmsg", className: "zlk-msg" + (fs.phase === "error" || fs.message.indexOf("失败") >= 0 ? " err" : "") }, fs.message));
505
+ if (ns.message) bodyKids.push(h("div", { key: "nmsg", className: "zlk-msg" + (ns.tone === "err" || ns.phase === "error" ? " err" : " ok") }, ns.message));
506
+ if (fs.phase === "loading" || ns.phase === "loading") bodyKids.push(h("div", { key: "ld", className: "zlk-hint" }, "读取中…"));
507
+ var segs = String(fs.path || "").split("/").filter(Boolean);
508
+ if (segs.length) {
509
+ var bc = [h("span", { key: "root", className: "lk", onClick: function () { loadFiles(""); } }, "架上")];
510
+ var acc = "";
511
+ segs.forEach(function (seg, i) {
512
+ acc = acc ? acc + "/" + seg : seg;
513
+ var here = acc;
514
+ bc.push(h("span", { key: "s" + i }, " / "));
515
+ bc.push(h("span", { key: "c" + i, className: "lk", onClick: function () { loadFiles(here); } }, seg));
516
+ });
517
+ bodyKids.push(h("div", { key: "bc", className: "zlk-bc" }, bc));
518
+ }
519
+ bodyKids.push(h("div", { key: "bar", className: "zlk-row" },
520
+ h("button", { type: "button", className: "zlk-btn gh", "data-zlk-mkdir": "1", onClick: function () { patchFs({ newFolder: !fs.newFolder }); } }, "新建文件夹"),
521
+ h("input", { ref: qRef, className: "zlk-inp zlk-search", "data-zlk-search": "1", placeholder: "在架上找一句", onKeyDown: function (e) { if (e.key === "Enter") runSearch(); } }),
522
+ h("button", { type: "button", className: "zlk-btn gh", "data-zlk-search-btn": "1", onClick: runSearch }, "找")
523
+ ));
524
+ if (fs.newFolder) {
525
+ bodyKids.push(h("div", { key: "nf", className: "zlk-row" },
526
+ h("input", { ref: folderRef, className: "zlk-inp zlk-search", "data-zlk-folder-name": "1", placeholder: "文件夹名字", onKeyDown: function (e) { if (e.key === "Enter") createFolder(); } }),
527
+ h("button", { type: "button", className: "zlk-btn", "data-zlk-mkdir-save": "1", onClick: createFolder }, "创建"),
528
+ h("button", { type: "button", className: "zlk-btn gh", onClick: function () { patchFs({ newFolder: false }); } }, "取消")
529
+ ));
530
+ }
531
+ if (ns.q) {
532
+ bodyKids.push(h("div", { key: "hc", className: "zlk-shelf-title" }, "找到 " + ns.hits.length));
533
+ if (!ns.hits.length) bodyKids.push(h("div", { key: "miss", className: "zlk-hint" }, "没有这句话"));
534
+ ns.hits.forEach(function (hit, i) {
535
+ bodyKids.push(h("div", { key: "h" + i, className: "zlk-it" },
536
+ h("span", { className: "zlk-ico" }, "🔎"),
537
+ h("div", { className: "zlk-gr" }, h("div", { className: "zlk-title" }, hit.text))
538
+ ));
539
+ });
540
+ }
541
+ if (!ns.q && ns.notes && ns.notes.length) {
542
+ bodyKids.push(h("div", { key: "nt", className: "zlk-shelf-title" }, "句子"));
543
+ ns.notes.forEach(function (note) {
544
+ var shown = ns.expanded === note.name;
545
+ var acts = [h("button", { key: "v", type: "button", className: "zlk-mini", "data-zlk-view": note.name, onClick: function () { toggleNote(note.name); } }, shown ? "收起" : "查看")];
546
+ if (canDeleteNote(ns.role)) acts.push(h("button", { key: "x", type: "button", className: "zlk-mini", "data-zlk-del": note.name, onClick: function () { deleteNote(note.name); } }, "删除"));
547
+ bodyKids.push(h("div", { key: note.name, className: "zlk-it", "data-zlk-note": note.name },
548
+ h("span", { className: "zlk-ico" }, "✎"),
549
+ h("div", { className: "zlk-gr" },
550
+ h("div", { className: "zlk-top" },
551
+ h("div", { className: "zlk-title" }, note.title || note.name),
552
+ h("div", { className: "zlk-acts row" }, acts)
553
+ ),
554
+ h("div", { className: "zlk-meta" }, formatWhen(note.mtime) + (note.author ? " · " + note.author : "")),
555
+ shown ? h("div", { className: "zlk-body" }, ns.content) : null
556
+ )
557
+ ));
558
+ });
559
+ }
560
+ if (fs.entries && fs.entries.length) {
561
+ bodyKids.push(h("div", { key: "ft", className: "zlk-shelf-title" }, "文件"));
562
+ fs.entries.forEach(function (en) {
563
+ var full = joinPath(fs.path, en.name);
564
+ var acts = [];
565
+ if (en.dir) acts.push(h("button", { key: "o", type: "button", className: "zlk-mini", onClick: function () { loadFiles(full); } }, "打开"));
566
+ else acts.push(h("a", { key: "d", className: "zlk-mini", href: apiRef.current.downloadUrl(full) }, "下载"));
567
+ acts.push(h("button", { key: "x", type: "button", className: "zlk-mini", "data-zlk-del-file": en.name, onClick: function () { removeEntry(full, en.dir); } }, "删除"));
568
+ bodyKids.push(h("div", { key: "f-" + en.name, className: "zlk-it", "data-zlk-file": en.name },
569
+ h("span", { className: "zlk-ico" }, en.dir ? "📁" : "📄"),
570
+ h("div", { className: "zlk-gr" },
571
+ h("div", { className: "zlk-top" },
572
+ h("div", { className: "zlk-title" + (en.dir ? " link" : ""), onClick: en.dir ? function () { loadFiles(full); } : null }, en.name),
573
+ h("div", { className: "zlk-acts row" }, acts)
574
+ ),
575
+ h("div", { className: "zlk-meta" }, (en.dir ? "文件夹" : formatSize(en.size)) + (en.mtime ? " · " + formatWhen(en.mtime) : ""))
576
+ )
577
+ ));
578
+ });
579
+ }
580
+
581
+ return h("div", { "data-zlk-root": "1" },
582
+ trigger,
583
+ h("section", { className: "zlk-fv", "data-zlk-panel": "1" },
584
+ h("header", { className: "zlk-hd" },
585
+ h("span", { className: "zlk-mark" }, iconFolder(22)),
586
+ h("div", { className: "zlk-hd-text" },
587
+ h("div", { className: "zlk-t1" }, "资料库"),
588
+ h("div", { className: "zlk-t2" }, "丢进来,全员就能看见")
589
+ ),
590
+ h("button", { type: "button", className: "zlk-back", "data-zlk-back": "1", onClick: close }, "← 返回对话")
591
+ ),
592
+ h("div", { className: "zlk-bd" }, bodyKids)
593
+ )
594
+ );
595
+ }
596
+
597
+ function apply(ctx) {
598
+ ctx.slots.inject("sidebar.footer.action", function () {
599
+ return ctx.slots.register(
600
+ {
601
+ name: "sidebar.footer.action",
602
+ id: "ziliaoku",
603
+ order: 91,
604
+ label: function () { return "资料库"; },
605
+ },
606
+ LibraryPanel
607
+ );
608
+ });
609
+ }
610
+
611
+ ensureCss();
612
+
613
+ exports.apply = apply;
614
+ exports.inject = inject;
615
+ return module.exports;
616
+ },
617
+ });