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 <noreply@anthropic.com>
This commit is contained in:
DemonGatanjieu
2026-09-27 14:24:52 +08:00
co-authored by Claude Opus 5.5
parent 5fd9e8c872
commit 685de2fa15
7 changed files with 34 additions and 5 deletions
+2 -1
View File
@@ -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
+1
View File
@@ -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
+18
View File
@@ -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;
+6
View File
@@ -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();
+2
View File
@@ -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);
+1 -1
View File
@@ -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");
+4 -3
View File
@@ -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;