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/README.md +36 -3
- package/cordis.patch.yml +7 -0
- package/icon.svg +3 -0
- package/lib/api.js +110 -0
- package/lib/client.js +632 -0
- package/lib/index.js +8 -0
- package/lib/panel.js +506 -0
- package/package.json +52 -6
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.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
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
|
+
}
|