@aicupa/plugin-todo-dependency 1.0.4 → 1.0.5
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/view/index.html +42 -20
package/package.json
CHANGED
package/view/index.html
CHANGED
|
@@ -109,10 +109,16 @@
|
|
|
109
109
|
|
|
110
110
|
#edgeSvg { position: absolute; top: 0; left: 0; pointer-events: none; }
|
|
111
111
|
|
|
112
|
+
#graphInner { transition: opacity 0.35s ease; }
|
|
113
|
+
#graphInner.fade-out { opacity: 0; }
|
|
114
|
+
|
|
112
115
|
.empty-state {
|
|
113
116
|
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
114
|
-
|
|
117
|
+
position: absolute; inset: 0;
|
|
118
|
+
color: #aaa; padding: 40px 24px; text-align: center; user-select: none;
|
|
119
|
+
opacity: 0; pointer-events: none; transition: opacity 0.35s ease;
|
|
115
120
|
}
|
|
121
|
+
.empty-state.visible { opacity: 1; pointer-events: auto; }
|
|
116
122
|
.empty-icon { width: 64px; height: 64px; margin-bottom: 16px; opacity: 0.35; }
|
|
117
123
|
.empty-title { font-size: 15px; font-weight: 500; margin-bottom: 10px; color: #888; }
|
|
118
124
|
.dark .empty-title { color: #777; }
|
|
@@ -128,20 +134,19 @@
|
|
|
128
134
|
</div>
|
|
129
135
|
<div id="warnings"></div>
|
|
130
136
|
<div id="graphArea">
|
|
131
|
-
<div id="graphContainer">
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
</div>
|
|
137
|
+
<div id="graphContainer"></div>
|
|
138
|
+
<div class="empty-state visible" id="emptyState">
|
|
139
|
+
<svg class="empty-icon" viewBox="0 0 80 80" fill="none" stroke="currentColor" stroke-width="2">
|
|
140
|
+
<rect x="8" y="10" width="24" height="16" rx="4"/>
|
|
141
|
+
<rect x="48" y="10" width="24" height="16" rx="4"/>
|
|
142
|
+
<rect x="28" y="50" width="24" height="16" rx="4"/>
|
|
143
|
+
<line x1="26" y1="26" x2="36" y2="50" stroke-dasharray="3,2"/>
|
|
144
|
+
<line x1="54" y1="26" x2="44" y2="50" stroke-dasharray="3,2"/>
|
|
145
|
+
<polygon points="36,50 33,45 39,45" fill="currentColor" stroke="none"/>
|
|
146
|
+
<polygon points="44,50 41,45 47,45" fill="currentColor" stroke="none"/>
|
|
147
|
+
</svg>
|
|
148
|
+
<div class="empty-title" data-i18n="emptyTitle"></div>
|
|
149
|
+
<div class="empty-hint" data-i18n="emptyHint"></div>
|
|
145
150
|
</div>
|
|
146
151
|
</div>
|
|
147
152
|
</div>
|
|
@@ -153,6 +158,8 @@
|
|
|
153
158
|
title: '依赖图谱', refresh: '刷新',
|
|
154
159
|
emptyTitle: '暂无依赖关系',
|
|
155
160
|
emptyHint: '右键 Todo 节点,选择「设置依赖」<br>即可建立待办之间的依赖关系',
|
|
161
|
+
allDoneTitle: '所有依赖任务已完成 🎉',
|
|
162
|
+
allDoneHint: '当前依赖链路中的任务均已完成<br>如有新的依赖关系,请重新创建',
|
|
156
163
|
done: '已完成', pending: '待完成', blocked: '阻塞中', notFound: '未找到该 Todo',
|
|
157
164
|
cycleWarning: '检测到循环依赖,部分节点的层级可能不准确',
|
|
158
165
|
},
|
|
@@ -160,6 +167,8 @@
|
|
|
160
167
|
title: 'Dependency Graph', refresh: 'Refresh',
|
|
161
168
|
emptyTitle: 'No dependencies yet',
|
|
162
169
|
emptyHint: 'Right-click a Todo and select "Set Dependencies"<br>to create dependency relationships',
|
|
170
|
+
allDoneTitle: 'All dependency tasks completed 🎉',
|
|
171
|
+
allDoneHint: 'All tasks in dependency chains are done<br>Create new dependencies if needed',
|
|
163
172
|
done: 'Done', pending: 'Pending', blocked: 'Blocked', notFound: 'Todo not found',
|
|
164
173
|
cycleWarning: 'Cycle detected — some nodes may be positioned incorrectly',
|
|
165
174
|
},
|
|
@@ -243,6 +252,7 @@
|
|
|
243
252
|
if (!data) return
|
|
244
253
|
|
|
245
254
|
const { todos, edges: allEdges } = data
|
|
255
|
+
hideEmpty()
|
|
246
256
|
|
|
247
257
|
// Build adjacency (both directions) to find connected components
|
|
248
258
|
const allIds = new Set()
|
|
@@ -275,7 +285,7 @@
|
|
|
275
285
|
}
|
|
276
286
|
const edges = allEdges.filter(([from, to]) => visibleIds.has(from) && visibleIds.has(to))
|
|
277
287
|
const nodeIds = [...visibleIds]
|
|
278
|
-
if (!nodeIds.length) {
|
|
288
|
+
if (!nodeIds.length) { fadeToEmpty(allEdges.length > 0); return }
|
|
279
289
|
|
|
280
290
|
const { layers, hasCycle } = assignLayers(nodeIds, edges)
|
|
281
291
|
if (hasCycle) {
|
|
@@ -285,11 +295,23 @@
|
|
|
285
295
|
renderGraph(nodeIds, edges, layout.positions, todos, layout)
|
|
286
296
|
}
|
|
287
297
|
|
|
288
|
-
function showEmpty() {
|
|
289
|
-
|
|
298
|
+
function showEmpty(allDone) {
|
|
299
|
+
document.getElementById('graphContainer').innerHTML = ''
|
|
290
300
|
const e = document.getElementById('emptyState')
|
|
291
|
-
|
|
292
|
-
|
|
301
|
+
e.querySelector('.empty-title').innerHTML = allDone ? t.allDoneTitle : t.emptyTitle
|
|
302
|
+
e.querySelector('.empty-hint').innerHTML = allDone ? t.allDoneHint : t.emptyHint
|
|
303
|
+
e.classList.add('visible')
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function hideEmpty() {
|
|
307
|
+
document.getElementById('emptyState').classList.remove('visible')
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function fadeToEmpty(allDone) {
|
|
311
|
+
const inner = document.getElementById('graphInner')
|
|
312
|
+
if (!inner) { showEmpty(allDone); return }
|
|
313
|
+
inner.classList.add('fade-out')
|
|
314
|
+
inner.addEventListener('transitionend', () => showEmpty(allDone), { once: true })
|
|
293
315
|
}
|
|
294
316
|
|
|
295
317
|
// ── Layout algorithm ──
|