@aicupa/plugin-todo-dependency 1.0.5 → 1.0.7
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/package.json +1 -1
- package/service.js +30 -2
- package/view/index.html +49 -10
package/package.json
CHANGED
package/service.js
CHANGED
|
@@ -11,6 +11,7 @@ module.exports = (api) => {
|
|
|
11
11
|
id: node.todo.id,
|
|
12
12
|
content: node.todo.content,
|
|
13
13
|
done: node.todo.done,
|
|
14
|
+
focus: node.todo.focus || false,
|
|
14
15
|
level: node.todo.level,
|
|
15
16
|
depIds: node.todo.depIds || [],
|
|
16
17
|
})
|
|
@@ -83,6 +84,32 @@ module.exports = (api) => {
|
|
|
83
84
|
}
|
|
84
85
|
},
|
|
85
86
|
|
|
87
|
+
async toggleFocus({ todoId, focus, filePath }) {
|
|
88
|
+
try {
|
|
89
|
+
const content = await api.readFile(filePath)
|
|
90
|
+
const data = JSON.parse(content)
|
|
91
|
+
const todotree = data.todotree
|
|
92
|
+
|
|
93
|
+
function findAndUpdate(nodes) {
|
|
94
|
+
for (const node of nodes) {
|
|
95
|
+
if (node.todo && node.todo.id === todoId) {
|
|
96
|
+
node.todo.focus = focus
|
|
97
|
+
return true
|
|
98
|
+
}
|
|
99
|
+
if (node.children?.length && findAndUpdate(node.children)) return true
|
|
100
|
+
}
|
|
101
|
+
return false
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
findAndUpdate(todotree.tree)
|
|
105
|
+
await api.store('todotree', todotree, filePath)
|
|
106
|
+
await api.reload(filePath)
|
|
107
|
+
return { ok: true }
|
|
108
|
+
} catch (e) {
|
|
109
|
+
return { ok: false, error: e.message }
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
|
|
86
113
|
async toggleDone({ todoId, done, filePath }) {
|
|
87
114
|
try {
|
|
88
115
|
const content = await api.readFile(filePath)
|
|
@@ -94,9 +121,10 @@ module.exports = (api) => {
|
|
|
94
121
|
if (node.todo && node.todo.id === todoId) {
|
|
95
122
|
node.todo.done = done
|
|
96
123
|
if (done) {
|
|
97
|
-
node.todo.
|
|
124
|
+
node.todo.end = Date.now()
|
|
125
|
+
node.todo.focus = false
|
|
98
126
|
} else {
|
|
99
|
-
delete node.todo.
|
|
127
|
+
delete node.todo.end
|
|
100
128
|
}
|
|
101
129
|
return true
|
|
102
130
|
}
|
package/view/index.html
CHANGED
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
padding: 10px 12px; cursor: default;
|
|
53
53
|
box-shadow: 0 1px 4px rgba(0,0,0,0.06);
|
|
54
54
|
transition: box-shadow 0.2s, transform 0.15s;
|
|
55
|
-
display: flex; align-items: flex-start; gap:
|
|
55
|
+
display: flex; align-items: flex-start; gap: 8px;
|
|
56
56
|
}
|
|
57
57
|
.node:hover { box-shadow: 0 4px 16px rgba(0,0,0,0.1); transform: translateY(-1px); }
|
|
58
58
|
.dark .node { background: #2d2d2d; border-color: #3c3c3c; box-shadow: 0 1px 4px rgba(0,0,0,0.3); }
|
|
@@ -79,7 +79,22 @@
|
|
|
79
79
|
.dark .node-check.checked { border-color: #73d13d; background: #73d13d; }
|
|
80
80
|
.dark .node-check.checked::after { border-color: #2d2d2d; }
|
|
81
81
|
|
|
82
|
-
.node-body { flex: 1; min-width: 0; }
|
|
82
|
+
.node-body { flex: 1; min-width: 0; position: relative; }
|
|
83
|
+
|
|
84
|
+
.node-focus {
|
|
85
|
+
position: absolute; top: -2px; right: -4px;
|
|
86
|
+
width: 16px; height: 16px; cursor: pointer;
|
|
87
|
+
border: none; background: none; padding: 0;
|
|
88
|
+
color: #bbb; transition: color 0.15s;
|
|
89
|
+
display: flex; align-items: center; justify-content: center;
|
|
90
|
+
opacity: 0; transition: opacity 0.15s, color 0.15s;
|
|
91
|
+
}
|
|
92
|
+
.node:hover .node-focus { opacity: 1; }
|
|
93
|
+
.node-focus.active { opacity: 1; color: #1890ff; }
|
|
94
|
+
.node-focus:hover { color: #1890ff; }
|
|
95
|
+
.dark .node-focus { color: #555; }
|
|
96
|
+
.dark .node-focus:hover { color: #40a9ff; }
|
|
97
|
+
.dark .node-focus.active { color: #40a9ff; }
|
|
83
98
|
|
|
84
99
|
.node-content {
|
|
85
100
|
font-size: 12px; line-height: 1.5; word-break: break-word;
|
|
@@ -91,12 +106,14 @@
|
|
|
91
106
|
display: inline-block; font-size: 10px; padding: 1px 6px;
|
|
92
107
|
border-radius: 10px; margin-top: 5px;
|
|
93
108
|
}
|
|
94
|
-
.badge-pending
|
|
95
|
-
.badge-done
|
|
96
|
-
.badge-blocked
|
|
97
|
-
.
|
|
98
|
-
.dark .badge-
|
|
99
|
-
.dark .badge-
|
|
109
|
+
.badge-pending { background: #fff7e6; color: #d46b08; }
|
|
110
|
+
.badge-done { background: #f6ffed; color: #389e0d; }
|
|
111
|
+
.badge-blocked { background: #fff1f0; color: #cf1322; }
|
|
112
|
+
.badge-focus { background: #e6f7ff; color: #096dd9; }
|
|
113
|
+
.dark .badge-pending { background: #3a3000; color: #ffc53d; }
|
|
114
|
+
.dark .badge-done { background: #1e3a1e; color: #73d13d; }
|
|
115
|
+
.dark .badge-blocked { background: #3a1a1a; color: #ff4d4f; }
|
|
116
|
+
.dark .badge-focus { background: #111d2c; color: #40a9ff; }
|
|
100
117
|
|
|
101
118
|
.node.blocked { border-style: dashed; opacity: 0.7; }
|
|
102
119
|
.dark .node.blocked { opacity: 0.7; }
|
|
@@ -160,7 +177,7 @@
|
|
|
160
177
|
emptyHint: '右键 Todo 节点,选择「设置依赖」<br>即可建立待办之间的依赖关系',
|
|
161
178
|
allDoneTitle: '所有依赖任务已完成 🎉',
|
|
162
179
|
allDoneHint: '当前依赖链路中的任务均已完成<br>如有新的依赖关系,请重新创建',
|
|
163
|
-
done: '已完成', pending: '待完成', blocked: '阻塞中', notFound: '未找到该 Todo',
|
|
180
|
+
done: '已完成', pending: '待完成', blocked: '阻塞中', focus: '进行中', unfocus: '取消进行', notFound: '未找到该 Todo',
|
|
164
181
|
cycleWarning: '检测到循环依赖,部分节点的层级可能不准确',
|
|
165
182
|
},
|
|
166
183
|
en: {
|
|
@@ -169,7 +186,7 @@
|
|
|
169
186
|
emptyHint: 'Right-click a Todo and select "Set Dependencies"<br>to create dependency relationships',
|
|
170
187
|
allDoneTitle: 'All dependency tasks completed 🎉',
|
|
171
188
|
allDoneHint: 'All tasks in dependency chains are done<br>Create new dependencies if needed',
|
|
172
|
-
done: 'Done', pending: 'Pending', blocked: 'Blocked', notFound: 'Todo not found',
|
|
189
|
+
done: 'Done', pending: 'Pending', blocked: 'Blocked', focus: 'In Progress', unfocus: 'Cancel Focus', notFound: 'Todo not found',
|
|
173
190
|
cycleWarning: 'Cycle detected — some nodes may be positioned incorrectly',
|
|
174
191
|
},
|
|
175
192
|
}
|
|
@@ -374,6 +391,13 @@
|
|
|
374
391
|
autoScan()
|
|
375
392
|
}
|
|
376
393
|
|
|
394
|
+
async function toggleTodoFocus(todoId, focus) {
|
|
395
|
+
try {
|
|
396
|
+
await callPlugin('toggleFocus', { todoId, focus, filePath: currentFilePath })
|
|
397
|
+
} catch {}
|
|
398
|
+
autoScan()
|
|
399
|
+
}
|
|
400
|
+
|
|
377
401
|
function renderGraph(nodeIds, edges, positions, todoData, layout) {
|
|
378
402
|
const container = document.getElementById('graphContainer')
|
|
379
403
|
container.innerHTML = ''
|
|
@@ -464,6 +488,18 @@
|
|
|
464
488
|
}
|
|
465
489
|
|
|
466
490
|
const body = document.createElement('div'); body.className = 'node-body'
|
|
491
|
+
|
|
492
|
+
if (todo && !todo.done && !blocked) {
|
|
493
|
+
const focusBtn = document.createElement('button')
|
|
494
|
+
focusBtn.className = 'node-focus' + (todo.focus ? ' active' : '')
|
|
495
|
+
focusBtn.title = todo.focus ? t.unfocus : t.focus
|
|
496
|
+
focusBtn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2" fill="currentColor"/></svg>'
|
|
497
|
+
focusBtn.addEventListener('click', e => {
|
|
498
|
+
e.stopPropagation()
|
|
499
|
+
toggleTodoFocus(id, !todo.focus)
|
|
500
|
+
})
|
|
501
|
+
body.appendChild(focusBtn)
|
|
502
|
+
}
|
|
467
503
|
const content = document.createElement('div'); content.className = 'node-content'
|
|
468
504
|
if (todo) {
|
|
469
505
|
content.textContent = todo.content
|
|
@@ -481,6 +517,9 @@
|
|
|
481
517
|
} else if (blocked) {
|
|
482
518
|
sb.className = 'node-badge badge-blocked'
|
|
483
519
|
sb.textContent = t.blocked
|
|
520
|
+
} else if (todo.focus) {
|
|
521
|
+
sb.className = 'node-badge badge-focus'
|
|
522
|
+
sb.textContent = t.focus
|
|
484
523
|
} else {
|
|
485
524
|
sb.className = 'node-badge badge-pending'
|
|
486
525
|
sb.textContent = t.pending
|