Files
DemonGatanjieu-Anomalous_Mo…/web/modules/ui_settings_hub.js
T
DemonGatanjieuandClaude Opus 5.5 a8b75d33a6 Faster model cards, video posters, and a settings page
Card thumbnails lived in ComfyUI's temp folder, which ComfyUI empties on
every start, so each first visit after a restart remade them all. They now
live in <user>/anomalous/cache/card_thumbnails (still capped at 256 MB).
Listing a model type queues the missing ones for one background thread;
the first screen of cards loads before the rest. A video cover gets a
first-frame poster (PyAV) and fetches nothing until it plays; hover-play
is now the default, as the setting already recommended.

The gear opens a settings page instead of a pop-up with a dialog inside:
look and language, model cards and memory with the thumbnail cache (size,
empty), folders, workflow fingerprints, opening mode and window, help.
Display preferences live behind owner.displayPrefs. Also removes a dead
overlay rule that shared the new page's id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 12:00:47 +08:00

135 lines
6.0 KiB
JavaScript

/**
* The browser's display preferences (view mode, interface scale, background atmosphere,
* window layout) and how they apply to the window; the rail's gear button, which opens
* the settings page (ui_settings_page.js); and redrawing the browser when the language
* changes. The settings page changes preferences only through `owner.displayPrefs`.
*/
import { app } from "../../../scripts/app.js";
import { translate } from './locales.js';
import { openSettingsPage, isSettingsPageOpen, leaveSettingsPage } from './ui_settings_page.js';
const t = (key, params) => translate(key, params);
const VIEW_MODES = ['compact', 'standard', 'aesthetic'];
export function createSettingsHub(owner, {
container,
savedScale,
savedBgOpacity,
updateLangClass,
dockBtn,
updateNoticeBtn,
icons,
}) {
const prefs = {
viewMode: VIEW_MODES.includes(localStorage.getItem('anomalous_view_mode')) ? localStorage.getItem('anomalous_view_mode') : 'compact',
scale: parseFloat(savedScale) || 1,
bgOpacity: Number.isFinite(parseFloat(savedBgOpacity)) ? parseFloat(savedBgOpacity) : 0.2,
};
const applyViewMode = (mode) => {
prefs.viewMode = VIEW_MODES.includes(mode) ? mode : 'compact';
container.classList.remove(...VIEW_MODES.map(name => `view-mode-${name}`));
container.classList.add(`view-mode-${prefs.viewMode}`);
};
applyViewMode(prefs.viewMode);
/** What the settings page reads and changes; each change is kept for the next session. */
owner.displayPrefs = {
get: () => ({ ...prefs }),
setViewMode(mode) {
applyViewMode(mode);
localStorage.setItem('anomalous_view_mode', prefs.viewMode);
},
setScale(value) {
prefs.scale = Math.max(0.5, Math.min(1.5, Math.round(value * 10) / 10));
container.style.setProperty('--anomalous-scale', prefs.scale);
localStorage.setItem('anomalous_ui_scale', prefs.scale);
},
setBgOpacity(value) {
prefs.bgOpacity = Math.max(0, Math.min(1, Math.round(value * 100) / 100));
container.style.setProperty('--anomalous-bg-opacity', prefs.bgOpacity);
localStorage.setItem('anomalous_bg_opacity', prefs.bgOpacity);
},
/** Window position, size, docking, scale, atmosphere and view mode back to their defaults. */
resetLayout() {
for (const key of ['anomalous_pos_x', 'anomalous_pos_y', 'anomalous_width', 'anomalous_height', 'anomalous_docked',
'anomalous_ui_scale', 'anomalous_bg_opacity', 'anomalous_view_mode']) {
localStorage.removeItem(key);
}
applyViewMode('compact');
Object.assign(container.style, { left: '5%', top: '5%', width: '90%', height: '90%' });
prefs.scale = 1;
prefs.bgOpacity = 0.2;
container.style.setProperty('--anomalous-scale', '1');
container.style.setProperty('--anomalous-bg-opacity', '0.2');
container.classList.remove('anomalous-docked');
},
};
const settingsBtn = document.createElement('button');
settingsBtn.id = 'anomalous-global-settings-btn';
settingsBtn.className = 'anomalous-tooltip-target';
settingsBtn.innerHTML = icons.SETTINGS;
settingsBtn.setAttribute('aria-label', t('sidebarSettings'));
settingsBtn.setAttribute('data-tooltip', t('sidebarSettings'));
settingsBtn.setAttribute('data-tooltip-pos', 'right');
// The gear opens the settings page; on it, the gear goes back to where you were.
settingsBtn.onclick = (event) => {
event.stopPropagation();
if (isSettingsPageOpen(owner)) leaveSettingsPage(owner);
else openSettingsPage(owner);
};
const refreshLanguageUi = () => {
updateLangClass();
owner.renderRailTools?.();
settingsBtn.setAttribute('aria-label', t('sidebarSettings'));
settingsBtn.setAttribute('data-tooltip', t('sidebarSettings'));
owner.refreshShellLanguage?.();
if (dockBtn) {
dockBtn.removeAttribute('title');
dockBtn.setAttribute('aria-label', t('dockTitle'));
dockBtn.setAttribute('data-tooltip', t('dockTitle'));
dockBtn.setAttribute('data-tooltip-pos', 'bottom');
}
if (updateNoticeBtn) {
updateNoticeBtn.setAttribute('data-tooltip', t('updateGuideNoticeTooltip'));
updateNoticeBtn.setAttribute('aria-label', t('updateGuideNoticeTooltip'));
}
// Pages drawn in the old language are drawn again.
if (owner.doctorPanel && owner.doctorPanel.style.display !== 'none') owner.openDoctorPage();
if (owner.assistantPanel && owner.assistantPanelInitialized) {
const selectedNode = Object.values(app.canvas?.selected_nodes || {})[0] || null;
owner.assistantPanelInitialized = false;
owner.initAssistantPanel();
owner.diagnoseNode(selectedNode);
}
if (owner.notebookNotesTab) owner.notebookNotesTab.textContent = t('promptNotes');
if (owner.notebookRecipesTab) owner.notebookRecipesTab.textContent = t('recipeTitle');
document.querySelectorAll('[data-anomalous-i18n-key]').forEach((element) => {
const key = element.dataset.anomalousI18nKey;
if (key) element.textContent = t(key);
});
document.getElementById('anomalous-import-overlay')?.remove();
if (isSettingsPageOpen(owner)) openSettingsPage(owner, { keepReturn: true });
owner.renderSidebar();
owner.loadModels();
if (owner.detailPanel.style.display !== 'none' && owner.currentDetailModel) {
owner.showDetail(owner.currentDetailModel);
}
if (owner.nbEditor && owner.nbEditor.innerHTML !== '') {
owner.renderNotebookEditor();
owner.refreshNotebooks();
}
};
window.addEventListener('anomalous-language-change', refreshLanguageUi);
return {
button: settingsBtn,
refreshLanguage: refreshLanguageUi,
};
}