From 41a382c592b2f59ad9bc6bb489d2c66211994139 Mon Sep 17 00:00:00 2001 From: Whale-Zhang <53304091+Whale-Zhang@users.noreply.github.com> Date: Mon, 24 Aug 2026 17:13:59 +0800 Subject: [PATCH] Lay the job editor in the center column so it tracks the sidebar grid. The overlay used a measured left offset that sampled width in steps during the frame's grid-template-columns transition, which stuttered and flashed the chat behind it. --- lib/client.js | 28 +++++++++++++++++++++++++--- test/package.test.js | 4 ++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/lib/client.js b/lib/client.js index ecd946f..9b1041e 100644 --- a/lib/client.js +++ b/lib/client.js @@ -255,9 +255,11 @@ window.__ModuleLoader__.load({ .dsh-ct-runsInner{overflow:hidden;min-height:0} .dsh-ct-runsInner>*+*{margin-top:2px} .dsh-ct-chevronHit{appearance:none;border:none;background:transparent;padding:0;margin:0;color:inherit;cursor:pointer;display:inline-flex} -.dsh-ct-main{position:fixed;top:0;right:0;bottom:0;left:var(--dsh-ct-sidebar,260px);z-index:30;background:var(--dsw-alias-bg-layer-1);overflow:auto;opacity:0;pointer-events:none;transform:translateY(8px);transition:opacity .2s var(--ds-ease-in-out,ease),transform .2s var(--ds-ease-in-out,ease)} -.dsh-ct-main[data-open=true]{opacity:1;pointer-events:auto;transform:none} +[data-dsh-ct-host]{position:relative} +.dsh-ct-main{position:absolute;inset:0;z-index:8;background:var(--dsw-alias-bg-layer-1);overflow:auto;pointer-events:none;visibility:hidden} +.dsh-ct-main[data-open=true]{pointer-events:auto;visibility:visible} .dsh-ct-main[data-open=true] .dsh-ct-editor{animation:dsh-ct-pane-in .2s var(--ds-ease-in-out,ease)} +body>.dsh-ct-main{position:fixed;top:0;right:0;bottom:0;left:var(--dsh-ct-sidebar,260px)} @media (prefers-reduced-motion:reduce){ .dsh-ct-region,.dsh-ct-main,.dsh-ct-runs,.dsh-ct-arrow,[data-dsh-ct-mode=on] .dsh-ct-region{animation:none;transition:none} } @@ -876,8 +878,28 @@ window.__ModuleLoader__.load({ const [cronMode, setCronMode] = useState(false) const [workspaces, setWorkspaces] = useState([]) const [catalog, setCatalog] = useState({ groups: [], current: null }) + const [paneHost, setPaneHost] = useState(() => (typeof document === 'undefined' ? null : document.body)) const skipAutoSelect = useRef(false) + useEffect(() => { + const bind = () => { + const col = document.querySelector('[class*="centerCol"]') + if (!col) { + setPaneHost(document.body) + return + } + if (col.getAttribute('data-dsh-ct-host') !== '1') col.setAttribute('data-dsh-ct-host', '1') + setPaneHost((prev) => (prev === col ? prev : col)) + } + bind() + const obs = new MutationObserver(bind) + if (document.body) obs.observe(document.body, { childList: true, subtree: true }) + return () => { + obs.disconnect() + document.querySelectorAll('[data-dsh-ct-host="1"]').forEach((el) => el.removeAttribute('data-dsh-ct-host')) + } + }, []) + const load = useCallback(async () => { try { const [jobBody, histBody, wsBody, modelBody] = await Promise.all([ @@ -1065,7 +1087,7 @@ window.__ModuleLoader__.load({ onRemove: (id) => api(`/jobs/${id}`, { method: 'DELETE' }).then(() => { selectNew(); return load() }).catch((err) => setError(err.message)), onToggleGroup: (id) => setExpanded((prev) => ({ ...prev, [id]: prev[id] !== true })), }), - ReactDOM.createPortal(editor, document.body), + paneHost ? ReactDOM.createPortal(editor, paneHost) : null, ) } diff --git a/test/package.test.js b/test/package.test.js index f696ec2..d463475 100644 --- a/test/package.test.js +++ b/test/package.test.js @@ -58,6 +58,10 @@ test('installable bundle declares host apply, client half, unique id, and no @de assert.match(client, /新建会话/) assert.match(client, /logoRow/) assert.match(client, /dsh-ct-entry/) + assert.match(client, /centerCol/) + assert.match(client, /data-dsh-ct-host/) + assert.match(client, /visibility:hidden/) + assert.match(client, /createPortal\(editor, paneHost\)/) assert.match(client, /sidebarCollapsed/) assert.match(client, /_collapsed/) assert.match(client, /width:36px/)