diff --git a/plugins/dsh-ui-tweaks/lib/client.js b/plugins/dsh-ui-tweaks/lib/client.js index fff87eb..c0c160c 100644 --- a/plugins/dsh-ui-tweaks/lib/client.js +++ b/plugins/dsh-ui-tweaks/lib/client.js @@ -218,20 +218,17 @@ window.__ModuleLoader__.load({ rules.push( '[data-sidebar-collapsed] [class*="_sidebarCol"] [class*="_regionArea"]{display:none !important;}', - '[data-composer-seat]{position:relative}', - '.dsh-chat-controls{position:absolute;right:24px;bottom:calc(100% + 6px);z-index:12;display:flex;align-items:center;gap:6px}', + '[data-phase]{position:relative}', + '.dsh-chat-controls{position:absolute;right:24px;top:56px;z-index:12;display:flex;align-items:center;gap:6px}', '.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"]{min-height:38px;justify-content:center}', - '[data-composer-seat][data-dsh-composer-collapsed="1"]>:not(.dsh-chat-controls){display:none !important}', - '[data-composer-seat][data-dsh-composer-collapsed="1"]>.dsh-chat-controls{position:static;align-self:flex-end;margin:4px 24px 6px 0}', + '[data-composer-seat][data-dsh-composer-collapsed="1"]{display: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]>[class*="_header"]{display:none !important}', - 'html[data-dsh-zen="1"] [data-composer-seat]{min-height:38px;justify-content:center}', - 'html[data-dsh-zen="1"] [data-composer-seat]>:not(.dsh-chat-controls){display:none !important}', - 'html[data-dsh-zen="1"] [data-composer-seat]>.dsh-chat-controls{position:static;align-self:flex-end;margin:4px 24px 6px 0}', + 'html[data-dsh-zen="1"] [data-phase] header[class*="_header"]{display:none !important}', + 'html[data-dsh-zen="1"] [data-composer-seat]{display:none !important}', + 'html[data-dsh-zen="1"] .dsh-chat-controls{top:12px}', 'html[data-dsh-zen="1"] .dsh-composer-collapse-toggle{display:none !important}' ); @@ -270,14 +267,16 @@ window.__ModuleLoader__.load({ document.querySelectorAll("[data-composer-seat]").forEach((seat) => { if (composerCollapsed) seat.setAttribute("data-dsh-composer-collapsed", "1"); else seat.removeAttribute("data-dsh-composer-collapsed"); - const collapse = seat.querySelector(".dsh-composer-collapse-toggle"); + }); + 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 = seat.querySelector(".dsh-zen-toggle"); + const zen = controls.querySelector(".dsh-zen-toggle"); if (zen) { const zenLabel = zenActive ? "Exit Zen" : "Zen"; if (zen.textContent !== zenLabel) zen.textContent = zenLabel; @@ -321,8 +320,8 @@ window.__ModuleLoader__.load({ } function enhanceChatControls() { - document.querySelectorAll("[data-composer-seat]").forEach((seat) => { - if (!seat.querySelector(":scope > .dsh-chat-controls")) seat.appendChild(makeChatControls()); + document.querySelectorAll("[data-phase]").forEach((conversation) => { + if (!conversation.querySelector(":scope > .dsh-chat-controls")) conversation.appendChild(makeChatControls()); }); updateChatControls(); } diff --git a/plugins/dsh-ui-tweaks/package.json b/plugins/dsh-ui-tweaks/package.json index 1ea794e..fb6f06c 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.0", + "version": "0.2.1", "private": true, "type": "module", "engines": { diff --git a/test/ui-controls.test.mjs b/test/ui-controls.test.mjs index 78b95bb..4ab0be4 100644 --- a/test/ui-controls.test.mjs +++ b/test/ui-controls.test.mjs @@ -70,9 +70,12 @@ class Element { const documentElement = new Element('html') const head = new Element('head') const body = new Element('body') +const conversation = new Element('div') +conversation.setAttribute('data-phase', 'active') const seat = new Element('div') seat.setAttribute('data-composer-seat', '') -body.appendChild(seat) +conversation.appendChild(seat) +body.appendChild(conversation) const documentListeners = new Map() const allElements = () => [documentElement, head, body, ...head.descendants(), ...body.descendants()] @@ -83,6 +86,7 @@ const document = { createElement: (tagName) => new Element(tagName), getElementById: (id) => allElements().find((element) => element.id === id) ?? null, querySelectorAll(selector) { + if (selector === '[data-phase]') return allElements().filter((element) => element.attributes.has('data-phase')) if (selector === '[data-composer-seat]') return allElements().filter((element) => element.attributes.has('data-composer-seat')) if (selector === '.dsh-chat-controls') return allElements().filter((element) => element.hasClass('dsh-chat-controls')) if (selector === '.dsh-hdr-menu-trigger' || selector === '[data-dsh-hdr-menu]' || selector === '[class*="_headerUtilities"]') return [] @@ -122,7 +126,7 @@ const plugin = definition.factory(() => {}) let cleanup plugin.apply({ effect: (start) => { cleanup = start() } }) -const controls = seat.querySelector(':scope > .dsh-chat-controls') +const controls = conversation.querySelector(':scope > .dsh-chat-controls') assert(controls) const collapse = controls.querySelector('.dsh-composer-collapse-toggle') const zen = controls.querySelector('.dsh-zen-toggle') @@ -144,11 +148,13 @@ assert.equal(documentElement.getAttribute('data-dsh-zen'), null) assert.equal(zen.textContent, 'Zen') cleanup() -assert.equal(seat.querySelector(':scope > .dsh-chat-controls'), null) +assert.equal(conversation.querySelector(':scope > .dsh-chat-controls'), null) assert.equal(seat.getAttribute('data-dsh-composer-collapsed'), null) assert.equal(documentElement.getAttribute('data-dsh-zen'), null) assert(source.includes('[data-sidebar-collapsed] [class*="_sidebarCol"] [class*="_regionArea"]')) assert(source.includes('[class*="_detailsCol"]{visibility:hidden !important;pointer-events:none !important;border:0 !important}')) assert(!source.includes('[class*="_detailsCol"],html[data-dsh-zen="1"] [class*="_handle"]{display:none')) +assert(source.includes('.dsh-chat-controls{position:absolute;right:24px;top:56px')) +assert(source.includes('[data-phase] header[class*="_header"]{display:none !important}')) console.log('UI controls test passed')