From 9ca766a809b15ca8734e4200057daaeaf669536a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D1=83=D1=80=D1=83=D0=BF=D0=BE=D0=B2=20=D0=98=D0=BB?= =?UTF-8?q?=D1=8C=D1=8F=20=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B8=D1=87?= Date: Mon, 14 Sep 2026 13:30:54 +0300 Subject: [PATCH] Restore native composer behavior Remove the persistent Chat collapse feature, its button, storage state, seat attribute, and sizing selectors because they interfere with DSH composer auto-height measurements. Clear stale collapse state on startup and keep only the Zen control, which temporarily removes the composer from flow without constraining its measured height. --- plugins/dsh-ui-tweaks/lib/client.js | 50 +++++------------------------ plugins/dsh-ui-tweaks/package.json | 4 +-- test/ui-controls.test.mjs | 21 ++++++------ 3 files changed, 20 insertions(+), 55 deletions(-) diff --git a/plugins/dsh-ui-tweaks/lib/client.js b/plugins/dsh-ui-tweaks/lib/client.js index ca49a2d..c7ab30b 100644 --- a/plugins/dsh-ui-tweaks/lib/client.js +++ b/plugins/dsh-ui-tweaks/lib/client.js @@ -89,8 +89,6 @@ window.__ModuleLoader__.load({ // ----------------------------------------------------------------------- const STYLE_ID = "dsh-ui-tweaks-style"; - const COMPOSER_STORAGE_KEY = "dsh-ui-tweaks:composer-collapsed"; - let composerCollapsed = readStoredComposerState(); let zenActive = false; /** Assemble the combined static CSS for whichever features are enabled. */ @@ -222,14 +220,12 @@ window.__ModuleLoader__.load({ '.dsh-chat-controls{z-index:12;display:flex;flex:none;align-items:center;gap:6px;margin-left:8px}', '.dsh-chat-control{height:28px;min-width:28px;padding:0 9px;border:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.12));border-radius:14px;background:var(--dsw-specific-input-major);color:var(--dsw-alias-label-secondary);font:var(--dsw-font-xs-13);cursor:pointer;box-shadow:var(--dsw-shadow-lv1)}', '.dsh-chat-control:hover{color:var(--dsw-alias-label-primary);background:color-mix(in srgb,var(--dsw-specific-input-major),#fff 6%)}', - '[data-composer-seat][data-dsh-composer-collapsed="1"]{max-height:0 !important;min-height:0 !important;overflow:clip !important;visibility:hidden !important;pointer-events:none !important}', 'html[data-dsh-zen="1"] [class*="_frame"][style*="grid-template-columns"]{grid-template-columns:0 minmax(0,1fr) 0 !important}', 'html[data-dsh-zen="1"] [class*="_sidebarCol"],html[data-dsh-zen="1"] [class*="_detailsCol"]{visibility:hidden !important;pointer-events:none !important;border:0 !important}', 'html[data-dsh-zen="1"] [class*="_handle"]{display:none !important}', 'html[data-dsh-zen="1"] [data-phase] header[class*="_header"]{display:none !important}', - 'html[data-dsh-zen="1"] [data-composer-seat]{max-height:0 !important;min-height:0 !important;overflow:clip !important;visibility:hidden !important;pointer-events:none !important}', - '.dsh-chat-controls[data-floating="1"]{position:absolute;right:24px;top:12px;margin-left:0}', - 'html[data-dsh-zen="1"] .dsh-composer-collapse-toggle{display:none !important}' + 'html[data-dsh-zen="1"] [data-composer-seat]{position:absolute !important;left:0;right:0;bottom:0;visibility:hidden !important;pointer-events:none !important}', + '.dsh-chat-controls[data-floating="1"]{position:absolute;right:24px;top:12px;margin-left:0}' ); return rules.join(""); @@ -249,33 +245,15 @@ window.__ModuleLoader__.load({ // ---- (3) header-menu dynamic behavior --------------------------------- - function readStoredComposerState() { + function restoreNativeComposer() { try { - return window.localStorage.getItem(COMPOSER_STORAGE_KEY) === "1"; - } catch { - return false; - } - } - - function storeComposerState() { - try { - window.localStorage.setItem(COMPOSER_STORAGE_KEY, composerCollapsed ? "1" : "0"); + window.localStorage.removeItem("dsh-ui-tweaks:composer-collapsed"); } catch {} + document.querySelectorAll("[data-composer-seat]").forEach((seat) => seat.removeAttribute("data-dsh-composer-collapsed")); } function updateChatControls() { - document.querySelectorAll("[data-composer-seat]").forEach((seat) => { - if (composerCollapsed) seat.setAttribute("data-dsh-composer-collapsed", "1"); - else seat.removeAttribute("data-dsh-composer-collapsed"); - }); document.querySelectorAll(".dsh-chat-controls").forEach((controls) => { - const collapse = controls.querySelector(".dsh-composer-collapse-toggle"); - if (collapse) { - const collapseLabel = composerCollapsed ? "⌃ Chat" : "⌄ Chat"; - if (collapse.textContent !== collapseLabel) collapse.textContent = collapseLabel; - collapse.title = composerCollapsed ? "Expand bottom chat bar" : "Collapse bottom chat bar"; - collapse.setAttribute("aria-expanded", composerCollapsed ? "false" : "true"); - } const zen = controls.querySelector(".dsh-zen-toggle"); if (zen) { const zenLabel = zenActive ? "Exit Zen" : "Zen"; @@ -286,12 +264,6 @@ window.__ModuleLoader__.load({ }); } - function setComposerCollapsed(collapsed) { - composerCollapsed = collapsed; - storeComposerState(); - updateChatControls(); - } - function conversationRoots() { const roots = []; document.querySelectorAll("[data-composer-seat]").forEach((seat) => { @@ -351,19 +323,13 @@ window.__ModuleLoader__.load({ const controls = document.createElement("div"); controls.className = "dsh-chat-controls"; - const collapse = document.createElement("button"); - collapse.type = "button"; - collapse.className = "dsh-chat-control dsh-composer-collapse-toggle"; - collapse.setAttribute("aria-label", "Toggle bottom chat bar"); - collapse.addEventListener("click", () => setComposerCollapsed(!composerCollapsed)); - const zen = document.createElement("button"); zen.type = "button"; zen.className = "dsh-chat-control dsh-zen-toggle"; zen.setAttribute("aria-label", "Toggle Zen mode"); zen.addEventListener("click", () => setZenActive(!zenActive)); - controls.append(collapse, zen); + controls.append(zen); return controls; } @@ -376,7 +342,7 @@ window.__ModuleLoader__.load({ function removeChatControls() { setZenActive(false); document.querySelectorAll(".dsh-chat-controls").forEach((controls) => controls.remove()); - document.querySelectorAll("[data-composer-seat]").forEach((seat) => seat.removeAttribute("data-dsh-composer-collapsed")); + restoreNativeComposer(); } /** Close every open header menu (optionally sparing one host). */ @@ -460,7 +426,7 @@ window.__ModuleLoader__.load({ function apply(ctx) { const start = () => { installStyle(); - + restoreNativeComposer(); enhance(); const observer = new MutationObserver(scheduleEnhance); diff --git a/plugins/dsh-ui-tweaks/package.json b/plugins/dsh-ui-tweaks/package.json index 6560cef..27e3451 100644 --- a/plugins/dsh-ui-tweaks/package.json +++ b/plugins/dsh-ui-tweaks/package.json @@ -1,7 +1,7 @@ { "name": "dsh-ui-tweaks", - "description": "dsh web plugin: cohesive sidebar, header, composer-collapse, and Zen-mode controls for the DSH Web chat interface. Client-only.", - "version": "0.2.3", + "description": "dsh web plugin: cohesive sidebar, header, and Zen-mode controls for the DSH Web chat interface. Client-only.", + "version": "0.3.0", "private": true, "type": "module", "engines": { diff --git a/test/ui-controls.test.mjs b/test/ui-controls.test.mjs index aed554d..686f4a1 100644 --- a/test/ui-controls.test.mjs +++ b/test/ui-controls.test.mjs @@ -108,6 +108,7 @@ titleRow.append(headerActions, utilities) header.appendChild(titleRow) const seat = new Element('div') seat.setAttribute('data-composer-seat', '') +seat.setAttribute('data-dsh-composer-collapsed', '1') const nestedPhase = new Element('div') nestedPhase.setAttribute('data-phase', 'streaming') const strayControls = new Element('div') @@ -135,12 +136,13 @@ const document = { removeEventListener: (name) => documentListeners.delete(name), } -const storage = new Map() +const storage = new Map([['dsh-ui-tweaks:composer-collapsed', '1']]) const window = { document, localStorage: { getItem: (key) => storage.get(key) ?? null, setItem: (key, value) => storage.set(key, String(value)), + removeItem: (key) => storage.delete(key), }, } window.window = window @@ -171,20 +173,16 @@ assert.equal(document.querySelectorAll('.dsh-chat-controls').length, 1) assert.equal(strayControls.parentElement, null) assert.equal(controls.parentElement, headerActions) assert(controls.parentElement.children.indexOf(controls) < controls.parentElement.children.indexOf(git)) -const collapse = controls.querySelector('.dsh-composer-collapse-toggle') const zen = controls.querySelector('.dsh-zen-toggle') -assert.equal(collapse.textContent, '⌄ Chat') +assert.equal(controls.querySelector('.dsh-composer-collapse-toggle'), null) assert.equal(zen.textContent, 'Zen') - -collapse.click() -assert.equal(seat.getAttribute('data-dsh-composer-collapsed'), '1') -assert.equal(storage.get('dsh-ui-tweaks:composer-collapsed'), '1') -assert.equal(collapse.textContent, '⌃ Chat') +assert.equal(seat.getAttribute('data-dsh-composer-collapsed'), null) +assert.equal(storage.has('dsh-ui-tweaks:composer-collapsed'), false) zen.click() assert.equal(documentElement.getAttribute('data-dsh-zen'), '1') assert.equal(zen.textContent, 'Exit Zen') -assert.equal(seat.getAttribute('data-dsh-composer-collapsed'), '1') +assert.equal(seat.getAttribute('data-dsh-composer-collapsed'), null) assert.equal(controls.parentElement, conversation) assert.equal(controls.getAttribute('data-floating'), '1') @@ -204,8 +202,9 @@ assert(source.includes('[class*="_detailsCol"]{visibility:hidden !important;poin assert(!source.includes('[class*="_detailsCol"],html[data-dsh-zen="1"] [class*="_handle"]{display:none')) assert(source.includes('.dsh-chat-controls{z-index:12;display:flex;flex:none')) assert(source.includes('.dsh-chat-controls[data-floating="1"]{position:absolute;right:24px;top:12px')) -assert(source.includes('[data-composer-seat][data-dsh-composer-collapsed="1"]{max-height:0 !important')) -assert(!source.includes('[data-composer-seat][data-dsh-composer-collapsed="1"]{display:none')) +assert(!source.includes('dsh-composer-collapse-toggle')) +assert(!source.includes('[data-composer-seat][data-dsh-composer-collapsed="1"]')) +assert(source.includes('[data-composer-seat]{position:absolute !important;left:0;right:0;bottom:0;visibility:hidden')) assert(source.includes('[data-phase] header[class*="_header"]{display:none !important}')) console.log('UI controls test passed')