From 685de2fa151dd44e40c9dd87535866d4f247e9c2 Mon Sep 17 00:00:00 2001 From: DemonGatanjieu <1027066412@qq.com> Date: Sun, 27 Sep 2026 14:24:52 +0800 Subject: [PATCH] fix(workspace): keep the header tabs usable, close with Esc, restore after the translator - The recipe / notes / material workspace (nbPanel) starts below the 48px header instead of covering it, so Models / Gallery / Workflows stay clickable while it is open. - Esc closes that workspace like a click beside it, unless one of this plugin's dialogs or a ComfyUI dialog is above it or a text field has focus. - Closing the Prompt Translator shows the browser again when opening it had folded the browser away (not after sending text on to the studio). Found in a browser audit; checked in an isolated ComfyUI. Co-Authored-By: Claude Opus 5.5 --- ARCHITECTURE.md | 3 ++- CHANGELOG.md | 1 + web/modules/ui_browser_navigation.js | 18 ++++++++++++++++++ web/modules/ui_prompt_translator.js | 6 ++++++ web/modules/ui_sidebar.js | 2 ++ web/styles.css | 2 +- web/styles/02-notebooks.css | 7 ++++--- 7 files changed, 34 insertions(+), 5 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 3348710..adc11c8 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -248,7 +248,8 @@ covered by the `styles.css` manifest. - `ui_sidebar.js` creates the browser shell, domain-aware header tabs, and folder navigation. `ui_settings_hub.js` owns settings and model-card preferences; `ui_toolbox.js` owns the tool catalog, fixed shortcut bar, and tool dispatch; - `ui_browser_navigation.js` owns shared panel hiding/cleanup and workspace return. + `ui_browser_navigation.js` owns shared panel hiding/cleanup and workspace return, + including Esc on the workspace panel (`nbPanel`, which starts below the header). Scan-wizard launch, single-model precision scans (`triggerDirectModelScan` with strictly factual Civitai vs non-Civitai feedback reporting inferred base-model or match status directly within the bottom-right progress panel and toasts without blocking browser alerts), modal lifecycle ergonomics (backdrop click and Escape key dismissal with listener detachment, scrollable content area with sticky footer actions), post-scan frontend hash and native combo refreshes (`app.refreshComboInNodes()`, `window.anomalous_reload_hashes()`), and polling live in `ui_scan_wizard.js`; folder visibility/order lives in `ui_folder_manager.js`; and help content lives in `ui_help.js`. `scan_progress.js` owns the bottom-right scan progress panel diff --git a/CHANGELOG.md b/CHANGELOG.md index 68ef914..f261633 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ### Fixes - All-in-one loader recipes and cross-node prompt injection use one verified adapter table; prompt text never crosses between positive and negative. +- The Workflows, Prompt Notes and Material Library workspace no longer covers the header: the Models / Gallery / Workflows tabs stay clickable while it is open, and **Esc** closes it (back to what was open before) unless a dialog is above it or a text field has focus. Closing the Prompt Translator brings back the browser it folded away. ## v1.57.2 Beta (Canvas Performance Hotfix) — 2026-09-26 diff --git a/web/modules/ui_browser_navigation.js b/web/modules/ui_browser_navigation.js index aecc05f..a174e5f 100644 --- a/web/modules/ui_browser_navigation.js +++ b/web/modules/ui_browser_navigation.js @@ -56,6 +56,24 @@ export function closeWorkspace() { restoreWorkspaceReturnPanel(this); } +/** + * Esc on the recipe / notes / material workspace does what a click beside it does: + * `closeWorkspace()`. Not while one of this plugin's dialogs or a ComfyUI dialog sits + * above it, and not while a text field has the key (Esc there belongs to the field). + * ComfyUI's own keybindings mark Esc as handled, so `defaultPrevented` says nothing here. + */ +export function bindWorkspaceEscape(owner) { + window.addEventListener('keydown', (e) => { + if (e.key !== 'Escape') return; + if (!owner.modal?.classList.contains('visible') || owner.nbPanel?.style.display !== 'flex') return; + if (e.target?.closest?.('input, textarea, select, [contenteditable="true"]')) return; + const layered = [...document.body.children, ...owner.nbPanel.children] + .some(el => [...el.classList].some(c => c.startsWith('anomalous-') && c.endsWith('overlay')) && el.getClientRects().length); + if (layered || document.querySelector('dialog[open], .p-dialog-mask')) return; + owner.closeWorkspace(); + }); +} + export function hideAllPanels() { const abandonedRecipeModel = typeof this.recipeModelReturn === 'function'; this.recipeModelReturn = null; diff --git a/web/modules/ui_prompt_translator.js b/web/modules/ui_prompt_translator.js index ad69317..a20b1b0 100644 --- a/web/modules/ui_prompt_translator.js +++ b/web/modules/ui_prompt_translator.js @@ -252,6 +252,11 @@ export function openPromptTranslator(owner) { owner.close(); } } + // Closing the translator gives the browser back, unless the text went on to the studio. + let restoreMaster = masterWasVisible; + scope.onDispose(() => { + if (restoreMaster && !owner.modal?.classList.contains('visible')) owner.show?.(); + }); // Left/Right edge resize handle for sidebar mode const resizeHandle = document.createElement('div'); @@ -601,6 +606,7 @@ export function openPromptTranslator(owner) { if (/[,、;;||]/.test(out) && !hasChinese(out)) { out = normalizePromptFormatting(out); } + restoreMaster = false; scope.dispose(); if (typeof owner?.openPromptStudio === 'function') { owner.openPromptStudio(); diff --git a/web/modules/ui_sidebar.js b/web/modules/ui_sidebar.js index afbf4bf..23eec9e 100644 --- a/web/modules/ui_sidebar.js +++ b/web/modules/ui_sidebar.js @@ -14,6 +14,7 @@ import { createToolbox } from './ui_toolbox.js'; import { createDomainSwitcher, getActiveDomain } from './ui_domain_switcher.js'; import { renderAudioSidebar } from './ui_audio_sidebar.js'; import { createGallerySearchBar } from './ui_gallery.js'; +import { bindWorkspaceEscape } from './ui_browser_navigation.js'; const t = (key, params) => translate(key, params); @@ -601,6 +602,7 @@ export function createDOM() { this.nbPanel.onclick = (e) => { if (e.target === this.nbPanel) this.closeWorkspace(); }; + bindWorkspaceEscape(this); content.appendChild(header); content.appendChild(this.grid); diff --git a/web/styles.css b/web/styles.css index 9c64109..86cd1d8 100644 --- a/web/styles.css +++ b/web/styles.css @@ -1,6 +1,6 @@ @import url("./styles/00-foundation-models.css?v=20260921-flicker-free-1"); @import url("./styles/01-shell-tools.css?v=20260926-canvas-perf-1"); -@import url("./styles/02-notebooks.css?v=20260918-model-sources-1"); +@import url("./styles/02-notebooks.css?v=20260927-workspace-below-header"); @import url("./styles/03-gallery-recipes.css?v=20260918-model-sources-1"); @import url("./styles/04-dialogs-materials.css?v=20260926-material-apply-1"); @import url("./styles/05-recipe-studio-overrides.css?v=20260918-model-sources-1"); diff --git a/web/styles/02-notebooks.css b/web/styles/02-notebooks.css index e157ee7..bbe0523 100644 --- a/web/styles/02-notebooks.css +++ b/web/styles/02-notebooks.css @@ -1,10 +1,11 @@ -/* Notebook UI */ +/* Notebook UI: the recipe / notes / material workspace. It starts below the 48px + #anomalous-header, so the Models / Gallery / Workflows tabs stay clickable. */ .anomalous-nb-modal { position: absolute; - top: 0; + top: 48px; + bottom: 0; left: 0; width: 100%; - height: 100%; background: var(--amb-bg-page, #131315); z-index: 10001; display: flex;