anywork-library-plugin 0.0.0-stage → 0.1.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/panel.js ADDED
@@ -0,0 +1,506 @@
1
+ var inject = ["slots"];
2
+ var ZLK_SEQ = 0;
3
+
4
+ var ZLK_CSS = `
5
+ .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; }
6
+ .zlk-nav:hover { background:rgba(127,127,127,.12); }
7
+ .zlk-nav.on { background:rgba(79,124,247,.13); }
8
+ .zlk-nav .ic { width:16px; height:16px; display:flex; align-items:center; justify-content:center; flex:0 0 auto; }
9
+ .zlk-nav .lbl { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
10
+ .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; }
11
+ .zlk-hd { position:sticky; top:0; z-index:2; display:flex; align-items:center; gap:12px; padding:16px 16px 14px; background:#fff; }
12
+ .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; }
13
+ .zlk-hd-text { flex:1; min-width:0; }
14
+ .zlk-t1 { font-size:18px; font-weight:700; line-height:1.3; }
15
+ .zlk-t2 { margin-top:3px; font-size:12px; line-height:1.45; color:#8b919a; }
16
+ .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; }
17
+ .zlk-back:hover { background:#f6f6f6; }
18
+ .zlk-bd { padding:14px 16px 72px; }
19
+ .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); }
20
+ .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; }
21
+ .zlk-tab.on { background:#fff; color:#1c1e21; font-weight:650; box-shadow:0 1px 3px rgba(16,24,40,.14); }
22
+ .zlk-hint { margin:0 2px 12px; font-size:13px; line-height:1.65; color:#8b9098; }
23
+ .zlk-row { display:flex; gap:8px; align-items:center; margin-top:12px; flex-wrap:wrap; }
24
+ .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; }
25
+ .zlk-inp::placeholder { color:#c5c8ce; }
26
+ .zlk-inp:focus { border-color:#4f7cf7; box-shadow:0 0 0 3px rgba(79,124,247,.15); }
27
+ .zlk-ta { height:auto; min-height:88px; padding:10px 12px; resize:vertical; }
28
+ .zlk-search { flex:1; }
29
+ .zlk-btn { height:36px; padding:0 16px; border:0; border-radius:10px; background:#3478f6; color:#fff; font:600 14px/1 inherit; cursor:pointer; }
30
+ .zlk-btn:hover { background:#2d6ae0; }
31
+ .zlk-btn.gh { background:#fff; border:1px solid #e1e1e1; color:#3a3a3a; font-weight:500; }
32
+ .zlk-btn.gh:hover { background:#f7f7f7; }
33
+ .zlk-form { display:flex; flex-direction:column; gap:8px; margin-top:12px; }
34
+ .zlk-msg { margin-top:8px; font-size:12.5px; color:#8b9098; }
35
+ .zlk-msg.ok { color:#248a3d; }
36
+ .zlk-msg.err { color:#d64545; }
37
+ .zlk-it { display:flex; gap:10px; align-items:flex-start; padding:8px 2px 14px; }
38
+ .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; }
39
+ .zlk-gr { flex:1; min-width:0; }
40
+ .zlk-top { display:flex; align-items:flex-start; gap:10px; }
41
+ .zlk-title { flex:1; min-width:0; font-size:15px; font-weight:650; line-height:1.45; color:#222; word-break:break-word; }
42
+ .zlk-title.link { cursor:pointer; }
43
+ .zlk-meta { margin-top:6px; font-size:13px; line-height:1.4; color:#9aa0a6; }
44
+ .zlk-acts { display:flex; flex-direction:column; gap:8px; flex:0 0 auto; }
45
+ .zlk-acts.row { flex-direction:row; flex-wrap:wrap; justify-content:flex-end; }
46
+ .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; }
47
+ .zlk-mini:hover { background:#f7f7f7; }
48
+ .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; }
49
+ .zlk-empty { margin-top:12px; padding:18px 14px; border:1.5px dashed #cfd3d8; border-radius:12px; background:#f7f8fa; color:#4f7cf7; cursor:pointer; }
50
+ .zlk-empty b { display:block; font-size:14px; }
51
+ .zlk-empty span { display:block; margin-top:4px; font-size:12px; color:#8b9098; font-weight:400; }
52
+ .zlk-file { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); }
53
+ .zlk-bc { font-size:13px; margin:2px 0 4px; color:#4b5563; }
54
+ .zlk-bc .lk { color:#3478f6; cursor:pointer; }
55
+ .zlk-drop { margin-top:12px; border:1.5px dashed #cfd3d8; border-radius:12px; background:#f7f8fa; text-align:center; padding:14px 10px; }
56
+ .zlk-drop.on { border-color:#3478f6; background:#f3f7ff; }
57
+ .zlk-drop b { display:block; color:#3478f6; font-size:14px; }
58
+ .zlk-drop span { display:block; margin-top:4px; font-size:12px; color:#8b9098; }
59
+ .zlk-pick { margin-top:12px; padding:12px; border-radius:12px; background:#fff; border:1px solid #e6e6e6; }
60
+ `;
61
+
62
+ function ensureCss() {
63
+ if (typeof document === "undefined") return;
64
+ if (document.getElementById("library-plugin-css")) return;
65
+ var st = document.createElement("style");
66
+ st.id = "library-plugin-css";
67
+ st.textContent = ZLK_CSS;
68
+ (document.head || document.documentElement).appendChild(st);
69
+ }
70
+
71
+ function h(type, props) {
72
+ var args = [type, props];
73
+ for (var i = 2; i < arguments.length; i++) args.push(arguments[i]);
74
+ return React.createElement.apply(React, args);
75
+ }
76
+
77
+ function svg(size) {
78
+ var props = {
79
+ viewBox: "0 0 24 24", width: size, height: size, fill: "none", stroke: "currentColor",
80
+ strokeWidth: 1.7, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true",
81
+ };
82
+ var args = ["svg", props];
83
+ for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
84
+ return h.apply(null, args);
85
+ }
86
+
87
+ function iconFolder(size) {
88
+ 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" }));
89
+ }
90
+
91
+ function measureFv() {
92
+ var left = 0;
93
+ try {
94
+ if (!(window.matchMedia && window.matchMedia("(max-width: 820px)").matches)) {
95
+ var sc = document.querySelector('[class*="sidebarCol"]');
96
+ if (sc) {
97
+ var r = sc.getBoundingClientRect();
98
+ if (r && r.right > 40 && r.right < window.innerWidth * 0.6) left = Math.round(r.right);
99
+ }
100
+ }
101
+ document.documentElement.style.setProperty("--zlk-fv-left", left + "px");
102
+ } catch (e) { /* ignore */ }
103
+ }
104
+
105
+ function notifyFv(id) {
106
+ try { window.dispatchEvent(new CustomEvent("desk-fv", { detail: { id: id } })); } catch (e) { /* ignore */ }
107
+ }
108
+
109
+ function deskLang() {
110
+ try {
111
+ var lang = (document.documentElement && document.documentElement.lang) || (navigator.language || "zh");
112
+ return String(lang).toLowerCase().indexOf("en") === 0 ? "en" : "zh";
113
+ } catch (e) { return "zh"; }
114
+ }
115
+
116
+ function formatSize(n) {
117
+ n = Number(n) || 0;
118
+ if (n < 1024) return n + " B";
119
+ if (n < 1048576) return (n / 1024).toFixed(n < 10240 ? 1 : 0) + " KB";
120
+ return (n / 1048576).toFixed(1) + " MB";
121
+ }
122
+
123
+ function formatWhen(value) {
124
+ var m = /^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2})/.exec(String(value || ""));
125
+ if (m) return m[1] + " " + m[2];
126
+ return String(value || "");
127
+ }
128
+
129
+ function joinPath(dir, name) {
130
+ return dir ? dir + "/" + name : name;
131
+ }
132
+
133
+ function LibraryPanel(props) {
134
+ var wide = !!(props && props.wide);
135
+ var openPair = React.useState(false);
136
+ var open = openPair[0];
137
+ var setOpen = openPair[1];
138
+ var tabPair = React.useState("notes");
139
+ var tab = tabPair[0];
140
+ var setTab = tabPair[1];
141
+ var fsPair = React.useState({ phase: "idle", path: "", entries: [], message: "", newFolder: false, pick: null, drag: false });
142
+ var fs = fsPair[0];
143
+ var setFs = fsPair[1];
144
+ var nsPair = React.useState({ phase: "idle", role: "member", notes: [], q: "", hits: [], message: "", expanded: "", content: "", composing: false });
145
+ var ns = nsPair[0];
146
+ var setNs = nsPair[1];
147
+ var apiRef = React.useRef(null);
148
+ var idRef = React.useRef("");
149
+ var openRef = React.useRef(false);
150
+ var fileRef = React.useRef(null);
151
+ var qRef = React.useRef(null);
152
+ var titleRef = React.useRef(null);
153
+ var bodyRef = React.useRef(null);
154
+ var folderRef = React.useRef(null);
155
+ var pathRef = React.useRef("");
156
+ if (!idRef.current) idRef.current = "ziliaoku-" + (++ZLK_SEQ);
157
+ if (!apiRef.current) apiRef.current = createPortalApi(function () { return window.fetch.bind(window); });
158
+ openRef.current = open;
159
+ pathRef.current = fs.path;
160
+
161
+ function patchFs(p) { setFs(function (prev) { return Object.assign({}, prev, p); }); }
162
+ function patchNs(p) { setNs(function (prev) { return Object.assign({}, prev, p); }); }
163
+
164
+ function loadFiles(path) {
165
+ var p = String(path == null ? "" : path);
166
+ patchFs({ phase: "loading", path: p, entries: [], message: "", pick: null, newFolder: false });
167
+ apiRef.current.listDrive(p).then(function (d) {
168
+ patchFs({ phase: "ready", path: d.path != null ? d.path : p, entries: d.entries || [], message: "" });
169
+ }).catch(function (e) {
170
+ patchFs({ phase: "error", message: portalErrorText(e) });
171
+ });
172
+ }
173
+
174
+ function loadNotes() {
175
+ patchNs({ phase: "loading", message: "" });
176
+ apiRef.current.listNotes().then(function (d) {
177
+ patchNs({ phase: "ready", role: d.role || "member", notes: d.notes || [], message: "", tone: "" });
178
+ }).catch(function (e) {
179
+ patchNs({ phase: "error", tone: "err", message: portalErrorText(e) });
180
+ });
181
+ }
182
+
183
+ React.useEffect(function () {
184
+ function onFv(e) {
185
+ var who = e && e.detail ? e.detail.id : null;
186
+ if (who !== idRef.current) setOpen(false);
187
+ }
188
+ function onKey(e) { if (e.key === "Escape" && openRef.current) setOpen(false); }
189
+ function onDown(e) {
190
+ if (!openRef.current) return;
191
+ var t = e.target;
192
+ if (t && t.closest && (t.closest(".zlk-fv") || t.closest(".zlk-nav"))) return;
193
+ setOpen(false);
194
+ }
195
+ window.addEventListener("desk-fv", onFv);
196
+ document.addEventListener("keydown", onKey);
197
+ document.addEventListener("pointerdown", onDown, true);
198
+ return function () {
199
+ window.removeEventListener("desk-fv", onFv);
200
+ document.removeEventListener("keydown", onKey);
201
+ document.removeEventListener("pointerdown", onDown, true);
202
+ };
203
+ }, []);
204
+
205
+ React.useEffect(function () {
206
+ if (!open) return;
207
+ measureFv();
208
+ notifyFv(idRef.current);
209
+ loadFiles("");
210
+ loadNotes();
211
+ }, [open]);
212
+
213
+ function toggle() { setOpen(function (v) { return !v; }); }
214
+ function close() { setOpen(false); }
215
+
216
+ function uploadFiles(list) {
217
+ var files = [];
218
+ if (list) for (var i = 0; i < list.length; i++) files.push(list[i]);
219
+ var cursor = 0;
220
+ function next() {
221
+ if (cursor >= files.length) { loadFiles(pathRef.current); return; }
222
+ var f = files[cursor++];
223
+ if (f.size > MAX_UPLOAD) {
224
+ patchFs({ message: "上传失败:" + f.name + " 超过 50MB" });
225
+ next();
226
+ return;
227
+ }
228
+ patchFs({ message: "上传中:" + f.name + " …" });
229
+ apiRef.current.upload(pathRef.current, f).then(next).catch(function (e) {
230
+ patchFs({ message: "上传失败:" + portalErrorText(e) });
231
+ });
232
+ }
233
+ if (files.length) next();
234
+ }
235
+
236
+ function createFolder() {
237
+ var name = folderRef.current ? String(folderRef.current.value || "").trim() : "";
238
+ if (!name) { if (folderRef.current) folderRef.current.focus(); return; }
239
+ apiRef.current.mkdir(fs.path, name).then(function () { loadFiles(fs.path); }).catch(function (e) {
240
+ patchFs({ message: portalErrorText(e) });
241
+ });
242
+ }
243
+
244
+ function removeEntry(full, isDir) {
245
+ var label = (isDir ? "删除文件夹「" : "删除文件「") + full.split("/").pop() + "」?此操作不可恢复。";
246
+ if (window.confirm && !window.confirm(label)) return;
247
+ apiRef.current.rm(full).then(function () { loadFiles(fs.path); }).catch(function (e) {
248
+ patchFs({ message: portalErrorText(e) });
249
+ });
250
+ }
251
+
252
+ function openPicker(name) {
253
+ patchFs({ pick: { name: name, path: "", entries: [] } });
254
+ apiRef.current.listDrive("").then(function (d) {
255
+ patchFs({ pick: { name: name, path: d.path != null ? d.path : "", entries: d.entries || [] } });
256
+ }).catch(function (e) { patchFs({ message: portalErrorText(e), pick: null }); });
257
+ }
258
+
259
+ function pickerGo(path) {
260
+ apiRef.current.listDrive(path).then(function (d) {
261
+ setFs(function (prev) {
262
+ var pick = prev.pick || { name: "" };
263
+ return Object.assign({}, prev, { pick: { name: pick.name, path: d.path != null ? d.path : path, entries: d.entries || [] } });
264
+ });
265
+ }).catch(function (e) { patchFs({ message: portalErrorText(e) }); });
266
+ }
267
+
268
+ function moveHere() {
269
+ if (!fs.pick) return;
270
+ var from = joinPath(fs.path, fs.pick.name);
271
+ apiRef.current.mv(from, fs.pick.path).then(function () { loadFiles(fs.path); }).catch(function (e) {
272
+ patchFs({ message: portalErrorText(e) });
273
+ });
274
+ }
275
+
276
+ function runSearch() {
277
+ var q = qRef.current ? String(qRef.current.value || "").trim() : "";
278
+ if (!q) { patchNs({ q: "", hits: [] }); return; }
279
+ apiRef.current.searchNotes(q).then(function (d) {
280
+ patchNs({ q: q, hits: (d && d.hits) || [], message: "" });
281
+ }).catch(function (e) { patchNs({ message: portalErrorText(e) }); });
282
+ }
283
+
284
+ function saveNote() {
285
+ var title = titleRef.current ? String(titleRef.current.value || "").trim() : "";
286
+ var body = bodyRef.current ? String(bodyRef.current.value || "").trim() : "";
287
+ if (!body) { if (bodyRef.current) bodyRef.current.focus(); return; }
288
+ if (!title) title = body.split("\n")[0].slice(0, 36);
289
+ apiRef.current.saveNote({ title: title, content: body }, deskLang()).then(function () {
290
+ if (qRef.current) qRef.current.value = "";
291
+ return apiRef.current.listNotes();
292
+ }).then(function (d) {
293
+ patchNs({ phase: "ready", role: (d && d.role) || "member", notes: (d && d.notes) || [], composing: false, q: "", hits: [], message: "已记下 ✓", tone: "ok" });
294
+ }).catch(function (e) { patchNs({ message: portalErrorText(e), tone: "err" }); });
295
+ }
296
+
297
+ function toggleNote(name) {
298
+ if (ns.expanded === name) { patchNs({ expanded: "", content: "" }); return; }
299
+ patchNs({ expanded: name, content: "读取中…" });
300
+ apiRef.current.readNote(name).then(function (d) {
301
+ patchNs({ expanded: name, content: d && d.ok ? d.content : ((d && d.error) || "读取失败") });
302
+ }).catch(function (e) { patchNs({ expanded: name, content: portalErrorText(e) }); });
303
+ }
304
+
305
+ function deleteNote(name) {
306
+ if (window.confirm && !window.confirm("删除笔记:" + name + "?")) return;
307
+ apiRef.current.removeNote(name, deskLang()).then(function () {
308
+ patchNs({ expanded: "", content: "" });
309
+ loadNotes();
310
+ }).catch(function (e) { patchNs({ message: portalErrorText(e) }); });
311
+ }
312
+
313
+ var trigger = h("button", {
314
+ type: "button", className: "zlk-nav" + (open ? " on" : ""), onClick: toggle, title: "资料库", "data-zlk-open": "1",
315
+ }, h("span", { className: "ic" }, iconFolder(16)), wide ? h("span", { className: "lbl" }, "资料库") : null);
316
+ if (!open) return h("div", { "data-zlk-root": "1" }, trigger);
317
+
318
+ var bodyKids = [
319
+ h("div", { key: "tabs", className: "zlk-tabs" },
320
+ h("button", { type: "button", className: "zlk-tab" + (tab === "files" ? " on" : ""), "data-zlk-tab": "files", onClick: function () { setTab("files"); } }, "📁 文件"),
321
+ h("button", { type: "button", className: "zlk-tab" + (tab === "notes" ? " on" : ""), "data-zlk-tab": "notes", onClick: function () { setTab("notes"); } }, "📝 笔记")
322
+ ),
323
+ ];
324
+
325
+ if (tab === "files") {
326
+ bodyKids.push(h("div", { key: "hint", className: "zlk-hint" }, "放原始文件;按项目或客户建文件夹,找起来最快"));
327
+ var segs = String(fs.path || "").split("/").filter(Boolean);
328
+ var bc = [h("span", { key: "root", className: "lk", onClick: function () { loadFiles(""); } }, "🏠 根目录")];
329
+ var acc = "";
330
+ segs.forEach(function (seg, i) {
331
+ acc = acc ? acc + "/" + seg : seg;
332
+ var here = acc;
333
+ bc.push(h("span", { key: "s" + i }, " / "));
334
+ bc.push(h("span", { key: "c" + i, className: "lk", onClick: function () { loadFiles(here); } }, seg));
335
+ });
336
+ bodyKids.push(h("div", { key: "bc", className: "zlk-bc" }, bc));
337
+ bodyKids.push(h("div", { key: "bar", className: "zlk-row" },
338
+ h("button", { type: "button", className: "zlk-btn gh", "data-zlk-mkdir": "1", onClick: function () { patchFs({ newFolder: !fs.newFolder, pick: null }); } }, "+ 新建文件夹"),
339
+ h("button", { type: "button", className: "zlk-btn", "data-zlk-upload": "1", onClick: function () { if (fileRef.current) fileRef.current.click(); } }, "⬆ 上传"),
340
+ 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 = ""; } })
341
+ ));
342
+ if (fs.newFolder) {
343
+ bodyKids.push(h("div", { key: "nf", className: "zlk-row" },
344
+ 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(); } }),
345
+ h("button", { type: "button", className: "zlk-btn", "data-zlk-mkdir-save": "1", onClick: createFolder }, "创建"),
346
+ h("button", { type: "button", className: "zlk-btn gh", onClick: function () { patchFs({ newFolder: false }); } }, "取消")
347
+ ));
348
+ }
349
+ bodyKids.push(h("div", {
350
+ key: "drop",
351
+ className: "zlk-drop" + (fs.drag ? " on" : ""),
352
+ "data-zlk-drop": "1",
353
+ onDragOver: function (e) { e.preventDefault(); if (!fs.drag) patchFs({ drag: true }); },
354
+ onDragLeave: function () { patchFs({ drag: false }); },
355
+ onDrop: function (e) { e.preventDefault(); patchFs({ drag: false }); uploadFiles(e.dataTransfer && e.dataTransfer.files); },
356
+ }, h("b", null, "⬆ 拖文件到这里上传"), h("span", null, "上传到当前文件夹 · 单个 ≤50MB")));
357
+ if (fs.message) bodyKids.push(h("div", { key: "msg", className: "zlk-msg" + (fs.phase === "error" || fs.message.indexOf("失败") >= 0 ? " err" : "") }, fs.message));
358
+ if (fs.phase === "loading") bodyKids.push(h("div", { key: "ld", className: "zlk-hint" }, "读取中…"));
359
+ if (fs.pick) {
360
+ var pk = fs.pick;
361
+ var psegs = String(pk.path || "").split("/").filter(Boolean);
362
+ var pbc = [h("span", { key: "pr", className: "lk", onClick: function () { pickerGo(""); } }, "🏠 根目录")];
363
+ var pacc = "";
364
+ psegs.forEach(function (seg, i) {
365
+ pacc = pacc ? pacc + "/" + seg : seg;
366
+ var there = pacc;
367
+ pbc.push(h("span", { key: "ps" + i }, " / "));
368
+ pbc.push(h("span", { key: "pc" + i, className: "lk", onClick: function () { pickerGo(there); } }, seg));
369
+ });
370
+ var folders = (pk.entries || []).filter(function (en) { return en.dir; }).map(function (en) {
371
+ var next = joinPath(pk.path, en.name);
372
+ return h("div", { key: en.name, className: "zlk-it", onClick: function () { pickerGo(next); } },
373
+ h("span", { className: "zlk-ico" }, "📁"),
374
+ h("div", { className: "zlk-title link" }, en.name)
375
+ );
376
+ });
377
+ bodyKids.push(h("div", { key: "pick", className: "zlk-pick" },
378
+ h("div", { className: "zlk-hint" }, "把「" + pk.name + "」移动到:"),
379
+ h("div", { className: "zlk-bc" }, pbc),
380
+ folders.length ? h("div", null, folders) : h("div", { className: "zlk-hint" }, "(没有子文件夹,可直接「移到这里」)"),
381
+ h("div", { className: "zlk-row" },
382
+ h("button", { type: "button", className: "zlk-btn", "data-zlk-move-here": "1", onClick: moveHere }, "移到这里"),
383
+ h("button", { type: "button", className: "zlk-btn gh", onClick: function () { patchFs({ pick: null }); } }, "取消")
384
+ )
385
+ ));
386
+ }
387
+ var rootEmpty = !fs.path && !(fs.entries && fs.entries.length) && fs.phase !== "error";
388
+ (fs.entries || []).forEach(function (en) {
389
+ var full = joinPath(fs.path, en.name);
390
+ var acts = [];
391
+ if (en.dir) acts.push(h("button", { key: "o", type: "button", className: "zlk-mini", onClick: function () { loadFiles(full); } }, "打开"));
392
+ else acts.push(h("a", { key: "d", className: "zlk-mini", href: apiRef.current.downloadUrl(full) }, "下载"));
393
+ acts.push(h("button", { key: "m", type: "button", className: "zlk-mini", "data-zlk-move": en.name, onClick: function () { openPicker(en.name); } }, "移动到…"));
394
+ acts.push(h("button", { key: "x", type: "button", className: "zlk-mini", "data-zlk-del-file": en.name, onClick: function () { removeEntry(full, en.dir); } }, "删除"));
395
+ bodyKids.push(h("div", { key: "f-" + en.name, className: "zlk-it", "data-zlk-file": en.name },
396
+ h("span", { className: "zlk-ico" }, en.dir ? "📁" : "📄"),
397
+ h("div", { className: "zlk-gr" },
398
+ h("div", { className: "zlk-top" },
399
+ h("div", { className: "zlk-title" + (en.dir ? " link" : ""), onClick: en.dir ? function () { loadFiles(full); } : null }, en.name),
400
+ h("div", { className: "zlk-acts row" }, acts)
401
+ ),
402
+ h("div", { className: "zlk-meta" }, (en.dir ? "文件夹" : formatSize(en.size)) + (en.mtime ? " · " + formatWhen(en.mtime) : ""))
403
+ )
404
+ ));
405
+ });
406
+ if (rootEmpty) {
407
+ bodyKids.push(h("div", { key: "ea", className: "zlk-empty", onClick: function () { if (fileRef.current) fileRef.current.click(); } },
408
+ h("b", null, "① 建个文件夹,把文件传进来"), h("span", null, "比如「客户A」「2026报价」—— 拖进去就行")));
409
+ bodyKids.push(h("div", { key: "eb", className: "zlk-empty", onClick: function () { setTab("notes"); patchNs({ composing: true }); } },
410
+ h("b", null, "② 记第一条笔记"), h("span", null, "今天有什么结论?写一句话也算")));
411
+ }
412
+ } else {
413
+ bodyKids.push(h("div", { key: "hint", className: "zlk-hint" }, "记结论和经验,搜一下就能找到 —— AI 助理也能直接引用"));
414
+ bodyKids.push(h("div", { key: "search", className: "zlk-row" },
415
+ h("input", { ref: qRef, className: "zlk-inp zlk-search", "data-zlk-search": "1", placeholder: "搜笔记,比如「印尼」「定价」…", onKeyDown: function (e) { if (e.key === "Enter") runSearch(); } }),
416
+ h("button", { type: "button", className: "zlk-btn gh", "data-zlk-search-btn": "1", onClick: runSearch }, "搜索")
417
+ ));
418
+ bodyKids.push(h("div", { key: "compose", className: "zlk-row" },
419
+ h("button", { type: "button", className: "zlk-btn", "data-zlk-compose": "1", onClick: function () { patchNs({ composing: !ns.composing }); } }, "+ 记一条")
420
+ ));
421
+ if (ns.composing) {
422
+ bodyKids.push(h("div", { key: "form", className: "zlk-form" },
423
+ h("input", { ref: titleRef, className: "zlk-inp", "data-zlk-title": "1", placeholder: "标题(不填就用第一行)" }),
424
+ h("textarea", { ref: bodyRef, className: "zlk-inp zlk-ta", "data-zlk-body": "1", placeholder: "想到什么写什么…… 一句话也算" }),
425
+ h("div", { className: "zlk-row" },
426
+ h("button", { type: "button", className: "zlk-btn", "data-zlk-save": "1", onClick: saveNote }, "保存 ✓"),
427
+ h("button", { type: "button", className: "zlk-btn gh", onClick: function () { patchNs({ composing: false }); } }, "取消")
428
+ )
429
+ ));
430
+ }
431
+ if (ns.message) bodyKids.push(h("div", { key: "nm", className: "zlk-msg" + (ns.tone === "err" || ns.phase === "error" ? " err" : " ok") }, ns.message));
432
+ if (ns.phase === "loading") bodyKids.push(h("div", { key: "ld", className: "zlk-hint" }, "读取中…"));
433
+ if (ns.q) {
434
+ bodyKids.push(h("div", { key: "hc", className: "zlk-hint" }, "命中 " + ns.hits.length));
435
+ if (!ns.hits.length) bodyKids.push(h("div", { key: "miss", className: "zlk-empty" }, h("b", null, "没有命中,换个短点的词试试")));
436
+ ns.hits.forEach(function (hit, i) {
437
+ bodyKids.push(h("div", { key: "h" + i, className: "zlk-it" },
438
+ h("span", { className: "zlk-ico" }, "🔎"),
439
+ h("div", { className: "zlk-gr" },
440
+ h("div", { className: "zlk-meta" }, hit.file + " : " + hit.line),
441
+ h("div", { className: "zlk-body" }, hit.text)
442
+ )
443
+ ));
444
+ });
445
+ bodyKids.push(h("div", { key: "back", className: "zlk-row" },
446
+ h("button", { type: "button", className: "zlk-btn gh", "data-zlk-back-list": "1", onClick: function () { if (qRef.current) qRef.current.value = ""; patchNs({ q: "", hits: [] }); } }, "返回笔记列表")
447
+ ));
448
+ } else if (ns.phase === "ready") {
449
+ if (!ns.notes.length) {
450
+ bodyKids.push(h("div", { key: "empty", className: "zlk-empty", onClick: function () { patchNs({ composing: true }); } },
451
+ h("b", null, "还没有笔记 —— 点「+ 记一条」写第一句"),
452
+ h("span", null, "结论、口径、经验,一句话也算")
453
+ ));
454
+ }
455
+ ns.notes.forEach(function (note) {
456
+ var shown = ns.expanded === note.name;
457
+ var acts = [h("button", { key: "v", type: "button", className: "zlk-mini", "data-zlk-view": note.name, onClick: function () { toggleNote(note.name); } }, shown ? "收起" : "查看")];
458
+ if (canDeleteNote(ns.role)) {
459
+ acts.push(h("button", { key: "x", type: "button", className: "zlk-mini", "data-zlk-del": note.name, onClick: function () { deleteNote(note.name); } }, "删除"));
460
+ }
461
+ bodyKids.push(h("div", { key: note.name, className: "zlk-it", "data-zlk-note": note.name },
462
+ h("span", { className: "zlk-ico" }, "📝"),
463
+ h("div", { className: "zlk-gr" },
464
+ h("div", { className: "zlk-top" },
465
+ h("div", { className: "zlk-title" }, note.title || note.name),
466
+ h("div", { className: "zlk-acts" }, acts)
467
+ ),
468
+ h("div", { className: "zlk-meta" }, formatWhen(note.mtime) + (note.author ? " · " + note.author : "")),
469
+ shown ? h("div", { className: "zlk-body" }, ns.content) : null
470
+ )
471
+ ));
472
+ });
473
+ }
474
+ }
475
+
476
+ return h("div", { "data-zlk-root": "1" },
477
+ trigger,
478
+ h("section", { className: "zlk-fv", "data-zlk-panel": "1" },
479
+ h("header", { className: "zlk-hd" },
480
+ h("span", { className: "zlk-mark" }, iconFolder(22)),
481
+ h("div", { className: "zlk-hd-text" },
482
+ h("div", { className: "zlk-t1" }, "资料库"),
483
+ h("div", { className: "zlk-t2" }, "文件 + 笔记 · 放进来 = 全员可见")
484
+ ),
485
+ h("button", { type: "button", className: "zlk-back", "data-zlk-back": "1", onClick: close }, "← 返回对话")
486
+ ),
487
+ h("div", { className: "zlk-bd" }, bodyKids)
488
+ )
489
+ );
490
+ }
491
+
492
+ function apply(ctx) {
493
+ ctx.slots.inject("sidebar.footer.action", function () {
494
+ return ctx.slots.register(
495
+ {
496
+ name: "sidebar.footer.action",
497
+ id: "ziliaoku",
498
+ order: 91,
499
+ label: function () { return "资料库"; },
500
+ },
501
+ LibraryPanel
502
+ );
503
+ });
504
+ }
505
+
506
+ ensureCss();
package/package.json CHANGED
@@ -1,6 +1,52 @@
1
- {
2
- "name": "anywork-library-plugin",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
1
+ {
2
+ "name": "anywork-library-plugin",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "description": "资料库:文件 + 笔记(DSH Web 插件)",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "engines": {
9
+ "node": ">=20",
10
+ "dsh": ">=0.2.1-rc.3 <0.3.0"
11
+ },
12
+ "main": "lib/index.js",
13
+ "exports": {
14
+ ".": "./lib/index.js",
15
+ "./client": "./lib/client.js",
16
+ "./cordis.patch.yml": "./cordis.patch.yml",
17
+ "./icon": "./icon.svg",
18
+ "./package.json": "./package.json"
19
+ },
20
+ "files": [
21
+ "lib/index.js",
22
+ "lib/client.js",
23
+ "lib/api.js",
24
+ "lib/panel.js",
25
+ "cordis.patch.yml",
26
+ "icon.svg",
27
+ "README.md"
28
+ ],
29
+ "peerDependencies": {
30
+ "@deepseek-ai/cordis": "^4.0.1"
31
+ },
32
+ "dsh": {
33
+ "bundle": {
34
+ "patch": "./cordis.patch.yml"
35
+ },
36
+ "client": {
37
+ "inject": [
38
+ "@deepseek-ai/dsh-client-ui-slots",
39
+ "@deepseek-ai/dsh-client-ui-sidebar"
40
+ ],
41
+ "platform": "web"
42
+ }
43
+ },
44
+ "scripts": {
45
+ "assemble": "node scripts/assemble.mjs",
46
+ "test": "node scripts/assemble.mjs --check && node --test"
47
+ },
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://github.com/TokenAI-Beta/library-plugin.git"
51
+ }
52
+ }