dsh-global-todo 0.6.0 → 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 +16 -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 +42 -20
- package/lib/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
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
|
+
|
|
1
17
|
## [0.6.0] — 2026-10-20
|
|
2
18
|
|
|
3
19
|
A design pass over the whole panel: one list, fewer competing controls, one type scale.
|
|
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
|
|
|
@@ -1051,7 +1051,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1051
1051
|
.gt-list { display: flex; flex-direction: column; gap: 8px; }
|
|
1052
1052
|
.gt-item { position: relative; display: flex; flex-direction: column; gap: 8px;
|
|
1053
1053
|
background: var(--dsw-alias-bg-layer-2); border: 1px solid var(--dsw-alias-border-l1);
|
|
1054
|
-
border-radius:
|
|
1054
|
+
border-radius: 10px; padding: 12px 14px; min-height: 72px; box-sizing: border-box; }
|
|
1055
1055
|
.gt-item:hover { border-color: var(--dsw-alias-border-l2); }
|
|
1056
1056
|
.gt-item[data-status="doing"] { border-left: 2px solid var(--dsw-alias-brand-primary); }
|
|
1057
1057
|
.gt-item[data-overdue="1"] { border-left: 2px solid var(--dsw-alias-state-error-primary); }
|
|
@@ -1105,6 +1105,9 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1105
1105
|
background: var(--dsw-alias-bg-layer-1); }
|
|
1106
1106
|
.gt-context-details[data-open="1"] { display: flex; }
|
|
1107
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; }
|
|
1108
1111
|
.gt-detail-title { font-size: 14px; line-height: 22px; font-weight: 600; min-width: 0;
|
|
1109
1112
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1110
1113
|
.gt-truncated { color: var(--dsw-alias-state-warn-primary); font-size: 12px; }
|
|
@@ -1139,12 +1142,12 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1139
1142
|
/* Wide screens: the open row's detail becomes a card on the right instead of pushing the list
|
|
1140
1143
|
down. Deliberately CSS-only over unchanged markup: one detail implementation, and it only
|
|
1141
1144
|
applies where there is room for a second column. */
|
|
1142
|
-
|
|
1145
|
+
/* Wide layout follows the panel's measured width (data-wide), not the viewport. */
|
|
1143
1146
|
/* Only the list gives way: the title row and the toolbar keep their full width, so the
|
|
1144
1147
|
controls never wrap or hide behind the card. */
|
|
1145
|
-
.gt-root[data-wide-detail="1"] .gt-groups { padding-right: 360px; }
|
|
1146
|
-
.gt-root[data-wide-detail="1"] .gt-inner { position: relative; }
|
|
1147
|
-
.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 {
|
|
1148
1151
|
/* Anchored to the panel's own column (.gt-inner), not to the viewport: the slot does not
|
|
1149
1152
|
always fill the window, and a viewport-centred offset put the card over the list. */
|
|
1150
1153
|
/* The var fallback matters for the static previews (server-rendered, so effects never
|
|
@@ -1158,7 +1161,6 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1158
1161
|
overflow: auto; padding: 16px; margin: 0; border: 1px solid var(--dsw-alias-border-l2);
|
|
1159
1162
|
border-radius: 12px; background: var(--dsw-alias-bg-overlay); z-index: 30;
|
|
1160
1163
|
}
|
|
1161
|
-
}
|
|
1162
1164
|
.gt-section { display: flex; flex-direction: column; gap: 5px; }
|
|
1163
1165
|
.gt-completion { white-space: pre-wrap; word-break: break-word; line-height: 1.5; }
|
|
1164
1166
|
.gt-section-title { color: var(--dsw-alias-label-secondary); font-size: 12px; line-height: 18px; font-weight: 600; }
|
|
@@ -2166,6 +2168,10 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2166
2168
|
// reach without curl.
|
|
2167
2169
|
const [settingsOpen, setSettingsOpen] = useState(false)
|
|
2168
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)
|
|
2169
2175
|
const [contextOpen, setContextOpen] = useState(false)
|
|
2170
2176
|
const [tokenDraft, setTokenDraft] = useState('')
|
|
2171
2177
|
const [ingestDraft, setIngestDraft] = useState(false)
|
|
@@ -2406,6 +2412,20 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2406
2412
|
}
|
|
2407
2413
|
}, [lang])
|
|
2408
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
|
+
|
|
2409
2429
|
useEffect(() => {
|
|
2410
2430
|
if (!settingsOpen || typeof window === 'undefined') {
|
|
2411
2431
|
setSettingsBox(null)
|
|
@@ -3157,6 +3177,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3157
3177
|
{
|
|
3158
3178
|
className: 'gt-root',
|
|
3159
3179
|
'data-wide-detail': expandedId === '' ? '0' : '1',
|
|
3180
|
+
'data-wide': panelWidth === null || panelWidth >= 960 ? '1' : '0',
|
|
3160
3181
|
// The slot does not always fill the window, so the card's viewport offsets are
|
|
3161
3182
|
// measured from the panel itself instead of assumed from 50vw.
|
|
3162
3183
|
style:
|
|
@@ -3198,15 +3219,16 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3198
3219
|
'button',
|
|
3199
3220
|
{
|
|
3200
3221
|
type: 'button',
|
|
3201
|
-
className: 'gt-btn gt-btn-primary',
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
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
|
+
},
|
|
3206
3229
|
},
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
t('action.add'),
|
|
3230
|
+
h(Icon, { name: adding ? 'close' : 'plus', size: 13 }),
|
|
3231
|
+
adding ? '' : t('action.add'),
|
|
3210
3232
|
),
|
|
3211
3233
|
// One overflow menu instead of four competing buttons: the primary action is
|
|
3212
3234
|
// adding a todo; everything else is occasional.
|
|
@@ -3351,14 +3373,14 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3351
3373
|
}),
|
|
3352
3374
|
h(
|
|
3353
3375
|
'button',
|
|
3354
|
-
{ type: 'button', className: 'gt-btn gt-btn-
|
|
3355
|
-
|
|
3356
|
-
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'),
|
|
3357
3378
|
),
|
|
3358
3379
|
h(
|
|
3359
3380
|
'button',
|
|
3360
|
-
{ type: 'button', className: 'gt-btn gt-btn-
|
|
3361
|
-
|
|
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'),
|
|
3362
3384
|
),
|
|
3363
3385
|
),
|
|
3364
3386
|
more
|
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.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.6.
|
|
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",
|