anywork-library-plugin 0.1.0 → 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/README.md CHANGED
@@ -1,16 +1,14 @@
1
- # library-plugin
1
+ # anywork-library-plugin
2
2
 
3
- 资料库:文件 + 笔记。DSH Web 客户端插件。侧栏文案是「资料库」,槽位 id 是 `ziliaoku`,和 desk-panel 自带的 `desk-hub` 分开,可以同时装着,以后也可以只留这一份。
3
+ 资料库是单独的 DSH Web 插件,不并进门户插件。侧栏「资料库」,槽位 id 是 `ziliaoku`。
4
4
 
5
- 界面跟工作台里的资料库一致:标题「资料库」,副标题「文件 + 笔记 · 放进来 = 全员可见」,页签「📁 文件 / 📝 笔记」。文件走公司盘(上传、文件夹、下载、移动、删除),笔记走知识库(搜索、记一条、查看;删除只给管理员)。
5
+ 打开后是一块黑板:把文件拖进去,或写一句回车。文件和句子写在这个工作台自己的目录 `~/.dsh/anywork-library-plugin`(设置了 `DSH_HOME` 就写在那里)。不调用门户的 `/portal/api/drive` 或 `/portal/api/kb`。
6
6
 
7
7
  ## 安装和卸下
8
8
 
9
- 在这个目录:
10
-
11
9
  ```sh
12
10
  npm pack anywork-library-plugin --registry https://registry.npmjs.org
13
- dsh plugin --profile web add ./anywork-library-plugin-0.1.0.tgz
11
+ dsh plugin --profile web add ./anywork-library-plugin-0.2.0.tgz
14
12
  ```
15
13
 
16
14
  `--profile` 写在子命令前面。`add` 会把本包写进该 profile 的 `dsh.profile.bundles`。浏览器入口是导出的 `./client`(`dsh.client.platform` 为 `web`,并依赖 `@deepseek-ai/dsh-client-ui-slots` 和 `@deepseek-ai/dsh-client-ui-sidebar`)。
@@ -23,10 +21,6 @@ dsh plugin --profile web remove anywork-library-plugin
23
21
 
24
22
  装上或卸下之后重启那个实例。`file:` 或 tgz 装进去的是副本,改源码不会自动更新。
25
23
 
26
- 需要 Anywork 门户已经提供 `/portal/api/drive/*` 和 `/portal/api/kb/*`,并且浏览器带着登录会话打开工作台。没登录时面板会提示从门户再进。本包不自带盘和知识库服务。
27
-
28
- 本地 Docker / 工作台安装先不做。
29
-
30
24
  ## 开发
31
25
 
32
26
  ```sh
package/lib/api.js CHANGED
@@ -1,4 +1,4 @@
1
- // Portal client for 资料库. Drive and notes stay on the Anywork host.
1
+ // Client for the library shelf. Files and notes stay on this plugin.
2
2
 
3
3
  export const MAX_UPLOAD = 50 * 1024 * 1024;
4
4
 
@@ -9,8 +9,9 @@ export function canDeleteNote(role) {
9
9
  export function portalErrorText(err) {
10
10
  var msg = err && err.message ? String(err.message) : String(err || "");
11
11
  var status = err && err.status;
12
+ if (status === 404) return "资料库还没挂到这个工作台。装上插件后重启一次再打开。";
12
13
  if (status === 401 || /login required/i.test(msg)) {
13
- return "读不到资料库(需要门户登录)。请从门户地址打开工作台后再试。";
14
+ return "读不到资料库。请先登录这个工作台再试。";
14
15
  }
15
16
  return msg || "读取失败";
16
17
  }
@@ -45,51 +46,51 @@ export function createPortalApi(getFetch) {
45
46
 
46
47
  return {
47
48
  listDrive: function (path) {
48
- return doFetch("/portal/api/drive/list?path=" + encodeURIComponent(path || ""), {
49
+ return doFetch("/plugins/anywork-library-plugin/drive/list?path=" + encodeURIComponent(path || ""), {
49
50
  headers: { accept: "application/json" },
50
51
  });
51
52
  },
52
53
  upload: function (path, file) {
53
54
  return doFetch(
54
- "/portal/api/drive/upload?path=" + encodeURIComponent(path || "") + "&name=" + encodeURIComponent(file.name),
55
+ "/plugins/anywork-library-plugin/drive/upload?path=" + encodeURIComponent(path || "") + "&name=" + encodeURIComponent(file.name),
55
56
  { method: "POST", body: file, headers: { accept: "application/json" } }
56
57
  );
57
58
  },
58
59
  mkdir: function (path, name) {
59
- return doFetch("/portal/api/drive/mkdir", {
60
+ return doFetch("/plugins/anywork-library-plugin/drive/mkdir", {
60
61
  method: "POST",
61
62
  headers: { "content-type": "application/json", accept: "application/json" },
62
63
  body: JSON.stringify({ path: path || "", name: name }),
63
64
  });
64
65
  },
65
66
  rm: function (path) {
66
- return doFetch("/portal/api/drive/rm", {
67
+ return doFetch("/plugins/anywork-library-plugin/drive/rm", {
67
68
  method: "POST",
68
69
  headers: { "content-type": "application/json", accept: "application/json" },
69
70
  body: JSON.stringify({ path: path }),
70
71
  });
71
72
  },
72
73
  mv: function (from, to) {
73
- return doFetch("/portal/api/drive/mv", {
74
+ return doFetch("/plugins/anywork-library-plugin/drive/mv", {
74
75
  method: "POST",
75
76
  headers: { "content-type": "application/json", accept: "application/json" },
76
77
  body: JSON.stringify({ from: from, to: to || "" }),
77
78
  });
78
79
  },
79
80
  downloadUrl: function (path) {
80
- return "/portal/api/drive/download?path=" + encodeURIComponent(path);
81
+ return "/plugins/anywork-library-plugin/drive/download?path=" + encodeURIComponent(path);
81
82
  },
82
83
  listNotes: function () {
83
- return doFetch("/portal/api/kb/list", { headers: { accept: "application/json" } });
84
+ return doFetch("/plugins/anywork-library-plugin/kb/list", { headers: { accept: "application/json" } });
84
85
  },
85
86
  searchNotes: function (q) {
86
- return doFetch("/portal/api/kb/search?q=" + encodeURIComponent(q), { headers: { accept: "application/json" } });
87
+ return doFetch("/plugins/anywork-library-plugin/kb/search?q=" + encodeURIComponent(q), { headers: { accept: "application/json" } });
87
88
  },
88
89
  readNote: function (name) {
89
- return doFetch("/portal/api/kb/note?name=" + encodeURIComponent(name), { headers: { accept: "application/json" } });
90
+ return doFetch("/plugins/anywork-library-plugin/kb/note?name=" + encodeURIComponent(name), { headers: { accept: "application/json" } });
90
91
  },
91
92
  saveNote: function (input, lang) {
92
- return doFetch("/portal/api/kb/save?lang=" + encodeURIComponent(lang || "zh"), {
93
+ return doFetch("/plugins/anywork-library-plugin/kb/save?lang=" + encodeURIComponent(lang || "zh"), {
93
94
  method: "POST",
94
95
  headers: { "content-type": "application/json", accept: "application/json" },
95
96
  body: JSON.stringify({
@@ -100,7 +101,7 @@ export function createPortalApi(getFetch) {
100
101
  });
101
102
  },
102
103
  removeNote: function (name, lang) {
103
- return doFetch("/portal/api/kb/rm?lang=" + encodeURIComponent(lang || "zh"), {
104
+ return doFetch("/plugins/anywork-library-plugin/kb/rm?lang=" + encodeURIComponent(lang || "zh"), {
104
105
  method: "POST",
105
106
  headers: { "content-type": "application/json", accept: "application/json" },
106
107
  body: JSON.stringify({ name: name }),
package/lib/client.js CHANGED
@@ -7,7 +7,7 @@ window.__ModuleLoader__.load({
7
7
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
8
8
  var React = require("react");
9
9
 
10
- // Portal client for 资料库. Drive and notes stay on the Anywork host.
10
+ // Client for the library shelf. Files and notes stay on this plugin.
11
11
 
12
12
  const MAX_UPLOAD = 50 * 1024 * 1024;
13
13
 
@@ -18,8 +18,9 @@ window.__ModuleLoader__.load({
18
18
  function portalErrorText(err) {
19
19
  var msg = err && err.message ? String(err.message) : String(err || "");
20
20
  var status = err && err.status;
21
+ if (status === 404) return "资料库还没挂到这个工作台。装上插件后重启一次再打开。";
21
22
  if (status === 401 || /login required/i.test(msg)) {
22
- return "读不到资料库(需要门户登录)。请从门户地址打开工作台后再试。";
23
+ return "读不到资料库。请先登录这个工作台再试。";
23
24
  }
24
25
  return msg || "读取失败";
25
26
  }
@@ -54,51 +55,51 @@ window.__ModuleLoader__.load({
54
55
 
55
56
  return {
56
57
  listDrive: function (path) {
57
- return doFetch("/portal/api/drive/list?path=" + encodeURIComponent(path || ""), {
58
+ return doFetch("/plugins/anywork-library-plugin/drive/list?path=" + encodeURIComponent(path || ""), {
58
59
  headers: { accept: "application/json" },
59
60
  });
60
61
  },
61
62
  upload: function (path, file) {
62
63
  return doFetch(
63
- "/portal/api/drive/upload?path=" + encodeURIComponent(path || "") + "&name=" + encodeURIComponent(file.name),
64
+ "/plugins/anywork-library-plugin/drive/upload?path=" + encodeURIComponent(path || "") + "&name=" + encodeURIComponent(file.name),
64
65
  { method: "POST", body: file, headers: { accept: "application/json" } }
65
66
  );
66
67
  },
67
68
  mkdir: function (path, name) {
68
- return doFetch("/portal/api/drive/mkdir", {
69
+ return doFetch("/plugins/anywork-library-plugin/drive/mkdir", {
69
70
  method: "POST",
70
71
  headers: { "content-type": "application/json", accept: "application/json" },
71
72
  body: JSON.stringify({ path: path || "", name: name }),
72
73
  });
73
74
  },
74
75
  rm: function (path) {
75
- return doFetch("/portal/api/drive/rm", {
76
+ return doFetch("/plugins/anywork-library-plugin/drive/rm", {
76
77
  method: "POST",
77
78
  headers: { "content-type": "application/json", accept: "application/json" },
78
79
  body: JSON.stringify({ path: path }),
79
80
  });
80
81
  },
81
82
  mv: function (from, to) {
82
- return doFetch("/portal/api/drive/mv", {
83
+ return doFetch("/plugins/anywork-library-plugin/drive/mv", {
83
84
  method: "POST",
84
85
  headers: { "content-type": "application/json", accept: "application/json" },
85
86
  body: JSON.stringify({ from: from, to: to || "" }),
86
87
  });
87
88
  },
88
89
  downloadUrl: function (path) {
89
- return "/portal/api/drive/download?path=" + encodeURIComponent(path);
90
+ return "/plugins/anywork-library-plugin/drive/download?path=" + encodeURIComponent(path);
90
91
  },
91
92
  listNotes: function () {
92
- return doFetch("/portal/api/kb/list", { headers: { accept: "application/json" } });
93
+ return doFetch("/plugins/anywork-library-plugin/kb/list", { headers: { accept: "application/json" } });
93
94
  },
94
95
  searchNotes: function (q) {
95
- return doFetch("/portal/api/kb/search?q=" + encodeURIComponent(q), { headers: { accept: "application/json" } });
96
+ return doFetch("/plugins/anywork-library-plugin/kb/search?q=" + encodeURIComponent(q), { headers: { accept: "application/json" } });
96
97
  },
97
98
  readNote: function (name) {
98
- return doFetch("/portal/api/kb/note?name=" + encodeURIComponent(name), { headers: { accept: "application/json" } });
99
+ return doFetch("/plugins/anywork-library-plugin/kb/note?name=" + encodeURIComponent(name), { headers: { accept: "application/json" } });
99
100
  },
100
101
  saveNote: function (input, lang) {
101
- return doFetch("/portal/api/kb/save?lang=" + encodeURIComponent(lang || "zh"), {
102
+ return doFetch("/plugins/anywork-library-plugin/kb/save?lang=" + encodeURIComponent(lang || "zh"), {
102
103
  method: "POST",
103
104
  headers: { "content-type": "application/json", accept: "application/json" },
104
105
  body: JSON.stringify({
@@ -109,7 +110,7 @@ window.__ModuleLoader__.load({
109
110
  });
110
111
  },
111
112
  removeNote: function (name, lang) {
112
- return doFetch("/portal/api/kb/rm?lang=" + encodeURIComponent(lang || "zh"), {
113
+ return doFetch("/plugins/anywork-library-plugin/kb/rm?lang=" + encodeURIComponent(lang || "zh"), {
113
114
  method: "POST",
114
115
  headers: { "content-type": "application/json", accept: "application/json" },
115
116
  body: JSON.stringify({ name: name }),
@@ -174,9 +175,38 @@ window.__ModuleLoader__.load({
174
175
  .zlk-bc .lk { color:#3478f6; cursor:pointer; }
175
176
  .zlk-drop { margin-top:12px; border:1.5px dashed #cfd3d8; border-radius:12px; background:#f7f8fa; text-align:center; padding:14px 10px; }
176
177
  .zlk-drop.on { border-color:#3478f6; background:#f3f7ff; }
177
- .zlk-drop b { display:block; color:#3478f6; font-size:14px; }
178
- .zlk-drop span { display:block; margin-top:4px; font-size:12px; color:#8b9098; }
179
- .zlk-pick { margin-top:12px; padding:12px; border-radius:12px; background:#fff; border:1px solid #e6e6e6; }
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; }
180
210
  `;
181
211
 
182
212
  function ensureCss() {
@@ -430,169 +460,124 @@ window.__ModuleLoader__.load({
430
460
  }).catch(function (e) { patchNs({ message: portalErrorText(e) }); });
431
461
  }
432
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
+
433
475
  var trigger = h("button", {
434
476
  type: "button", className: "zlk-nav" + (open ? " on" : ""), onClick: toggle, title: "资料库", "data-zlk-open": "1",
435
477
  }, h("span", { className: "ic" }, iconFolder(16)), wide ? h("span", { className: "lbl" }, "资料库") : null);
436
478
  if (!open) return h("div", { "data-zlk-root": "1" }, trigger);
437
479
 
438
- var bodyKids = [
439
- h("div", { key: "tabs", className: "zlk-tabs" },
440
- h("button", { type: "button", className: "zlk-tab" + (tab === "files" ? " on" : ""), "data-zlk-tab": "files", onClick: function () { setTab("files"); } }, "📁 文件"),
441
- h("button", { type: "button", className: "zlk-tab" + (tab === "notes" ? " on" : ""), "data-zlk-tab": "notes", onClick: function () { setTab("notes"); } }, "📝 笔记")
442
- ),
443
- ];
444
-
445
- if (tab === "files") {
446
- bodyKids.push(h("div", { key: "hint", className: "zlk-hint" }, "放原始文件;按项目或客户建文件夹,找起来最快"));
447
- var segs = String(fs.path || "").split("/").filter(Boolean);
448
- var bc = [h("span", { key: "root", className: "lk", onClick: function () { loadFiles(""); } }, "🏠 根目录")];
449
- var acc = "";
450
- segs.forEach(function (seg, i) {
451
- acc = acc ? acc + "/" + seg : seg;
452
- var here = acc;
453
- bc.push(h("span", { key: "s" + i }, " / "));
454
- bc.push(h("span", { key: "c" + i, className: "lk", onClick: function () { loadFiles(here); } }, seg));
455
- });
456
- bodyKids.push(h("div", { key: "bc", className: "zlk-bc" }, bc));
457
- bodyKids.push(h("div", { key: "bar", className: "zlk-row" },
458
- h("button", { type: "button", className: "zlk-btn gh", "data-zlk-mkdir": "1", onClick: function () { patchFs({ newFolder: !fs.newFolder, pick: null }); } }, "+ 新建文件夹"),
459
- h("button", { type: "button", className: "zlk-btn", "data-zlk-upload": "1", onClick: function () { if (fileRef.current) fileRef.current.click(); } }, "⬆ 上传"),
460
- 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 = ""; } })
461
- ));
462
- if (fs.newFolder) {
463
- bodyKids.push(h("div", { key: "nf", className: "zlk-row" },
464
- h("input", { ref: folderRef, className: "zlk-inp zlk-search", "data-zlk-folder-name": "1", placeholder: "文件夹名字,比如「客户A」「2026报价」", onKeyDown: function (e) { if (e.key === "Enter") createFolder(); } }),
465
- h("button", { type: "button", className: "zlk-btn", "data-zlk-mkdir-save": "1", onClick: createFolder }, "创建"),
466
- h("button", { type: "button", className: "zlk-btn gh", onClick: function () { patchFs({ newFolder: false }); } }, "取消")
467
- ));
468
- }
469
- bodyKids.push(h("div", {
470
- key: "drop",
471
- className: "zlk-drop" + (fs.drag ? " on" : ""),
472
- "data-zlk-drop": "1",
473
- onDragOver: function (e) { e.preventDefault(); if (!fs.drag) patchFs({ drag: true }); },
474
- onDragLeave: function () { patchFs({ drag: false }); },
475
- onDrop: function (e) { e.preventDefault(); patchFs({ drag: false }); uploadFiles(e.dataTransfer && e.dataTransfer.files); },
476
- }, h("b", null, "⬆ 拖文件到这里上传"), h("span", null, "上传到当前文件夹 · 单个 ≤50MB")));
477
- if (fs.message) bodyKids.push(h("div", { key: "msg", className: "zlk-msg" + (fs.phase === "error" || fs.message.indexOf("失败") >= 0 ? " err" : "") }, fs.message));
478
- if (fs.phase === "loading") bodyKids.push(h("div", { key: "ld", className: "zlk-hint" }, "读取中…"));
479
- if (fs.pick) {
480
- var pk = fs.pick;
481
- var psegs = String(pk.path || "").split("/").filter(Boolean);
482
- var pbc = [h("span", { key: "pr", className: "lk", onClick: function () { pickerGo(""); } }, "🏠 根目录")];
483
- var pacc = "";
484
- psegs.forEach(function (seg, i) {
485
- pacc = pacc ? pacc + "/" + seg : seg;
486
- var there = pacc;
487
- pbc.push(h("span", { key: "ps" + i }, " / "));
488
- pbc.push(h("span", { key: "pc" + i, className: "lk", onClick: function () { pickerGo(there); } }, seg));
489
- });
490
- var folders = (pk.entries || []).filter(function (en) { return en.dir; }).map(function (en) {
491
- var next = joinPath(pk.path, en.name);
492
- return h("div", { key: en.name, className: "zlk-it", onClick: function () { pickerGo(next); } },
493
- h("span", { className: "zlk-ico" }, "📁"),
494
- h("div", { className: "zlk-title link" }, en.name)
495
- );
496
- });
497
- bodyKids.push(h("div", { key: "pick", className: "zlk-pick" },
498
- h("div", { className: "zlk-hint" }, "把「" + pk.name + "」移动到:"),
499
- h("div", { className: "zlk-bc" }, pbc),
500
- folders.length ? h("div", null, folders) : h("div", { className: "zlk-hint" }, "(没有子文件夹,可直接「移到这里」)"),
501
- h("div", { className: "zlk-row" },
502
- h("button", { type: "button", className: "zlk-btn", "data-zlk-move-here": "1", onClick: moveHere }, "移到这里"),
503
- h("button", { type: "button", className: "zlk-btn gh", onClick: function () { patchFs({ pick: null }); } }, "取消")
504
- )
505
- ));
506
- }
507
- var rootEmpty = !fs.path && !(fs.entries && fs.entries.length) && fs.phase !== "error";
508
- (fs.entries || []).forEach(function (en) {
509
- var full = joinPath(fs.path, en.name);
510
- var acts = [];
511
- if (en.dir) acts.push(h("button", { key: "o", type: "button", className: "zlk-mini", onClick: function () { loadFiles(full); } }, "打开"));
512
- else acts.push(h("a", { key: "d", className: "zlk-mini", href: apiRef.current.downloadUrl(full) }, "下载"));
513
- acts.push(h("button", { key: "m", type: "button", className: "zlk-mini", "data-zlk-move": en.name, onClick: function () { openPicker(en.name); } }, "移动到…"));
514
- acts.push(h("button", { key: "x", type: "button", className: "zlk-mini", "data-zlk-del-file": en.name, onClick: function () { removeEntry(full, en.dir); } }, "删除"));
515
- bodyKids.push(h("div", { key: "f-" + en.name, className: "zlk-it", "data-zlk-file": en.name },
516
- h("span", { className: "zlk-ico" }, en.dir ? "📁" : "📄"),
517
- h("div", { className: "zlk-gr" },
518
- h("div", { className: "zlk-top" },
519
- h("div", { className: "zlk-title" + (en.dir ? " link" : ""), onClick: en.dir ? function () { loadFiles(full); } : null }, en.name),
520
- h("div", { className: "zlk-acts row" }, acts)
521
- ),
522
- h("div", { className: "zlk-meta" }, (en.dir ? "文件夹" : formatSize(en.size)) + (en.mtime ? " · " + formatWhen(en.mtime) : ""))
523
- )
524
- ));
525
- });
526
- if (rootEmpty) {
527
- bodyKids.push(h("div", { key: "ea", className: "zlk-empty", onClick: function () { if (fileRef.current) fileRef.current.click(); } },
528
- h("b", null, "① 建个文件夹,把文件传进来"), h("span", null, "比如「客户A」「2026报价」—— 拖进去就行")));
529
- bodyKids.push(h("div", { key: "eb", className: "zlk-empty", onClick: function () { setTab("notes"); patchNs({ composing: true }); } },
530
- h("b", null, "② 记第一条笔记"), h("span", null, "今天有什么结论?写一句话也算")));
531
- }
532
- } else {
533
- bodyKids.push(h("div", { key: "hint", className: "zlk-hint" }, "记结论和经验,搜一下就能找到 —— AI 助理也能直接引用"));
534
- bodyKids.push(h("div", { key: "search", className: "zlk-row" },
535
- h("input", { ref: qRef, className: "zlk-inp zlk-search", "data-zlk-search": "1", placeholder: "搜笔记,比如「印尼」「定价」…", onKeyDown: function (e) { if (e.key === "Enter") runSearch(); } }),
536
- h("button", { type: "button", className: "zlk-btn gh", "data-zlk-search-btn": "1", onClick: runSearch }, "搜索")
537
- ));
538
- bodyKids.push(h("div", { key: "compose", className: "zlk-row" },
539
- h("button", { type: "button", className: "zlk-btn", "data-zlk-compose": "1", onClick: function () { patchNs({ composing: !ns.composing }); } }, "+ 记一条")
540
- ));
541
- if (ns.composing) {
542
- bodyKids.push(h("div", { key: "form", className: "zlk-form" },
543
- h("input", { ref: titleRef, className: "zlk-inp", "data-zlk-title": "1", placeholder: "标题(不填就用第一行)" }),
544
- h("textarea", { ref: bodyRef, className: "zlk-inp zlk-ta", "data-zlk-body": "1", placeholder: "想到什么写什么…… 一句话也算" }),
545
- h("div", { className: "zlk-row" },
546
- h("button", { type: "button", className: "zlk-btn", "data-zlk-save": "1", onClick: saveNote }, "保存 ✓"),
547
- h("button", { type: "button", className: "zlk-btn gh", onClick: function () { patchNs({ composing: false }); } }, "取消")
548
- )
549
- ));
550
- }
551
- if (ns.message) bodyKids.push(h("div", { key: "nm", className: "zlk-msg" + (ns.tone === "err" || ns.phase === "error" ? " err" : " ok") }, ns.message));
552
- if (ns.phase === "loading") bodyKids.push(h("div", { key: "ld", className: "zlk-hint" }, "读取中…"));
553
- if (ns.q) {
554
- bodyKids.push(h("div", { key: "hc", className: "zlk-hint" }, "命中 " + ns.hits.length));
555
- if (!ns.hits.length) bodyKids.push(h("div", { key: "miss", className: "zlk-empty" }, h("b", null, "没有命中,换个短点的词试试")));
556
- ns.hits.forEach(function (hit, i) {
557
- bodyKids.push(h("div", { key: "h" + i, className: "zlk-it" },
558
- h("span", { className: "zlk-ico" }, "🔎"),
559
- h("div", { className: "zlk-gr" },
560
- h("div", { className: "zlk-meta" }, hit.file + " : " + hit.line),
561
- h("div", { className: "zlk-body" }, hit.text)
562
- )
563
- ));
564
- });
565
- bodyKids.push(h("div", { key: "back", className: "zlk-row" },
566
- h("button", { type: "button", className: "zlk-btn gh", "data-zlk-back-list": "1", onClick: function () { if (qRef.current) qRef.current.value = ""; patchNs({ q: "", hits: [] }); } }, "返回笔记列表")
567
- ));
568
- } else if (ns.phase === "ready") {
569
- if (!ns.notes.length) {
570
- bodyKids.push(h("div", { key: "empty", className: "zlk-empty", onClick: function () { patchNs({ composing: true }); } },
571
- h("b", null, "还没有笔记 —— 点「+ 记一条」写第一句"),
572
- h("span", null, "结论、口径、经验,一句话也算")
573
- ));
574
- }
575
- ns.notes.forEach(function (note) {
576
- var shown = ns.expanded === note.name;
577
- var acts = [h("button", { key: "v", type: "button", className: "zlk-mini", "data-zlk-view": note.name, onClick: function () { toggleNote(note.name); } }, shown ? "收起" : "查看")];
578
- if (canDeleteNote(ns.role)) {
579
- acts.push(h("button", { key: "x", type: "button", className: "zlk-mini", "data-zlk-del": note.name, onClick: function () { deleteNote(note.name); } }, "删除"));
580
- }
581
- bodyKids.push(h("div", { key: note.name, className: "zlk-it", "data-zlk-note": note.name },
582
- h("span", { className: "zlk-ico" }, "📝"),
583
- h("div", { className: "zlk-gr" },
584
- h("div", { className: "zlk-top" },
585
- h("div", { className: "zlk-title" }, note.title || note.name),
586
- h("div", { className: "zlk-acts" }, acts)
587
- ),
588
- h("div", { className: "zlk-meta" }, formatWhen(note.mtime) + (note.author ? " · " + note.author : "")),
589
- shown ? h("div", { className: "zlk-body" }, ns.content) : null
590
- )
591
- ));
592
- });
593
- }
594
- }
595
-
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
+
596
581
  return h("div", { "data-zlk-root": "1" },
597
582
  trigger,
598
583
  h("section", { className: "zlk-fv", "data-zlk-panel": "1" },
@@ -600,7 +585,7 @@ window.__ModuleLoader__.load({
600
585
  h("span", { className: "zlk-mark" }, iconFolder(22)),
601
586
  h("div", { className: "zlk-hd-text" },
602
587
  h("div", { className: "zlk-t1" }, "资料库"),
603
- h("div", { className: "zlk-t2" }, "文件 + 笔记 · 放进来 = 全员可见")
588
+ h("div", { className: "zlk-t2" }, "丢进来,全员就能看见")
604
589
  ),
605
590
  h("button", { type: "button", className: "zlk-back", "data-zlk-back": "1", onClick: close }, "← 返回对话")
606
591
  ),