dsh-global-todo 0.4.5 → 0.4.6

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
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.6] — 2026-10-19
11
+
12
+ The card existed; where it landed depended on a viewport assumption that the real shell does not
13
+ honour.
14
+
15
+ - **The detail card is measured from the panel, not from `50vw`.** In the GUI the plugin slot does
16
+ not fill the window, so the viewport-derived right edge put the card on top of the list; the card
17
+ now measures `.gt-inner` on open, on window resize and on a slot resize (sidebar collapse), and
18
+ positions itself from that rectangle. The CSS fallback (used by the static previews, which are
19
+ server-rendered and run no effects) assumes the centred 980px column.
10
20
  ## [0.4.5] — 2026-10-19
11
21
 
12
22
  Polishing where the side detail sits, now that it exists.
package/docs/DESIGN.md CHANGED
@@ -63,7 +63,9 @@ Expanding a row inline is right on a narrow window and wrong on a wide one: the
63
63
  row you were reading slides away, and the rest of the screen sits empty. Above 1100px the open
64
64
  row's detail is lifted out of the flow into a card bracketed between the toolbar and the footer
65
65
  at the panel's right edge; only the list gives way (the toolbar keeps full width), and the list gets
66
- padding equal to that card. This is a CSS-only override over unchanged markup
66
+ padding equal to that card. The card's offsets are measured from the panel's own column on mount
67
+ and on resize — the slot does not always fill the window, so a viewport-derived offset put the card
68
+ over the list inside the real GUI. This is a CSS-only override over unchanged markup
67
69
  (`.gt-root[data-wide-detail]` plus one media query) precisely so there is still exactly one
68
70
  detail implementation — a second render path for wide screens would drift from the inline one at
69
71
  the first field change.
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 = 'ui28'
53
+ const UI_REV = 'ui29'
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
 
@@ -1014,13 +1014,16 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
1014
1014
  @media (min-width: 1100px) {
1015
1015
  /* Only the list gives way: the title row and the toolbar keep their full width, so the
1016
1016
  controls never wrap or hide behind the card. */
1017
- .gt-root[data-wide-detail="1"] .gt-groups { padding-right: 400px; }
1017
+ .gt-root[data-wide-detail="1"] .gt-groups { padding-right: 380px; }
1018
+ .gt-root[data-wide-detail="1"] .gt-inner { position: relative; }
1018
1019
  .gt-root[data-wide-detail="1"] .gt-item[data-open="1"] .gt-detail {
1019
- /* Aligned to the panel's own right edge (centred, capped at 980px) and bracketed between
1020
- the toolbar and the footer, so it reads as a second column rather than a floating
1021
- dialog. */
1022
- position: fixed; top: 208px; bottom: 64px;
1023
- right: max(24px, calc(50vw - 466px)); width: 360px;
1020
+ /* Anchored to the panel's own column (.gt-inner), not to the viewport: the slot does not
1021
+ always fill the window, and a viewport-centred offset put the card over the list. */
1022
+ /* The var fallback matters for the static previews (server-rendered, so effects never
1023
+ run): they assume the panel is the centred 980px column. */
1024
+ position: fixed; top: var(--gt-detail-top, 208px);
1025
+ right: var(--gt-detail-right, max(24px, calc((100vw - 980px) / 2 + 24px)));
1026
+ bottom: var(--gt-detail-bottom, 64px); width: 360px;
1024
1027
  overflow: auto; padding: 16px; margin: 0; border: 1px solid var(--dsw-alias-border-l2);
1025
1028
  border-radius: 12px; background: var(--dsw-alias-bg-overlay); z-index: 30;
1026
1029
  }
@@ -2147,6 +2150,10 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
2147
2150
  // The store counts file changes made outside this process (another machine, a sync
2148
2151
  // client). A new count means the panel's view was stale a moment ago; say so once.
2149
2152
  const externalRef = useRef(null)
2153
+ // The wide-screen detail card floats over the panel, so its offsets are measured from
2154
+ // the panel's own column rather than derived from the viewport width.
2155
+ const innerRef = useRef(null)
2156
+ const [detailAnchor, setDetailAnchor] = useState(null)
2150
2157
  const titleRef = useRef(null)
2151
2158
  const searchRef = useRef(null)
2152
2159
  const undoTimer = useRef(null)
@@ -2200,6 +2207,35 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
2200
2207
  }
2201
2208
  }, [lang])
2202
2209
 
2210
+ useEffect(() => {
2211
+ if (expandedId === '' || typeof window === 'undefined') {
2212
+ setDetailAnchor(null)
2213
+ return undefined
2214
+ }
2215
+ const measure = () => {
2216
+ const element = innerRef.current
2217
+ if (element === null) return
2218
+ const rect = element.getBoundingClientRect()
2219
+ setDetailAnchor({
2220
+ top: Math.round(rect.top + 170),
2221
+ right: Math.round(window.innerWidth - rect.right + 20),
2222
+ bottom: Math.round(window.innerHeight - rect.bottom + 20),
2223
+ })
2224
+ }
2225
+ measure()
2226
+ window.addEventListener('resize', measure)
2227
+ // The slot can change width without a window resize (sidebar collapse), which would
2228
+ // leave the card at stale coordinates.
2229
+ // `window.` on purpose: the static scan rejects a bare global it cannot see defined.
2230
+ const Observer = typeof window.ResizeObserver === 'function' ? window.ResizeObserver : null
2231
+ const observer = Observer === null ? null : new Observer(measure)
2232
+ if (observer !== null && innerRef.current !== null) observer.observe(innerRef.current)
2233
+ return () => {
2234
+ window.removeEventListener('resize', measure)
2235
+ if (observer !== null) observer.disconnect()
2236
+ }
2237
+ }, [expandedId, lang])
2238
+
2203
2239
  useEffect(() => {
2204
2240
  mounted.current = true
2205
2241
  void reload()
@@ -2777,10 +2813,23 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
2777
2813
 
2778
2814
  return h(
2779
2815
  'div',
2780
- { className: 'gt-root', 'data-wide-detail': expandedId === '' ? '0' : '1' },
2816
+ {
2817
+ className: 'gt-root',
2818
+ 'data-wide-detail': expandedId === '' ? '0' : '1',
2819
+ // The slot does not always fill the window, so the card's viewport offsets are
2820
+ // measured from the panel itself instead of assumed from 50vw.
2821
+ style:
2822
+ detailAnchor === null
2823
+ ? undefined
2824
+ : {
2825
+ '--gt-detail-top': `${detailAnchor.top}px`,
2826
+ '--gt-detail-right': `${detailAnchor.right}px`,
2827
+ '--gt-detail-bottom': `${detailAnchor.bottom}px`,
2828
+ },
2829
+ },
2781
2830
  h(
2782
2831
  'div',
2783
- { className: 'gt-inner' },
2832
+ { className: 'gt-inner', ref: innerRef },
2784
2833
  h(
2785
2834
  'div',
2786
2835
  { className: 'gt-head' },
package/lib/index.js CHANGED
@@ -35,7 +35,7 @@ import { createStore, resolveStorePath } from './store.js'
35
35
  import { createTools } from './tools.js'
36
36
 
37
37
  /** Must equal `package.json`'s version; `npm run check` enforces that. */
38
- export const VERSION = '0.4.5'
38
+ export const VERSION = '0.4.6'
39
39
 
40
40
  /** Plugin id. Also the Loader row id in `cordis.patch.yml`. */
41
41
  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.4.5",
3
+ "version": "0.4.6",
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",