mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
feat: add setting to toggle folder sidebar visibility
This commit is contained in:
@@ -248,6 +248,8 @@
|
||||
"compact": "7 (1080p), 8 (2K), 10 (4K)"
|
||||
},
|
||||
"displayDensityWarning": "Warnung: Höhere Dichten können bei Systemen mit begrenzten Ressourcen zu Performance-Problemen führen.",
|
||||
"showFolderSidebar": "Ordner-Seitenleiste anzeigen",
|
||||
"showFolderSidebarHelp": "Blenden Sie die Ordner-Navigationsleiste auf den Modellseiten ein oder aus. Wenn deaktiviert, bleiben Seitenleiste und Hoverbereich verborgen.",
|
||||
"cardInfoDisplay": "Karten-Info-Anzeige",
|
||||
"cardInfoDisplayOptions": {
|
||||
"always": "Immer sichtbar",
|
||||
|
||||
@@ -238,7 +238,7 @@
|
||||
"displayDensity": "Display Density",
|
||||
"displayDensityOptions": {
|
||||
"default": "Default",
|
||||
"medium": "Medium",
|
||||
"medium": "Medium",
|
||||
"compact": "Compact"
|
||||
},
|
||||
"displayDensityHelp": "Choose how many cards to display per row:",
|
||||
@@ -248,6 +248,8 @@
|
||||
"compact": "7 (1080p), 8 (2K), 10 (4K)"
|
||||
},
|
||||
"displayDensityWarning": "Warning: Higher densities may cause performance issues on systems with limited resources.",
|
||||
"showFolderSidebar": "Show Folder Sidebar",
|
||||
"showFolderSidebarHelp": "Toggle the folder navigation sidebar on model pages. When disabled, the sidebar and hover area stay hidden.",
|
||||
"cardInfoDisplay": "Card Info Display",
|
||||
"cardInfoDisplayOptions": {
|
||||
"always": "Always Visible",
|
||||
|
||||
@@ -248,6 +248,8 @@
|
||||
"compact": "7 (1080p), 8 (2K), 10 (4K)"
|
||||
},
|
||||
"displayDensityWarning": "Advertencia: Densidades más altas pueden causar problemas de rendimiento en sistemas con recursos limitados.",
|
||||
"showFolderSidebar": "Mostrar barra lateral de carpetas",
|
||||
"showFolderSidebarHelp": "Activa o desactiva la barra lateral de navegación de carpetas en las páginas de modelos. Cuando está desactivada, la barra lateral y el área de desplazamiento permanecen ocultas.",
|
||||
"cardInfoDisplay": "Visualización de información de tarjeta",
|
||||
"cardInfoDisplayOptions": {
|
||||
"always": "Siempre visible",
|
||||
|
||||
@@ -248,6 +248,8 @@
|
||||
"compact": "7 (1080p), 8 (2K), 10 (4K)"
|
||||
},
|
||||
"displayDensityWarning": "Attention : Des densités plus élevées peuvent causer des problèmes de performance sur les systèmes avec des ressources limitées.",
|
||||
"showFolderSidebar": "Afficher la barre latérale des dossiers",
|
||||
"showFolderSidebarHelp": "Activez ou désactivez la barre latérale de navigation des dossiers sur les pages de modèles. Lorsqu'elle est désactivée, la barre latérale et la zone de survol restent masquées.",
|
||||
"cardInfoDisplay": "Affichage des informations de carte",
|
||||
"cardInfoDisplayOptions": {
|
||||
"always": "Toujours visible",
|
||||
|
||||
@@ -248,6 +248,8 @@
|
||||
"compact": "7 (1080p), 8 (2K), 10 (4K)"
|
||||
},
|
||||
"displayDensityWarning": "אזהרה: צפיפויות גבוהות יותר עלולות לגרום לבעיות ביצועים במערכות עם משאבים מוגבלים.",
|
||||
"showFolderSidebar": "הצג סרגל צד תיקיות",
|
||||
"showFolderSidebarHelp": "הפעל או כבה את סרגל הצד לניווט תיקיות בדפי המודל. כאשר הוא כבוי, סרגל הצד ואזור הריחוף נשארים מוסתרים.",
|
||||
"cardInfoDisplay": "תצוגת מידע בכרטיס",
|
||||
"cardInfoDisplayOptions": {
|
||||
"always": "תמיד גלוי",
|
||||
|
||||
@@ -248,6 +248,8 @@
|
||||
"compact": "7(1080p)、8(2K)、10(4K)"
|
||||
},
|
||||
"displayDensityWarning": "警告:高密度設定は、リソースが限られたシステムでパフォーマンスの問題を引き起こす可能性があります。",
|
||||
"showFolderSidebar": "フォルダサイドバーを表示",
|
||||
"showFolderSidebarHelp": "モデルページのフォルダナビゲーションサイドバーを表示/非表示にします。無効にするとサイドバーとホバーエリアは表示されません。",
|
||||
"cardInfoDisplay": "カード情報表示",
|
||||
"cardInfoDisplayOptions": {
|
||||
"always": "常に表示",
|
||||
|
||||
@@ -248,6 +248,8 @@
|
||||
"compact": "7개 (1080p), 8개 (2K), 10개 (4K)"
|
||||
},
|
||||
"displayDensityWarning": "경고: 높은 밀도는 리소스가 제한된 시스템에서 성능 문제를 일으킬 수 있습니다.",
|
||||
"showFolderSidebar": "폴더 사이드바 표시",
|
||||
"showFolderSidebarHelp": "모델 페이지에서 폴더 탐색 사이드바를 켜거나 끕니다. 비활성화하면 사이드바와 호버 영역이 표시되지 않습니다.",
|
||||
"cardInfoDisplay": "카드 정보 표시",
|
||||
"cardInfoDisplayOptions": {
|
||||
"always": "항상 표시",
|
||||
|
||||
@@ -248,6 +248,8 @@
|
||||
"compact": "7 (1080p), 8 (2K), 10 (4K)"
|
||||
},
|
||||
"displayDensityWarning": "Предупреждение: Высокая плотность может вызвать проблемы с производительностью на системах с ограниченными ресурсами.",
|
||||
"showFolderSidebar": "Показывать боковую панель папок",
|
||||
"showFolderSidebarHelp": "Включает или выключает боковую панель навигации по папкам на страницах моделей. При отключении панель и область наведения скрыты.",
|
||||
"cardInfoDisplay": "Отображение информации карточки",
|
||||
"cardInfoDisplayOptions": {
|
||||
"always": "Всегда видимо",
|
||||
|
||||
@@ -248,6 +248,8 @@
|
||||
"compact": "7(1080p),8(2K),10(4K)"
|
||||
},
|
||||
"displayDensityWarning": "警告:高密度可能导致资源有限的系统性能下降。",
|
||||
"showFolderSidebar": "显示文件夹侧边栏",
|
||||
"showFolderSidebarHelp": "在模型页面启用或禁用文件夹导航侧边栏。关闭后,侧边栏和悬停区域将保持隐藏。",
|
||||
"cardInfoDisplay": "卡片信息显示",
|
||||
"cardInfoDisplayOptions": {
|
||||
"always": "始终可见",
|
||||
|
||||
@@ -248,6 +248,8 @@
|
||||
"compact": "7(1080p)、8(2K)、10(4K)"
|
||||
},
|
||||
"displayDensityWarning": "警告:較高密度可能導致資源有限的系統效能下降。",
|
||||
"showFolderSidebar": "顯示資料夾側邊欄",
|
||||
"showFolderSidebarHelp": "在模型頁面啟用或停用資料夾導覽側邊欄。停用後,側邊欄與滑鼠懸停區域將保持隱藏。",
|
||||
"cardInfoDisplay": "卡片資訊顯示",
|
||||
"cardInfoDisplayOptions": {
|
||||
"always": "永遠顯示",
|
||||
|
||||
@@ -193,6 +193,7 @@ class SettingsHandler:
|
||||
"autoplay_on_hover",
|
||||
"display_density",
|
||||
"card_info_display",
|
||||
"show_folder_sidebar",
|
||||
"include_trigger_words",
|
||||
"show_only_sfw",
|
||||
"compact_mode",
|
||||
|
||||
@@ -51,6 +51,7 @@ DEFAULT_SETTINGS: Dict[str, Any] = {
|
||||
"autoplay_on_hover": False,
|
||||
"display_density": "default",
|
||||
"card_info_display": "always",
|
||||
"show_folder_sidebar": True,
|
||||
"include_trigger_words": False,
|
||||
"compact_mode": False,
|
||||
"priority_tags": DEFAULT_PRIORITY_TAG_CONFIG.copy(),
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.folder-sidebar.hidden-by-setting {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Visible state */
|
||||
.folder-sidebar.visible {
|
||||
transform: translateX(0);
|
||||
@@ -59,6 +63,10 @@
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.sidebar-hover-area.hidden-by-setting {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.sidebar-hover-area.disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ export class SidebarManager {
|
||||
this.dragHandlersInitialized = false;
|
||||
this.folderTreeElement = null;
|
||||
this.currentDropTarget = null;
|
||||
this.lastPageControls = null;
|
||||
this.isDisabledBySetting = false;
|
||||
this.initializationPromise = null;
|
||||
|
||||
// Bind methods
|
||||
this.handleTreeClick = this.handleTreeClick.bind(this);
|
||||
@@ -55,7 +58,15 @@ export class SidebarManager {
|
||||
this.handleFolderDrop = this.handleFolderDrop.bind(this);
|
||||
}
|
||||
|
||||
setHostPageControls(pageControls) {
|
||||
this.lastPageControls = pageControls;
|
||||
}
|
||||
|
||||
async initialize(pageControls) {
|
||||
if (this.isDisabledBySetting) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up previous initialization if exists
|
||||
if (this.isInitialized) {
|
||||
this.cleanup();
|
||||
@@ -63,6 +74,7 @@ export class SidebarManager {
|
||||
|
||||
this.pageControls = pageControls;
|
||||
this.pageType = pageControls.pageType;
|
||||
this.lastPageControls = pageControls;
|
||||
this.apiClient = getModelApiClient();
|
||||
|
||||
// Set initial sidebar state immediately (hidden by default)
|
||||
@@ -73,6 +85,10 @@ export class SidebarManager {
|
||||
this.updateSidebarTitle();
|
||||
this.restoreSidebarState();
|
||||
await this.loadFolderTree();
|
||||
if (this.isDisabledBySetting) {
|
||||
this.cleanup();
|
||||
return;
|
||||
}
|
||||
this.restoreSelectedFolder();
|
||||
|
||||
// Apply final state with animation after everything is loaded
|
||||
@@ -132,8 +148,9 @@ export class SidebarManager {
|
||||
|
||||
// Remove resize event listener
|
||||
window.removeEventListener('resize', this.updateContainerMargin);
|
||||
|
||||
|
||||
console.log('SidebarManager cleaned up');
|
||||
this.initializationPromise = null;
|
||||
}
|
||||
|
||||
removeEventHandlers() {
|
||||
@@ -471,9 +488,11 @@ export class SidebarManager {
|
||||
}
|
||||
|
||||
setInitialSidebarState() {
|
||||
if (this.isDisabledBySetting) return;
|
||||
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
const hoverArea = document.getElementById('sidebarHoverArea');
|
||||
|
||||
|
||||
if (!sidebar || !hoverArea) return;
|
||||
|
||||
// Get stored pin state
|
||||
@@ -492,6 +511,8 @@ export class SidebarManager {
|
||||
}
|
||||
|
||||
applyFinalSidebarState() {
|
||||
if (this.isDisabledBySetting) return;
|
||||
|
||||
// Use requestAnimationFrame to ensure DOM is ready
|
||||
requestAnimationFrame(() => {
|
||||
this.updateAutoHideState();
|
||||
@@ -668,6 +689,8 @@ export class SidebarManager {
|
||||
}
|
||||
|
||||
updateAutoHideState() {
|
||||
if (this.isDisabledBySetting) return;
|
||||
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
const hoverArea = document.getElementById('sidebarHoverArea');
|
||||
|
||||
@@ -708,8 +731,8 @@ export class SidebarManager {
|
||||
updateContainerMargin() {
|
||||
const container = document.querySelector('.container');
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
|
||||
if (!container || !sidebar) return;
|
||||
|
||||
if (!container || !sidebar || this.isDisabledBySetting) return;
|
||||
|
||||
// Reset margin to default
|
||||
container.style.marginLeft = '';
|
||||
@@ -729,6 +752,65 @@ export class SidebarManager {
|
||||
}
|
||||
}
|
||||
|
||||
updateDomVisibility(enabled) {
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
const hoverArea = document.getElementById('sidebarHoverArea');
|
||||
|
||||
if (sidebar) {
|
||||
sidebar.classList.toggle('hidden-by-setting', !enabled);
|
||||
sidebar.setAttribute('aria-hidden', (!enabled).toString());
|
||||
}
|
||||
|
||||
if (hoverArea) {
|
||||
hoverArea.classList.toggle('hidden-by-setting', !enabled);
|
||||
if (!enabled) {
|
||||
hoverArea.classList.add('disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async setSidebarEnabled(enabled) {
|
||||
this.isDisabledBySetting = !enabled;
|
||||
this.updateDomVisibility(enabled);
|
||||
|
||||
if (!enabled) {
|
||||
this.isHovering = false;
|
||||
this.isVisible = false;
|
||||
|
||||
if (this.isInitialized) {
|
||||
this.cleanup();
|
||||
} else {
|
||||
const container = document.querySelector('.container');
|
||||
if (container) {
|
||||
container.style.marginLeft = '';
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isInitialized) {
|
||||
this.updateAutoHideState();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.lastPageControls) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.initializationPromise) {
|
||||
this.initializationPromise = this.initialize(this.lastPageControls)
|
||||
.catch((error) => {
|
||||
console.error('Sidebar initialization failed:', error);
|
||||
})
|
||||
.finally(() => {
|
||||
this.initializationPromise = null;
|
||||
});
|
||||
}
|
||||
|
||||
await this.initializationPromise;
|
||||
}
|
||||
|
||||
updatePinButton() {
|
||||
const pinBtn = document.getElementById('sidebarPinToggle');
|
||||
if (pinBtn) {
|
||||
@@ -1327,6 +1409,10 @@ export class SidebarManager {
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
if (this.isDisabledBySetting || !this.isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.loadFolderTree();
|
||||
this.restoreSelectedFolder();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// PageControls.js - Manages controls for both LoRAs and Checkpoints pages
|
||||
import { getCurrentPageState, setCurrentPageType } from '../../state/index.js';
|
||||
import { state, getCurrentPageState, setCurrentPageType } from '../../state/index.js';
|
||||
import { getStorageItem, setStorageItem, getSessionItem, setSessionItem } from '../../utils/storageHelpers.js';
|
||||
import { showToast } from '../../utils/uiHelpers.js';
|
||||
import { performModelUpdateCheck } from '../../utils/updateCheckHelpers.js';
|
||||
@@ -75,7 +75,9 @@ export class PageControls {
|
||||
*/
|
||||
async initSidebarManager() {
|
||||
try {
|
||||
await this.sidebarManager.initialize(this);
|
||||
this.sidebarManager.setHostPageControls(this);
|
||||
const shouldShowSidebar = state?.global?.settings?.show_folder_sidebar !== false;
|
||||
await this.sidebarManager.setSidebarEnabled(shouldShowSidebar);
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize SidebarManager:', error);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { i18n } from '../i18n/index.js';
|
||||
import { configureModelCardVideo } from '../components/shared/ModelCard.js';
|
||||
import { validatePriorityTagString, getPriorityTagSuggestionsMap, invalidatePriorityTagSuggestionsCache } from '../utils/priorityTagHelpers.js';
|
||||
import { bannerService } from './BannerService.js';
|
||||
import { sidebarManager } from '../components/SidebarManager.js';
|
||||
|
||||
export class SettingsManager {
|
||||
constructor() {
|
||||
@@ -388,6 +389,12 @@ export class SettingsManager {
|
||||
cardInfoDisplaySelect.value = state.global.settings.card_info_display || 'always';
|
||||
}
|
||||
|
||||
const showFolderSidebarCheckbox = document.getElementById('showFolderSidebar');
|
||||
if (showFolderSidebarCheckbox) {
|
||||
const showSidebarSetting = state.global.settings.show_folder_sidebar;
|
||||
showFolderSidebarCheckbox.checked = showSidebarSetting !== false;
|
||||
}
|
||||
|
||||
// Set model card footer action
|
||||
const modelCardFooterActionSelect = document.getElementById('modelCardFooterAction');
|
||||
if (modelCardFooterActionSelect) {
|
||||
@@ -1699,6 +1706,13 @@ export class SettingsManager {
|
||||
// Apply card info display setting
|
||||
const cardInfoDisplay = state.global.settings.card_info_display || 'always';
|
||||
document.body.classList.toggle('hover-reveal', cardInfoDisplay === 'hover');
|
||||
|
||||
const shouldShowSidebar = state.global.settings.show_folder_sidebar !== false;
|
||||
if (sidebarManager && typeof sidebarManager.setSidebarEnabled === 'function') {
|
||||
sidebarManager.setSidebarEnabled(shouldShowSidebar).catch((error) => {
|
||||
console.error('Failed to apply sidebar visibility setting:', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ const DEFAULT_SETTINGS_BASE = Object.freeze({
|
||||
autoplay_on_hover: false,
|
||||
display_density: 'default',
|
||||
card_info_display: 'always',
|
||||
show_folder_sidebar: true,
|
||||
model_name_display: 'model_name',
|
||||
model_card_footer_action: 'example_images',
|
||||
include_trigger_words: false,
|
||||
|
||||
@@ -104,7 +104,25 @@
|
||||
<!-- Add Layout Settings Section -->
|
||||
<div class="settings-section">
|
||||
<h3>{{ t('settings.sections.layoutSettings') }}</h3>
|
||||
|
||||
|
||||
<div class="setting-item">
|
||||
<div class="setting-row">
|
||||
<div class="setting-info">
|
||||
<label for="showFolderSidebar">{{ t('settings.layoutSettings.showFolderSidebar') }}</label>
|
||||
</div>
|
||||
<div class="setting-control">
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="showFolderSidebar"
|
||||
onchange="settingsManager.saveToggleSetting('showFolderSidebar', 'show_folder_sidebar')">
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-help">
|
||||
{{ t('settings.layoutSettings.showFolderSidebarHelp') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting-item">
|
||||
<div class="setting-row">
|
||||
<div class="setting-info">
|
||||
|
||||
@@ -18,7 +18,8 @@ const downloadManagerMock = {
|
||||
};
|
||||
|
||||
const sidebarManagerMock = {
|
||||
initialize: vi.fn(async () => {
|
||||
setHostPageControls: vi.fn(),
|
||||
setSidebarEnabled: vi.fn(async () => {
|
||||
sidebarManagerMock.isInitialized = true;
|
||||
}),
|
||||
refresh: vi.fn(async () => {}),
|
||||
@@ -70,8 +71,8 @@ beforeEach(() => {
|
||||
performModelUpdateCheckMock.mockResolvedValue({ status: 'success', displayName: 'LoRA', records: [] });
|
||||
|
||||
sidebarManagerMock.isInitialized = false;
|
||||
sidebarManagerMock.initialize.mockImplementation(async () => {
|
||||
sidebarManagerMock.isInitialized = true;
|
||||
sidebarManagerMock.setSidebarEnabled.mockImplementation(async (enabled) => {
|
||||
sidebarManagerMock.isInitialized = enabled;
|
||||
});
|
||||
|
||||
global.fetch = vi.fn().mockResolvedValue({
|
||||
|
||||
Reference in New Issue
Block a user