dsh-worktodo 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/client.js ADDED
@@ -0,0 +1,987 @@
1
+ window.__ModuleLoader__.load({ id: "dsh-worktodo", factory: (require) => {
2
+ var module = { exports: {} }; var exports = module.exports;
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/client/index.js
32
+ var index_exports = {};
33
+ __export(index_exports, {
34
+ apply: () => apply,
35
+ inject: () => inject
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+ var import_react = __toESM(require("react"), 1);
39
+ var PKG_NAME = true ? "dsh-worktodo" : "dsh-worktodo";
40
+ var DERIVED_NAME = PKG_NAME.replace(/^dsh-/, "");
41
+ var SHORT_NAME = DERIVED_NAME === "worktodo" ? DERIVED_NAME : "worktodo";
42
+ var SLOT_ID = SHORT_NAME;
43
+ var ROUTE_BASE = `/${SHORT_NAME}`;
44
+ var LOCALE_NS = SHORT_NAME;
45
+ var ROUTE_LIST = `${ROUTE_BASE}/list`;
46
+ var zh = {
47
+ "nav": "\u5F85\u529E",
48
+ "title": "\u5DE5\u4F5C\u5F85\u529E",
49
+ "statOpen": "\u672A\u5B8C\u6210",
50
+ "statOverdue": "\u903E\u671F",
51
+ "statToday": "\u4ECA\u5929",
52
+ "statDoing": "\u8FDB\u884C\u4E2D",
53
+ "statDoneToday": "\u4ECA\u65E5\u5B8C\u6210",
54
+ "refresh": "\u5237\u65B0",
55
+ "loading": "\u8BFB\u53D6\u5F85\u529E\u2026",
56
+ "failed": "\u8BFB\u53D6\u5931\u8D25",
57
+ "retry": "\u91CD\u8BD5",
58
+ "dismiss": "\u5173\u95ED",
59
+ "storeAt": "\u5B58\u50A8\u4F4D\u7F6E",
60
+ "storeDomain": "\u5B98\u65B9 storage",
61
+ "storeFile": "JSON \u6587\u4EF6",
62
+ "addPlaceholder": "\u52A0\u4E00\u4EF6\u8981\u505A\u7684\u4E8B\uFF0C\u56DE\u8F66\u4FDD\u5B58",
63
+ "add": "\u6DFB\u52A0",
64
+ "dueLabel": "\u622A\u6B62",
65
+ "priorityLabel": "\u4F18\u5148\u7EA7",
66
+ "prioHigh": "\u9AD8",
67
+ "prioNormal": "\u666E\u901A",
68
+ "prioLow": "\u4F4E",
69
+ "groupOverdue": "\u903E\u671F",
70
+ "groupToday": "\u4ECA\u5929",
71
+ "groupWeek": "\u672C\u5468",
72
+ "groupLater": "\u4EE5\u540E",
73
+ "groupCompleted": "\u5DF2\u5B8C\u6210",
74
+ "expand": "\u5C55\u5F00",
75
+ "collapse": "\u6536\u8D77",
76
+ "empty": "\u8FD8\u6CA1\u6709\u5F85\u529E",
77
+ "emptyHint": "\u5728\u4E0A\u9762\u8F93\u5165\u6846\u52A0\u7B2C\u4E00\u4EF6\u4E8B",
78
+ "overdueTag": "\u903E\u671F",
79
+ "sourceAgent": "AI",
80
+ "sourceSession": "\u4F1A\u8BDD",
81
+ "markDone": "\u6807\u4E3A\u5B8C\u6210",
82
+ "unmarkDone": "\u53D6\u6D88\u5B8C\u6210",
83
+ "editHint": "\u70B9\u51FB\u6807\u9898\u53EF\u7F16\u8F91",
84
+ "deleteBtn": "\u5220\u9664",
85
+ "confirmDelete": "\u786E\u8BA4\u5220\u9664\uFF1F",
86
+ "save": "\u4FDD\u5B58",
87
+ "cancel": "\u53D6\u6D88",
88
+ "projectLabel": "\u9879\u76EE",
89
+ "projectPlaceholder": "\u9879\u76EE\u540D\uFF08\u53EF\u9009\uFF09",
90
+ "titlePlaceholder": "\u5F85\u529E\u6807\u9898",
91
+ "notesLabel": "\u5907\u6CE8",
92
+ "notesPlaceholder": "\u5907\u6CE8\uFF08\u53EF\u9009\uFF09",
93
+ "notesAdd": "\u52A0\u5907\u6CE8",
94
+ "notesHide": "\u6536\u8D77\u5907\u6CE8",
95
+ "adoptPre": "\u628A\u672C\u4F1A\u8BDD\u7684",
96
+ "adoptPost": "\u6761\u5F85\u529E\u63D0\u5347\u4E3A\u5DE5\u4F5C\u5F85\u529E",
97
+ "adoptHint": "\u8FD9\u662F\u6A21\u578B\u5728\u672C\u4F1A\u8BDD\u91CC\u5217\u7684\u5F85\u529E\u3002\u63D0\u5347\u540E\u5F52\u4F60\u6240\u6709\uFF1A\u8DE8\u4F1A\u8BDD\u4FDD\u7559\uFF0C\u8FD8\u80FD\u52A0\u4F18\u5148\u7EA7\u548C\u622A\u6B62\u65E5\u671F\u3002",
98
+ "adoptPending": "\u5F85\u5B8C\u6210",
99
+ "adoptDone": "\u5DF2\u63D0\u5347",
100
+ "adoptSkipped": "\u8DF3\u8FC7",
101
+ "titleEmpty": "\u8BF7\u5148\u5199\u70B9\u4EC0\u4E48",
102
+ "untitled": "\uFF08\u65E0\u6807\u9898\uFF09"
103
+ };
104
+ var en = {
105
+ "nav": "To-dos",
106
+ "title": "Work to-dos",
107
+ "statOpen": "Open",
108
+ "statOverdue": "Overdue",
109
+ "statToday": "Today",
110
+ "statDoing": "In progress",
111
+ "statDoneToday": "Done today",
112
+ "refresh": "Refresh",
113
+ "loading": "Loading to-dos\u2026",
114
+ "failed": "Failed to load",
115
+ "retry": "Retry",
116
+ "dismiss": "Dismiss",
117
+ "storeAt": "Stored at",
118
+ "storeDomain": "official storage",
119
+ "storeFile": "JSON file",
120
+ "addPlaceholder": "Add something to do \u2014 Enter saves",
121
+ "add": "Add",
122
+ "dueLabel": "Due",
123
+ "priorityLabel": "Priority",
124
+ "prioHigh": "High",
125
+ "prioNormal": "Normal",
126
+ "prioLow": "Low",
127
+ "groupOverdue": "Overdue",
128
+ "groupToday": "Today",
129
+ "groupWeek": "This week",
130
+ "groupLater": "Later",
131
+ "groupCompleted": "Completed",
132
+ "expand": "Expand",
133
+ "collapse": "Collapse",
134
+ "empty": "No to-dos yet",
135
+ "emptyHint": "Add your first one in the box above",
136
+ "overdueTag": "overdue",
137
+ "sourceAgent": "AI",
138
+ "sourceSession": "Session",
139
+ "markDone": "Mark as done",
140
+ "unmarkDone": "Mark as not done",
141
+ "editHint": "Click the title to edit",
142
+ "deleteBtn": "Delete",
143
+ "confirmDelete": "Delete?",
144
+ "save": "Save",
145
+ "cancel": "Cancel",
146
+ "projectLabel": "Project",
147
+ "projectPlaceholder": "project (optional)",
148
+ "titlePlaceholder": "To-do title",
149
+ "notesLabel": "Notes",
150
+ "notesPlaceholder": "Notes (optional)",
151
+ "notesAdd": "Add notes",
152
+ "notesHide": "Hide notes",
153
+ "adoptPre": "Promote this session's ",
154
+ "adoptPost": " to-dos into your work list",
155
+ "adoptHint": "These are the to-dos the model listed in this session. Promoting makes them yours: they survive across sessions and take priorities and due dates.",
156
+ "adoptPending": "open",
157
+ "adoptDone": "Promoted",
158
+ "adoptSkipped": "skipped",
159
+ "titleEmpty": "Type something first",
160
+ "untitled": "(untitled)"
161
+ };
162
+ var C = {
163
+ label: "var(--dsw-alias-label-primary)",
164
+ label2: "var(--dsw-alias-label-secondary)",
165
+ label3: "var(--dsw-alias-label-tertiary)",
166
+ border: "var(--dsw-alias-border-l2)",
167
+ border1: "var(--dsw-alias-border-l1)",
168
+ layer1: "var(--dsw-alias-bg-layer-1)",
169
+ hover: "var(--dsw-alias-interactive-bg-hover)",
170
+ brand: "var(--dsw-alias-brand-primary)",
171
+ warn: "var(--dsw-alias-state-warn-primary)",
172
+ error: "var(--dsw-alias-state-error-primary)",
173
+ ok: "var(--dsw-alias-state-success-primary)"
174
+ };
175
+ var tint = (color, pct) => `color-mix(in srgb, ${color} ${pct}%, transparent)`;
176
+ var STYLE_TEXT = `
177
+ @keyframes wt-spin { to { transform: rotate(360deg); } }
178
+ .wt-root {
179
+ height: 100%; overflow: auto; padding: 16px 18px 40px; box-sizing: border-box;
180
+ color: ${C.label}; font-family: var(--dsw-font-family, system-ui, sans-serif); font-size: 13px;
181
+ }
182
+ .wt-input {
183
+ min-width: 0; font-family: inherit; font-size: 12px; line-height: 1.5; padding: 4px 8px;
184
+ border-radius: 8px; border: 1px solid ${C.border}; background: transparent; color: ${C.label};
185
+ color-scheme: light dark;
186
+ }
187
+ .wt-input::placeholder { color: ${C.label3}; }
188
+ .wt-input:focus {
189
+ outline: none; border-color: ${C.brand};
190
+ box-shadow: 0 0 0 2px ${tint(C.brand, 22)};
191
+ }
192
+ .wt-btn {
193
+ display: inline-flex; align-items: center; gap: 4px; font-family: inherit; font-size: 12px;
194
+ line-height: 1.6; padding: 3px 10px; border-radius: 8px; cursor: pointer; user-select: none;
195
+ border: 1px solid ${C.border}; background: transparent; color: ${C.label2}; white-space: nowrap;
196
+ }
197
+ .wt-btn:hover { background: ${C.hover}; color: ${C.label}; }
198
+ .wt-btn:disabled { opacity: .55; cursor: default; }
199
+ .wt-btn:disabled:hover { background: transparent; color: ${C.label2}; }
200
+ .wt-btn-primary {
201
+ border-color: ${tint(C.brand, 50)}; color: ${C.brand}; background: ${tint(C.brand, 10)};
202
+ }
203
+ .wt-btn-primary:hover { background: ${tint(C.brand, 18)}; color: ${C.brand}; }
204
+ .wt-btn-primary:disabled:hover { background: ${tint(C.brand, 10)}; color: ${C.brand}; }
205
+ .wt-btn-danger { color: ${C.error}; border-color: ${tint(C.error, 45)}; }
206
+ .wt-btn-danger:hover { background: var(--dsw-alias-interactive-bg-hover-danger); color: ${C.error}; }
207
+ .wt-icon-btn {
208
+ display: inline-flex; align-items: center; justify-content: center; flex: none;
209
+ width: 22px; height: 22px; padding: 0; border: none; border-radius: 6px;
210
+ background: transparent; color: ${C.label3}; cursor: pointer;
211
+ }
212
+ .wt-icon-btn:hover { background: ${C.hover}; color: ${C.label}; }
213
+ .wt-icon-btn-danger:hover { background: var(--dsw-alias-interactive-bg-hover-danger); color: ${C.error}; }
214
+ .wt-check {
215
+ display: inline-flex; align-items: center; justify-content: center; flex: none;
216
+ width: 17px; height: 17px; margin-top: 1px; padding: 0; border-radius: 5px;
217
+ border: 1px solid ${C.border}; background: transparent; color: transparent; cursor: pointer;
218
+ }
219
+ .wt-check:hover { border-color: ${C.brand}; }
220
+ .wt-check-done {
221
+ border-color: ${tint(C.ok, 55)}; background: ${tint(C.ok, 14)}; color: ${C.ok};
222
+ }
223
+ .wt-row { display: flex; align-items: flex-start; gap: 8px; padding: 5px 8px; border-radius: 10px; }
224
+ .wt-row:hover { background: ${C.hover}; }
225
+ .wt-row-edit {
226
+ flex-direction: column; align-items: stretch; gap: 6px;
227
+ border: 1px solid ${C.border1}; background: ${C.layer1};
228
+ }
229
+ .wt-group-head {
230
+ display: flex; align-items: center; gap: 7px; padding: 3px 8px; border-radius: 8px;
231
+ cursor: pointer; user-select: none; color: ${C.label2};
232
+ }
233
+ .wt-group-head:hover { background: ${C.hover}; }
234
+ .wt-chip {
235
+ display: inline-flex; align-items: baseline; gap: 4px; font-size: 11px; line-height: 1.7;
236
+ padding: 0 8px; border-radius: 999px; border: 1px solid ${C.border1}; color: ${C.label3};
237
+ white-space: nowrap;
238
+ }
239
+ .wt-tag {
240
+ display: inline-flex; align-items: center; gap: 3px; font-size: 10.5px; line-height: 1.6;
241
+ padding: 0 6px; border-radius: 999px; border: 1px solid ${C.border1}; color: ${C.label3};
242
+ white-space: nowrap;
243
+ }
244
+ .wt-link { cursor: pointer; user-select: none; color: var(--dsw-alias-link); font-size: 11px; }
245
+ .wt-link:hover { text-decoration: underline; }
246
+ .wt-title { cursor: pointer; word-break: break-word; }
247
+ .wt-title:hover { text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 3px; }
248
+ .wt-spin {
249
+ display: inline-block; width: 12px; height: 12px; border-radius: 50%;
250
+ border: 2px solid ${C.border}; border-top-color: ${C.brand}; animation: wt-spin .8s linear infinite;
251
+ }
252
+ `;
253
+ function WorkTodoIcon({ size = 16, active }) {
254
+ return import_react.default.createElement("svg", {
255
+ width: size,
256
+ height: size,
257
+ viewBox: "0 0 16 16",
258
+ fill: "none",
259
+ stroke: "currentColor",
260
+ strokeWidth: 1.3,
261
+ strokeLinecap: "round",
262
+ strokeLinejoin: "round",
263
+ style: { opacity: active ? 1 : 0.82 }
264
+ }, [
265
+ import_react.default.createElement("rect", { key: "a", x: "2.7", y: "3.1", width: "10.6", height: "10.4", rx: "2" }),
266
+ import_react.default.createElement("path", { key: "b", d: "M5.6 1.7h4.8v2.7H5.6z" }),
267
+ import_react.default.createElement("path", { key: "c", d: "M5.7 9.3l1.7 1.7 3.1-3.5" })
268
+ ]);
269
+ }
270
+ function IconCheck({ size = 11 }) {
271
+ return import_react.default.createElement("svg", {
272
+ width: size,
273
+ height: size,
274
+ viewBox: "0 0 12 12",
275
+ fill: "none",
276
+ stroke: "currentColor",
277
+ strokeWidth: 2,
278
+ strokeLinecap: "round",
279
+ strokeLinejoin: "round"
280
+ }, import_react.default.createElement("path", { d: "M2 6.3 4.6 8.9 10 3.1" }));
281
+ }
282
+ function IconChevron({ open, size = 10 }) {
283
+ return import_react.default.createElement("svg", {
284
+ width: size,
285
+ height: size,
286
+ viewBox: "0 0 14 14",
287
+ fill: "none",
288
+ stroke: "currentColor",
289
+ strokeWidth: 1.8,
290
+ strokeLinecap: "round",
291
+ strokeLinejoin: "round",
292
+ // 收起时把「向下」的箭头转成「向右」:比画两个图标便宜,也不会因为尺寸不同而跳一下
293
+ style: { flex: "none", transform: open ? "none" : "rotate(-90deg)", transition: "transform .15s ease" }
294
+ }, import_react.default.createElement("path", { d: "m3.4 5.2 3.6 3.6 3.6-3.6" }));
295
+ }
296
+ function IconTrash({ size = 13 }) {
297
+ return import_react.default.createElement("svg", {
298
+ width: size,
299
+ height: size,
300
+ viewBox: "0 0 16 16",
301
+ fill: "none",
302
+ stroke: "currentColor",
303
+ strokeWidth: 1.3,
304
+ strokeLinecap: "round",
305
+ strokeLinejoin: "round"
306
+ }, [
307
+ import_react.default.createElement("path", { key: "a", d: "M2.8 4.4h10.4" }),
308
+ import_react.default.createElement("path", { key: "b", d: "M6.4 4.4V2.9h3.2v1.5" }),
309
+ import_react.default.createElement("path", { key: "c", d: "M4.5 4.4l.7 8.4h5.6l.7-8.4" }),
310
+ import_react.default.createElement("path", { key: "d", d: "M6.9 6.8v3.9M9.1 6.8v3.9" })
311
+ ]);
312
+ }
313
+ function IconClose({ size = 11 }) {
314
+ return import_react.default.createElement("svg", {
315
+ width: size,
316
+ height: size,
317
+ viewBox: "0 0 12 12",
318
+ fill: "none",
319
+ stroke: "currentColor",
320
+ strokeWidth: 1.6,
321
+ strokeLinecap: "round"
322
+ }, [
323
+ import_react.default.createElement("path", { key: "a", d: "M3 3l6 6" }),
324
+ import_react.default.createElement("path", { key: "b", d: "M9 3l-6 6" })
325
+ ]);
326
+ }
327
+ function IconRefresh({ size = 12 }) {
328
+ return import_react.default.createElement("svg", {
329
+ width: size,
330
+ height: size,
331
+ viewBox: "0 0 16 16",
332
+ fill: "none",
333
+ stroke: "currentColor",
334
+ strokeWidth: 1.4,
335
+ strokeLinecap: "round",
336
+ strokeLinejoin: "round"
337
+ }, [
338
+ import_react.default.createElement("path", { key: "a", d: "M2.6 8a5.4 5.4 0 0 1 9.1-3.9" }),
339
+ import_react.default.createElement("path", { key: "b", d: "M13.4 8a5.4 5.4 0 0 1-9.1 3.9" }),
340
+ import_react.default.createElement("path", { key: "c", d: "M12.3 1.9v2.6H9.7" }),
341
+ import_react.default.createElement("path", { key: "d", d: "M3.7 14.1v-2.6h2.6" })
342
+ ]);
343
+ }
344
+ function localToday() {
345
+ const d = /* @__PURE__ */ new Date();
346
+ const pad = (n) => String(n).padStart(2, "0");
347
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
348
+ }
349
+ var asArray = (value) => Array.isArray(value) ? value : [];
350
+ async function postJson(path, body) {
351
+ const response = await fetch(`${ROUTE_BASE}${path}`, {
352
+ method: "POST",
353
+ headers: { "content-type": "application/json" },
354
+ cache: "no-store",
355
+ credentials: "same-origin",
356
+ body: JSON.stringify(body ?? {})
357
+ });
358
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
359
+ const parsed = await response.json().catch(() => null);
360
+ if (!parsed) throw new Error("\u54CD\u5E94\u4E0D\u662F JSON");
361
+ if (!parsed.ok) throw new Error(parsed.error ?? parsed.reason ?? "\u672A\u77E5\u9519\u8BEF");
362
+ return parsed.data ?? {};
363
+ }
364
+ var lastList = null;
365
+ function useList() {
366
+ const [state, setState] = import_react.default.useState(() => lastList ? { status: "ready", data: lastList, error: null } : { status: "loading", data: null, error: null });
367
+ const [tick, setTick] = import_react.default.useState(0);
368
+ import_react.default.useEffect(() => {
369
+ let alive = true;
370
+ fetch(`${ROUTE_LIST}?filter=all`, { cache: "no-store", credentials: "same-origin" }).then(async (response) => {
371
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
372
+ const body = await response.json().catch(() => null);
373
+ if (!body?.ok) throw new Error(body?.error ?? body?.reason ?? "\u672A\u77E5\u9519\u8BEF");
374
+ lastList = body.data;
375
+ if (alive) setState({ status: "ready", data: body.data, error: null });
376
+ }).catch((error) => {
377
+ if (alive) {
378
+ setState((prev) => ({
379
+ ...prev,
380
+ status: prev.data ? "ready" : "failed",
381
+ error: String(error?.message ?? error)
382
+ }));
383
+ }
384
+ });
385
+ return () => {
386
+ alive = false;
387
+ };
388
+ }, [tick]);
389
+ const refresh = import_react.default.useCallback(() => setTick((n) => n + 1), []);
390
+ return { ...state, refresh };
391
+ }
392
+ function QuickAdd({ t, onAdd, busy }) {
393
+ const [title, setTitle] = import_react.default.useState("");
394
+ const [due, setDue] = import_react.default.useState("");
395
+ const [priority, setPriority] = import_react.default.useState("normal");
396
+ const submit = () => {
397
+ if (busy) return;
398
+ Promise.resolve(onAdd({ title, due, priority })).then((ok) => {
399
+ if (ok !== false) setTitle("");
400
+ }).catch(() => {
401
+ });
402
+ };
403
+ return import_react.default.createElement("div", {
404
+ style: { display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap", marginBottom: 10 }
405
+ }, [
406
+ import_react.default.createElement("input", {
407
+ key: "ti",
408
+ className: "wt-input",
409
+ style: { flex: "1 1 200px", fontSize: 12.5, padding: "5px 9px" },
410
+ value: title,
411
+ placeholder: t("addPlaceholder"),
412
+ "aria-label": t("addPlaceholder"),
413
+ onChange: (event) => setTitle(event.target.value),
414
+ onKeyDown: (event) => {
415
+ if (event.key === "Enter") submit();
416
+ }
417
+ }),
418
+ import_react.default.createElement("label", {
419
+ key: "due",
420
+ title: t("dueLabel"),
421
+ style: { display: "inline-flex", alignItems: "center", gap: 4, fontSize: 11, color: C.label3 }
422
+ }, [
423
+ t("dueLabel"),
424
+ import_react.default.createElement("input", {
425
+ key: "i",
426
+ className: "wt-input",
427
+ type: "date",
428
+ value: due,
429
+ "aria-label": t("dueLabel"),
430
+ onChange: (event) => setDue(event.target.value)
431
+ })
432
+ ]),
433
+ import_react.default.createElement("label", {
434
+ key: "prio",
435
+ title: t("priorityLabel"),
436
+ style: { display: "inline-flex", alignItems: "center", gap: 4, fontSize: 11, color: C.label3 }
437
+ }, [
438
+ t("priorityLabel"),
439
+ import_react.default.createElement("select", {
440
+ key: "s",
441
+ className: "wt-input",
442
+ value: priority,
443
+ "aria-label": t("priorityLabel"),
444
+ onChange: (event) => setPriority(event.target.value)
445
+ }, [
446
+ import_react.default.createElement("option", { key: "high", value: "high" }, t("prioHigh")),
447
+ import_react.default.createElement("option", { key: "normal", value: "normal" }, t("prioNormal")),
448
+ import_react.default.createElement("option", { key: "low", value: "low" }, t("prioLow"))
449
+ ])
450
+ ]),
451
+ import_react.default.createElement("button", {
452
+ key: "add",
453
+ type: "button",
454
+ className: "wt-btn wt-btn-primary",
455
+ disabled: Boolean(busy),
456
+ onClick: submit
457
+ }, t("add"))
458
+ ]);
459
+ }
460
+ function TodoRow({ todo, today, t, onToggle, onRemove, onSave }) {
461
+ const [editing, setEditing] = import_react.default.useState(false);
462
+ const [draft, setDraft] = import_react.default.useState(null);
463
+ const [notesOpen, setNotesOpen] = import_react.default.useState(false);
464
+ const [confirming, setConfirming] = import_react.default.useState(false);
465
+ import_react.default.useEffect(() => {
466
+ if (!confirming) return void 0;
467
+ const id = setTimeout(() => setConfirming(false), 5e3);
468
+ return () => clearTimeout(id);
469
+ }, [confirming]);
470
+ const row = todo ?? {};
471
+ const done = row.status === "completed";
472
+ const due = typeof row.due === "string" ? row.due : "";
473
+ const overdue = !done && Boolean(due) && Boolean(today) && due < today;
474
+ const beginEdit = () => {
475
+ setDraft({
476
+ title: typeof row.title === "string" ? row.title : "",
477
+ due,
478
+ priority: row.priority === "high" || row.priority === "low" ? row.priority : "normal",
479
+ project: typeof row.project === "string" ? row.project : "",
480
+ notes: typeof row.notes === "string" ? row.notes : ""
481
+ });
482
+ setNotesOpen(Boolean(row.notes));
483
+ setEditing(true);
484
+ };
485
+ const stopEdit = () => {
486
+ setEditing(false);
487
+ setDraft(null);
488
+ };
489
+ const submit = () => {
490
+ if (!draft) return;
491
+ const patch = {};
492
+ const title = String(draft.title ?? "").trim();
493
+ if (title !== (row.title ?? "")) patch.title = title;
494
+ const nextDue = draft.due || "";
495
+ if (nextDue !== due) patch.due = nextDue;
496
+ const priority = draft.priority || "normal";
497
+ if (priority !== (row.priority ?? "normal")) patch.priority = priority;
498
+ const project = String(draft.project ?? "").trim();
499
+ if (project !== (row.project ?? "")) patch.project = project;
500
+ const notes = String(draft.notes ?? "").trim();
501
+ if (notes !== (row.notes ?? "")) patch.notes = notes;
502
+ stopEdit();
503
+ if (!Object.keys(patch).length) return;
504
+ Promise.resolve(onSave(row.id, patch)).catch(() => {
505
+ });
506
+ };
507
+ const inputStyle = { fontSize: 12, padding: "3px 7px" };
508
+ if (editing && draft) {
509
+ const field = (key, label, control) => import_react.default.createElement("label", {
510
+ key,
511
+ style: { display: "inline-flex", alignItems: "center", gap: 4, fontSize: 11, color: C.label3 }
512
+ }, [label, control]);
513
+ return import_react.default.createElement("div", { className: "wt-row wt-row-edit" }, [
514
+ import_react.default.createElement("div", { key: "top", style: { display: "flex", gap: 6, alignItems: "center" } }, [
515
+ import_react.default.createElement("input", {
516
+ key: "ti",
517
+ className: "wt-input",
518
+ style: { ...inputStyle, flex: 1, minWidth: 0 },
519
+ value: draft.title,
520
+ autoFocus: true,
521
+ placeholder: t("titlePlaceholder"),
522
+ "aria-label": t("titlePlaceholder"),
523
+ onChange: (event) => setDraft((prev) => ({ ...prev, title: event.target.value })),
524
+ onKeyDown: (event) => {
525
+ if (event.key === "Enter") submit();
526
+ if (event.key === "Escape") stopEdit();
527
+ }
528
+ }),
529
+ import_react.default.createElement("button", {
530
+ key: "save",
531
+ type: "button",
532
+ className: "wt-btn wt-btn-primary",
533
+ onClick: submit
534
+ }, t("save")),
535
+ import_react.default.createElement("button", {
536
+ key: "cancel",
537
+ type: "button",
538
+ className: "wt-btn",
539
+ onClick: stopEdit
540
+ }, t("cancel"))
541
+ ]),
542
+ import_react.default.createElement("div", {
543
+ key: "fields",
544
+ style: { display: "flex", gap: 10, flexWrap: "wrap", alignItems: "center" }
545
+ }, [
546
+ field("due", t("dueLabel"), import_react.default.createElement("input", {
547
+ className: "wt-input",
548
+ style: inputStyle,
549
+ type: "date",
550
+ value: draft.due,
551
+ "aria-label": t("dueLabel"),
552
+ onChange: (event) => setDraft((prev) => ({ ...prev, due: event.target.value }))
553
+ })),
554
+ field("prio", t("priorityLabel"), import_react.default.createElement("select", {
555
+ className: "wt-input",
556
+ style: inputStyle,
557
+ value: draft.priority,
558
+ "aria-label": t("priorityLabel"),
559
+ onChange: (event) => setDraft((prev) => ({ ...prev, priority: event.target.value }))
560
+ }, [
561
+ import_react.default.createElement("option", { key: "high", value: "high" }, t("prioHigh")),
562
+ import_react.default.createElement("option", { key: "normal", value: "normal" }, t("prioNormal")),
563
+ import_react.default.createElement("option", { key: "low", value: "low" }, t("prioLow"))
564
+ ])),
565
+ field("project", t("projectLabel"), import_react.default.createElement("input", {
566
+ className: "wt-input",
567
+ style: { ...inputStyle, width: 130 },
568
+ value: draft.project,
569
+ placeholder: t("projectPlaceholder"),
570
+ "aria-label": t("projectPlaceholder"),
571
+ onChange: (event) => setDraft((prev) => ({ ...prev, project: event.target.value }))
572
+ }))
573
+ ]),
574
+ import_react.default.createElement("div", { key: "notes" }, [
575
+ notesOpen ? import_react.default.createElement("div", { key: "box", style: { display: "flex", flexDirection: "column", gap: 4 } }, [
576
+ import_react.default.createElement("textarea", {
577
+ key: "ta",
578
+ className: "wt-input",
579
+ style: { width: "100%", boxSizing: "border-box", resize: "vertical", minHeight: 54 },
580
+ rows: 3,
581
+ value: draft.notes,
582
+ placeholder: t("notesPlaceholder"),
583
+ "aria-label": t("notesLabel"),
584
+ onChange: (event) => setDraft((prev) => ({ ...prev, notes: event.target.value })),
585
+ // textarea 里回车要换行,所以保存用 Ctrl/Cmd+Enter
586
+ onKeyDown: (event) => {
587
+ if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) submit();
588
+ if (event.key === "Escape") stopEdit();
589
+ }
590
+ }),
591
+ import_react.default.createElement("span", {
592
+ key: "hide",
593
+ className: "wt-link",
594
+ onClick: () => setNotesOpen(false)
595
+ }, t("notesHide"))
596
+ ]) : import_react.default.createElement("span", {
597
+ key: "add",
598
+ className: "wt-link",
599
+ onClick: () => setNotesOpen(true)
600
+ }, t("notesAdd"))
601
+ ])
602
+ ]);
603
+ }
604
+ const meta = [];
605
+ if (row.priority === "high") {
606
+ meta.push(import_react.default.createElement("span", {
607
+ key: "p",
608
+ className: "wt-tag",
609
+ style: { color: C.warn, borderColor: tint(C.warn, 50), background: tint(C.warn, 12), fontWeight: 600 }
610
+ }, t("prioHigh")));
611
+ } else if (row.priority === "low") {
612
+ meta.push(import_react.default.createElement("span", { key: "p", className: "wt-tag" }, t("prioLow")));
613
+ }
614
+ if (due) {
615
+ meta.push(import_react.default.createElement("span", {
616
+ key: "d",
617
+ style: { color: overdue ? C.warn : C.label3, fontSize: 11 }
618
+ }, overdue ? `${t("overdueTag")} ${due}` : due));
619
+ }
620
+ if (row.project) {
621
+ meta.push(import_react.default.createElement("span", { key: "j", className: "wt-tag" }, `#${row.project}`));
622
+ }
623
+ if (row.source === "agent" || row.source === "session") {
624
+ meta.push(import_react.default.createElement("span", {
625
+ key: "s",
626
+ className: "wt-tag",
627
+ title: row.source === "agent" ? t("sourceAgent") : t("sourceSession")
628
+ }, row.source === "agent" ? t("sourceAgent") : t("sourceSession")));
629
+ }
630
+ return import_react.default.createElement("div", { className: "wt-row" }, [
631
+ import_react.default.createElement("button", {
632
+ key: "check",
633
+ type: "button",
634
+ className: `wt-check${done ? " wt-check-done" : ""}`,
635
+ "aria-label": done ? t("unmarkDone") : t("markDone"),
636
+ title: done ? t("unmarkDone") : t("markDone"),
637
+ onClick: () => {
638
+ Promise.resolve(onToggle(row.id)).catch(() => {
639
+ });
640
+ }
641
+ }, done ? import_react.default.createElement(IconCheck, { key: "i" }) : null),
642
+ import_react.default.createElement("div", { key: "main", style: { flex: 1, minWidth: 0 } }, [
643
+ import_react.default.createElement("div", {
644
+ key: "title",
645
+ className: "wt-title",
646
+ title: t("editHint"),
647
+ onClick: beginEdit,
648
+ style: {
649
+ color: done ? C.label3 : C.label,
650
+ textDecoration: done ? "line-through" : "none",
651
+ fontWeight: row.priority === "high" && !done ? 650 : 400
652
+ }
653
+ }, typeof row.title === "string" && row.title ? row.title : t("untitled")),
654
+ meta.length ? import_react.default.createElement("div", {
655
+ key: "meta",
656
+ style: { display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap", marginTop: 2 }
657
+ }, meta) : null
658
+ ]),
659
+ import_react.default.createElement("button", {
660
+ key: "del",
661
+ type: "button",
662
+ className: confirming ? "wt-btn wt-btn-danger" : "wt-icon-btn wt-icon-btn-danger",
663
+ title: confirming ? t("confirmDelete") : t("deleteBtn"),
664
+ "aria-label": t("deleteBtn"),
665
+ onClick: () => {
666
+ if (!confirming) {
667
+ setConfirming(true);
668
+ return;
669
+ }
670
+ setConfirming(false);
671
+ Promise.resolve(onRemove(row.id)).catch(() => {
672
+ });
673
+ }
674
+ }, confirming ? t("confirmDelete") : import_react.default.createElement(IconTrash, { key: "i" }))
675
+ ]);
676
+ }
677
+ function Group({ label, items, closed, t, today, onToggleOpen, onToggleTodo, onRemove, onSave }) {
678
+ const list = asArray(items);
679
+ if (!list.length) return null;
680
+ return import_react.default.createElement("div", { style: { marginTop: 6 } }, [
681
+ import_react.default.createElement("div", {
682
+ key: "head",
683
+ className: "wt-group-head",
684
+ onClick: onToggleOpen,
685
+ title: closed ? t("expand") : t("collapse"),
686
+ role: "button",
687
+ "aria-expanded": !closed
688
+ }, [
689
+ import_react.default.createElement(IconChevron, { key: "c", open: !closed }),
690
+ import_react.default.createElement("span", { key: "l", style: { fontWeight: 600, fontSize: 12 } }, label),
691
+ import_react.default.createElement("span", { key: "n", style: { fontSize: 11, color: C.label3 } }, String(list.length)),
692
+ import_react.default.createElement("span", { key: "sp", style: { flex: 1 } }),
693
+ import_react.default.createElement("span", { key: "h", style: { fontSize: 11, color: C.label3 } }, closed ? t("expand") : t("collapse"))
694
+ ]),
695
+ closed ? null : import_react.default.createElement("div", { key: "body" }, list.map((todo, index) => import_react.default.createElement(TodoRow, {
696
+ key: todo && todo.id || `row-${index}`,
697
+ todo,
698
+ today,
699
+ t,
700
+ onToggle: onToggleTodo,
701
+ onRemove,
702
+ onSave
703
+ })))
704
+ ]);
705
+ }
706
+ function SessionAdopt({ useProjection, t, onAdopt, busy }) {
707
+ let projected;
708
+ try {
709
+ projected = useProjection("todos");
710
+ } catch {
711
+ projected = null;
712
+ }
713
+ const raw = Array.isArray(projected) ? projected : asArray(projected?.todos);
714
+ const items = raw.map((item) => ({
715
+ content: typeof item?.content === "string" ? item.content : typeof item?.title === "string" ? item.title : "",
716
+ status: typeof item?.status === "string" ? item.status : "pending"
717
+ })).filter((item) => item.content.trim());
718
+ if (!items.length) return null;
719
+ const openCount = items.filter((item) => item.status !== "completed").length;
720
+ return import_react.default.createElement("div", {
721
+ style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", marginBottom: 10 }
722
+ }, [
723
+ import_react.default.createElement("button", {
724
+ key: "b",
725
+ type: "button",
726
+ className: "wt-btn wt-btn-primary",
727
+ disabled: Boolean(busy),
728
+ title: t("adoptHint"),
729
+ onClick: () => {
730
+ Promise.resolve(onAdopt(items)).catch(() => {
731
+ });
732
+ }
733
+ }, `${t("adoptPre")}${items.length}${t("adoptPost")}`),
734
+ import_react.default.createElement("span", {
735
+ key: "h",
736
+ title: t("adoptHint"),
737
+ style: { fontSize: 11, color: C.label3 }
738
+ }, `${t("adoptPending")} ${openCount}`)
739
+ ]);
740
+ }
741
+ var GROUPS = [
742
+ { key: "overdue", label: "groupOverdue" },
743
+ { key: "today", label: "groupToday" },
744
+ { key: "week", label: "groupWeek" },
745
+ { key: "later", label: "groupLater" },
746
+ { key: "completed", label: "groupCompleted" }
747
+ ];
748
+ function WorkTodoPanel(props) {
749
+ const t = typeof props?.t === "function" ? props.t : (key) => zh[key] ?? key;
750
+ const { status, data, error, refresh } = useList();
751
+ const [barError, setBarError] = import_react.default.useState(null);
752
+ const [dismissedReadError, setDismissedReadError] = import_react.default.useState(null);
753
+ const readError = error && error !== dismissedReadError ? error : null;
754
+ const shownError = barError ?? readError;
755
+ const [notice, setNotice] = import_react.default.useState(null);
756
+ const [pending, setPending] = import_react.default.useState(0);
757
+ const [closed, setClosed] = import_react.default.useState({ completed: true });
758
+ const runWrite = import_react.default.useCallback(async (job) => {
759
+ setPending((n) => n + 1);
760
+ try {
761
+ const data2 = await job();
762
+ setBarError(null);
763
+ return { ok: true, data: data2 ?? {} };
764
+ } catch (writeError) {
765
+ setBarError(String(writeError?.message ?? writeError));
766
+ return { ok: false, data: {} };
767
+ } finally {
768
+ setPending((n) => Math.max(0, n - 1));
769
+ refresh();
770
+ }
771
+ }, [refresh]);
772
+ const handleAdd = import_react.default.useCallback((input) => {
773
+ const title = String(input?.title ?? "").trim();
774
+ if (!title) {
775
+ setBarError(t("titleEmpty"));
776
+ return Promise.resolve(false);
777
+ }
778
+ return runWrite(() => postJson("/create", {
779
+ title,
780
+ due: input?.due ? String(input.due) : null,
781
+ priority: input?.priority ?? "normal"
782
+ })).then((result) => result.ok);
783
+ }, [runWrite, t]);
784
+ const handleToggle = import_react.default.useCallback((ref) => runWrite(() => postJson("/status", { ref, toggle: true })), [runWrite]);
785
+ const handleRemove = import_react.default.useCallback((ref) => runWrite(() => postJson("/remove", { ref })), [runWrite]);
786
+ const handleSave = import_react.default.useCallback((ref, patch) => runWrite(() => postJson("/update", { ref, ...patch })), [runWrite]);
787
+ const handleAdopt = import_react.default.useCallback((sessionTodos) => runWrite(() => postJson("/adopt", { todos: sessionTodos })).then((result) => {
788
+ if (result.ok) {
789
+ const created = Array.isArray(result.data?.created) ? result.data.created.length : 0;
790
+ const skipped = Number.isFinite(Number(result.data?.skipped)) ? Number(result.data.skipped) : 0;
791
+ setNotice(`${t("adoptDone")} ${created} \xB7 ${t("adoptSkipped")} ${skipped}`);
792
+ }
793
+ return result.ok;
794
+ }), [runWrite, t]);
795
+ const useProjection = typeof props?.useProjection === "function" ? props.useProjection : void 0;
796
+ const rootStyle = {
797
+ height: "100%",
798
+ overflow: "auto",
799
+ padding: "16px 18px 40px",
800
+ boxSizing: "border-box",
801
+ color: C.label,
802
+ fontFamily: "var(--dsw-font-family, system-ui, sans-serif)",
803
+ fontSize: 13
804
+ };
805
+ if (status === "loading" && !data) {
806
+ return import_react.default.createElement("div", {
807
+ className: "wt-root",
808
+ style: { ...rootStyle, display: "flex", alignItems: "center", gap: 8, color: C.label3, padding: 28 }
809
+ }, [
810
+ import_react.default.createElement("style", { key: "css" }, STYLE_TEXT),
811
+ import_react.default.createElement("span", { key: "sp", className: "wt-spin" }),
812
+ import_react.default.createElement("span", { key: "t" }, t("loading"))
813
+ ]);
814
+ }
815
+ if (status === "failed" && !data) {
816
+ return import_react.default.createElement("div", {
817
+ className: "wt-root",
818
+ style: { ...rootStyle, padding: 28, color: C.error }
819
+ }, [
820
+ import_react.default.createElement("style", { key: "css" }, STYLE_TEXT),
821
+ import_react.default.createElement("div", { key: "m" }, `${t("failed")}\uFF1A${error ?? ""}`),
822
+ import_react.default.createElement("button", {
823
+ key: "r",
824
+ type: "button",
825
+ className: "wt-btn",
826
+ style: { marginTop: 10 },
827
+ onClick: refresh
828
+ }, t("retry"))
829
+ ]);
830
+ }
831
+ const groups = data?.groups ?? {};
832
+ const stats = data?.stats ?? {};
833
+ const today = typeof data?.today === "string" && data.today ? data.today : localToday();
834
+ const store = data?.store ?? null;
835
+ const num = (value) => Number.isFinite(Number(value)) ? Number(value) : 0;
836
+ const overdueCount = num(stats.overdue);
837
+ const totalVisible = GROUPS.reduce((sum, group) => sum + asArray(groups[group.key]).length, 0);
838
+ const chips = [
839
+ { key: "open", label: t("statOpen"), value: num(stats.open) },
840
+ { key: "overdue", label: t("statOverdue"), value: overdueCount, alert: overdueCount > 0 },
841
+ { key: "today", label: t("statToday"), value: num(stats.today) },
842
+ { key: "doing", label: t("statDoing"), value: num(stats.doing) },
843
+ { key: "done", label: t("statDoneToday"), value: num(stats.completedToday) }
844
+ ];
845
+ return import_react.default.createElement("div", { className: "wt-root", style: rootStyle }, [
846
+ import_react.default.createElement("style", { key: "css" }, STYLE_TEXT),
847
+ /* 顶部:标题 + 统计 + 刷新 */
848
+ import_react.default.createElement("div", {
849
+ key: "head",
850
+ style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", marginBottom: 10 }
851
+ }, [
852
+ import_react.default.createElement("div", { key: "ti", style: { fontWeight: 700, fontSize: 15 } }, t("title")),
853
+ ...chips.map((chip) => import_react.default.createElement("span", {
854
+ key: chip.key,
855
+ className: "wt-chip",
856
+ style: chip.alert ? { color: C.warn, borderColor: tint(C.warn, 50), background: tint(C.warn, 12) } : void 0
857
+ }, [
858
+ import_react.default.createElement("span", { key: "l", style: { color: C.label3 } }, chip.label),
859
+ import_react.default.createElement("b", { key: "v", style: { fontWeight: 650 } }, String(chip.value))
860
+ ])),
861
+ import_react.default.createElement("span", { key: "sp", style: { flex: 1 } }),
862
+ import_react.default.createElement("button", {
863
+ key: "rf",
864
+ type: "button",
865
+ className: "wt-btn",
866
+ disabled: status === "loading" || pending > 0,
867
+ title: t("refresh"),
868
+ onClick: refresh
869
+ }, [
870
+ import_react.default.createElement(IconRefresh, { key: "i" }),
871
+ t("refresh")
872
+ ])
873
+ ]),
874
+ /* 错误条:宿主的 error 原文照贴,绝不吞掉 */
875
+ shownError ? import_react.default.createElement("div", {
876
+ key: "err",
877
+ style: {
878
+ display: "flex",
879
+ alignItems: "flex-start",
880
+ gap: 8,
881
+ marginBottom: 10,
882
+ padding: "6px 9px",
883
+ borderRadius: 8,
884
+ border: `1px solid ${tint(C.error, 45)}`,
885
+ background: tint(C.error, 12),
886
+ color: C.error,
887
+ fontSize: 12,
888
+ lineHeight: 1.6
889
+ }
890
+ }, [
891
+ import_react.default.createElement("span", {
892
+ key: "m",
893
+ style: { flex: 1, minWidth: 0, wordBreak: "break-word" }
894
+ }, `${t("failed")}\uFF1A${shownError}`),
895
+ import_react.default.createElement("button", {
896
+ key: "x",
897
+ type: "button",
898
+ className: "wt-icon-btn",
899
+ style: { width: 18, height: 18, color: C.error },
900
+ title: t("dismiss"),
901
+ "aria-label": t("dismiss"),
902
+ onClick: () => {
903
+ setBarError(null);
904
+ setDismissedReadError(error ?? null);
905
+ }
906
+ }, import_react.default.createElement(IconClose, { key: "i" }))
907
+ ]) : null,
908
+ /* 提升结果提示:点完按钮要有个回执 */
909
+ notice ? import_react.default.createElement("div", {
910
+ key: "notice",
911
+ style: {
912
+ display: "flex",
913
+ alignItems: "center",
914
+ gap: 8,
915
+ marginBottom: 10,
916
+ padding: "5px 9px",
917
+ borderRadius: 8,
918
+ border: `1px solid ${tint(C.ok, 40)}`,
919
+ background: tint(C.ok, 10),
920
+ color: C.label2,
921
+ fontSize: 11.5
922
+ }
923
+ }, [
924
+ import_react.default.createElement("span", { key: "m", style: { flex: 1 } }, notice),
925
+ import_react.default.createElement("span", {
926
+ key: "x",
927
+ className: "wt-link",
928
+ onClick: () => setNotice(null)
929
+ }, t("dismiss"))
930
+ ]) : null,
931
+ /* 会话待办:只在拿得到 useProjection 时挂载(见 SessionAdopt 的说明) */
932
+ useProjection ? import_react.default.createElement(SessionAdopt, {
933
+ key: "adopt",
934
+ useProjection,
935
+ t,
936
+ busy: pending > 0,
937
+ onAdopt: handleAdopt
938
+ }) : null,
939
+ import_react.default.createElement(QuickAdd, { key: "quick", t, busy: pending > 0, onAdd: handleAdd }),
940
+ /* 分组列表 */
941
+ totalVisible ? import_react.default.createElement("div", { key: "groups" }, GROUPS.map((group) => import_react.default.createElement(Group, {
942
+ key: group.key,
943
+ label: t(group.label),
944
+ items: groups[group.key],
945
+ closed: Boolean(closed[group.key]),
946
+ t,
947
+ today,
948
+ onToggleOpen: () => setClosed((prev) => ({ ...prev, [group.key]: !prev[group.key] })),
949
+ onToggleTodo: handleToggle,
950
+ onRemove: handleRemove,
951
+ onSave: handleSave
952
+ }))) : import_react.default.createElement("div", {
953
+ key: "empty",
954
+ style: { padding: "22px 12px", textAlign: "center", color: C.label3 }
955
+ }, [
956
+ import_react.default.createElement("div", { key: "a", style: { fontSize: 13, color: C.label2 } }, t("empty")),
957
+ import_react.default.createElement("div", { key: "b", style: { fontSize: 11.5, marginTop: 4 } }, t("emptyHint"))
958
+ ]),
959
+ /* 底部:数据到底存在哪(排查「我的待办不见了」时第一眼要看的东西) */
960
+ import_react.default.createElement("div", {
961
+ key: "foot",
962
+ style: { marginTop: 14, paddingTop: 8, borderTop: `1px solid ${C.border1}`, fontSize: 10.5, color: C.label3, lineHeight: 1.7 }
963
+ }, store && store.location ? import_react.default.createElement("div", {
964
+ key: "store",
965
+ title: `${t("storeAt")}\uFF1A${store.location}`,
966
+ style: { wordBreak: "break-all" }
967
+ }, `${t("storeAt")} \xB7 ${store.kind === "domain" ? t("storeDomain") : t("storeFile")} \xB7 ${store.location}`) : null)
968
+ ]);
969
+ }
970
+ var inject = ["slots", "locale"];
971
+ function apply(ctx) {
972
+ ctx.effect(() => ctx.locale.register(LOCALE_NS, { zh, en }), `${LOCALE_NS}: dictionaries`);
973
+ ctx.slots.inject("sidebar.panellist", () => ctx.slots.register({
974
+ name: "sidebar.panellist",
975
+ id: SLOT_ID,
976
+ order: 88,
977
+ label: () => "\u5F85\u529E",
978
+ locale: LOCALE_NS
979
+ }, (props) => import_react.default.createElement(WorkTodoIcon, { size: props?.size ?? 16, active: props?.active })));
980
+ ctx.slots.inject("main", () => ctx.slots.register({
981
+ name: "main",
982
+ key: SLOT_ID,
983
+ locale: LOCALE_NS
984
+ }, WorkTodoPanel));
985
+ }
986
+ return module.exports; } });
987
+ //# sourceMappingURL=client.js.map