dsh-global-todo 0.5.3 → 0.6.1
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 +38 -0
- package/docs/screenshots/detail-dark.png +0 -0
- package/docs/screenshots/panel-dark.png +0 -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 +369 -197
- package/lib/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,41 @@
|
|
|
1
|
+
## [0.6.1] — 2026-10-20
|
|
2
|
+
|
|
3
|
+
The follow-up pass from the design spec: the breakpoint now follows the panel, not the window,
|
|
4
|
+
and the form stops competing with itself.
|
|
5
|
+
|
|
6
|
+
- **Panel-measured breakpoint.** A `ResizeObserver` on the column sets `data-wide`; the detail card
|
|
7
|
+
becomes a right-hand card only when the column itself is at least 960px. At 1100 the detail now
|
|
8
|
+
expands inline under its row instead of squeezing the list into a 416px strip.
|
|
9
|
+
- **Inline detail stops repeating itself.** The card title is hidden in inline mode (the row title
|
|
10
|
+
is directly above it) and keeps only the close affordance.
|
|
11
|
+
- **Add form.** The header action turns into an icon-only close while the form is open, so there is
|
|
12
|
+
one `+ Add` on screen; the form orders 更多字段 before 添加, matching the spec.
|
|
13
|
+
- **Rows are 72px tall** at minimum, matching the spec's rhythm, and the detail/card radius is 10px.
|
|
14
|
+
- Dark theme verified against the real host: layer-2 rows, overlay inspector and ghost-active
|
|
15
|
+
selected states all resolve correctly.
|
|
16
|
+
|
|
17
|
+
## [0.6.0] — 2026-10-20
|
|
18
|
+
|
|
19
|
+
A design pass over the whole panel: one list, fewer competing controls, one type scale.
|
|
20
|
+
|
|
21
|
+
- **The layout is a column, not a wrapping row.** `.gt-root`/`.gt-inner` gained `min-width: 0` so the
|
|
22
|
+
column shrinks with its slot instead of overflowing at 1280 and 1100; the header wraps its actions
|
|
23
|
+
and the toolbar is two semantic rows (filter/search above, context above the list). The working
|
|
24
|
+
directory, handoff target and browse controls move behind a single Context toggle, collapsed by
|
|
25
|
+
default.
|
|
26
|
+
- **Five type sizes and one weight scale.** 20/28 panel title, 14/22 row title, 13/20 controls and
|
|
27
|
+
body, 12/18 metadata and section labels, 11.5 mono for paths. Buttons, inputs and tabs share a
|
|
28
|
+
28px control height; the settings card is a 340px floating inspector (fixed, mutually exclusive
|
|
29
|
+
with the detail card) instead of an in-flow block that pushed the list down.
|
|
30
|
+
- **Rows read top-down.** The title opens the detail (the kebab remains as a redundant door); the
|
|
31
|
+
dispatch button is a quiet action instead of an outlined primary; metadata loses the origin path
|
|
32
|
+
and the stray separator (CSS-generated dots), and tags cap at four. Group-level priority hides
|
|
33
|
+
while the group is expanded, where every row already shows it.
|
|
34
|
+
- **Copy and states.** Full-width colons no longer leak into the English UI, `1 items` is fixed,
|
|
35
|
+
priority chips say Urgent/High/Normal/Low instead of P-codes, the empty state has a primary
|
|
36
|
+
action, the error banner can be dismissed, and the reminder bar keeps its accent on a 2px edge
|
|
37
|
+
(amber text failed contrast). The footer's store path and version move into Settings → About.
|
|
38
|
+
|
|
1
39
|
## [0.5.3] — 2026-10-20
|
|
2
40
|
|
|
3
41
|
Settings a person can reach, and reminders that behave like reminders.
|
|
Binary file
|
|
Binary file
|
|
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 = 'ui37'
|
|
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,79 @@ 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: 10px; padding: 12px 14px; min-height: 72px; box-sizing: border-box; }
|
|
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
|
+
/* Inline detail sits directly under its row: repeating the title would read as a second item. */
|
|
1109
|
+
.gt-root[data-wide="0"][data-wide-detail="1"] .gt-detail-title { display: none; }
|
|
1110
|
+
.gt-root[data-wide="0"][data-wide-detail="1"] .gt-detail-head { justify-content: flex-end; }
|
|
1111
|
+
.gt-detail-title { font-size: 14px; line-height: 22px; font-weight: 600; min-width: 0;
|
|
1112
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1113
|
+
.gt-truncated { color: var(--dsw-alias-state-warn-primary); font-size: 12px; }
|
|
1114
|
+
.gt-bulk-tag { flex: 0 1 120px; min-width: 90px; }
|
|
1054
1115
|
.gt-inbox { margin-left: 6px; padding: 1px 6px; border-radius: 999px; font-size: 10.5px; font-weight: 600;
|
|
1055
1116
|
color: var(--dsw-alias-state-warn-primary); border: 1px solid var(--dsw-alias-state-warn-primary);
|
|
1056
1117
|
vertical-align: 1px; }
|
|
1057
1118
|
.gt-item[data-status="done"] .gt-item-title, .gt-item[data-status="cancelled"] .gt-item-title {
|
|
1058
1119
|
text-decoration: line-through; color: var(--dsw-alias-label-secondary); }
|
|
1059
|
-
.gt-meta { display: flex; gap:
|
|
1060
|
-
align-items: center; }
|
|
1120
|
+
.gt-meta { display: flex; gap: 2px 0; flex-wrap: wrap; color: var(--dsw-alias-label-secondary); font-size: 12px;
|
|
1121
|
+
line-height: 18px; align-items: center; }
|
|
1061
1122
|
.gt-meta > span { display: inline-flex; align-items: center; }
|
|
1062
|
-
.gt-meta
|
|
1123
|
+
.gt-meta > span + span::before { content: '·'; margin: 0 6px; opacity: .45; }
|
|
1063
1124
|
.gt-tag { color: var(--dsw-alias-brand-primary); }
|
|
1064
1125
|
/* The dispatch action stays put: hiding the only way to hand work to an agent
|
|
1065
1126
|
behind a hover makes a lone todo look like it can do nothing. */
|
|
@@ -1068,25 +1129,25 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1068
1129
|
.gt-attach .gt-chip { max-width: 280px; color: var(--dsw-alias-label-secondary); }
|
|
1069
1130
|
.gt-attach a.gt-chip:hover { color: var(--dsw-alias-label-primary); border-color: var(--dsw-alias-border-l2); }
|
|
1070
1131
|
.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:
|
|
1132
|
+
.gt-menu { position: absolute; top: 40px; right: 10px; z-index: 3; min-width: 184px; display: flex;
|
|
1133
|
+
flex-direction: column; padding: 5px; background: var(--dsw-alias-bg-overlay);
|
|
1073
1134
|
border: 1px solid var(--dsw-alias-border-l2); border-radius: 10px; }
|
|
1074
1135
|
.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:
|
|
1136
|
+
background: transparent; color: var(--dsw-alias-label-primary); font: inherit; font-size: 13px; padding: 8px 10px;
|
|
1076
1137
|
border-radius: 7px; cursor: pointer; }
|
|
1077
|
-
.gt-menu button:hover { background: var(--dsw-alias-
|
|
1138
|
+
.gt-menu button:hover { background: var(--dsw-alias-button-ghost-active-fill); }
|
|
1078
1139
|
.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:
|
|
1140
|
+
.gt-detail { display: flex; flex-direction: column; gap: 12px; border-top: 1px solid var(--dsw-alias-border-l1);
|
|
1141
|
+
padding-top: 12px; margin-top: 2px; }
|
|
1081
1142
|
/* Wide screens: the open row's detail becomes a card on the right instead of pushing the list
|
|
1082
1143
|
down. Deliberately CSS-only over unchanged markup: one detail implementation, and it only
|
|
1083
1144
|
applies where there is room for a second column. */
|
|
1084
|
-
|
|
1145
|
+
/* Wide layout follows the panel's measured width (data-wide), not the viewport. */
|
|
1085
1146
|
/* Only the list gives way: the title row and the toolbar keep their full width, so the
|
|
1086
1147
|
controls never wrap or hide behind the card. */
|
|
1087
|
-
.gt-root[data-wide-detail="1"] .gt-groups { padding-right:
|
|
1088
|
-
.gt-root[data-wide-detail="1"] .gt-inner { position: relative; }
|
|
1089
|
-
.gt-root[data-wide-detail="1"] .gt-item[data-open="1"] .gt-detail {
|
|
1148
|
+
.gt-root[data-wide="1"][data-wide-detail="1"] .gt-groups { padding-right: 360px; }
|
|
1149
|
+
.gt-root[data-wide="1"][data-wide-detail="1"] .gt-inner { position: relative; }
|
|
1150
|
+
.gt-root[data-wide="1"][data-wide-detail="1"] .gt-item[data-open="1"] .gt-detail {
|
|
1090
1151
|
/* Anchored to the panel's own column (.gt-inner), not to the viewport: the slot does not
|
|
1091
1152
|
always fill the window, and a viewport-centred offset put the card over the list. */
|
|
1092
1153
|
/* The var fallback matters for the static previews (server-rendered, so effects never
|
|
@@ -1095,21 +1156,24 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1095
1156
|
a gap instead of overlapping by the padding width. */
|
|
1096
1157
|
box-sizing: border-box;
|
|
1097
1158
|
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:
|
|
1159
|
+
right: var(--gt-detail-right, max(24px, calc((100vw - 1040px) / 2 + 24px)));
|
|
1160
|
+
bottom: var(--gt-detail-bottom, 64px); width: 340px;
|
|
1100
1161
|
overflow: auto; padding: 16px; margin: 0; border: 1px solid var(--dsw-alias-border-l2);
|
|
1101
1162
|
border-radius: 12px; background: var(--dsw-alias-bg-overlay); z-index: 30;
|
|
1102
1163
|
}
|
|
1103
|
-
}
|
|
1104
1164
|
.gt-section { display: flex; flex-direction: column; gap: 5px; }
|
|
1105
1165
|
.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; }
|
|
1166
|
+
.gt-section-title { color: var(--dsw-alias-label-secondary); font-size: 12px; line-height: 18px; font-weight: 600; }
|
|
1108
1167
|
.gt-pre { white-space: pre-wrap; word-break: break-word; margin: 0; line-height: 1.6; }
|
|
1109
1168
|
.gt-muted { color: var(--dsw-alias-label-secondary); }
|
|
1110
1169
|
.gt-links { display: flex; flex-direction: column; gap: 4px; margin: 0; padding: 0; list-style: none; }
|
|
1111
1170
|
.gt-link { display: flex; gap: 8px; align-items: center; padding: 4px 0; min-width: 0; }
|
|
1112
1171
|
.gt-link-main { display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1; }
|
|
1172
|
+
.gt-note-item { display: flex; flex-direction: column; gap: 4px; padding: 8px 0; }
|
|
1173
|
+
.gt-note-item + .gt-note-item { border-top: 1px solid var(--dsw-alias-border-l1); }
|
|
1174
|
+
.gt-note-meta { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--dsw-alias-label-secondary);
|
|
1175
|
+
white-space: nowrap; }
|
|
1176
|
+
.gt-note-text { font-size: 13px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; max-width: 68ch; }
|
|
1113
1177
|
.gt-link a { color: var(--dsw-alias-brand-primary); text-decoration: none; }
|
|
1114
1178
|
.gt-link a:hover { text-decoration: underline; }
|
|
1115
1179
|
.gt-link-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 320px; }
|
|
@@ -1471,9 +1535,19 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1471
1535
|
if (Number.isInteger(todo.seq) && todo.seq > 0) {
|
|
1472
1536
|
meta.push(h('span', { key: 'seq', className: 'gt-seq', title: t('meta.seqHint') }, `#${todo.seq}`))
|
|
1473
1537
|
}
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1538
|
+
if (todo.dueAt !== null) {
|
|
1539
|
+
meta.push(
|
|
1540
|
+
h(
|
|
1541
|
+
'span',
|
|
1542
|
+
{ key: 'due', className: overdue ? 'gt-chip-bad' : '', title: new Date(todo.dueAt).toLocaleString() },
|
|
1543
|
+
overdue
|
|
1544
|
+
? t('meta.overdue', { n: daysLate(todo.dueAt, now) })
|
|
1545
|
+
: sameLocalDay(Date.parse(todo.dueAt), now)
|
|
1546
|
+
? t('meta.today')
|
|
1547
|
+
: `${t('meta.due')} ${absoluteTime(Date.parse(todo.dueAt))}`,
|
|
1548
|
+
),
|
|
1549
|
+
)
|
|
1550
|
+
}
|
|
1477
1551
|
if (todo.priority !== 'normal') {
|
|
1478
1552
|
meta.push(
|
|
1479
1553
|
h(
|
|
@@ -1484,23 +1558,17 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1484
1558
|
),
|
|
1485
1559
|
)
|
|
1486
1560
|
}
|
|
1487
|
-
|
|
1561
|
+
meta.push(h('span', { key: 'added', title: new Date(todo.createdAt).toLocaleString() }, ageText(lang, todo.createdAt, now)))
|
|
1562
|
+
if (todo.tags.length > 0) {
|
|
1563
|
+
const shown = todo.tags.slice(0, 4)
|
|
1488
1564
|
meta.push(
|
|
1489
1565
|
h(
|
|
1490
1566
|
'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))}`,
|
|
1567
|
+
{ key: 'tags', className: 'gt-tag', title: todo.tags.map((tag) => `#${tag}`).join(' ') },
|
|
1568
|
+
shown.map((tag) => `#${tag}`).join(' ') + (todo.tags.length > shown.length ? ` +${todo.tags.length - shown.length}` : ''),
|
|
1497
1569
|
),
|
|
1498
1570
|
)
|
|
1499
1571
|
}
|
|
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
1572
|
if (Array.isArray(todo.notes) && todo.notes.length > 0) {
|
|
1505
1573
|
const latest = todo.notes[todo.notes.length - 1]
|
|
1506
1574
|
meta.push(h('span', { key: 'notes', title: latest.text }, t('note.count', { n: todo.notes.length })))
|
|
@@ -1508,12 +1576,8 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1508
1576
|
if (todo.completion !== null && todo.completion !== undefined) {
|
|
1509
1577
|
meta.push(h('span', { key: 'completed', title: todo.completion.summary }, t('meta.completed', { when: absoluteTime(todo.completion.at) })))
|
|
1510
1578
|
}
|
|
1511
|
-
|
|
1512
|
-
meta.push(h('span', { key: 'origin', title: todo.originDir }, t('meta.origin', { dir: shortPath(todo.originDir) })))
|
|
1513
|
-
}
|
|
1579
|
+
meta.push(h('span', { key: 'by' }, t(`meta.by.${todo.createdBy === 'agent' ? 'agent' : 'human'}`)))
|
|
1514
1580
|
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
1581
|
const stranded = todo.sessionAlive === true && (todo.sessionDir ?? '') === ''
|
|
1518
1582
|
meta.push(
|
|
1519
1583
|
h(
|
|
@@ -1521,9 +1585,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1521
1585
|
{
|
|
1522
1586
|
key: 'session',
|
|
1523
1587
|
className: stranded ? 'gt-chip-warn' : todo.sessionAlive === true ? 'gt-chip-ok' : '',
|
|
1524
|
-
title: stranded
|
|
1525
|
-
? t('meta.session.noDirHint')
|
|
1526
|
-
: (todo.sessionDir ?? ''),
|
|
1588
|
+
title: stranded ? t('meta.session.noDirHint') : (todo.sessionDir ?? ''),
|
|
1527
1589
|
},
|
|
1528
1590
|
stranded ? t('meta.session.noDir') : todo.sessionAlive === true ? t('meta.session.live') : t('meta.session.bound'),
|
|
1529
1591
|
),
|
|
@@ -1588,7 +1650,21 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1588
1650
|
),
|
|
1589
1651
|
h(
|
|
1590
1652
|
'div',
|
|
1591
|
-
{
|
|
1653
|
+
{
|
|
1654
|
+
className: 'gt-item-body',
|
|
1655
|
+
role: 'button',
|
|
1656
|
+
tabIndex: 0,
|
|
1657
|
+
'aria-expanded': open,
|
|
1658
|
+
onClick: (event) => {
|
|
1659
|
+
if (event.target?.closest?.('a,button,input,textarea,select') !== null) return
|
|
1660
|
+
onToggleOpen(todo.id)
|
|
1661
|
+
},
|
|
1662
|
+
onKeyDown: (event) => {
|
|
1663
|
+
if (event.key !== 'Enter' && event.key !== ' ') return
|
|
1664
|
+
event.preventDefault()
|
|
1665
|
+
onToggleOpen(todo.id)
|
|
1666
|
+
},
|
|
1667
|
+
},
|
|
1592
1668
|
h(
|
|
1593
1669
|
'div',
|
|
1594
1670
|
{ className: 'gt-item-title' },
|
|
@@ -1600,9 +1676,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1600
1676
|
h(
|
|
1601
1677
|
'div',
|
|
1602
1678
|
{ className: 'gt-meta' },
|
|
1603
|
-
meta
|
|
1604
|
-
index === 0 ? [node] : [h('span', { key: `sep${index}`, className: 'gt-meta-sep' }, '·'), node],
|
|
1605
|
-
),
|
|
1679
|
+
meta,
|
|
1606
1680
|
),
|
|
1607
1681
|
// What is attached is half the point of the list, so the first few are
|
|
1608
1682
|
// shown as chips instead of being reported as a number.
|
|
@@ -1701,7 +1775,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1701
1775
|
'button',
|
|
1702
1776
|
{
|
|
1703
1777
|
type: 'button',
|
|
1704
|
-
className: 'gt-btn gt-btn-
|
|
1778
|
+
className: 'gt-btn gt-btn-quiet',
|
|
1705
1779
|
disabled: busy,
|
|
1706
1780
|
title: dispatchLabel,
|
|
1707
1781
|
onClick: () => onAction('dispatch', todo),
|
|
@@ -1752,6 +1826,16 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1752
1826
|
? h(
|
|
1753
1827
|
'div',
|
|
1754
1828
|
{ className: 'gt-detail' },
|
|
1829
|
+
h(
|
|
1830
|
+
'div',
|
|
1831
|
+
{ className: 'gt-detail-head' },
|
|
1832
|
+
h('span', { className: 'gt-detail-title' }, `${Number.isInteger(todo.seq) && todo.seq > 0 ? `#${todo.seq} ` : ''}${todo.title}`),
|
|
1833
|
+
h(
|
|
1834
|
+
'button',
|
|
1835
|
+
{ type: 'button', className: 'gt-iconbtn', title: t('action.hide'), 'aria-label': t('action.hide'), onClick: () => onToggleOpen(todo.id) },
|
|
1836
|
+
h(Icon, { name: 'close', size: 13 }),
|
|
1837
|
+
),
|
|
1838
|
+
),
|
|
1755
1839
|
h(
|
|
1756
1840
|
'div',
|
|
1757
1841
|
{ className: 'gt-section' },
|
|
@@ -1836,14 +1920,15 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1836
1920
|
(todo.notes ?? []).map((entry, index) =>
|
|
1837
1921
|
h(
|
|
1838
1922
|
'li',
|
|
1839
|
-
{ className: 'gt-
|
|
1923
|
+
{ className: 'gt-note-item', key: `note:${index}:${entry.at}` },
|
|
1840
1924
|
h(
|
|
1841
|
-
'
|
|
1842
|
-
{ className: 'gt-
|
|
1843
|
-
h(Icon, { name: 'doc', size:
|
|
1844
|
-
h('span',
|
|
1845
|
-
h('span',
|
|
1925
|
+
'div',
|
|
1926
|
+
{ className: 'gt-note-meta' },
|
|
1927
|
+
h(Icon, { name: 'doc', size: 12 }),
|
|
1928
|
+
h('span', null, absoluteTime(entry.at)),
|
|
1929
|
+
h('span', null, entry.by === 'agent' ? t('note.by.agent') : t('note.by.human')),
|
|
1846
1930
|
),
|
|
1931
|
+
h('div', { className: 'gt-note-text' }, entry.text),
|
|
1847
1932
|
),
|
|
1848
1933
|
),
|
|
1849
1934
|
),
|
|
@@ -2082,6 +2167,12 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2082
2167
|
// One settings popover: reminders and the external door both need a place a person can
|
|
2083
2168
|
// reach without curl.
|
|
2084
2169
|
const [settingsOpen, setSettingsOpen] = useState(false)
|
|
2170
|
+
const [settingsBox, setSettingsBox] = useState(null)
|
|
2171
|
+
// The detail card's breakpoint follows the panel's own width, not the viewport: the
|
|
2172
|
+
// slot is ~265px narrower than the window, so a viewport query opens the two-column
|
|
2173
|
+
// layout while the panel is still too narrow for it.
|
|
2174
|
+
const [panelWidth, setPanelWidth] = useState(null)
|
|
2175
|
+
const [contextOpen, setContextOpen] = useState(false)
|
|
2085
2176
|
const [tokenDraft, setTokenDraft] = useState('')
|
|
2086
2177
|
const [ingestDraft, setIngestDraft] = useState(false)
|
|
2087
2178
|
const [belowDraft, setBelowDraft] = useState('0.8')
|
|
@@ -2321,6 +2412,40 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2321
2412
|
}
|
|
2322
2413
|
}, [lang])
|
|
2323
2414
|
|
|
2415
|
+
useEffect(() => {
|
|
2416
|
+
const element = innerRef.current
|
|
2417
|
+
if (element === null || typeof window === 'undefined') return undefined
|
|
2418
|
+
const measure = () => setPanelWidth(element.getBoundingClientRect().width)
|
|
2419
|
+
measure()
|
|
2420
|
+
window.addEventListener('resize', measure)
|
|
2421
|
+
const observer = typeof window.ResizeObserver === 'function' ? new window.ResizeObserver(measure) : null
|
|
2422
|
+
if (observer !== null) observer.observe(element)
|
|
2423
|
+
return () => {
|
|
2424
|
+
window.removeEventListener('resize', measure)
|
|
2425
|
+
if (observer !== null) observer.disconnect()
|
|
2426
|
+
}
|
|
2427
|
+
}, [])
|
|
2428
|
+
|
|
2429
|
+
useEffect(() => {
|
|
2430
|
+
if (!settingsOpen || typeof window === 'undefined') {
|
|
2431
|
+
setSettingsBox(null)
|
|
2432
|
+
return undefined
|
|
2433
|
+
}
|
|
2434
|
+
const measure = () => {
|
|
2435
|
+
const element = innerRef.current
|
|
2436
|
+
if (element === null) return
|
|
2437
|
+
const rect = element.getBoundingClientRect()
|
|
2438
|
+
setSettingsBox({
|
|
2439
|
+
top: Math.round(rect.top + 210),
|
|
2440
|
+
right: Math.round(window.innerWidth - rect.right + 20),
|
|
2441
|
+
bottom: Math.round(window.innerHeight - rect.bottom + 20),
|
|
2442
|
+
})
|
|
2443
|
+
}
|
|
2444
|
+
measure()
|
|
2445
|
+
window.addEventListener('resize', measure)
|
|
2446
|
+
return () => window.removeEventListener('resize', measure)
|
|
2447
|
+
}, [settingsOpen, lang])
|
|
2448
|
+
|
|
2324
2449
|
useEffect(() => {
|
|
2325
2450
|
if (expandedId === '' || typeof window === 'undefined') {
|
|
2326
2451
|
setDetailAnchor(null)
|
|
@@ -2916,6 +3041,8 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2916
3041
|
|
|
2917
3042
|
/** Fill the popover from the host's state, so saving cannot send stale values. */
|
|
2918
3043
|
const openSettings = () => {
|
|
3044
|
+
// One inspector at a time: the settings card and the detail card occupy the same side.
|
|
3045
|
+
setExpandedId('')
|
|
2919
3046
|
const current = state.health?.settings ?? {}
|
|
2920
3047
|
setIngestDraft(current.ingest?.enabled === true)
|
|
2921
3048
|
setBelowDraft(String(current.ingest?.confirmBelow ?? 0.8))
|
|
@@ -3050,6 +3177,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3050
3177
|
{
|
|
3051
3178
|
className: 'gt-root',
|
|
3052
3179
|
'data-wide-detail': expandedId === '' ? '0' : '1',
|
|
3180
|
+
'data-wide': panelWidth === null || panelWidth >= 960 ? '1' : '0',
|
|
3053
3181
|
// The slot does not always fill the window, so the card's viewport offsets are
|
|
3054
3182
|
// measured from the panel itself instead of assumed from 50vw.
|
|
3055
3183
|
style:
|
|
@@ -3071,71 +3199,48 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3071
3199
|
'div',
|
|
3072
3200
|
{ className: 'gt-headline' },
|
|
3073
3201
|
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
|
-
),
|
|
3202
|
+
h('div', { className: 'gt-sub' }, t('panel.subtitle')),
|
|
3087
3203
|
),
|
|
3088
|
-
h('div', { className: 'gt-spacer' }),
|
|
3089
3204
|
h(
|
|
3090
|
-
'
|
|
3091
|
-
{
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3205
|
+
'div',
|
|
3206
|
+
{ className: 'gt-head-actions' },
|
|
3207
|
+
h(
|
|
3208
|
+
'button',
|
|
3209
|
+
{
|
|
3210
|
+
type: 'button',
|
|
3211
|
+
className: 'gt-iconbtn',
|
|
3212
|
+
title: t('settings.title'),
|
|
3213
|
+
'aria-label': t('settings.title'),
|
|
3214
|
+
onClick: openSettings,
|
|
3098
3215
|
},
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
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'),
|
|
3216
|
+
h(Icon, { name: 'gear' }),
|
|
3217
|
+
),
|
|
3218
|
+
h(
|
|
3219
|
+
'button',
|
|
3220
|
+
{
|
|
3221
|
+
type: 'button',
|
|
3222
|
+
className: adding ? 'gt-btn gt-btn-quiet' : 'gt-btn gt-btn-primary',
|
|
3223
|
+
'aria-expanded': adding,
|
|
3224
|
+
title: adding ? t('action.less') : t('action.add'),
|
|
3225
|
+
onClick: () => {
|
|
3226
|
+
setAdding((value) => !value)
|
|
3227
|
+
setMore(false)
|
|
3228
|
+
},
|
|
3229
|
+
},
|
|
3230
|
+
h(Icon, { name: adding ? 'close' : 'plus', size: 13 }),
|
|
3231
|
+
adding ? '' : t('action.add'),
|
|
3129
3232
|
),
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
'
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3233
|
+
// One overflow menu instead of four competing buttons: the primary action is
|
|
3234
|
+
// adding a todo; everything else is occasional.
|
|
3235
|
+
h(Menu, {
|
|
3236
|
+
label: t('action.overflow'),
|
|
3237
|
+
items: [
|
|
3238
|
+
{ key: 'refresh', label: t('action.refresh'), icon: 'refresh', onSelect: () => void reload() },
|
|
3239
|
+
{ key: 'export', label: t('action.export'), icon: 'doc', onSelect: () => void exportJson() },
|
|
3240
|
+
{ key: 'import', label: t('action.import'), icon: 'plus', onSelect: () => importRef.current?.click?.() },
|
|
3241
|
+
{ key: 'settings', label: t('settings.title'), icon: 'gear', onSelect: () => openSettings() },
|
|
3242
|
+
],
|
|
3243
|
+
}),
|
|
3139
3244
|
),
|
|
3140
3245
|
h('input', {
|
|
3141
3246
|
ref: importRef,
|
|
@@ -3149,7 +3254,23 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3149
3254
|
settingsOpen
|
|
3150
3255
|
? h(
|
|
3151
3256
|
'div',
|
|
3152
|
-
{
|
|
3257
|
+
{
|
|
3258
|
+
className: 'gt-settings',
|
|
3259
|
+
role: 'dialog',
|
|
3260
|
+
'aria-label': t('settings.title'),
|
|
3261
|
+
style:
|
|
3262
|
+
settingsBox === null
|
|
3263
|
+
? undefined
|
|
3264
|
+
: {
|
|
3265
|
+
position: 'fixed',
|
|
3266
|
+
top: `${settingsBox.top}px`,
|
|
3267
|
+
right: `${settingsBox.right}px`,
|
|
3268
|
+
bottom: `${settingsBox.bottom}px`,
|
|
3269
|
+
maxHeight: 'none',
|
|
3270
|
+
overflow: 'auto',
|
|
3271
|
+
zIndex: 40,
|
|
3272
|
+
},
|
|
3273
|
+
},
|
|
3153
3274
|
h('div', { className: 'gt-settings-head' }, t('settings.title')),
|
|
3154
3275
|
h('div', { className: 'gt-section-title' }, t('settings.reminders')),
|
|
3155
3276
|
h(
|
|
@@ -3191,8 +3312,8 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3191
3312
|
'div',
|
|
3192
3313
|
{ className: 'gt-settings-row' },
|
|
3193
3314
|
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
3315
|
h('button', { type: 'button', className: 'gt-btn gt-btn-quiet', onClick: () => setSettingsOpen(false) }, t('settings.cancel')),
|
|
3316
|
+
h('button', { type: 'button', className: 'gt-btn gt-btn-primary', onClick: () => void saveSettings() }, t('settings.save')),
|
|
3196
3317
|
),
|
|
3197
3318
|
h(
|
|
3198
3319
|
'label',
|
|
@@ -3208,6 +3329,13 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3208
3329
|
onChange: (event) => setBelowDraft(event.target.value),
|
|
3209
3330
|
}),
|
|
3210
3331
|
),
|
|
3332
|
+
h('div', { className: 'gt-section-title' }, t('settings.about')),
|
|
3333
|
+
h(
|
|
3334
|
+
'div',
|
|
3335
|
+
{ className: 'gt-muted gt-mono gt-settings-path', title: state.health?.store?.file ?? '' },
|
|
3336
|
+
state.health?.store?.file ?? '',
|
|
3337
|
+
),
|
|
3338
|
+
h('div', { className: 'gt-muted' }, `v${state.health?.version ?? ''} · ${UI_REV}`),
|
|
3211
3339
|
)
|
|
3212
3340
|
: null,
|
|
3213
3341
|
|
|
@@ -3215,8 +3343,13 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3215
3343
|
? h(
|
|
3216
3344
|
'div',
|
|
3217
3345
|
{ className: 'gt-banner', role: 'alert' },
|
|
3218
|
-
`${t('error.prefix')}: ${error.message}
|
|
3346
|
+
h('span', { className: 'gt-banner-text' }, `${t('error.prefix')}: ${error.message}`),
|
|
3219
3347
|
h('button', { type: 'button', className: 'gt-btn', onClick: () => void reload() }, t('action.retry')),
|
|
3348
|
+
h(
|
|
3349
|
+
'button',
|
|
3350
|
+
{ type: 'button', className: 'gt-iconbtn', title: t('action.hide'), 'aria-label': t('action.hide'), onClick: () => setError(null) },
|
|
3351
|
+
h(Icon, { name: 'close', size: 13 }),
|
|
3352
|
+
),
|
|
3220
3353
|
)
|
|
3221
3354
|
: null,
|
|
3222
3355
|
|
|
@@ -3240,14 +3373,14 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3240
3373
|
}),
|
|
3241
3374
|
h(
|
|
3242
3375
|
'button',
|
|
3243
|
-
{ type: 'button', className: 'gt-btn gt-btn-
|
|
3244
|
-
|
|
3245
|
-
t('action.add'),
|
|
3376
|
+
{ type: 'button', className: 'gt-btn gt-btn-quiet', 'aria-expanded': more, onClick: () => setMore((value) => !value) },
|
|
3377
|
+
more ? t('action.less') : t('action.more'),
|
|
3246
3378
|
),
|
|
3247
3379
|
h(
|
|
3248
3380
|
'button',
|
|
3249
|
-
{ type: 'button', className: 'gt-btn gt-btn-
|
|
3250
|
-
|
|
3381
|
+
{ type: 'button', className: 'gt-btn gt-btn-primary', disabled: busyId === '__new__' || draft.title.trim() === '', onClick: () => void submit() },
|
|
3382
|
+
h(Icon, { name: 'plus', size: 13 }),
|
|
3383
|
+
t('action.add'),
|
|
3251
3384
|
),
|
|
3252
3385
|
),
|
|
3253
3386
|
more
|
|
@@ -3306,6 +3439,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3306
3439
|
h(
|
|
3307
3440
|
'div',
|
|
3308
3441
|
{ className: 'gt-toolbar' },
|
|
3442
|
+
h('div', { className: 'gt-toolbar-main' },
|
|
3309
3443
|
h(
|
|
3310
3444
|
'span',
|
|
3311
3445
|
{ className: 'gt-tabs', role: 'group', 'aria-label': t('filter.label') },
|
|
@@ -3361,12 +3495,37 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3361
3495
|
),
|
|
3362
3496
|
),
|
|
3363
3497
|
),
|
|
3498
|
+
),
|
|
3364
3499
|
h('div', { className: 'gt-spacer' }),
|
|
3500
|
+
h(
|
|
3501
|
+
'div',
|
|
3502
|
+
{ className: 'gt-context-summary' },
|
|
3503
|
+
h(
|
|
3504
|
+
'button',
|
|
3505
|
+
{ type: 'button', className: 'gt-chip', title: effectiveDir === '' ? t('dir.none') : effectiveDir, onClick: () => setContextOpen((value) => !value) },
|
|
3506
|
+
h(Icon, { name: 'doc', size: 12 }),
|
|
3507
|
+
effectiveDir === '' ? t('dir.none') : effectiveDir,
|
|
3508
|
+
),
|
|
3509
|
+
h(
|
|
3510
|
+
'button',
|
|
3511
|
+
{ type: 'button', className: 'gt-chip', title: t('target.pick'), onClick: () => setContextOpen((value) => !value) },
|
|
3512
|
+
h(Icon, { name: 'play', size: 11 }),
|
|
3513
|
+
`${t('target.label')}: ${conversations.find((entry) => entry.id === targetValue)?.title ?? t('target.auto')}`,
|
|
3514
|
+
),
|
|
3515
|
+
h(
|
|
3516
|
+
'button',
|
|
3517
|
+
{ type: 'button', className: 'gt-btn gt-btn-quiet', 'aria-expanded': contextOpen, onClick: () => setContextOpen((value) => !value) },
|
|
3518
|
+
t('settings.context'),
|
|
3519
|
+
),
|
|
3520
|
+
),
|
|
3521
|
+
h(
|
|
3522
|
+
'div',
|
|
3523
|
+
{ className: 'gt-context-details', 'data-open': contextOpen ? '1' : '0' },
|
|
3365
3524
|
h(
|
|
3366
3525
|
'span',
|
|
3367
3526
|
{ className: 'gt-dir', title: effectiveDir === '' ? t('dir.none') : effectiveDir },
|
|
3368
3527
|
h(Icon, { name: 'doc', size: 12 }),
|
|
3369
|
-
h('span', { className: 'gt-muted' }, `${t('field.dir')}
|
|
3528
|
+
h('span', { className: 'gt-muted' }, `${t('field.dir')}: `),
|
|
3370
3529
|
h('span', { className: 'gt-dir-path' }, effectiveDir === '' ? t('dir.none') : effectiveDir),
|
|
3371
3530
|
h('span', { className: 'gt-muted' }, pickedDir === '' ? t('dir.fromSession') : t('dir.picked')),
|
|
3372
3531
|
h('button', { type: 'button', className: 'gt-btn gt-btn-quiet', onClick: () => void chooseDir() }, t('action.pickDir')),
|
|
@@ -3471,7 +3630,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3471
3630
|
),
|
|
3472
3631
|
),
|
|
3473
3632
|
),
|
|
3474
|
-
h('span', { className: 'gt-muted' }, `${t('target.label')}
|
|
3633
|
+
h('span', { className: 'gt-muted' }, `${t('target.label')}: `),
|
|
3475
3634
|
h(
|
|
3476
3635
|
'select',
|
|
3477
3636
|
{
|
|
@@ -3501,6 +3660,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3501
3660
|
{ value: 'auto', label: t('target.auto') },
|
|
3502
3661
|
].map((option) => h('option', { key: option.value, value: option.value }, option.label)),
|
|
3503
3662
|
),
|
|
3663
|
+
),
|
|
3504
3664
|
h('span', { className: 'gt-spacer' }),
|
|
3505
3665
|
h('span', { className: 'gt-tabs', role: 'group', 'aria-label': t('autoCollect.label') }, togglesNodes),
|
|
3506
3666
|
),
|
|
@@ -3731,6 +3891,20 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3731
3891
|
'div',
|
|
3732
3892
|
{ className: 'gt-empty' },
|
|
3733
3893
|
h('div', { className: 'gt-empty-title' }, (state.counts?.total ?? 0) === 0 && query.trim() === '' ? t('empty.none') : t('empty.filtered')),
|
|
3894
|
+
(state.counts?.total ?? 0) === 0 && query.trim() === ''
|
|
3895
|
+
? h(
|
|
3896
|
+
'button',
|
|
3897
|
+
{
|
|
3898
|
+
type: 'button',
|
|
3899
|
+
className: 'gt-btn gt-btn-primary',
|
|
3900
|
+
onClick: () => {
|
|
3901
|
+
setAdding(true)
|
|
3902
|
+
setMore(false)
|
|
3903
|
+
},
|
|
3904
|
+
},
|
|
3905
|
+
t('empty.add'),
|
|
3906
|
+
)
|
|
3907
|
+
: null,
|
|
3734
3908
|
h('div', { className: 'gt-sub' }, t('hint.keys')),
|
|
3735
3909
|
)
|
|
3736
3910
|
: h(
|
|
@@ -3755,7 +3929,11 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3755
3929
|
},
|
|
3756
3930
|
h(Icon, { name: 'chevron', size: 12 }),
|
|
3757
3931
|
h('span', { className: 'gt-group-label' }, group.label),
|
|
3758
|
-
h(
|
|
3932
|
+
h(
|
|
3933
|
+
'span',
|
|
3934
|
+
{ className: 'gt-group-count' },
|
|
3935
|
+
group.todos.length === 1 ? t('group.item') : t('group.items', { n: group.todos.length }),
|
|
3936
|
+
),
|
|
3759
3937
|
group.level === 'normal'
|
|
3760
3938
|
? null
|
|
3761
3939
|
: h(
|
|
@@ -3821,7 +3999,10 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3821
3999
|
open: expandedId === todo.id,
|
|
3822
4000
|
dispatchLabel,
|
|
3823
4001
|
onAction,
|
|
3824
|
-
onToggleOpen: (id) =>
|
|
4002
|
+
onToggleOpen: (id) => {
|
|
4003
|
+
setSettingsOpen(false)
|
|
4004
|
+
setExpandedId((current) => (current === id ? '' : id))
|
|
4005
|
+
},
|
|
3825
4006
|
}),
|
|
3826
4007
|
),
|
|
3827
4008
|
),
|
|
@@ -3837,15 +4018,6 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3837
4018
|
)
|
|
3838
4019
|
: null,
|
|
3839
4020
|
|
|
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
4021
|
),
|
|
3850
4022
|
notice !== null && notice !== undefined
|
|
3851
4023
|
? 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.1'
|
|
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.1",
|
|
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",
|