315 lines
12 KiB
JavaScript
315 lines
12 KiB
JavaScript
/**
|
|
* Toolbox catalog, fixed shortcut actions, and tool dispatch.
|
|
*/
|
|
|
|
import { app } from "../../../scripts/app.js";
|
|
import { translate } from './locales.js';
|
|
import { openModelSourcesModal } from './ui_model_sources.js';
|
|
import { configureSidebarActions } from './sidebar_actions.js';
|
|
import { CATALOG_TOOLS, getToolDefinition } from './tool_registry.js';
|
|
import { setScanButtonState } from './ui_scan_wizard.js';
|
|
|
|
const t = (key, params) => translate(key, params);
|
|
|
|
export function createToolbox(owner, {
|
|
container,
|
|
menuBtn,
|
|
toolboxIcon,
|
|
isScanning,
|
|
getSettingsButton,
|
|
onBeforeOpen,
|
|
}) {
|
|
const toolboxBtn = document.createElement('button');
|
|
toolboxBtn.id = 'anomalous-toolbox-btn';
|
|
toolboxBtn.className = 'anomalous-tooltip-target';
|
|
toolboxBtn.removeAttribute('title');
|
|
toolboxBtn.setAttribute('aria-label', t('sidebarToolbox'));
|
|
toolboxBtn.setAttribute('data-tooltip', t('sidebarToolbox'));
|
|
toolboxBtn.setAttribute('data-tooltip-pos', 'top');
|
|
toolboxBtn.innerHTML = toolboxIcon;
|
|
toolboxBtn.style.background = 'transparent';
|
|
toolboxBtn.style.border = 'none';
|
|
toolboxBtn.style.borderRadius = '6px';
|
|
toolboxBtn.style.padding = '6px';
|
|
toolboxBtn.style.fontSize = '1.1em';
|
|
toolboxBtn.style.cursor = 'pointer';
|
|
|
|
|
|
const toolboxModal = document.createElement('div');
|
|
toolboxModal.id = 'anomalous-toolbox-modal';
|
|
toolboxModal.style.display = 'none';
|
|
toolboxModal.addEventListener('mouseenter', () => {
|
|
if (window.AMB_hideTooltipImmediately) window.AMB_hideTooltipImmediately();
|
|
});
|
|
|
|
const closeToolbox = (e) => {
|
|
if (toolboxModal.style.display !== 'none' && !toolboxModal.contains(e.target) && !toolboxBtn.contains(e.target)) {
|
|
toolboxModal.style.display = 'none';
|
|
toolboxBtn.classList.remove('is-active');
|
|
document.removeEventListener('mousedown', closeToolbox);
|
|
}
|
|
};
|
|
|
|
toolboxBtn.onclick = (e) => {
|
|
e.stopPropagation();
|
|
if (window.AMB_hideTooltipImmediately) window.AMB_hideTooltipImmediately();
|
|
toolboxBtn.classList.remove('anomalous-action-label-active');
|
|
toolboxBtn.__suppress_text_until_leave = true;
|
|
onBeforeOpen();
|
|
if (toolboxModal.style.display === 'none') {
|
|
toolboxModal.style.display = 'flex';
|
|
toolboxBtn.classList.add('is-active');
|
|
setTimeout(() => document.addEventListener('mousedown', closeToolbox), 10);
|
|
} else {
|
|
toolboxModal.style.display = 'none';
|
|
toolboxBtn.classList.remove('is-active');
|
|
document.removeEventListener('mousedown', closeToolbox);
|
|
}
|
|
};
|
|
|
|
const executeToolAction = async (toolId) => {
|
|
switch (toolId) {
|
|
case 'scan':
|
|
owner.openScanWizard({ isGlobal: true });
|
|
break;
|
|
case 'doctor':
|
|
owner.hideAllPanels();
|
|
if (localStorage.getItem('anomalous_user_sidebar_closed') === 'true') {
|
|
container.classList.add('anomalous-sidebar-closed');
|
|
} else {
|
|
container.classList.remove('anomalous-sidebar-closed');
|
|
}
|
|
menuBtn.disabled = false;
|
|
menuBtn.style.opacity = '1';
|
|
menuBtn.style.cursor = 'pointer';
|
|
owner.doctorPanel.style.display = 'flex';
|
|
if (!owner.doctorPanelInitialized) {
|
|
owner.initDoctorPanel();
|
|
}
|
|
if (window.anomalous_reload_hashes) await window.anomalous_reload_hashes();
|
|
if (window.anomalous_resolve_all_missing_nodes) {
|
|
await window.anomalous_resolve_all_missing_nodes(true, false);
|
|
}
|
|
owner.renderGlobalDashboard();
|
|
break;
|
|
case 'assistant':
|
|
owner.hideAllPanels();
|
|
if (owner.setActiveHeaderTab) owner.setActiveHeaderTab(null);
|
|
container.classList.add('anomalous-sidebar-closed');
|
|
menuBtn.disabled = false;
|
|
menuBtn.style.opacity = '1';
|
|
menuBtn.style.cursor = 'pointer';
|
|
owner.assistantPanel.style.display = 'flex';
|
|
if (!owner.assistantPanelInitialized) {
|
|
owner.initAssistantPanel();
|
|
}
|
|
if (Object.keys(app.canvas?.selected_nodes || {}).length > 0) {
|
|
const firstSelected = Object.values(app.canvas.selected_nodes)[0];
|
|
owner.diagnoseNode(firstSelected);
|
|
} else {
|
|
owner.diagnoseNode(null);
|
|
}
|
|
break;
|
|
case 'materials':
|
|
owner.openMaterialLibrary();
|
|
break;
|
|
case 'workflow-transfer':
|
|
if (window.AMB_WorkflowShare && typeof window.AMB_WorkflowShare.showUnifiedModal === 'function') {
|
|
window.AMB_WorkflowShare.showUnifiedModal();
|
|
}
|
|
break;
|
|
case 'prompt-studio':
|
|
if (typeof owner.openPromptStudio === 'function') {
|
|
owner.openPromptStudio();
|
|
} else if (typeof owner.openMaterialLibrary === 'function') {
|
|
owner.openMaterialLibrary();
|
|
}
|
|
break;
|
|
case 'prompt-translator':
|
|
if (typeof owner.openPromptTranslator === 'function') {
|
|
owner.openPromptTranslator();
|
|
}
|
|
break;
|
|
case 'model-sources':
|
|
openModelSourcesModal('workflow');
|
|
break;
|
|
case 'prompt-notes':
|
|
if (typeof owner.showNotebooks === 'function') {
|
|
owner.showNotebooks();
|
|
}
|
|
break;
|
|
default: {
|
|
const custom = (owner.customToolboxItems || []).find(it => it.id === toolId);
|
|
if (custom && typeof custom.action === 'function') {
|
|
custom.action();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
owner.executeToolAction = executeToolAction;
|
|
|
|
const renderShortcutActions = () => {
|
|
owner.sidebarActions.replaceChildren();
|
|
owner.sidebarActions.appendChild(toolboxBtn);
|
|
|
|
const defaultLayout = ['scan', 'doctor', 'assistant', 'materials'];
|
|
for (const toolId of defaultLayout) {
|
|
const def = getToolDefinition(toolId);
|
|
if (!def) continue;
|
|
|
|
const btn = document.createElement('button');
|
|
btn.id = def.domId;
|
|
btn.setAttribute('data-tool-id', toolId);
|
|
btn.className = 'anomalous-tooltip-target';
|
|
btn.removeAttribute('title');
|
|
btn.setAttribute('aria-label', t(def.nameKey));
|
|
btn.setAttribute('data-tooltip', t(def.nameKey));
|
|
btn.setAttribute('data-tooltip-pos', 'top');
|
|
btn.style.background = 'transparent';
|
|
btn.style.border = 'none';
|
|
btn.style.borderRadius = '6px';
|
|
btn.style.padding = '6px';
|
|
btn.style.fontSize = '1.1em';
|
|
btn.style.cursor = 'pointer';
|
|
|
|
if (toolId === 'scan') {
|
|
setScanButtonState(btn, isScanning());
|
|
} else {
|
|
btn.innerHTML = def.icon;
|
|
}
|
|
|
|
btn.onclick = (e) => {
|
|
e.stopPropagation();
|
|
executeToolAction(toolId);
|
|
};
|
|
|
|
owner.sidebarActions.appendChild(btn);
|
|
}
|
|
|
|
owner.sidebarActions.appendChild(getSettingsButton());
|
|
configureSidebarActions(owner.sidebarWrapper);
|
|
};
|
|
owner.renderShortcutActions = renderShortcutActions;
|
|
|
|
const renderToolboxModal = () => {
|
|
toolboxModal.replaceChildren();
|
|
|
|
const headerRow = document.createElement('div');
|
|
headerRow.style.display = 'flex';
|
|
headerRow.style.alignItems = 'center';
|
|
headerRow.style.justifyContent = 'space-between';
|
|
headerRow.style.padding = '1px 2px 3px';
|
|
headerRow.style.borderBottom = '1px solid rgba(255, 255, 255, 0.06)';
|
|
|
|
const titleBox = document.createElement('div');
|
|
titleBox.style.display = 'flex';
|
|
titleBox.style.alignItems = 'center';
|
|
titleBox.style.gap = '5px';
|
|
|
|
const titleIcon = document.createElement('span');
|
|
titleIcon.textContent = '🧰';
|
|
titleIcon.style.fontSize = '11px';
|
|
|
|
const titleText = document.createElement('span');
|
|
titleText.textContent = t('toolboxTitle');
|
|
titleText.style.fontWeight = '600';
|
|
titleText.style.fontSize = '11px';
|
|
titleText.style.color = '#fff';
|
|
|
|
titleBox.append(titleIcon, titleText);
|
|
|
|
const closeModalBtn = document.createElement('div');
|
|
closeModalBtn.innerHTML = '×';
|
|
closeModalBtn.style.cursor = 'pointer';
|
|
closeModalBtn.style.color = '#888';
|
|
closeModalBtn.style.fontSize = '14px';
|
|
closeModalBtn.style.lineHeight = '1';
|
|
closeModalBtn.style.padding = '1px 3px';
|
|
closeModalBtn.style.borderRadius = '3px';
|
|
closeModalBtn.onmouseover = () => { closeModalBtn.style.color = '#fff'; closeModalBtn.style.background = 'rgba(255,255,255,0.08)'; };
|
|
closeModalBtn.onmouseout = () => { closeModalBtn.style.color = '#888'; closeModalBtn.style.background = 'transparent'; };
|
|
closeModalBtn.onclick = () => {
|
|
toolboxModal.style.display = 'none';
|
|
toolboxBtn.classList.remove('is-active');
|
|
};
|
|
|
|
headerRow.appendChild(titleBox);
|
|
headerRow.appendChild(closeModalBtn);
|
|
toolboxModal.appendChild(headerRow);
|
|
|
|
const gridContainer = document.createElement('div');
|
|
gridContainer.className = 'anomalous-toolbox-grid';
|
|
|
|
// 过滤掉已经常驻底栏的工具(scan, doctor, assistant, materials 及两端锚点)
|
|
const outsideToolIds = new Set(['scan', 'doctor', 'assistant', 'materials', 'toolbox', 'settings']);
|
|
const allTools = [...CATALOG_TOOLS, ...(owner.customToolboxItems || [])];
|
|
const toolboxTools = allTools.filter(tool => !outsideToolIds.has(tool.id));
|
|
|
|
const COLOR_ICONS = {
|
|
'workflow-transfer': '🔄',
|
|
'prompt-studio': '🎛️',
|
|
'prompt-translator': '🌐',
|
|
'model-sources': '🔗',
|
|
'prompt-notes': '📝',
|
|
};
|
|
|
|
toolboxTools.forEach(tool => {
|
|
const tile = document.createElement('div');
|
|
tile.className = 'anomalous-toolbox-tile';
|
|
tile.setAttribute('data-tool-id', tool.id);
|
|
|
|
const iconEl = document.createElement('div');
|
|
iconEl.className = 'anomalous-toolbox-tile-icon';
|
|
iconEl.innerHTML = COLOR_ICONS[tool.id] || tool.icon || '🔧';
|
|
tile.appendChild(iconEl);
|
|
|
|
const labelEl = document.createElement('div');
|
|
labelEl.className = 'anomalous-toolbox-tile-label';
|
|
labelEl.textContent = t(tool.labelKey) || t(tool.nameKey);
|
|
tile.appendChild(labelEl);
|
|
|
|
tile.onclick = (e) => {
|
|
e.stopPropagation();
|
|
if (window.AMB_hideTooltipImmediately) window.AMB_hideTooltipImmediately();
|
|
toolboxModal.style.display = 'none';
|
|
toolboxBtn.classList.remove('is-active');
|
|
executeToolAction(tool.id);
|
|
};
|
|
|
|
gridContainer.appendChild(tile);
|
|
});
|
|
|
|
toolboxModal.appendChild(gridContainer);
|
|
};
|
|
owner.renderToolboxModal = renderToolboxModal;
|
|
owner.registerToolboxItem = (item) => {
|
|
owner.customToolboxItems = owner.customToolboxItems || [];
|
|
owner.customToolboxItems.push(item);
|
|
if (owner.renderToolboxModal) owner.renderToolboxModal();
|
|
};
|
|
owner.openModelSources = (scope = 'workflow') => openModelSourcesModal(scope);
|
|
|
|
container.appendChild(toolboxModal);
|
|
|
|
const close = () => {
|
|
toolboxModal.style.display = 'none';
|
|
toolboxBtn.classList.remove('is-active');
|
|
document.removeEventListener('mousedown', closeToolbox);
|
|
};
|
|
|
|
return {
|
|
button: toolboxBtn,
|
|
modal: toolboxModal,
|
|
close,
|
|
mount() {
|
|
renderToolboxModal();
|
|
renderShortcutActions();
|
|
},
|
|
refreshLanguage() {
|
|
renderToolboxModal();
|
|
renderShortcutActions();
|
|
},
|
|
};
|
|
}
|