Place chat controls before header utilities
Insert Chat and Zen immediately before the Git utility group in normal mode, then relocate them to the conversation root while Zen hides the header. Collapse the composer with measurement-safe clipping instead of display none to prevent incorrect empty textarea height after restoring it.
This commit is contained in:
parent
ebd1ea84ea
commit
3eccc0411d
3 changed files with 52 additions and 10 deletions
|
|
@ -219,16 +219,16 @@ window.__ModuleLoader__.load({
|
|||
rules.push(
|
||||
'[data-sidebar-collapsed] [class*="_sidebarCol"] [class*="_regionArea"]{display:none !important;}',
|
||||
'[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-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"]{display:none !important}',
|
||||
'[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]{display:none !important}',
|
||||
'html[data-dsh-zen="1"] .dsh-chat-controls{top:12px}',
|
||||
'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}'
|
||||
);
|
||||
|
||||
|
|
@ -292,10 +292,26 @@ window.__ModuleLoader__.load({
|
|||
updateChatControls();
|
||||
}
|
||||
|
||||
function placeChatControls() {
|
||||
document.querySelectorAll("[data-phase]").forEach((conversation) => {
|
||||
const controls = conversation.querySelector(".dsh-chat-controls");
|
||||
if (!controls) return;
|
||||
const utilities = conversation.querySelector('header [class*="_headerUtilities"]');
|
||||
if (!zenActive && utilities?.parentElement) {
|
||||
controls.removeAttribute("data-floating");
|
||||
if (controls.parentElement !== utilities.parentElement) utilities.parentElement.insertBefore(controls, utilities);
|
||||
return;
|
||||
}
|
||||
controls.setAttribute("data-floating", "1");
|
||||
if (controls.parentElement !== conversation) conversation.appendChild(controls);
|
||||
});
|
||||
}
|
||||
|
||||
function setZenActive(active) {
|
||||
zenActive = active;
|
||||
if (active) document.documentElement.setAttribute("data-dsh-zen", "1");
|
||||
else document.documentElement.removeAttribute("data-dsh-zen");
|
||||
placeChatControls();
|
||||
updateChatControls();
|
||||
}
|
||||
|
||||
|
|
@ -321,8 +337,9 @@ window.__ModuleLoader__.load({
|
|||
|
||||
function enhanceChatControls() {
|
||||
document.querySelectorAll("[data-phase]").forEach((conversation) => {
|
||||
if (!conversation.querySelector(":scope > .dsh-chat-controls")) conversation.appendChild(makeChatControls());
|
||||
if (!conversation.querySelector(".dsh-chat-controls")) conversation.appendChild(makeChatControls());
|
||||
});
|
||||
placeChatControls();
|
||||
updateChatControls();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.1",
|
||||
"version": "0.2.2",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"engines": {
|
||||
|
|
|
|||
|
|
@ -21,11 +21,20 @@ class Element {
|
|||
}
|
||||
|
||||
appendChild(child) {
|
||||
if (child.parentElement) child.parentElement.children = child.parentElement.children.filter((candidate) => candidate !== child)
|
||||
child.parentElement = this
|
||||
this.children.push(child)
|
||||
return child
|
||||
}
|
||||
|
||||
insertBefore(child, reference) {
|
||||
if (child.parentElement) child.parentElement.children = child.parentElement.children.filter((candidate) => candidate !== child)
|
||||
const index = this.children.indexOf(reference)
|
||||
child.parentElement = this
|
||||
this.children.splice(index < 0 ? this.children.length : index, 0, child)
|
||||
return child
|
||||
}
|
||||
|
||||
addEventListener(name, listener) {
|
||||
this.listeners.set(name, listener)
|
||||
}
|
||||
|
|
@ -48,6 +57,7 @@ class Element {
|
|||
|
||||
querySelector(selector) {
|
||||
if (selector === ':scope > .dsh-chat-controls') return this.children.find((child) => child.hasClass('dsh-chat-controls')) ?? null
|
||||
if (selector === 'header [class*="_headerUtilities"]') return this.descendants().find((child) => child.tagName === 'div' && child.className.includes('_headerUtilities')) ?? null
|
||||
if (selector.startsWith('.')) return this.descendants().find((child) => child.hasClass(selector.slice(1))) ?? null
|
||||
return null
|
||||
}
|
||||
|
|
@ -72,9 +82,15 @@ const head = new Element('head')
|
|||
const body = new Element('body')
|
||||
const conversation = new Element('div')
|
||||
conversation.setAttribute('data-phase', 'active')
|
||||
const header = new Element('header')
|
||||
const titleRow = new Element('div')
|
||||
const utilities = new Element('div')
|
||||
utilities.className = 'fixture_headerUtilities'
|
||||
titleRow.appendChild(utilities)
|
||||
header.appendChild(titleRow)
|
||||
const seat = new Element('div')
|
||||
seat.setAttribute('data-composer-seat', '')
|
||||
conversation.appendChild(seat)
|
||||
conversation.append(header, seat)
|
||||
body.appendChild(conversation)
|
||||
const documentListeners = new Map()
|
||||
|
||||
|
|
@ -126,8 +142,10 @@ const plugin = definition.factory(() => {})
|
|||
let cleanup
|
||||
plugin.apply({ effect: (start) => { cleanup = start() } })
|
||||
|
||||
const controls = conversation.querySelector(':scope > .dsh-chat-controls')
|
||||
const controls = conversation.querySelector('.dsh-chat-controls')
|
||||
assert(controls)
|
||||
assert.equal(controls.parentElement, titleRow)
|
||||
assert(controls.parentElement.children.indexOf(controls) < controls.parentElement.children.indexOf(utilities))
|
||||
const collapse = controls.querySelector('.dsh-composer-collapse-toggle')
|
||||
const zen = controls.querySelector('.dsh-zen-toggle')
|
||||
assert.equal(collapse.textContent, '⌄ Chat')
|
||||
|
|
@ -142,19 +160,26 @@ 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(controls.parentElement, conversation)
|
||||
assert.equal(controls.getAttribute('data-floating'), '1')
|
||||
|
||||
documentListeners.get('keydown')?.({ key: 'Escape' })
|
||||
assert.equal(documentElement.getAttribute('data-dsh-zen'), null)
|
||||
assert.equal(zen.textContent, 'Zen')
|
||||
assert.equal(controls.parentElement, titleRow)
|
||||
assert.equal(controls.getAttribute('data-floating'), null)
|
||||
|
||||
cleanup()
|
||||
assert.equal(conversation.querySelector(':scope > .dsh-chat-controls'), null)
|
||||
assert.equal(conversation.querySelector('.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('.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('[data-phase] header[class*="_header"]{display:none !important}'))
|
||||
|
||||
console.log('UI controls test passed')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue