dsh-global-todo 0.5.3 → 0.6.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/CHANGELOG.md +22 -0
- package/docs/screenshots/panel-detail.png +0 -0
- package/docs/screenshots/panel-select.png +0 -0
- package/docs/screenshots/panel.png +0 -0
- package/lib/client.js +332 -182
- package/lib/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
## [0.6.0] — 2026-10-20
|
|
2
|
+
|
|
3
|
+
A design pass over the whole panel: one list, fewer competing controls, one type scale.
|
|
4
|
+
|
|
5
|
+
- **The layout is a column, not a wrapping row.** `.gt-root`/`.gt-inner` gained `min-width: 0` so the
|
|
6
|
+
column shrinks with its slot instead of overflowing at 1280 and 1100; the header wraps its actions
|
|
7
|
+
and the toolbar is two semantic rows (filter/search above, context above the list). The working
|
|
8
|
+
directory, handoff target and browse controls move behind a single Context toggle, collapsed by
|
|
9
|
+
default.
|
|
10
|
+
- **Five type sizes and one weight scale.** 20/28 panel title, 14/22 row title, 13/20 controls and
|
|
11
|
+
body, 12/18 metadata and section labels, 11.5 mono for paths. Buttons, inputs and tabs share a
|
|
12
|
+
28px control height; the settings card is a 340px floating inspector (fixed, mutually exclusive
|
|
13
|
+
with the detail card) instead of an in-flow block that pushed the list down.
|
|
14
|
+
- **Rows read top-down.** The title opens the detail (the kebab remains as a redundant door); the
|
|
15
|
+
dispatch button is a quiet action instead of an outlined primary; metadata loses the origin path
|
|
16
|
+
and the stray separator (CSS-generated dots), and tags cap at four. Group-level priority hides
|
|
17
|
+
while the group is expanded, where every row already shows it.
|
|
18
|
+
- **Copy and states.** Full-width colons no longer leak into the English UI, `1 items` is fixed,
|
|
19
|
+
priority chips say Urgent/High/Normal/Low instead of P-codes, the empty state has a primary
|
|
20
|
+
action, the error banner can be dismissed, and the reminder bar keeps its accent on a 2px edge
|
|
21
|
+
(amber text failed contrast). The footer's store path and version move into Settings → About.
|
|
22
|
+
|
|
1
23
|
## [0.5.3] — 2026-10-20
|
|
2
24
|
|
|
3
25
|
Settings a person can reach, and reminders that behave like reminders.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/client.js
CHANGED
|
@@ -50,7 +50,7 @@ window.__ModuleLoader__.load({
|
|
|
50
50
|
* different mechanisms (restart vs. hot reload), so "which one am I looking
|
|
51
51
|
* at" needs an answer that the bundle itself carries.
|
|
52
52
|
*/
|
|
53
|
-
const UI_REV = '
|
|
53
|
+
const UI_REV = 'ui36'
|
|
54
54
|
/** Last language resolved for the shell; module-level so a fetch failure can be worded too. */
|
|
55
55
|
let activeLang = 'zh'
|
|
56
56
|
|
|
@@ -64,6 +64,7 @@ window.__ModuleLoader__.load({
|
|
|
64
64
|
'action.retry': '重试',
|
|
65
65
|
'action.add': '添加',
|
|
66
66
|
'action.more': '更多字段',
|
|
67
|
+
'action.overflow': '更多操作',
|
|
67
68
|
'action.less': '收起字段',
|
|
68
69
|
'action.detail': '详情',
|
|
69
70
|
'action.hide': '收起',
|
|
@@ -91,6 +92,7 @@ window.__ModuleLoader__.load({
|
|
|
91
92
|
'action.exportHint': '把整份清单导出成 JSON 文件(就是存储用的那份文档)',
|
|
92
93
|
'action.importHint': '从 JSON 文件导入:同 id 覆盖、新 id 追加,不删除现有待办',
|
|
93
94
|
'settings.title': '设置',
|
|
95
|
+
'settings.context': '上下文',
|
|
94
96
|
'settings.reminders': '到点提醒',
|
|
95
97
|
'settings.remindersEnable': '开启到点提醒',
|
|
96
98
|
'settings.lead': '提前(分钟)',
|
|
@@ -103,6 +105,7 @@ window.__ModuleLoader__.load({
|
|
|
103
105
|
'settings.save': '保存',
|
|
104
106
|
'settings.cancel': '取消',
|
|
105
107
|
'settings.saved': '设置已保存',
|
|
108
|
+
'settings.about': '关于',
|
|
106
109
|
'notice.exported': '已导出 {n} 条待办',
|
|
107
110
|
'notice.imported': '已导入 {n} 条(合并,现有共 {total} 条)',
|
|
108
111
|
'import.badJson': '这个文件不是合法的 JSON',
|
|
@@ -124,7 +127,7 @@ window.__ModuleLoader__.load({
|
|
|
124
127
|
'notice.bulk': '已更新 {n} 条',
|
|
125
128
|
'notice.bulkPartial': '已更新 {n} 条,跳过 {m} 条',
|
|
126
129
|
'select.clear': '清除',
|
|
127
|
-
'select.done': '
|
|
130
|
+
'select.done': '退出选择',
|
|
128
131
|
'select.hint': '先勾几条待办,再点「一键分配」:优先回到写下它的那个对话,其次同工作区的对话,都找不到才让你选。',
|
|
129
132
|
'assign.working': '正在分配…',
|
|
130
133
|
'assign.summary': '已分配 {n} 条(原对话 {origin} · 同工作区 {workspace} · 你选的 {chosen})',
|
|
@@ -218,10 +221,10 @@ window.__ModuleLoader__.load({
|
|
|
218
221
|
'field.linkValue': '文档绝对路径或网址',
|
|
219
222
|
'field.linkTitle': '给它起个短名字(可空)',
|
|
220
223
|
'field.search': '搜标题、描述、标签、附件…',
|
|
221
|
-
'priority.low': '
|
|
222
|
-
'priority.normal': '
|
|
223
|
-
'priority.high': '
|
|
224
|
-
'priority.urgent': '
|
|
224
|
+
'priority.low': '低',
|
|
225
|
+
'priority.normal': '常规',
|
|
226
|
+
'priority.high': '高',
|
|
227
|
+
'priority.urgent': '紧急',
|
|
225
228
|
'group.by': '分组',
|
|
226
229
|
'group.conversation': '对话',
|
|
227
230
|
'group.time': '时间',
|
|
@@ -229,6 +232,7 @@ window.__ModuleLoader__.load({
|
|
|
229
232
|
'group.manual': '手动添加',
|
|
230
233
|
'group.other': '其他',
|
|
231
234
|
'group.items': '{n} 条',
|
|
235
|
+
'group.item': '1 条',
|
|
232
236
|
'group.thisConversation': '本对话',
|
|
233
237
|
'group.overdue': '逾期',
|
|
234
238
|
'group.today': '今天',
|
|
@@ -238,6 +242,7 @@ window.__ModuleLoader__.load({
|
|
|
238
242
|
'group.done': '已完成',
|
|
239
243
|
'group.cancelled': '已取消',
|
|
240
244
|
'empty.none': '还没有待办。上面写一句,回车就记下了。',
|
|
245
|
+
'empty.add': '记第一条',
|
|
241
246
|
'empty.filtered': '这个筛选下没有待办。',
|
|
242
247
|
'meta.added': '加入于',
|
|
243
248
|
'meta.due': '截止',
|
|
@@ -300,6 +305,7 @@ window.__ModuleLoader__.load({
|
|
|
300
305
|
'action.retry': 'Retry',
|
|
301
306
|
'action.add': 'Add',
|
|
302
307
|
'action.more': 'More fields',
|
|
308
|
+
'action.overflow': 'More actions',
|
|
303
309
|
'action.less': 'Fewer fields',
|
|
304
310
|
'action.detail': 'Details',
|
|
305
311
|
'action.hide': 'Hide',
|
|
@@ -327,6 +333,7 @@ window.__ModuleLoader__.load({
|
|
|
327
333
|
'action.exportHint': 'Download the whole list as JSON (the document the store keeps)',
|
|
328
334
|
'action.importHint': 'Import a JSON file: same ids are updated, new ids appended, nothing deleted',
|
|
329
335
|
'settings.title': 'Settings',
|
|
336
|
+
'settings.context': 'Context',
|
|
330
337
|
'settings.reminders': 'Due reminders',
|
|
331
338
|
'settings.remindersEnable': 'Announce deadlines',
|
|
332
339
|
'settings.lead': 'Lead time (min)',
|
|
@@ -339,6 +346,7 @@ window.__ModuleLoader__.load({
|
|
|
339
346
|
'settings.save': 'Save',
|
|
340
347
|
'settings.cancel': 'Cancel',
|
|
341
348
|
'settings.saved': 'Settings saved',
|
|
349
|
+
'settings.about': 'About',
|
|
342
350
|
'notice.exported': 'Exported {n} todos',
|
|
343
351
|
'notice.imported': 'Imported {n} (merged; {total} in the list now)',
|
|
344
352
|
'import.badJson': 'That file is not valid JSON',
|
|
@@ -456,16 +464,17 @@ window.__ModuleLoader__.load({
|
|
|
456
464
|
'field.linkValue': 'Absolute document path or URL',
|
|
457
465
|
'field.linkTitle': 'Short label (optional)',
|
|
458
466
|
'field.search': 'Search title, description, tags, attachments…',
|
|
459
|
-
'priority.low': '
|
|
460
|
-
'priority.normal': '
|
|
461
|
-
'priority.high': '
|
|
462
|
-
'priority.urgent': '
|
|
467
|
+
'priority.low': 'Low',
|
|
468
|
+
'priority.normal': 'Normal',
|
|
469
|
+
'priority.high': 'High',
|
|
470
|
+
'priority.urgent': 'Urgent',
|
|
463
471
|
'group.by': 'Group',
|
|
464
472
|
'group.time': 'Time',
|
|
465
473
|
'group.level': 'Level',
|
|
466
474
|
'group.manual': 'Added by hand',
|
|
467
475
|
'group.other': 'Other',
|
|
468
476
|
'group.items': '{n} items',
|
|
477
|
+
'group.item': '1 item',
|
|
469
478
|
'group.thisConversation': 'this conversation',
|
|
470
479
|
'group.overdue': 'Overdue',
|
|
471
480
|
'group.today': 'Today',
|
|
@@ -475,6 +484,7 @@ window.__ModuleLoader__.load({
|
|
|
475
484
|
'group.done': 'Done',
|
|
476
485
|
'group.cancelled': 'Cancelled',
|
|
477
486
|
'empty.none': 'No todos yet. Write one above and press Enter.',
|
|
487
|
+
'empty.add': 'Add your first todo',
|
|
478
488
|
'empty.filtered': 'Nothing matches this filter.',
|
|
479
489
|
'meta.added': 'added',
|
|
480
490
|
'meta.due': 'due',
|
|
@@ -871,6 +881,17 @@ window.__ModuleLoader__.load({
|
|
|
871
881
|
)
|
|
872
882
|
}
|
|
873
883
|
if (props.name === 'clock') return h('svg', common, h('circle', { cx: 8, cy: 8, r: 5.6 }), h('path', { d: 'M8 4.8V8l2.2 1.4' }))
|
|
884
|
+
if (props.name === 'close') return h('svg', common, h('path', { d: 'M4.2 4.2l7.6 7.6M11.8 4.2l-7.6 7.6' }))
|
|
885
|
+
if (props.name === 'gear') {
|
|
886
|
+
return h(
|
|
887
|
+
'svg',
|
|
888
|
+
common,
|
|
889
|
+
h('path', { d: 'M2.6 4.4h10.8M2.6 8h10.8M2.6 11.6h10.8' }),
|
|
890
|
+
h('circle', { cx: 6, cy: 4.4, r: 1.5, fill: 'currentColor', stroke: 'none' }),
|
|
891
|
+
h('circle', { cx: 10, cy: 8, r: 1.5, fill: 'currentColor', stroke: 'none' }),
|
|
892
|
+
h('circle', { cx: 5.2, cy: 11.6, r: 1.5, fill: 'currentColor', stroke: 'none' }),
|
|
893
|
+
)
|
|
894
|
+
}
|
|
874
895
|
if (props.name === 'chevron') return h('svg', common, h('path', { d: 'M5.6 3.8L10 8l-4.4 4.2' }))
|
|
875
896
|
if (props.name === 'flag') return h('svg', common, h('path', { d: 'M4 14V2.6h7l-1.2 2.8L11 8.2H4' }))
|
|
876
897
|
if (props.name === 'mute') {
|
|
@@ -887,25 +908,29 @@ window.__ModuleLoader__.load({
|
|
|
887
908
|
// ------------------------------------------------------------------ 样式
|
|
888
909
|
|
|
889
910
|
const CSS = `
|
|
890
|
-
.gt-root { display: flex; flex-direction: column; height: 100%; min-height: 0;
|
|
891
|
-
color: var(--dsw-alias-label-primary); font-size: 13px; }
|
|
892
|
-
.gt-inner { display: flex; flex-direction: column; gap:
|
|
893
|
-
margin: 0 auto; padding:
|
|
894
|
-
.gt-head { display: flex; align-items:
|
|
911
|
+
.gt-root { display: flex; flex-direction: column; height: 100%; min-height: 0; min-width: 0;
|
|
912
|
+
color: var(--dsw-alias-label-primary); font-size: 13px; line-height: 1.5; }
|
|
913
|
+
.gt-inner { display: flex; flex-direction: column; gap: 14px; width: 100%; max-width: 1040px; min-width: 0;
|
|
914
|
+
box-sizing: border-box; margin: 0 auto; padding: 20px 24px 32px; flex: 1; }
|
|
915
|
+
.gt-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
|
|
916
|
+
.gt-head-actions { display: flex; align-items: center; gap: 6px; margin-left: auto; flex: 0 0 auto; }
|
|
895
917
|
.gt-headline { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
|
896
|
-
.gt-title { font-size:
|
|
897
|
-
.gt-sub { color: var(--dsw-alias-label-secondary); font-size:
|
|
918
|
+
.gt-title { font-size: 20px; line-height: 28px; font-weight: 600; letter-spacing: 0; }
|
|
919
|
+
.gt-sub { color: var(--dsw-alias-label-secondary); font-size: 13px; line-height: 20px; }
|
|
898
920
|
.gt-spacer { flex: 1; }
|
|
899
921
|
.gt-iconbtn { display: inline-flex; align-items: center; justify-content: center; gap: 5px;
|
|
900
922
|
background: transparent; color: var(--dsw-alias-label-secondary); border: 1px solid transparent;
|
|
901
|
-
border-radius: 8px; padding:
|
|
923
|
+
border-radius: 8px; padding: 0 7px; min-height: 28px; min-width: 28px; box-sizing: border-box;
|
|
924
|
+
font: inherit; cursor: pointer; }
|
|
902
925
|
.gt-iconbtn:hover { color: var(--dsw-alias-label-primary); border-color: var(--dsw-alias-border-l1);
|
|
903
926
|
background: var(--dsw-alias-bg-layer-1); }
|
|
904
|
-
.gt-btn { display: inline-flex; align-items: center; gap:
|
|
927
|
+
.gt-btn { display: inline-flex; align-items: center; gap: 6px; background: var(--dsw-alias-bg-layer-1);
|
|
905
928
|
color: var(--dsw-alias-label-primary); border: 1px solid var(--dsw-alias-border-l1); border-radius: 8px;
|
|
906
|
-
padding:
|
|
929
|
+
padding: 0 11px; min-height: 28px; box-sizing: border-box; font: inherit; font-size: 13px;
|
|
930
|
+
font-weight: 500; line-height: 20px; cursor: pointer; white-space: nowrap; }
|
|
907
931
|
.gt-btn:hover { border-color: var(--dsw-alias-border-l2); }
|
|
908
|
-
.gt-btn:disabled { opacity:
|
|
932
|
+
.gt-btn:disabled { opacity: 1; background: var(--dsw-alias-border-l1); color: var(--dsw-alias-label-secondary);
|
|
933
|
+
border-color: transparent; cursor: default; }
|
|
909
934
|
.gt-btn-primary { background: var(--dsw-alias-brand-primary); border-color: var(--dsw-alias-brand-primary);
|
|
910
935
|
color: var(--dsw-alias-bg-base); font-weight: 600; }
|
|
911
936
|
.gt-btn-primary:hover { border-color: var(--dsw-alias-brand-primary); }
|
|
@@ -922,22 +947,22 @@ window.__ModuleLoader__.load({
|
|
|
922
947
|
.gt-new { display: flex; flex-direction: column; gap: 10px; }
|
|
923
948
|
.gt-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
|
924
949
|
.gt-input, .gt-select, .gt-textarea { background: var(--dsw-alias-bg-base); color: var(--dsw-alias-label-primary);
|
|
925
|
-
border: 1px solid var(--dsw-alias-border-l1); border-radius: 8px; padding:
|
|
950
|
+
border: 1px solid var(--dsw-alias-border-l1); border-radius: 8px; padding: 7px 10px; font: inherit; }
|
|
926
951
|
.gt-input:focus, .gt-select:focus, .gt-textarea:focus { outline: none; border-color: var(--dsw-alias-brand-primary); }
|
|
927
952
|
.gt-input { flex: 1; min-width: 120px; }
|
|
928
953
|
.gt-input-sm { flex: 0 1 auto; min-width: 96px; }
|
|
929
954
|
.gt-textarea { width: 100%; min-height: 54px; resize: vertical; font-family: inherit; }
|
|
930
955
|
.gt-select { padding: 6px 7px; }
|
|
931
|
-
.gt-search { display: flex; align-items: center; gap: 6px; flex: 1; min-width:
|
|
956
|
+
.gt-search { display: flex; align-items: center; gap: 6px; flex: 1 1 220px; min-width: 0;
|
|
932
957
|
background: var(--dsw-alias-bg-base); border: 1px solid var(--dsw-alias-border-l1); border-radius: 8px;
|
|
933
|
-
padding: 0 9px; color: var(--dsw-alias-label-secondary); }
|
|
958
|
+
min-height: 30px; box-sizing: border-box; padding: 0 9px; color: var(--dsw-alias-label-secondary); }
|
|
934
959
|
.gt-search input { flex: 1; background: transparent; border: none; color: var(--dsw-alias-label-primary);
|
|
935
|
-
font: inherit; padding:
|
|
960
|
+
font: inherit; font-size: 13px; padding: 0; min-width: 0; }
|
|
936
961
|
.gt-search input:focus { outline: none; }
|
|
937
962
|
.gt-search:focus-within { border-color: var(--dsw-alias-brand-primary); }
|
|
938
963
|
.gt-kbd { font-size: 10.5px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 4px;
|
|
939
964
|
padding: 0 4px; color: var(--dsw-alias-label-secondary); }
|
|
940
|
-
.gt-dir { display: inline-flex; align-items: center; gap: 5px; font-size:
|
|
965
|
+
.gt-dir { display: inline-flex; align-items: center; gap: 5px; font-size: 12px;
|
|
941
966
|
color: var(--dsw-alias-label-secondary); border: 1px solid var(--dsw-alias-border-l1);
|
|
942
967
|
border-radius: 8px; padding: 3px 6px 3px 8px; max-width: 560px; }
|
|
943
968
|
/* Only the path may shrink. Everything else in the pill used to shrink with it, so a
|
|
@@ -946,20 +971,30 @@ window.__ModuleLoader__.load({
|
|
|
946
971
|
.gt-dir > .gt-muted, .gt-dir > .gt-btn, .gt-dir > svg { white-space: nowrap; flex-shrink: 0; }
|
|
947
972
|
.gt-dir-path { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--dsw-alias-label-primary);
|
|
948
973
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 300px; }
|
|
949
|
-
.gt-toolbar { display:
|
|
974
|
+
.gt-toolbar { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
|
|
975
|
+
gap: 8px 10px; }
|
|
976
|
+
.gt-toolbar-main { grid-column: 1 / -1; grid-row: 1; display: flex; align-items: center;
|
|
977
|
+
gap: 8px; min-width: 0; flex-wrap: nowrap; }
|
|
978
|
+
.gt-toolbar-main .gt-search { flex: 1 1 auto; }
|
|
979
|
+
.gt-toolbar > .gt-spacer { display: none; }
|
|
980
|
+
.gt-toolbar > .gt-context-summary { grid-row: 2; grid-column: 1; min-width: 0; }
|
|
981
|
+
.gt-toolbar > .gt-tabs { grid-row: 2; grid-column: 2; justify-self: end; }
|
|
982
|
+
.gt-toolbar > .gt-context-details { grid-column: 1 / -1; grid-row: 3; }
|
|
983
|
+
@media (max-width: 1250px) { .gt-toolbar-main { flex-wrap: wrap; } }
|
|
950
984
|
.gt-seg { display: inline-flex; background: var(--dsw-alias-bg-layer-1); border: 1px solid var(--dsw-alias-border-l1);
|
|
951
985
|
border-radius: 9px; padding: 2px; gap: 2px; }
|
|
952
986
|
.gt-seg button { border: none; background: transparent; color: var(--dsw-alias-label-secondary); font: inherit;
|
|
953
987
|
border-radius: 7px; padding: 3px 10px; cursor: pointer; }
|
|
954
|
-
.gt-seg button[data-on="1"] { background: var(--dsw-alias-
|
|
988
|
+
.gt-seg button[data-on="1"] { background: var(--dsw-alias-button-ghost-active-fill); color: var(--dsw-alias-label-primary); font-weight: 600; }
|
|
955
989
|
.gt-chips { display: flex; gap: 6px; flex-wrap: wrap; }
|
|
956
990
|
/* One segmented style for every control that is "pick one of these": filters, grouping,
|
|
957
991
|
the two toggles. Chips stay for facts about a todo (tags, levels, notes). */
|
|
958
992
|
.gt-tabs { display: inline-flex; gap: 2px; padding: 2px; border-radius: 8px; background: var(--dsw-alias-bg-layer-2); }
|
|
959
993
|
.gt-tab { border: none; background: transparent; color: var(--dsw-alias-label-secondary); font: inherit;
|
|
960
|
-
font-size:
|
|
994
|
+
font-size: 12.5px; border-radius: 6px; padding: 0 10px; min-height: 24px; box-sizing: border-box;
|
|
995
|
+
cursor: pointer; white-space: nowrap; }
|
|
961
996
|
.gt-tab:hover { color: var(--dsw-alias-label-primary); }
|
|
962
|
-
.gt-tab[data-on="1"] { background: var(--dsw-alias-
|
|
997
|
+
.gt-tab[data-on="1"] { background: var(--dsw-alias-button-ghost-active-fill); color: var(--dsw-alias-label-primary); font-weight: 600; }
|
|
963
998
|
.gt-summary { color: var(--dsw-alias-label-secondary); font-size: 12px; }
|
|
964
999
|
.gt-browse { border: 1px solid var(--dsw-alias-border-l1); border-radius: 9px; padding: 8px 10px;
|
|
965
1000
|
display: flex; flex-direction: column; gap: 6px; max-height: 220px; overflow: auto; }
|
|
@@ -971,7 +1006,7 @@ window.__ModuleLoader__.load({
|
|
|
971
1006
|
.gt-browse-item:hover { color: var(--dsw-alias-label-primary); border-color: var(--dsw-alias-brand-primary); }
|
|
972
1007
|
.gt-divider { width: 1px; height: 16px; background: var(--dsw-alias-border-l1); }
|
|
973
1008
|
.gt-context { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 12px; }
|
|
974
|
-
.gt-chip { display: inline-flex; align-items: center; gap: 5px; font-size:
|
|
1009
|
+
.gt-chip { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; line-height: 16px; padding: 2px 8px;
|
|
975
1010
|
border-radius: 999px; border: 1px solid var(--dsw-alias-border-l1); background: transparent;
|
|
976
1011
|
color: var(--dsw-alias-label-secondary); }
|
|
977
1012
|
button.gt-chip { cursor: pointer; font-family: inherit; }
|
|
@@ -981,27 +1016,31 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
981
1016
|
.gt-chip-warn { color: var(--dsw-alias-state-warn-primary); border-color: var(--dsw-alias-state-warn-primary); }
|
|
982
1017
|
.gt-chip-bad { color: var(--dsw-alias-state-error-primary); border-color: var(--dsw-alias-state-error-primary); }
|
|
983
1018
|
.gt-chip-ok { color: var(--dsw-alias-state-success-primary); }
|
|
984
|
-
.gt-groups { display: flex; flex-direction: column; gap:
|
|
1019
|
+
.gt-groups { display: flex; flex-direction: column; gap: 18px; overflow: auto; min-height: 0; flex: 1; }
|
|
985
1020
|
.gt-group { display: flex; flex-direction: column; gap: 6px; }
|
|
986
|
-
.gt-group-head { display: flex; align-items: center; gap:
|
|
987
|
-
font-size:
|
|
1021
|
+
.gt-group-head { display: flex; align-items: center; gap: 8px; color: var(--dsw-alias-label-secondary);
|
|
1022
|
+
font-size: 12px; line-height: 18px; padding: 0 2px; }
|
|
988
1023
|
.gt-group-head button { border: none; background: transparent; color: inherit; cursor: pointer;
|
|
989
1024
|
display: inline-flex; align-items: center; gap: 6px; font: inherit; padding: 2px 0; }
|
|
990
1025
|
.gt-group-head svg { transition: transform .12s ease; transform: rotate(90deg); }
|
|
991
1026
|
.gt-group[data-collapsed="1"] .gt-group-head svg { transform: rotate(0deg); }
|
|
992
1027
|
.gt-group-action { margin-left: 4px; border: 1px solid transparent; background: transparent; color: inherit;
|
|
993
|
-
border-radius: 999px; padding:
|
|
994
|
-
|
|
1028
|
+
border-radius: 999px; padding: 3px 8px; min-height: 24px; box-sizing: border-box; font: inherit;
|
|
1029
|
+
font-size: 0; letter-spacing: .04em; cursor: pointer; display: inline-flex; align-items: center; gap: 5px;
|
|
1030
|
+
opacity: .72; transition: opacity .12s ease; }
|
|
1031
|
+
.gt-group:hover .gt-group-action, .gt-group-action:focus-visible { font-size: 11px; }
|
|
995
1032
|
.gt-group:hover .gt-group-action, .gt-group-action:focus-visible { opacity: 1; }
|
|
996
1033
|
.gt-group-action:hover { color: var(--dsw-alias-label-primary); border-color: var(--dsw-alias-border-l2); }
|
|
997
1034
|
/* An exemption is a state, not an action: it stays visible and reads as "on" without a hover. */
|
|
998
1035
|
.gt-group-action[data-on="1"] { opacity: 1; color: var(--dsw-alias-label-primary);
|
|
999
1036
|
border-color: var(--dsw-alias-border-l2); }
|
|
1000
|
-
.gt-group-count { color: var(--dsw-alias-label-secondary); }
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
.gt-
|
|
1004
|
-
|
|
1037
|
+
.gt-group-count { color: var(--dsw-alias-label-secondary); font-size: 12px; font-weight: 400; }
|
|
1038
|
+
/* A group's level is redundant while it is expanded — the rows show it. */
|
|
1039
|
+
.gt-group:not([data-collapsed="1"]) .gt-group-head .gt-level { display: none; }
|
|
1040
|
+
.gt-group-label { color: var(--dsw-alias-label-primary); font-weight: 600; font-size: 12px;
|
|
1041
|
+
line-height: 18px; max-width: 480px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1042
|
+
.gt-level { display: inline-flex; align-items: center; gap: 3px; font-size: 11.5px; padding: 0;
|
|
1043
|
+
border: none; color: var(--dsw-alias-label-secondary); }
|
|
1005
1044
|
.gt-level[data-level="urgent"] { color: var(--dsw-alias-state-error-primary); border-color: var(--dsw-alias-state-error-primary); font-weight: 600; }
|
|
1006
1045
|
.gt-level[data-level="high"] { color: var(--dsw-alias-state-warn-primary); border-color: var(--dsw-alias-state-warn-primary); }
|
|
1007
1046
|
.gt-level[data-level="low"] { color: var(--dsw-alias-label-secondary); }
|
|
@@ -1009,57 +1048,76 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1009
1048
|
display: inline-block; }
|
|
1010
1049
|
.gt-here { font-size: 10.5px; padding: 0 5px; border-radius: 999px; border: 1px solid var(--dsw-alias-brand-primary);
|
|
1011
1050
|
color: var(--dsw-alias-brand-primary); }
|
|
1012
|
-
.gt-list { display: flex; flex-direction: column; gap:
|
|
1013
|
-
.gt-item { position: relative; display: flex; flex-direction: column; gap:
|
|
1051
|
+
.gt-list { display: flex; flex-direction: column; gap: 8px; }
|
|
1052
|
+
.gt-item { position: relative; display: flex; flex-direction: column; gap: 8px;
|
|
1014
1053
|
background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1);
|
|
1015
|
-
border-radius:
|
|
1054
|
+
border-radius: 12px; padding: 12px 14px; }
|
|
1016
1055
|
.gt-item:hover { border-color: var(--dsw-alias-border-l2); }
|
|
1017
1056
|
.gt-item[data-status="doing"] { border-left: 2px solid var(--dsw-alias-brand-primary); }
|
|
1018
1057
|
.gt-item[data-overdue="1"] { border-left: 2px solid var(--dsw-alias-state-error-primary); }
|
|
1019
1058
|
.gt-item[data-status="done"], .gt-item[data-status="cancelled"] { opacity: .72; }
|
|
1020
1059
|
.gt-item[data-open="1"] { border-color: var(--dsw-alias-brand-primary); }
|
|
1021
1060
|
.gt-item-head { display: flex; gap: 10px; align-items: flex-start; }
|
|
1022
|
-
.gt-check { flex: 0 0 auto; width:
|
|
1061
|
+
.gt-check { flex: 0 0 auto; width: 24px; height: 24px; margin-top: 0; border-radius: 999px; cursor: pointer;
|
|
1023
1062
|
border: 1.4px solid var(--dsw-alias-border-l2); background: transparent; color: transparent;
|
|
1024
1063
|
display: inline-flex; align-items: center; justify-content: center; padding: 0; }
|
|
1025
1064
|
.gt-check:hover { border-color: var(--dsw-alias-state-success-primary); color: var(--dsw-alias-state-success-primary); }
|
|
1026
1065
|
.gt-check[data-on="1"] { border-color: var(--dsw-alias-state-success-primary);
|
|
1027
1066
|
background: var(--dsw-alias-state-success-primary); color: var(--dsw-alias-bg-base); }
|
|
1028
|
-
.gt-pick { flex: 0 0 auto; width:
|
|
1067
|
+
.gt-pick { flex: 0 0 auto; width: 22px; height: 22px; margin-top: 1px; border-radius: 6px; cursor: pointer;
|
|
1029
1068
|
border: 1.4px solid var(--dsw-alias-border-l2); background: transparent; color: transparent;
|
|
1030
1069
|
display: inline-flex; align-items: center; justify-content: center; padding: 0; }
|
|
1031
1070
|
.gt-pick[data-on="1"] { border-color: var(--dsw-alias-brand-primary); background: var(--dsw-alias-brand-primary); color: var(--dsw-alias-bg-base); }
|
|
1032
1071
|
.gt-item[data-selected="1"] { border-color: var(--dsw-alias-brand-primary); }
|
|
1033
|
-
.gt-selectbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding:
|
|
1034
|
-
border: 1px solid var(--dsw-alias-brand-primary); border-radius:
|
|
1035
|
-
.gt-item-body { flex: 1; display: flex; flex-direction: column; gap: 5px; min-width: 0; }
|
|
1036
|
-
.gt-item-
|
|
1037
|
-
.gt-
|
|
1072
|
+
.gt-selectbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 9px 12px;
|
|
1073
|
+
border: 1px solid var(--dsw-alias-brand-primary); border-radius: 10px; background: var(--dsw-alias-bg-layer-1); font-size: 13px; }
|
|
1074
|
+
.gt-item-body { flex: 1; display: flex; flex-direction: column; gap: 5px; min-width: 0; cursor: pointer; }
|
|
1075
|
+
.gt-item-body:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 2px; border-radius: 6px; }
|
|
1076
|
+
.gt-item-title { font-weight: 600; font-size: 14px; word-break: break-word; line-height: 22px;
|
|
1077
|
+
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
|
1078
|
+
.gt-input-xs { width: 64px; flex: 0 0 auto; min-width: 0; padding: 0 8px; min-height: 28px;
|
|
1079
|
+
box-sizing: border-box; font-size: 12.5px; }
|
|
1038
1080
|
.gt-seq { font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-secondary); }
|
|
1039
|
-
.gt-reminders { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 8px
|
|
1040
|
-
border: 1px solid var(--dsw-alias-
|
|
1041
|
-
background: var(--dsw-alias-bg-layer-1); font-size:
|
|
1042
|
-
.gt-reminders
|
|
1043
|
-
.gt-
|
|
1044
|
-
|
|
1045
|
-
|
|
1081
|
+
.gt-reminders { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 8px 12px;
|
|
1082
|
+
min-height: 36px; box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l1);
|
|
1083
|
+
border-radius: 10px; background: var(--dsw-alias-bg-layer-1); font-size: 13px; }
|
|
1084
|
+
.gt-reminders { border-left: 2px solid var(--dsw-alias-state-warn-primary); }
|
|
1085
|
+
.gt-reminders-title { color: var(--dsw-alias-label-primary); font-weight: 600; }
|
|
1086
|
+
.gt-reminder-item { border: 1px solid transparent; background: transparent;
|
|
1087
|
+
color: var(--dsw-alias-label-primary); font: inherit; font-size: 13px; padding: 2px 6px;
|
|
1088
|
+
border-radius: 6px; cursor: pointer; max-width: 300px; overflow: hidden; text-overflow: ellipsis;
|
|
1046
1089
|
white-space: nowrap; }
|
|
1047
|
-
.gt-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
.gt-
|
|
1090
|
+
.gt-reminder-item:hover { background: var(--dsw-alias-button-ghost-active-fill); }
|
|
1091
|
+
.gt-settings { display: flex; flex-direction: column; gap: 12px; padding: 16px; width: 340px;
|
|
1092
|
+
box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l2); border-radius: 12px;
|
|
1093
|
+
background: var(--dsw-alias-bg-overlay); font-size: 13px; line-height: 20px; }
|
|
1094
|
+
.gt-settings-path { font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1095
|
+
.gt-settings .gt-input { flex: 0 0 auto; width: 100%; min-height: 32px; }
|
|
1096
|
+
.gt-settings .gt-check-line .gt-input { width: 64px; }
|
|
1097
|
+
.gt-settings-head { font-weight: 650; font-size: 14px; }
|
|
1098
|
+
.gt-check-line { display: flex; align-items: center; gap: 8px; justify-content: flex-start;
|
|
1052
1099
|
color: var(--dsw-alias-label-primary); }
|
|
1053
|
-
.gt-settings-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
|
1100
|
+
.gt-settings-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
|
|
1101
|
+
.gt-context-summary { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }
|
|
1102
|
+
.gt-context-summary .gt-chip { max-width: 340px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1103
|
+
.gt-context-details { display: none; flex-direction: column; gap: 8px; padding: 10px 12px;
|
|
1104
|
+
border: 1px solid var(--dsw-alias-border-l1); border-radius: 10px;
|
|
1105
|
+
background: var(--dsw-alias-bg-layer-1); }
|
|
1106
|
+
.gt-context-details[data-open="1"] { display: flex; }
|
|
1107
|
+
.gt-detail-head { display: flex; align-items: flex-start; gap: 8px; justify-content: space-between; }
|
|
1108
|
+
.gt-detail-title { font-size: 14px; line-height: 22px; font-weight: 600; min-width: 0;
|
|
1109
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1110
|
+
.gt-truncated { color: var(--dsw-alias-state-warn-primary); font-size: 12px; }
|
|
1111
|
+
.gt-bulk-tag { flex: 0 1 120px; min-width: 90px; }
|
|
1054
1112
|
.gt-inbox { margin-left: 6px; padding: 1px 6px; border-radius: 999px; font-size: 10.5px; font-weight: 600;
|
|
1055
1113
|
color: var(--dsw-alias-state-warn-primary); border: 1px solid var(--dsw-alias-state-warn-primary);
|
|
1056
1114
|
vertical-align: 1px; }
|
|
1057
1115
|
.gt-item[data-status="done"] .gt-item-title, .gt-item[data-status="cancelled"] .gt-item-title {
|
|
1058
1116
|
text-decoration: line-through; color: var(--dsw-alias-label-secondary); }
|
|
1059
|
-
.gt-meta { display: flex; gap:
|
|
1060
|
-
align-items: center; }
|
|
1117
|
+
.gt-meta { display: flex; gap: 2px 0; flex-wrap: wrap; color: var(--dsw-alias-label-secondary); font-size: 12px;
|
|
1118
|
+
line-height: 18px; align-items: center; }
|
|
1061
1119
|
.gt-meta > span { display: inline-flex; align-items: center; }
|
|
1062
|
-
.gt-meta
|
|
1120
|
+
.gt-meta > span + span::before { content: '·'; margin: 0 6px; opacity: .45; }
|
|
1063
1121
|
.gt-tag { color: var(--dsw-alias-brand-primary); }
|
|
1064
1122
|
/* The dispatch action stays put: hiding the only way to hand work to an agent
|
|
1065
1123
|
behind a hover makes a lone todo look like it can do nothing. */
|
|
@@ -1068,23 +1126,23 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1068
1126
|
.gt-attach .gt-chip { max-width: 280px; color: var(--dsw-alias-label-secondary); }
|
|
1069
1127
|
.gt-attach a.gt-chip:hover { color: var(--dsw-alias-label-primary); border-color: var(--dsw-alias-border-l2); }
|
|
1070
1128
|
.gt-attach-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1071
|
-
.gt-menu { position: absolute; top: 40px; right: 10px; z-index: 3; min-width:
|
|
1072
|
-
flex-direction: column; padding:
|
|
1129
|
+
.gt-menu { position: absolute; top: 40px; right: 10px; z-index: 3; min-width: 184px; display: flex;
|
|
1130
|
+
flex-direction: column; padding: 5px; background: var(--dsw-alias-bg-overlay);
|
|
1073
1131
|
border: 1px solid var(--dsw-alias-border-l2); border-radius: 10px; }
|
|
1074
1132
|
.gt-menu button { display: flex; align-items: center; gap: 8px; text-align: left; border: none;
|
|
1075
|
-
background: transparent; color: var(--dsw-alias-label-primary); font: inherit; padding:
|
|
1133
|
+
background: transparent; color: var(--dsw-alias-label-primary); font: inherit; font-size: 13px; padding: 8px 10px;
|
|
1076
1134
|
border-radius: 7px; cursor: pointer; }
|
|
1077
|
-
.gt-menu button:hover { background: var(--dsw-alias-
|
|
1135
|
+
.gt-menu button:hover { background: var(--dsw-alias-button-ghost-active-fill); }
|
|
1078
1136
|
.gt-menu button[data-danger="1"] { color: var(--dsw-alias-state-error-primary); }
|
|
1079
|
-
.gt-detail { display: flex; flex-direction: column; gap:
|
|
1080
|
-
padding-top:
|
|
1137
|
+
.gt-detail { display: flex; flex-direction: column; gap: 12px; border-top: 1px solid var(--dsw-alias-border-l1);
|
|
1138
|
+
padding-top: 12px; margin-top: 2px; }
|
|
1081
1139
|
/* Wide screens: the open row's detail becomes a card on the right instead of pushing the list
|
|
1082
1140
|
down. Deliberately CSS-only over unchanged markup: one detail implementation, and it only
|
|
1083
1141
|
applies where there is room for a second column. */
|
|
1084
|
-
@media (min-width:
|
|
1142
|
+
@media (min-width: 1224px) {
|
|
1085
1143
|
/* Only the list gives way: the title row and the toolbar keep their full width, so the
|
|
1086
1144
|
controls never wrap or hide behind the card. */
|
|
1087
|
-
.gt-root[data-wide-detail="1"] .gt-groups { padding-right:
|
|
1145
|
+
.gt-root[data-wide-detail="1"] .gt-groups { padding-right: 360px; }
|
|
1088
1146
|
.gt-root[data-wide-detail="1"] .gt-inner { position: relative; }
|
|
1089
1147
|
.gt-root[data-wide-detail="1"] .gt-item[data-open="1"] .gt-detail {
|
|
1090
1148
|
/* Anchored to the panel's own column (.gt-inner), not to the viewport: the slot does not
|
|
@@ -1095,21 +1153,25 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1095
1153
|
a gap instead of overlapping by the padding width. */
|
|
1096
1154
|
box-sizing: border-box;
|
|
1097
1155
|
position: fixed; top: var(--gt-detail-top, 208px);
|
|
1098
|
-
right: var(--gt-detail-right, max(24px, calc((100vw -
|
|
1099
|
-
bottom: var(--gt-detail-bottom, 64px); width:
|
|
1156
|
+
right: var(--gt-detail-right, max(24px, calc((100vw - 1040px) / 2 + 24px)));
|
|
1157
|
+
bottom: var(--gt-detail-bottom, 64px); width: 340px;
|
|
1100
1158
|
overflow: auto; padding: 16px; margin: 0; border: 1px solid var(--dsw-alias-border-l2);
|
|
1101
1159
|
border-radius: 12px; background: var(--dsw-alias-bg-overlay); z-index: 30;
|
|
1102
1160
|
}
|
|
1103
1161
|
}
|
|
1104
1162
|
.gt-section { display: flex; flex-direction: column; gap: 5px; }
|
|
1105
1163
|
.gt-completion { white-space: pre-wrap; word-break: break-word; line-height: 1.5; }
|
|
1106
|
-
.gt-section-title { color: var(--dsw-alias-label-secondary); font-size:
|
|
1107
|
-
letter-spacing: .06em; }
|
|
1164
|
+
.gt-section-title { color: var(--dsw-alias-label-secondary); font-size: 12px; line-height: 18px; font-weight: 600; }
|
|
1108
1165
|
.gt-pre { white-space: pre-wrap; word-break: break-word; margin: 0; line-height: 1.6; }
|
|
1109
1166
|
.gt-muted { color: var(--dsw-alias-label-secondary); }
|
|
1110
1167
|
.gt-links { display: flex; flex-direction: column; gap: 4px; margin: 0; padding: 0; list-style: none; }
|
|
1111
1168
|
.gt-link { display: flex; gap: 8px; align-items: center; padding: 4px 0; min-width: 0; }
|
|
1112
1169
|
.gt-link-main { display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1; }
|
|
1170
|
+
.gt-note-item { display: flex; flex-direction: column; gap: 4px; padding: 8px 0; }
|
|
1171
|
+
.gt-note-item + .gt-note-item { border-top: 1px solid var(--dsw-alias-border-l1); }
|
|
1172
|
+
.gt-note-meta { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--dsw-alias-label-secondary);
|
|
1173
|
+
white-space: nowrap; }
|
|
1174
|
+
.gt-note-text { font-size: 13px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; max-width: 68ch; }
|
|
1113
1175
|
.gt-link a { color: var(--dsw-alias-brand-primary); text-decoration: none; }
|
|
1114
1176
|
.gt-link a:hover { text-decoration: underline; }
|
|
1115
1177
|
.gt-link-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 320px; }
|
|
@@ -1471,9 +1533,19 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1471
1533
|
if (Number.isInteger(todo.seq) && todo.seq > 0) {
|
|
1472
1534
|
meta.push(h('span', { key: 'seq', className: 'gt-seq', title: t('meta.seqHint') }, `#${todo.seq}`))
|
|
1473
1535
|
}
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1536
|
+
if (todo.dueAt !== null) {
|
|
1537
|
+
meta.push(
|
|
1538
|
+
h(
|
|
1539
|
+
'span',
|
|
1540
|
+
{ key: 'due', className: overdue ? 'gt-chip-bad' : '', title: new Date(todo.dueAt).toLocaleString() },
|
|
1541
|
+
overdue
|
|
1542
|
+
? t('meta.overdue', { n: daysLate(todo.dueAt, now) })
|
|
1543
|
+
: sameLocalDay(Date.parse(todo.dueAt), now)
|
|
1544
|
+
? t('meta.today')
|
|
1545
|
+
: `${t('meta.due')} ${absoluteTime(Date.parse(todo.dueAt))}`,
|
|
1546
|
+
),
|
|
1547
|
+
)
|
|
1548
|
+
}
|
|
1477
1549
|
if (todo.priority !== 'normal') {
|
|
1478
1550
|
meta.push(
|
|
1479
1551
|
h(
|
|
@@ -1484,23 +1556,17 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1484
1556
|
),
|
|
1485
1557
|
)
|
|
1486
1558
|
}
|
|
1487
|
-
|
|
1559
|
+
meta.push(h('span', { key: 'added', title: new Date(todo.createdAt).toLocaleString() }, ageText(lang, todo.createdAt, now)))
|
|
1560
|
+
if (todo.tags.length > 0) {
|
|
1561
|
+
const shown = todo.tags.slice(0, 4)
|
|
1488
1562
|
meta.push(
|
|
1489
1563
|
h(
|
|
1490
1564
|
'span',
|
|
1491
|
-
{ key: '
|
|
1492
|
-
|
|
1493
|
-
? t('meta.overdue', { n: daysLate(todo.dueAt, now) })
|
|
1494
|
-
: sameLocalDay(Date.parse(todo.dueAt), now)
|
|
1495
|
-
? t('meta.today')
|
|
1496
|
-
: `${t('meta.due')} ${absoluteTime(Date.parse(todo.dueAt))}`,
|
|
1565
|
+
{ key: 'tags', className: 'gt-tag', title: todo.tags.map((tag) => `#${tag}`).join(' ') },
|
|
1566
|
+
shown.map((tag) => `#${tag}`).join(' ') + (todo.tags.length > shown.length ? ` +${todo.tags.length - shown.length}` : ''),
|
|
1497
1567
|
),
|
|
1498
1568
|
)
|
|
1499
1569
|
}
|
|
1500
|
-
if (todo.tags.length > 0) {
|
|
1501
|
-
meta.push(h('span', { key: 'tags', className: 'gt-tag' }, todo.tags.map((tag) => `#${tag}`).join(' ')))
|
|
1502
|
-
}
|
|
1503
|
-
meta.push(h('span', { key: 'by' }, t(`meta.by.${todo.createdBy === 'agent' ? 'agent' : 'human'}`)))
|
|
1504
1570
|
if (Array.isArray(todo.notes) && todo.notes.length > 0) {
|
|
1505
1571
|
const latest = todo.notes[todo.notes.length - 1]
|
|
1506
1572
|
meta.push(h('span', { key: 'notes', title: latest.text }, t('note.count', { n: todo.notes.length })))
|
|
@@ -1508,12 +1574,8 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1508
1574
|
if (todo.completion !== null && todo.completion !== undefined) {
|
|
1509
1575
|
meta.push(h('span', { key: 'completed', title: todo.completion.summary }, t('meta.completed', { when: absoluteTime(todo.completion.at) })))
|
|
1510
1576
|
}
|
|
1511
|
-
|
|
1512
|
-
meta.push(h('span', { key: 'origin', title: todo.originDir }, t('meta.origin', { dir: shortPath(todo.originDir) })))
|
|
1513
|
-
}
|
|
1577
|
+
meta.push(h('span', { key: 'by' }, t(`meta.by.${todo.createdBy === 'agent' ? 'agent' : 'human'}`)))
|
|
1514
1578
|
if (todo.sessionId !== '') {
|
|
1515
|
-
// A live conversation with no working directory cannot do the work. Say
|
|
1516
|
-
// so on the row instead of letting the next hand-off land there again.
|
|
1517
1579
|
const stranded = todo.sessionAlive === true && (todo.sessionDir ?? '') === ''
|
|
1518
1580
|
meta.push(
|
|
1519
1581
|
h(
|
|
@@ -1521,9 +1583,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1521
1583
|
{
|
|
1522
1584
|
key: 'session',
|
|
1523
1585
|
className: stranded ? 'gt-chip-warn' : todo.sessionAlive === true ? 'gt-chip-ok' : '',
|
|
1524
|
-
title: stranded
|
|
1525
|
-
? t('meta.session.noDirHint')
|
|
1526
|
-
: (todo.sessionDir ?? ''),
|
|
1586
|
+
title: stranded ? t('meta.session.noDirHint') : (todo.sessionDir ?? ''),
|
|
1527
1587
|
},
|
|
1528
1588
|
stranded ? t('meta.session.noDir') : todo.sessionAlive === true ? t('meta.session.live') : t('meta.session.bound'),
|
|
1529
1589
|
),
|
|
@@ -1588,7 +1648,21 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1588
1648
|
),
|
|
1589
1649
|
h(
|
|
1590
1650
|
'div',
|
|
1591
|
-
{
|
|
1651
|
+
{
|
|
1652
|
+
className: 'gt-item-body',
|
|
1653
|
+
role: 'button',
|
|
1654
|
+
tabIndex: 0,
|
|
1655
|
+
'aria-expanded': open,
|
|
1656
|
+
onClick: (event) => {
|
|
1657
|
+
if (event.target?.closest?.('a,button,input,textarea,select') !== null) return
|
|
1658
|
+
onToggleOpen(todo.id)
|
|
1659
|
+
},
|
|
1660
|
+
onKeyDown: (event) => {
|
|
1661
|
+
if (event.key !== 'Enter' && event.key !== ' ') return
|
|
1662
|
+
event.preventDefault()
|
|
1663
|
+
onToggleOpen(todo.id)
|
|
1664
|
+
},
|
|
1665
|
+
},
|
|
1592
1666
|
h(
|
|
1593
1667
|
'div',
|
|
1594
1668
|
{ className: 'gt-item-title' },
|
|
@@ -1600,9 +1674,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1600
1674
|
h(
|
|
1601
1675
|
'div',
|
|
1602
1676
|
{ className: 'gt-meta' },
|
|
1603
|
-
meta
|
|
1604
|
-
index === 0 ? [node] : [h('span', { key: `sep${index}`, className: 'gt-meta-sep' }, '·'), node],
|
|
1605
|
-
),
|
|
1677
|
+
meta,
|
|
1606
1678
|
),
|
|
1607
1679
|
// What is attached is half the point of the list, so the first few are
|
|
1608
1680
|
// shown as chips instead of being reported as a number.
|
|
@@ -1701,7 +1773,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1701
1773
|
'button',
|
|
1702
1774
|
{
|
|
1703
1775
|
type: 'button',
|
|
1704
|
-
className: 'gt-btn gt-btn-
|
|
1776
|
+
className: 'gt-btn gt-btn-quiet',
|
|
1705
1777
|
disabled: busy,
|
|
1706
1778
|
title: dispatchLabel,
|
|
1707
1779
|
onClick: () => onAction('dispatch', todo),
|
|
@@ -1752,6 +1824,16 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1752
1824
|
? h(
|
|
1753
1825
|
'div',
|
|
1754
1826
|
{ className: 'gt-detail' },
|
|
1827
|
+
h(
|
|
1828
|
+
'div',
|
|
1829
|
+
{ className: 'gt-detail-head' },
|
|
1830
|
+
h('span', { className: 'gt-detail-title' }, `${Number.isInteger(todo.seq) && todo.seq > 0 ? `#${todo.seq} ` : ''}${todo.title}`),
|
|
1831
|
+
h(
|
|
1832
|
+
'button',
|
|
1833
|
+
{ type: 'button', className: 'gt-iconbtn', title: t('action.hide'), 'aria-label': t('action.hide'), onClick: () => onToggleOpen(todo.id) },
|
|
1834
|
+
h(Icon, { name: 'close', size: 13 }),
|
|
1835
|
+
),
|
|
1836
|
+
),
|
|
1755
1837
|
h(
|
|
1756
1838
|
'div',
|
|
1757
1839
|
{ className: 'gt-section' },
|
|
@@ -1836,14 +1918,15 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1836
1918
|
(todo.notes ?? []).map((entry, index) =>
|
|
1837
1919
|
h(
|
|
1838
1920
|
'li',
|
|
1839
|
-
{ className: 'gt-
|
|
1921
|
+
{ className: 'gt-note-item', key: `note:${index}:${entry.at}` },
|
|
1840
1922
|
h(
|
|
1841
|
-
'
|
|
1842
|
-
{ className: 'gt-
|
|
1843
|
-
h(Icon, { name: 'doc', size:
|
|
1844
|
-
h('span',
|
|
1845
|
-
h('span',
|
|
1923
|
+
'div',
|
|
1924
|
+
{ className: 'gt-note-meta' },
|
|
1925
|
+
h(Icon, { name: 'doc', size: 12 }),
|
|
1926
|
+
h('span', null, absoluteTime(entry.at)),
|
|
1927
|
+
h('span', null, entry.by === 'agent' ? t('note.by.agent') : t('note.by.human')),
|
|
1846
1928
|
),
|
|
1929
|
+
h('div', { className: 'gt-note-text' }, entry.text),
|
|
1847
1930
|
),
|
|
1848
1931
|
),
|
|
1849
1932
|
),
|
|
@@ -2082,6 +2165,8 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2082
2165
|
// One settings popover: reminders and the external door both need a place a person can
|
|
2083
2166
|
// reach without curl.
|
|
2084
2167
|
const [settingsOpen, setSettingsOpen] = useState(false)
|
|
2168
|
+
const [settingsBox, setSettingsBox] = useState(null)
|
|
2169
|
+
const [contextOpen, setContextOpen] = useState(false)
|
|
2085
2170
|
const [tokenDraft, setTokenDraft] = useState('')
|
|
2086
2171
|
const [ingestDraft, setIngestDraft] = useState(false)
|
|
2087
2172
|
const [belowDraft, setBelowDraft] = useState('0.8')
|
|
@@ -2321,6 +2406,26 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2321
2406
|
}
|
|
2322
2407
|
}, [lang])
|
|
2323
2408
|
|
|
2409
|
+
useEffect(() => {
|
|
2410
|
+
if (!settingsOpen || typeof window === 'undefined') {
|
|
2411
|
+
setSettingsBox(null)
|
|
2412
|
+
return undefined
|
|
2413
|
+
}
|
|
2414
|
+
const measure = () => {
|
|
2415
|
+
const element = innerRef.current
|
|
2416
|
+
if (element === null) return
|
|
2417
|
+
const rect = element.getBoundingClientRect()
|
|
2418
|
+
setSettingsBox({
|
|
2419
|
+
top: Math.round(rect.top + 210),
|
|
2420
|
+
right: Math.round(window.innerWidth - rect.right + 20),
|
|
2421
|
+
bottom: Math.round(window.innerHeight - rect.bottom + 20),
|
|
2422
|
+
})
|
|
2423
|
+
}
|
|
2424
|
+
measure()
|
|
2425
|
+
window.addEventListener('resize', measure)
|
|
2426
|
+
return () => window.removeEventListener('resize', measure)
|
|
2427
|
+
}, [settingsOpen, lang])
|
|
2428
|
+
|
|
2324
2429
|
useEffect(() => {
|
|
2325
2430
|
if (expandedId === '' || typeof window === 'undefined') {
|
|
2326
2431
|
setDetailAnchor(null)
|
|
@@ -2916,6 +3021,8 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2916
3021
|
|
|
2917
3022
|
/** Fill the popover from the host's state, so saving cannot send stale values. */
|
|
2918
3023
|
const openSettings = () => {
|
|
3024
|
+
// One inspector at a time: the settings card and the detail card occupy the same side.
|
|
3025
|
+
setExpandedId('')
|
|
2919
3026
|
const current = state.health?.settings ?? {}
|
|
2920
3027
|
setIngestDraft(current.ingest?.enabled === true)
|
|
2921
3028
|
setBelowDraft(String(current.ingest?.confirmBelow ?? 0.8))
|
|
@@ -3071,26 +3178,27 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3071
3178
|
'div',
|
|
3072
3179
|
{ className: 'gt-headline' },
|
|
3073
3180
|
h('div', { className: 'gt-title' }, t('panel.title')),
|
|
3074
|
-
h(
|
|
3075
|
-
'div',
|
|
3076
|
-
{ className: 'gt-sub' },
|
|
3077
|
-
t('panel.subtitle'),
|
|
3078
|
-
h('span', { className: 'gt-summary' }, ' · '),
|
|
3079
|
-
h('span', { className: 'gt-summary' }, t('summary.active', { n: counts.open + counts.doing })),
|
|
3080
|
-
counts.overdue > 0
|
|
3081
|
-
? h('span', { className: 'gt-summary' }, ` · ${t('summary.overdue', { n: counts.overdue })}`)
|
|
3082
|
-
: null,
|
|
3083
|
-
counts.done > 0
|
|
3084
|
-
? h('span', { className: 'gt-summary' }, ` · ${t('summary.done', { n: counts.done })}`)
|
|
3085
|
-
: null,
|
|
3086
|
-
),
|
|
3181
|
+
h('div', { className: 'gt-sub' }, t('panel.subtitle')),
|
|
3087
3182
|
),
|
|
3088
|
-
h('div', { className: 'gt-spacer' }),
|
|
3089
3183
|
h(
|
|
3090
|
-
'
|
|
3091
|
-
{
|
|
3092
|
-
|
|
3093
|
-
|
|
3184
|
+
'div',
|
|
3185
|
+
{ className: 'gt-head-actions' },
|
|
3186
|
+
h(
|
|
3187
|
+
'button',
|
|
3188
|
+
{
|
|
3189
|
+
type: 'button',
|
|
3190
|
+
className: 'gt-iconbtn',
|
|
3191
|
+
title: t('settings.title'),
|
|
3192
|
+
'aria-label': t('settings.title'),
|
|
3193
|
+
onClick: openSettings,
|
|
3194
|
+
},
|
|
3195
|
+
h(Icon, { name: 'gear' }),
|
|
3196
|
+
),
|
|
3197
|
+
h(
|
|
3198
|
+
'button',
|
|
3199
|
+
{
|
|
3200
|
+
type: 'button',
|
|
3201
|
+
className: 'gt-btn gt-btn-primary',
|
|
3094
3202
|
'aria-expanded': adding,
|
|
3095
3203
|
onClick: () => {
|
|
3096
3204
|
setAdding((value) => !value)
|
|
@@ -3100,42 +3208,17 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3100
3208
|
h(Icon, { name: 'plus', size: 13 }),
|
|
3101
3209
|
t('action.add'),
|
|
3102
3210
|
),
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
className: 'gt-btn gt-btn-quiet',
|
|
3115
|
-
title: t('action.exportHint'),
|
|
3116
|
-
onClick: () => void exportJson(),
|
|
3117
|
-
},
|
|
3118
|
-
t('action.export'),
|
|
3119
|
-
),
|
|
3120
|
-
h(
|
|
3121
|
-
'button',
|
|
3122
|
-
{
|
|
3123
|
-
type: 'button',
|
|
3124
|
-
className: 'gt-btn gt-btn-quiet',
|
|
3125
|
-
title: t('action.importHint'),
|
|
3126
|
-
onClick: () => importRef.current?.click?.(),
|
|
3127
|
-
},
|
|
3128
|
-
t('action.import'),
|
|
3129
|
-
),
|
|
3130
|
-
h(
|
|
3131
|
-
'button',
|
|
3132
|
-
{
|
|
3133
|
-
type: 'button',
|
|
3134
|
-
className: 'gt-btn gt-btn-quiet',
|
|
3135
|
-
'aria-expanded': settingsOpen,
|
|
3136
|
-
onClick: () => (settingsOpen ? setSettingsOpen(false) : openSettings()),
|
|
3137
|
-
},
|
|
3138
|
-
t('settings.title'),
|
|
3211
|
+
// One overflow menu instead of four competing buttons: the primary action is
|
|
3212
|
+
// adding a todo; everything else is occasional.
|
|
3213
|
+
h(Menu, {
|
|
3214
|
+
label: t('action.overflow'),
|
|
3215
|
+
items: [
|
|
3216
|
+
{ key: 'refresh', label: t('action.refresh'), icon: 'refresh', onSelect: () => void reload() },
|
|
3217
|
+
{ key: 'export', label: t('action.export'), icon: 'doc', onSelect: () => void exportJson() },
|
|
3218
|
+
{ key: 'import', label: t('action.import'), icon: 'plus', onSelect: () => importRef.current?.click?.() },
|
|
3219
|
+
{ key: 'settings', label: t('settings.title'), icon: 'gear', onSelect: () => openSettings() },
|
|
3220
|
+
],
|
|
3221
|
+
}),
|
|
3139
3222
|
),
|
|
3140
3223
|
h('input', {
|
|
3141
3224
|
ref: importRef,
|
|
@@ -3149,7 +3232,23 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3149
3232
|
settingsOpen
|
|
3150
3233
|
? h(
|
|
3151
3234
|
'div',
|
|
3152
|
-
{
|
|
3235
|
+
{
|
|
3236
|
+
className: 'gt-settings',
|
|
3237
|
+
role: 'dialog',
|
|
3238
|
+
'aria-label': t('settings.title'),
|
|
3239
|
+
style:
|
|
3240
|
+
settingsBox === null
|
|
3241
|
+
? undefined
|
|
3242
|
+
: {
|
|
3243
|
+
position: 'fixed',
|
|
3244
|
+
top: `${settingsBox.top}px`,
|
|
3245
|
+
right: `${settingsBox.right}px`,
|
|
3246
|
+
bottom: `${settingsBox.bottom}px`,
|
|
3247
|
+
maxHeight: 'none',
|
|
3248
|
+
overflow: 'auto',
|
|
3249
|
+
zIndex: 40,
|
|
3250
|
+
},
|
|
3251
|
+
},
|
|
3153
3252
|
h('div', { className: 'gt-settings-head' }, t('settings.title')),
|
|
3154
3253
|
h('div', { className: 'gt-section-title' }, t('settings.reminders')),
|
|
3155
3254
|
h(
|
|
@@ -3191,8 +3290,8 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3191
3290
|
'div',
|
|
3192
3291
|
{ className: 'gt-settings-row' },
|
|
3193
3292
|
h('button', { type: 'button', className: 'gt-btn gt-btn-quiet', onClick: generateToken }, t('settings.generate')),
|
|
3194
|
-
h('button', { type: 'button', className: 'gt-btn gt-btn-brand', onClick: () => void saveSettings() }, t('settings.save')),
|
|
3195
3293
|
h('button', { type: 'button', className: 'gt-btn gt-btn-quiet', onClick: () => setSettingsOpen(false) }, t('settings.cancel')),
|
|
3294
|
+
h('button', { type: 'button', className: 'gt-btn gt-btn-primary', onClick: () => void saveSettings() }, t('settings.save')),
|
|
3196
3295
|
),
|
|
3197
3296
|
h(
|
|
3198
3297
|
'label',
|
|
@@ -3208,6 +3307,13 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3208
3307
|
onChange: (event) => setBelowDraft(event.target.value),
|
|
3209
3308
|
}),
|
|
3210
3309
|
),
|
|
3310
|
+
h('div', { className: 'gt-section-title' }, t('settings.about')),
|
|
3311
|
+
h(
|
|
3312
|
+
'div',
|
|
3313
|
+
{ className: 'gt-muted gt-mono gt-settings-path', title: state.health?.store?.file ?? '' },
|
|
3314
|
+
state.health?.store?.file ?? '',
|
|
3315
|
+
),
|
|
3316
|
+
h('div', { className: 'gt-muted' }, `v${state.health?.version ?? ''} · ${UI_REV}`),
|
|
3211
3317
|
)
|
|
3212
3318
|
: null,
|
|
3213
3319
|
|
|
@@ -3215,8 +3321,13 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3215
3321
|
? h(
|
|
3216
3322
|
'div',
|
|
3217
3323
|
{ className: 'gt-banner', role: 'alert' },
|
|
3218
|
-
`${t('error.prefix')}: ${error.message}
|
|
3324
|
+
h('span', { className: 'gt-banner-text' }, `${t('error.prefix')}: ${error.message}`),
|
|
3219
3325
|
h('button', { type: 'button', className: 'gt-btn', onClick: () => void reload() }, t('action.retry')),
|
|
3326
|
+
h(
|
|
3327
|
+
'button',
|
|
3328
|
+
{ type: 'button', className: 'gt-iconbtn', title: t('action.hide'), 'aria-label': t('action.hide'), onClick: () => setError(null) },
|
|
3329
|
+
h(Icon, { name: 'close', size: 13 }),
|
|
3330
|
+
),
|
|
3220
3331
|
)
|
|
3221
3332
|
: null,
|
|
3222
3333
|
|
|
@@ -3306,6 +3417,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3306
3417
|
h(
|
|
3307
3418
|
'div',
|
|
3308
3419
|
{ className: 'gt-toolbar' },
|
|
3420
|
+
h('div', { className: 'gt-toolbar-main' },
|
|
3309
3421
|
h(
|
|
3310
3422
|
'span',
|
|
3311
3423
|
{ className: 'gt-tabs', role: 'group', 'aria-label': t('filter.label') },
|
|
@@ -3361,12 +3473,37 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3361
3473
|
),
|
|
3362
3474
|
),
|
|
3363
3475
|
),
|
|
3476
|
+
),
|
|
3364
3477
|
h('div', { className: 'gt-spacer' }),
|
|
3478
|
+
h(
|
|
3479
|
+
'div',
|
|
3480
|
+
{ className: 'gt-context-summary' },
|
|
3481
|
+
h(
|
|
3482
|
+
'button',
|
|
3483
|
+
{ type: 'button', className: 'gt-chip', title: effectiveDir === '' ? t('dir.none') : effectiveDir, onClick: () => setContextOpen((value) => !value) },
|
|
3484
|
+
h(Icon, { name: 'doc', size: 12 }),
|
|
3485
|
+
effectiveDir === '' ? t('dir.none') : effectiveDir,
|
|
3486
|
+
),
|
|
3487
|
+
h(
|
|
3488
|
+
'button',
|
|
3489
|
+
{ type: 'button', className: 'gt-chip', title: t('target.pick'), onClick: () => setContextOpen((value) => !value) },
|
|
3490
|
+
h(Icon, { name: 'play', size: 11 }),
|
|
3491
|
+
`${t('target.label')}: ${conversations.find((entry) => entry.id === targetValue)?.title ?? t('target.auto')}`,
|
|
3492
|
+
),
|
|
3493
|
+
h(
|
|
3494
|
+
'button',
|
|
3495
|
+
{ type: 'button', className: 'gt-btn gt-btn-quiet', 'aria-expanded': contextOpen, onClick: () => setContextOpen((value) => !value) },
|
|
3496
|
+
t('settings.context'),
|
|
3497
|
+
),
|
|
3498
|
+
),
|
|
3499
|
+
h(
|
|
3500
|
+
'div',
|
|
3501
|
+
{ className: 'gt-context-details', 'data-open': contextOpen ? '1' : '0' },
|
|
3365
3502
|
h(
|
|
3366
3503
|
'span',
|
|
3367
3504
|
{ className: 'gt-dir', title: effectiveDir === '' ? t('dir.none') : effectiveDir },
|
|
3368
3505
|
h(Icon, { name: 'doc', size: 12 }),
|
|
3369
|
-
h('span', { className: 'gt-muted' }, `${t('field.dir')}
|
|
3506
|
+
h('span', { className: 'gt-muted' }, `${t('field.dir')}: `),
|
|
3370
3507
|
h('span', { className: 'gt-dir-path' }, effectiveDir === '' ? t('dir.none') : effectiveDir),
|
|
3371
3508
|
h('span', { className: 'gt-muted' }, pickedDir === '' ? t('dir.fromSession') : t('dir.picked')),
|
|
3372
3509
|
h('button', { type: 'button', className: 'gt-btn gt-btn-quiet', onClick: () => void chooseDir() }, t('action.pickDir')),
|
|
@@ -3471,7 +3608,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3471
3608
|
),
|
|
3472
3609
|
),
|
|
3473
3610
|
),
|
|
3474
|
-
h('span', { className: 'gt-muted' }, `${t('target.label')}
|
|
3611
|
+
h('span', { className: 'gt-muted' }, `${t('target.label')}: `),
|
|
3475
3612
|
h(
|
|
3476
3613
|
'select',
|
|
3477
3614
|
{
|
|
@@ -3501,6 +3638,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3501
3638
|
{ value: 'auto', label: t('target.auto') },
|
|
3502
3639
|
].map((option) => h('option', { key: option.value, value: option.value }, option.label)),
|
|
3503
3640
|
),
|
|
3641
|
+
),
|
|
3504
3642
|
h('span', { className: 'gt-spacer' }),
|
|
3505
3643
|
h('span', { className: 'gt-tabs', role: 'group', 'aria-label': t('autoCollect.label') }, togglesNodes),
|
|
3506
3644
|
),
|
|
@@ -3731,6 +3869,20 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3731
3869
|
'div',
|
|
3732
3870
|
{ className: 'gt-empty' },
|
|
3733
3871
|
h('div', { className: 'gt-empty-title' }, (state.counts?.total ?? 0) === 0 && query.trim() === '' ? t('empty.none') : t('empty.filtered')),
|
|
3872
|
+
(state.counts?.total ?? 0) === 0 && query.trim() === ''
|
|
3873
|
+
? h(
|
|
3874
|
+
'button',
|
|
3875
|
+
{
|
|
3876
|
+
type: 'button',
|
|
3877
|
+
className: 'gt-btn gt-btn-primary',
|
|
3878
|
+
onClick: () => {
|
|
3879
|
+
setAdding(true)
|
|
3880
|
+
setMore(false)
|
|
3881
|
+
},
|
|
3882
|
+
},
|
|
3883
|
+
t('empty.add'),
|
|
3884
|
+
)
|
|
3885
|
+
: null,
|
|
3734
3886
|
h('div', { className: 'gt-sub' }, t('hint.keys')),
|
|
3735
3887
|
)
|
|
3736
3888
|
: h(
|
|
@@ -3755,7 +3907,11 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3755
3907
|
},
|
|
3756
3908
|
h(Icon, { name: 'chevron', size: 12 }),
|
|
3757
3909
|
h('span', { className: 'gt-group-label' }, group.label),
|
|
3758
|
-
h(
|
|
3910
|
+
h(
|
|
3911
|
+
'span',
|
|
3912
|
+
{ className: 'gt-group-count' },
|
|
3913
|
+
group.todos.length === 1 ? t('group.item') : t('group.items', { n: group.todos.length }),
|
|
3914
|
+
),
|
|
3759
3915
|
group.level === 'normal'
|
|
3760
3916
|
? null
|
|
3761
3917
|
: h(
|
|
@@ -3821,7 +3977,10 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3821
3977
|
open: expandedId === todo.id,
|
|
3822
3978
|
dispatchLabel,
|
|
3823
3979
|
onAction,
|
|
3824
|
-
onToggleOpen: (id) =>
|
|
3980
|
+
onToggleOpen: (id) => {
|
|
3981
|
+
setSettingsOpen(false)
|
|
3982
|
+
setExpandedId((current) => (current === id ? '' : id))
|
|
3983
|
+
},
|
|
3825
3984
|
}),
|
|
3826
3985
|
),
|
|
3827
3986
|
),
|
|
@@ -3837,15 +3996,6 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3837
3996
|
)
|
|
3838
3997
|
: null,
|
|
3839
3998
|
|
|
3840
|
-
h(
|
|
3841
|
-
'div',
|
|
3842
|
-
{ className: 'gt-foot' },
|
|
3843
|
-
state.health !== null ? h('span', null, t('store.at', { file: state.health.store?.file ?? '' })) : null,
|
|
3844
|
-
state.health !== null
|
|
3845
|
-
? h('span', { className: 'gt-mono' }, `v${state.health.version ?? ''}·${UI_REV}`)
|
|
3846
|
-
: null,
|
|
3847
|
-
h('span', null, t('hint.keys')),
|
|
3848
|
-
),
|
|
3849
3999
|
),
|
|
3850
4000
|
notice !== null && notice !== undefined
|
|
3851
4001
|
? h(
|
package/lib/index.js
CHANGED
|
@@ -36,7 +36,7 @@ import { createStore, resolveStorePath } from './store.js'
|
|
|
36
36
|
import { createTools } from './tools.js'
|
|
37
37
|
|
|
38
38
|
/** Must equal `package.json`'s version; `npm run check` enforces that. */
|
|
39
|
-
export const VERSION = '0.
|
|
39
|
+
export const VERSION = '0.6.0'
|
|
40
40
|
|
|
41
41
|
/** Plugin id. Also the Loader row id in `cordis.patch.yml`. */
|
|
42
42
|
export const name = 'dsh-global-todo'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-global-todo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"icon": "./docs/icon.svg",
|
|
5
5
|
"description": "Global, cross-session todos for DeepSeek Harness: one list owned by the human and the agent together, with creation time, attached documents and links, and one-click hand-off to an agent session. 全局待办:跨会话一份清单,记录加入时间,可挂文档与地址,可一键交给 Agent 继续干。",
|
|
6
6
|
"type": "module",
|