dsh-global-todo 0.6.5 → 0.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
## [0.6.7] — 2026-10-20
|
|
2
|
+
|
|
3
|
+
Copy safety, and the last orphan of the old footer.
|
|
4
|
+
|
|
5
|
+
- **A test now guards the dictionaries.** `test/locale.test.mjs` reads them as source text
|
|
6
|
+
(a duplicate key is legal JavaScript and invisible at runtime) and fails on: a key defined
|
|
7
|
+
twice, a key present in one language and missing in the other, full-width punctuation inside
|
|
8
|
+
English copy, and a literal `t('…')` key that does not exist. It immediately found a real
|
|
9
|
+
duplicate — `select.clear` — the same class of bug that shipped "more fields" on the overflow
|
|
10
|
+
menu.
|
|
11
|
+
- **The duplicate is fixed properly**: the selection bar clears with its own key (`清空`/`Clear`)
|
|
12
|
+
while the pick toggle and the two ask-bars share `清除`/`取消`.
|
|
13
|
+
- **Keyboard shortcuts get a home.** The hints left the footer in 0.6.0 and only survived in the
|
|
14
|
+
empty state; they now open from `⋯ → Keyboard shortcuts` as a small card with `kbd` chips, and
|
|
15
|
+
Escape closes it before anything else.
|
|
16
|
+
|
|
17
|
+
## [0.6.6] — 2026-10-20
|
|
18
|
+
|
|
19
|
+
Both forms now look like forms.
|
|
20
|
+
|
|
21
|
+
- **Add form** gets real labels and a hint under each field instead of placeholder-only inputs
|
|
22
|
+
(a placeholder vanishes the moment you type, so it can never carry a rule), and the expanded
|
|
23
|
+
area is separated from the title row by a hairline.
|
|
24
|
+
- **Detail editor** gets the same treatment: labelled Title / Priority / Due / Description rows.
|
|
25
|
+
- **The 340px detail card no longer fights its own grid.** Meta rows stack to one column inside
|
|
26
|
+
the card, attachments wrap to their own lines, and the raw path is dropped there because the
|
|
27
|
+
card cannot show it next to two buttons — the title still carries it as a tooltip.
|
|
28
|
+
|
|
1
29
|
## [0.6.5] — 2026-10-20
|
|
2
30
|
|
|
3
31
|
The three loose ends the spec called out but the earlier passes left behind.
|
|
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 = 'ui43'
|
|
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
|
|
|
@@ -106,6 +106,11 @@ window.__ModuleLoader__.load({
|
|
|
106
106
|
'settings.cancel': '取消',
|
|
107
107
|
'settings.saved': '设置已保存',
|
|
108
108
|
'settings.about': '关于',
|
|
109
|
+
'action.keys': '快捷键',
|
|
110
|
+
'keys.search': '聚焦搜索',
|
|
111
|
+
'keys.new': '开始记一条',
|
|
112
|
+
'keys.save': '保存这条(在标题里)',
|
|
113
|
+
'keys.close': '收起最内层浮层',
|
|
109
114
|
'group.actions': '分组操作',
|
|
110
115
|
'group.capture': '从本对话抓取',
|
|
111
116
|
'group.exemptOn': '本工作区免打扰',
|
|
@@ -139,7 +144,7 @@ window.__ModuleLoader__.load({
|
|
|
139
144
|
'notice.bulkPartial': '已更新 {n} 条,跳过 {m} 条',
|
|
140
145
|
'select.clear': '清除',
|
|
141
146
|
'select.done': '退出选择',
|
|
142
|
-
'select.
|
|
147
|
+
'select.clearAll': '清空',
|
|
143
148
|
'select.hint': '先勾几条待办,再点「一键分配」:优先回到写下它的那个对话,其次同工作区的对话,都找不到才让你选。',
|
|
144
149
|
'assign.working': '正在分配…',
|
|
145
150
|
'assign.summary': '已分配 {n} 条(原对话 {origin} · 同工作区 {workspace} · 你选的 {chosen})',
|
|
@@ -229,6 +234,10 @@ window.__ModuleLoader__.load({
|
|
|
229
234
|
'field.title': '要做什么?回车即存',
|
|
230
235
|
'field.description': '描述:验收标准、已知的坑…',
|
|
231
236
|
'field.links': '相关文档与地址,一行一个(/绝对路径 或 https://…)',
|
|
237
|
+
'field.tagsLabel': '标签',
|
|
238
|
+
'field.titleLabel': '标题',
|
|
239
|
+
'field.descriptionHint': '验收标准、已知的坑都可以写在这里。',
|
|
240
|
+
'field.linksHint': '一行一个:绝对路径或 https:// 链接。',
|
|
232
241
|
'field.tags': '标签,逗号分隔',
|
|
233
242
|
'field.priority': '优先级',
|
|
234
243
|
'field.due': '截止时间',
|
|
@@ -363,6 +372,11 @@ window.__ModuleLoader__.load({
|
|
|
363
372
|
'settings.cancel': 'Cancel',
|
|
364
373
|
'settings.saved': 'Settings saved',
|
|
365
374
|
'settings.about': 'About',
|
|
375
|
+
'action.keys': 'Keyboard shortcuts',
|
|
376
|
+
'keys.search': 'Focus the search box',
|
|
377
|
+
'keys.new': 'Start a new todo',
|
|
378
|
+
'keys.save': 'Save it (from the title field)',
|
|
379
|
+
'keys.close': 'Close the innermost layer',
|
|
366
380
|
'group.actions': 'Group actions',
|
|
367
381
|
'group.capture': 'Collect from this conversation',
|
|
368
382
|
'group.exemptOn': 'Mute this workspace',
|
|
@@ -396,6 +410,7 @@ window.__ModuleLoader__.load({
|
|
|
396
410
|
'notice.bulkPartial': 'Updated {n}, skipped {m}',
|
|
397
411
|
'select.clear': 'Clear',
|
|
398
412
|
'select.done': 'Exit selection',
|
|
413
|
+
'select.clearAll': 'Clear',
|
|
399
414
|
'select.hint': 'Pick a few todos, then Assign: back to the conversation that wrote each one, else a conversation in the same workspace, else you choose.',
|
|
400
415
|
'assign.working': 'Assigning…',
|
|
401
416
|
'assign.summary': 'Assigned {n} ({origin} to origin · {workspace} same workspace · {chosen} chosen)',
|
|
@@ -487,6 +502,10 @@ window.__ModuleLoader__.load({
|
|
|
487
502
|
'field.title': 'What needs doing? Enter to save',
|
|
488
503
|
'field.description': 'Description: acceptance, known traps…',
|
|
489
504
|
'field.links': 'Documents and links, one per line (/abs/path or https://…)',
|
|
505
|
+
'field.tagsLabel': 'Tags',
|
|
506
|
+
'field.titleLabel': 'Title',
|
|
507
|
+
'field.descriptionHint': 'Acceptance criteria and known traps belong here.',
|
|
508
|
+
'field.linksHint': 'One per line: an absolute path or an https:// link.',
|
|
490
509
|
'field.tags': 'Tags, comma separated',
|
|
491
510
|
'field.priority': 'Priority',
|
|
492
511
|
'field.due': 'Due',
|
|
@@ -976,6 +995,19 @@ window.__ModuleLoader__.load({
|
|
|
976
995
|
.gt-card { background: var(--dsw-alias-bg-layer-1); border: 1px solid var(--dsw-alias-border-l1);
|
|
977
996
|
border-radius: 12px; padding: 12px 14px; }
|
|
978
997
|
.gt-new { display: flex; flex-direction: column; gap: 10px; }
|
|
998
|
+
.gt-new-fields { display: flex; flex-direction: column; gap: 12px; padding-top: 4px;
|
|
999
|
+
border-top: 1px solid var(--dsw-alias-border-l1); }
|
|
1000
|
+
.gt-new-fields .gt-textarea { min-height: 64px; }
|
|
1001
|
+
.gt-new-fields .gt-field-row { display: grid; grid-template-columns: minmax(0, 1fr) 190px; gap: 12px; }
|
|
1002
|
+
.gt-edit-meta { display: grid; grid-template-columns: minmax(0, 1fr) 190px; gap: 12px; align-items: start; }
|
|
1003
|
+
/* The 340px card cannot hold the two-column meta row or a path beside two buttons:
|
|
1004
|
+
stack them there, and let attachments wrap onto their own lines. */
|
|
1005
|
+
.gt-root[data-wide="1"][data-wide-detail="1"] .gt-detail .gt-edit-meta,
|
|
1006
|
+
.gt-root[data-wide="1"][data-wide-detail="1"] .gt-detail .gt-new-fields .gt-field-row {
|
|
1007
|
+
grid-template-columns: minmax(0, 1fr); }
|
|
1008
|
+
.gt-root[data-wide="1"][data-wide-detail="1"] .gt-detail .gt-link { flex-wrap: wrap; row-gap: 4px; }
|
|
1009
|
+
.gt-root[data-wide="1"][data-wide-detail="1"] .gt-detail .gt-link .gt-mono { display: none; }
|
|
1010
|
+
.gt-root[data-wide="1"][data-wide-detail="1"] .gt-detail .gt-link-main { flex: 1 1 100%; }
|
|
979
1011
|
.gt-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
|
980
1012
|
.gt-input, .gt-select, .gt-textarea { background: var(--dsw-alias-bg-base); color: var(--dsw-alias-label-primary);
|
|
981
1013
|
border: 1px solid var(--dsw-alias-border-l1); border-radius: 8px; padding: 7px 10px; font: inherit; }
|
|
@@ -1148,6 +1180,9 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1148
1180
|
.gt-about-row { display: grid; grid-template-columns: 88px minmax(0, 1fr); align-items: baseline; gap: 8px; }
|
|
1149
1181
|
.gt-settings-foot { display: flex; flex: 0 0 auto; justify-content: flex-end; gap: 8px;
|
|
1150
1182
|
padding: 12px 16px; border-top: 1px solid var(--dsw-alias-border-l1); }
|
|
1183
|
+
.gt-keys { width: 320px; }
|
|
1184
|
+
.gt-key-row { display: flex; align-items: center; gap: 10px; }
|
|
1185
|
+
.gt-key-row .gt-kbd { min-width: 44px; text-align: center; }
|
|
1151
1186
|
.gt-group-select { display: none; min-height: 28px; max-width: 150px; padding: 0 8px; font: inherit;
|
|
1152
1187
|
font-size: 12px; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-1);
|
|
1153
1188
|
border: 1px solid var(--dsw-alias-border-l1); border-radius: 8px; }
|
|
@@ -1905,34 +1940,59 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1905
1940
|
h('div', { className: 'gt-section-title' }, t('detail.edit')),
|
|
1906
1941
|
h(
|
|
1907
1942
|
'div',
|
|
1908
|
-
{ className: 'gt-
|
|
1909
|
-
h('
|
|
1910
|
-
h(Segmented, {
|
|
1911
|
-
label: t('field.priority'),
|
|
1912
|
-
value: draft.priority,
|
|
1913
|
-
onChange: (priority) => setDraft({ ...draft, priority }),
|
|
1914
|
-
options: [
|
|
1915
|
-
{ value: 'low', label: t('priority.low') },
|
|
1916
|
-
{ value: 'normal', label: t('priority.normal') },
|
|
1917
|
-
{ value: 'high', label: t('priority.high') },
|
|
1918
|
-
{ value: 'urgent', label: t('priority.urgent') },
|
|
1919
|
-
],
|
|
1920
|
-
}),
|
|
1943
|
+
{ className: 'gt-field' },
|
|
1944
|
+
h('label', { className: 'gt-field-label', htmlFor: 'gt-edit-title' }, t('field.titleLabel')),
|
|
1921
1945
|
h('input', {
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
value: draft.
|
|
1925
|
-
|
|
1926
|
-
|
|
1946
|
+
id: 'gt-edit-title',
|
|
1947
|
+
className: 'gt-input',
|
|
1948
|
+
value: draft.title,
|
|
1949
|
+
onChange: (event) => setDraft({ ...draft, title: event.target.value }),
|
|
1950
|
+
}),
|
|
1951
|
+
),
|
|
1952
|
+
h(
|
|
1953
|
+
'div',
|
|
1954
|
+
{ className: 'gt-field-row gt-edit-meta' },
|
|
1955
|
+
h(
|
|
1956
|
+
'div',
|
|
1957
|
+
{ className: 'gt-field' },
|
|
1958
|
+
h('span', { className: 'gt-field-label' }, t('field.priority')),
|
|
1959
|
+
h(Segmented, {
|
|
1960
|
+
label: t('field.priority'),
|
|
1961
|
+
value: draft.priority,
|
|
1962
|
+
onChange: (priority) => setDraft({ ...draft, priority }),
|
|
1963
|
+
options: [
|
|
1964
|
+
{ value: 'urgent', label: t('priority.urgent') },
|
|
1965
|
+
{ value: 'high', label: t('priority.high') },
|
|
1966
|
+
{ value: 'normal', label: t('priority.normal') },
|
|
1967
|
+
{ value: 'low', label: t('priority.low') },
|
|
1968
|
+
],
|
|
1969
|
+
}),
|
|
1970
|
+
),
|
|
1971
|
+
h(
|
|
1972
|
+
'div',
|
|
1973
|
+
{ className: 'gt-field' },
|
|
1974
|
+
h('label', { className: 'gt-field-label', htmlFor: 'gt-edit-due' }, t('field.due')),
|
|
1975
|
+
h('input', {
|
|
1976
|
+
id: 'gt-edit-due',
|
|
1977
|
+
className: 'gt-input',
|
|
1978
|
+
type: 'datetime-local',
|
|
1979
|
+
value: draft.due,
|
|
1980
|
+
onChange: (event) => setDraft({ ...draft, due: event.target.value }),
|
|
1981
|
+
}),
|
|
1982
|
+
),
|
|
1983
|
+
),
|
|
1984
|
+
h(
|
|
1985
|
+
'div',
|
|
1986
|
+
{ className: 'gt-field' },
|
|
1987
|
+
h('label', { className: 'gt-field-label', htmlFor: 'gt-edit-desc' }, t('detail.description')),
|
|
1988
|
+
h('textarea', {
|
|
1989
|
+
id: 'gt-edit-desc',
|
|
1990
|
+
className: 'gt-textarea',
|
|
1991
|
+
value: draft.description,
|
|
1992
|
+
placeholder: t('field.description'),
|
|
1993
|
+
onChange: (event) => setDraft({ ...draft, description: event.target.value }),
|
|
1927
1994
|
}),
|
|
1928
1995
|
),
|
|
1929
|
-
h('textarea', {
|
|
1930
|
-
className: 'gt-textarea',
|
|
1931
|
-
value: draft.description,
|
|
1932
|
-
placeholder: t('field.description'),
|
|
1933
|
-
'aria-label': t('detail.description'),
|
|
1934
|
-
onChange: (event) => setDraft({ ...draft, description: event.target.value }),
|
|
1935
|
-
}),
|
|
1936
1996
|
dirty
|
|
1937
1997
|
? h(
|
|
1938
1998
|
'div',
|
|
@@ -2233,6 +2293,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2233
2293
|
// One settings popover: reminders and the external door both need a place a person can
|
|
2234
2294
|
// reach without curl.
|
|
2235
2295
|
const [settingsOpen, setSettingsOpen] = useState(initialSettingsOpen)
|
|
2296
|
+
const [keysOpen, setKeysOpen] = useState(false)
|
|
2236
2297
|
const [settingsBox, setSettingsBox] = useState(null)
|
|
2237
2298
|
// The detail card's breakpoint follows the panel's own width, not the viewport: the
|
|
2238
2299
|
// slot is ~265px narrower than the window, so a viewport query opens the two-column
|
|
@@ -2591,6 +2652,10 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2591
2652
|
(target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable === true)
|
|
2592
2653
|
if (event.key === 'Escape') {
|
|
2593
2654
|
if (typing && typeof target.blur === 'function') target.blur()
|
|
2655
|
+
if (keysOpen) {
|
|
2656
|
+
setKeysOpen(false)
|
|
2657
|
+
return
|
|
2658
|
+
}
|
|
2594
2659
|
if (settingsOpen) {
|
|
2595
2660
|
setSettingsOpen(false)
|
|
2596
2661
|
return
|
|
@@ -2613,7 +2678,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2613
2678
|
}
|
|
2614
2679
|
document.addEventListener('keydown', onKey)
|
|
2615
2680
|
return () => document.removeEventListener('keydown', onKey)
|
|
2616
|
-
}, [settingsOpen, adding])
|
|
2681
|
+
}, [settingsOpen, keysOpen, adding])
|
|
2617
2682
|
|
|
2618
2683
|
// The settings card floats over the list, so a click anywhere else dismisses it
|
|
2619
2684
|
// the way every other popover on the web does.
|
|
@@ -3343,6 +3408,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3343
3408
|
{ key: 'export', label: t('action.export'), icon: 'doc', onSelect: () => void exportJson() },
|
|
3344
3409
|
{ key: 'import', label: t('action.import'), icon: 'plus', onSelect: () => importRef.current?.click?.() },
|
|
3345
3410
|
{ key: 'settings', label: t('settings.title'), icon: 'gear', onSelect: () => openSettings() },
|
|
3411
|
+
{ key: 'keys', label: t('action.keys'), icon: 'kebab', onSelect: () => setKeysOpen(true) },
|
|
3346
3412
|
],
|
|
3347
3413
|
}),
|
|
3348
3414
|
),
|
|
@@ -3508,6 +3574,57 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3508
3574
|
)
|
|
3509
3575
|
: null,
|
|
3510
3576
|
|
|
3577
|
+
// The keyboard hints used to sit in a footer nobody read; they belong where the
|
|
3578
|
+
// other occasional things live, one menu away.
|
|
3579
|
+
keysOpen
|
|
3580
|
+
? h(
|
|
3581
|
+
'div',
|
|
3582
|
+
{
|
|
3583
|
+
ref: settingsRef,
|
|
3584
|
+
className: 'gt-settings gt-keys',
|
|
3585
|
+
role: 'dialog',
|
|
3586
|
+
'aria-label': t('action.keys'),
|
|
3587
|
+
style:
|
|
3588
|
+
settingsBox === null
|
|
3589
|
+
? undefined
|
|
3590
|
+
: {
|
|
3591
|
+
position: 'fixed',
|
|
3592
|
+
top: `${settingsBox.top}px`,
|
|
3593
|
+
right: `${settingsBox.right}px`,
|
|
3594
|
+
maxHeight: `calc(100dvh - ${settingsBox.top + 20}px)`,
|
|
3595
|
+
zIndex: 40,
|
|
3596
|
+
},
|
|
3597
|
+
},
|
|
3598
|
+
h(
|
|
3599
|
+
'div',
|
|
3600
|
+
{ className: 'gt-settings-head' },
|
|
3601
|
+
h('span', { className: 'gt-settings-title' }, t('action.keys')),
|
|
3602
|
+
h(
|
|
3603
|
+
'button',
|
|
3604
|
+
{ type: 'button', className: 'gt-iconbtn', title: t('action.hide'), 'aria-label': t('action.hide'), onClick: () => setKeysOpen(false) },
|
|
3605
|
+
h(Icon, { name: 'close', size: 13 }),
|
|
3606
|
+
),
|
|
3607
|
+
),
|
|
3608
|
+
h(
|
|
3609
|
+
'div',
|
|
3610
|
+
{ className: 'gt-settings-body' },
|
|
3611
|
+
[
|
|
3612
|
+
['/', t('keys.search')],
|
|
3613
|
+
['n', t('keys.new')],
|
|
3614
|
+
['Enter', t('keys.save')],
|
|
3615
|
+
['Esc', t('keys.close')],
|
|
3616
|
+
].map(([combo, sentence]) =>
|
|
3617
|
+
h(
|
|
3618
|
+
'div',
|
|
3619
|
+
{ className: 'gt-key-row', key: combo },
|
|
3620
|
+
h('span', { className: 'gt-kbd' }, combo),
|
|
3621
|
+
h('span', { className: 'gt-hint' }, sentence),
|
|
3622
|
+
),
|
|
3623
|
+
),
|
|
3624
|
+
),
|
|
3625
|
+
)
|
|
3626
|
+
: null,
|
|
3627
|
+
|
|
3511
3628
|
error !== null
|
|
3512
3629
|
? h(
|
|
3513
3630
|
'div',
|
|
@@ -3555,31 +3672,65 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3555
3672
|
more
|
|
3556
3673
|
? h(
|
|
3557
3674
|
'div',
|
|
3558
|
-
{ className: 'gt-new' },
|
|
3559
|
-
h('textarea', {
|
|
3560
|
-
className: 'gt-textarea',
|
|
3561
|
-
placeholder: t('field.description'),
|
|
3562
|
-
value: draft.description,
|
|
3563
|
-
'aria-label': t('detail.description'),
|
|
3564
|
-
onChange: (event) => setDraft({ ...draft, description: event.target.value }),
|
|
3565
|
-
}),
|
|
3566
|
-
h('textarea', {
|
|
3567
|
-
className: 'gt-textarea',
|
|
3568
|
-
placeholder: t('field.links'),
|
|
3569
|
-
value: draft.links,
|
|
3570
|
-
'aria-label': t('detail.links'),
|
|
3571
|
-
onChange: (event) => setDraft({ ...draft, links: event.target.value }),
|
|
3572
|
-
}),
|
|
3675
|
+
{ className: 'gt-new-fields' },
|
|
3573
3676
|
h(
|
|
3574
3677
|
'div',
|
|
3575
|
-
{ className: 'gt-
|
|
3576
|
-
h('
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3678
|
+
{ className: 'gt-field' },
|
|
3679
|
+
h('label', { className: 'gt-field-label', htmlFor: 'gt-new-desc' }, t('detail.description')),
|
|
3680
|
+
h('textarea', {
|
|
3681
|
+
id: 'gt-new-desc',
|
|
3682
|
+
className: 'gt-textarea',
|
|
3683
|
+
placeholder: t('field.description'),
|
|
3684
|
+
value: draft.description,
|
|
3685
|
+
onChange: (event) => setDraft({ ...draft, description: event.target.value }),
|
|
3686
|
+
}),
|
|
3687
|
+
h('span', { className: 'gt-hint' }, t('field.descriptionHint')),
|
|
3688
|
+
),
|
|
3689
|
+
h(
|
|
3690
|
+
'div',
|
|
3691
|
+
{ className: 'gt-field' },
|
|
3692
|
+
h('label', { className: 'gt-field-label', htmlFor: 'gt-new-links' }, t('detail.links')),
|
|
3693
|
+
h('textarea', {
|
|
3694
|
+
id: 'gt-new-links',
|
|
3695
|
+
className: 'gt-textarea',
|
|
3696
|
+
placeholder: t('field.links'),
|
|
3697
|
+
value: draft.links,
|
|
3698
|
+
onChange: (event) => setDraft({ ...draft, links: event.target.value }),
|
|
3582
3699
|
}),
|
|
3700
|
+
h('span', { className: 'gt-hint' }, t('field.linksHint')),
|
|
3701
|
+
),
|
|
3702
|
+
h(
|
|
3703
|
+
'div',
|
|
3704
|
+
{ className: 'gt-field-row' },
|
|
3705
|
+
h(
|
|
3706
|
+
'div',
|
|
3707
|
+
{ className: 'gt-field' },
|
|
3708
|
+
h('label', { className: 'gt-field-label', htmlFor: 'gt-new-tags' }, t('field.tagsLabel')),
|
|
3709
|
+
h('input', {
|
|
3710
|
+
id: 'gt-new-tags',
|
|
3711
|
+
className: 'gt-input gt-input-sm',
|
|
3712
|
+
placeholder: t('field.tags'),
|
|
3713
|
+
value: draft.tags,
|
|
3714
|
+
onChange: (event) => setDraft({ ...draft, tags: event.target.value }),
|
|
3715
|
+
}),
|
|
3716
|
+
),
|
|
3717
|
+
h(
|
|
3718
|
+
'div',
|
|
3719
|
+
{ className: 'gt-field' },
|
|
3720
|
+
h('label', { className: 'gt-field-label', htmlFor: 'gt-new-due' }, t('field.due')),
|
|
3721
|
+
h('input', {
|
|
3722
|
+
id: 'gt-new-due',
|
|
3723
|
+
className: 'gt-input gt-input-sm',
|
|
3724
|
+
type: 'datetime-local',
|
|
3725
|
+
value: draft.due,
|
|
3726
|
+
onChange: (event) => setDraft({ ...draft, due: event.target.value }),
|
|
3727
|
+
}),
|
|
3728
|
+
),
|
|
3729
|
+
),
|
|
3730
|
+
h(
|
|
3731
|
+
'div',
|
|
3732
|
+
{ className: 'gt-field' },
|
|
3733
|
+
h('span', { className: 'gt-field-label' }, t('field.priority')),
|
|
3583
3734
|
h(Segmented, {
|
|
3584
3735
|
label: t('field.priority'),
|
|
3585
3736
|
value: draft.priority,
|
|
@@ -3591,14 +3742,6 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3591
3742
|
{ value: 'low', label: t('priority.low') },
|
|
3592
3743
|
],
|
|
3593
3744
|
}),
|
|
3594
|
-
h('input', {
|
|
3595
|
-
className: 'gt-input gt-input-sm',
|
|
3596
|
-
type: 'datetime-local',
|
|
3597
|
-
value: draft.due,
|
|
3598
|
-
title: t('field.due'),
|
|
3599
|
-
'aria-label': t('field.due'),
|
|
3600
|
-
onChange: (event) => setDraft({ ...draft, due: event.target.value }),
|
|
3601
|
-
}),
|
|
3602
3745
|
),
|
|
3603
3746
|
)
|
|
3604
3747
|
: null,
|
|
@@ -3877,7 +4020,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3877
4020
|
h(
|
|
3878
4021
|
'button',
|
|
3879
4022
|
{ type: 'button', className: 'gt-btn gt-btn-quiet', onClick: () => setSelected({}) },
|
|
3880
|
-
t('select.
|
|
4023
|
+
t('select.clearAll'),
|
|
3881
4024
|
),
|
|
3882
4025
|
h('span', { className: 'gt-spacer' }),
|
|
3883
4026
|
h(
|
|
@@ -4040,7 +4183,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
4040
4183
|
h(
|
|
4041
4184
|
'button',
|
|
4042
4185
|
{ type: 'button', className: 'gt-btn gt-btn-quiet', onClick: () => setAssignAsk(null) },
|
|
4043
|
-
t('
|
|
4186
|
+
t('action.cancel'),
|
|
4044
4187
|
),
|
|
4045
4188
|
),
|
|
4046
4189
|
|
|
@@ -4066,7 +4209,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
4066
4209
|
h(
|
|
4067
4210
|
'button',
|
|
4068
4211
|
{ type: 'button', className: 'gt-btn gt-btn-quiet', onClick: () => setImportAsk(null) },
|
|
4069
|
-
t('
|
|
4212
|
+
t('action.cancel'),
|
|
4070
4213
|
),
|
|
4071
4214
|
),
|
|
4072
4215
|
|
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.6.
|
|
39
|
+
export const VERSION = '0.6.7'
|
|
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.6.
|
|
3
|
+
"version": "0.6.7",
|
|
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",
|