mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-06-17 07:59:24 -03:00
refactor(sidebar): remove pin/unpin and global hide, use per-page hide only
- Remove pin/unpin and auto-hide hover mechanism (isPinned, isHovering, hoverTimeout, showSidebar/hideSidebar, updateAutoHideState, etc.) - Remove global show_folder_sidebar setting (SettingsManager, PageControls, recipes, backend default) - Simplify sidebar visibility to a single per-page toggle: · Dedicated chevron-left button in header to hide sidebar · Edge indicator (chevron-right) to restore when hidden · No dropdown, no hover area, no pin button - Add _migrateOldSettings() to convert old sidebarPinned and show_folder_sidebar states to per-page sidebarDisabled - Fix sidebar flicker on page load: CSS defaults to off-screen, JS explicitly sets .visible or .hidden-by-setting - Remove obsolete CSS classes: auto-hide, hover-active, collapsed - Remove i18n keys: pinSidebar, unpinSidebar, moreOptions - Update test mocks for the new initialize() interface
This commit is contained in:
@@ -956,10 +956,7 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"modelRoot": "Stammverzeichnis",
|
||||
"moreOptions": "Weitere Optionen",
|
||||
"collapseAll": "Alle Ordner einklappen",
|
||||
"pinSidebar": "Sidebar anheften",
|
||||
"unpinSidebar": "Sidebar lösen",
|
||||
"hideOnThisPage": "Seitenleiste auf dieser Seite ausblenden",
|
||||
"showSidebar": "Seitenleiste anzeigen",
|
||||
"sidebarHiddenNotification": "Seitenleiste auf der Seite {page} ausgeblendet",
|
||||
|
||||
@@ -956,10 +956,7 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"modelRoot": "Root",
|
||||
"moreOptions": "More options",
|
||||
"collapseAll": "Collapse All Folders",
|
||||
"pinSidebar": "Pin Sidebar",
|
||||
"unpinSidebar": "Unpin Sidebar",
|
||||
"hideOnThisPage": "Hide sidebar on this page",
|
||||
"showSidebar": "Show sidebar",
|
||||
"sidebarHiddenNotification": "Folder sidebar hidden on {page} page",
|
||||
|
||||
@@ -956,10 +956,7 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"modelRoot": "Raíz",
|
||||
"moreOptions": "Más opciones",
|
||||
"collapseAll": "Colapsar todas las carpetas",
|
||||
"pinSidebar": "Fijar barra lateral",
|
||||
"unpinSidebar": "Desfijar barra lateral",
|
||||
"hideOnThisPage": "Ocultar barra lateral en esta página",
|
||||
"showSidebar": "Mostrar barra lateral",
|
||||
"sidebarHiddenNotification": "Barra lateral oculta en la página {page}",
|
||||
|
||||
@@ -956,10 +956,7 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"modelRoot": "Racine",
|
||||
"moreOptions": "Plus d'options",
|
||||
"collapseAll": "Réduire tous les dossiers",
|
||||
"pinSidebar": "Épingler la barre latérale",
|
||||
"unpinSidebar": "Désépingler la barre latérale",
|
||||
"hideOnThisPage": "Masquer la barre latérale sur cette page",
|
||||
"showSidebar": "Afficher la barre latérale",
|
||||
"sidebarHiddenNotification": "Barre latérale masquée sur la page {page}",
|
||||
|
||||
@@ -956,10 +956,7 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"modelRoot": "שורש",
|
||||
"moreOptions": "אפשרויות נוספות",
|
||||
"collapseAll": "כווץ את כל התיקיות",
|
||||
"pinSidebar": "נעל סרגל צד",
|
||||
"unpinSidebar": "שחרר סרגל צד",
|
||||
"hideOnThisPage": "הסתר סרגל צד בדף זה",
|
||||
"showSidebar": "הצג סרגל צד",
|
||||
"sidebarHiddenNotification": "סרגל הצד מוסתר בדף {page}",
|
||||
|
||||
@@ -956,10 +956,7 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"modelRoot": "ルート",
|
||||
"moreOptions": "その他のオプション",
|
||||
"collapseAll": "すべてのフォルダを折りたたむ",
|
||||
"pinSidebar": "サイドバーを固定",
|
||||
"unpinSidebar": "サイドバーの固定を解除",
|
||||
"hideOnThisPage": "このページでサイドバーを非表示",
|
||||
"showSidebar": "サイドバーを表示",
|
||||
"sidebarHiddenNotification": "{page}ページでサイドバーが非表示になっています",
|
||||
|
||||
@@ -956,10 +956,7 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"modelRoot": "루트",
|
||||
"moreOptions": "더 많은 옵션",
|
||||
"collapseAll": "모든 폴더 접기",
|
||||
"pinSidebar": "사이드바 고정",
|
||||
"unpinSidebar": "사이드바 고정 해제",
|
||||
"hideOnThisPage": "이 페이지에서 사이드바 숨기기",
|
||||
"showSidebar": "사이드바 표시",
|
||||
"sidebarHiddenNotification": "{page} 페이지에서 사이드바가 숨겨져 있습니다",
|
||||
|
||||
@@ -956,10 +956,7 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"modelRoot": "Корень",
|
||||
"moreOptions": "Дополнительные параметры",
|
||||
"collapseAll": "Свернуть все папки",
|
||||
"pinSidebar": "Закрепить боковую панель",
|
||||
"unpinSidebar": "Открепить боковую панель",
|
||||
"hideOnThisPage": "Скрыть боковую панель на этой странице",
|
||||
"showSidebar": "Показать боковую панель",
|
||||
"sidebarHiddenNotification": "Боковая панель скрыта на странице {page}",
|
||||
|
||||
@@ -956,10 +956,7 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"modelRoot": "根目录",
|
||||
"moreOptions": "更多选项",
|
||||
"collapseAll": "折叠所有文件夹",
|
||||
"pinSidebar": "固定侧边栏",
|
||||
"unpinSidebar": "取消固定侧边栏",
|
||||
"hideOnThisPage": "隐藏此页面侧边栏",
|
||||
"showSidebar": "显示侧边栏",
|
||||
"sidebarHiddenNotification": "{page}页面的文件夹侧边栏已隐藏",
|
||||
|
||||
@@ -956,10 +956,7 @@
|
||||
},
|
||||
"sidebar": {
|
||||
"modelRoot": "根目錄",
|
||||
"moreOptions": "更多選項",
|
||||
"collapseAll": "全部摺疊資料夾",
|
||||
"pinSidebar": "固定側邊欄",
|
||||
"unpinSidebar": "取消固定側邊欄",
|
||||
"hideOnThisPage": "隱藏此頁面側邊欄",
|
||||
"showSidebar": "顯示側邊欄",
|
||||
"sidebarHiddenNotification": "{page}頁面的資料夾側邊欄已隱藏",
|
||||
|
||||
@@ -91,7 +91,6 @@ 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(),
|
||||
|
||||
@@ -8,69 +8,28 @@
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--border-radius-xs);
|
||||
overflow: hidden;
|
||||
transition: var(--transition-slow);
|
||||
flex-shrink: 0;
|
||||
z-index: var(--z-overlay);
|
||||
box-shadow: var(--shadow-header);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
backdrop-filter: blur(8px);
|
||||
/* Default state: hidden off-screen */
|
||||
/* Default: hidden off-screen — prevents flash before JS runs */
|
||||
transform: translateX(-100%);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.folder-sidebar.hidden-by-setting {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Visible state */
|
||||
.folder-sidebar.visible {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
/* Auto-hide states */
|
||||
.folder-sidebar.auto-hide {
|
||||
transform: translateX(-100%);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.folder-sidebar.auto-hide.hover-active {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.folder-sidebar.collapsed {
|
||||
transform: translateX(-100%);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Hover detection area for auto-hide */
|
||||
.sidebar-hover-area {
|
||||
position: fixed;
|
||||
top: 68px;
|
||||
left: 0;
|
||||
width: 20px;
|
||||
height: calc(100vh - 88px);
|
||||
z-index: calc(var(--z-overlay) - 1);
|
||||
background: transparent;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.sidebar-hover-area.hidden-by-setting {
|
||||
.folder-sidebar.hidden-by-setting {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.sidebar-hover-area.disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -151,65 +110,6 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ===== Sidebar More Options Dropdown ===== */
|
||||
.sidebar-more-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 8px;
|
||||
min-width: 190px;
|
||||
background: var(--bg-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--border-radius-xs);
|
||||
box-shadow: var(--shadow-lg);
|
||||
z-index: calc(var(--z-overlay) + 20);
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.sidebar-more-dropdown.open {
|
||||
display: block;
|
||||
animation: dropdownFadeIn 0.15s ease;
|
||||
}
|
||||
|
||||
@keyframes dropdownFadeIn {
|
||||
from { opacity: 0; transform: translateY(-4px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.sidebar-dropdown-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
font-size: 0.85em;
|
||||
color: var(--text-color);
|
||||
transition: var(--transition-base);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sidebar-dropdown-item:hover {
|
||||
background: var(--lora-surface);
|
||||
}
|
||||
|
||||
.sidebar-dropdown-item i {
|
||||
width: 16px;
|
||||
text-align: center;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.9em;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sidebar-dropdown-item:hover i {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.sidebar-dropdown-item.disabled {
|
||||
opacity: 0.4;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ===== Sidebar Hidden Indicator (left edge) ===== */
|
||||
.sidebar-hidden-indicator {
|
||||
position: fixed;
|
||||
@@ -630,7 +530,7 @@
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
/* Responsive Design — Mobile: overlay when shown */
|
||||
@media (max-width: 1024px) {
|
||||
.folder-sidebar {
|
||||
top: 68px;
|
||||
@@ -641,12 +541,8 @@
|
||||
z-index: calc(var(--z-overlay) + 10);
|
||||
}
|
||||
|
||||
.folder-sidebar.collapsed {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
/* Mobile overlay */
|
||||
.folder-sidebar:not(.collapsed)::before {
|
||||
/* Mobile overlay when sidebar is shown */
|
||||
.folder-sidebar.visible::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
||||
@@ -17,12 +17,8 @@ export class SidebarManager {
|
||||
this.treeData = {};
|
||||
this.selectedPath = '';
|
||||
this.expandedNodes = new Set();
|
||||
this.isVisible = true;
|
||||
this.isPinned = false;
|
||||
this.apiClient = null;
|
||||
this.openDropdown = null;
|
||||
this.hoverTimeout = null;
|
||||
this.isHovering = false;
|
||||
this.isInitialized = false;
|
||||
this.displayMode = 'tree'; // 'tree' or 'list'
|
||||
this.foldersList = [];
|
||||
@@ -35,9 +31,7 @@ export class SidebarManager {
|
||||
this.folderTreeElement = null;
|
||||
this.currentDropTarget = null;
|
||||
this.lastPageControls = null;
|
||||
this.isDisabledBySetting = false;
|
||||
this.isDisabledByPage = false;
|
||||
this.isMoreDropdownOpen = false;
|
||||
this.initializationPromise = null;
|
||||
this.isCreatingFolder = false;
|
||||
this._pendingDragState = null; // 用于保存拖拽创建文件夹时的状态
|
||||
@@ -48,12 +42,7 @@ export class SidebarManager {
|
||||
this.handleBreadcrumbClick = this.handleBreadcrumbClick.bind(this);
|
||||
this.handleDocumentClick = this.handleDocumentClick.bind(this);
|
||||
this.handleSidebarHeaderClick = this.handleSidebarHeaderClick.bind(this);
|
||||
this.handlePinToggle = this.handlePinToggle.bind(this);
|
||||
this.handleCollapseAll = this.handleCollapseAll.bind(this);
|
||||
this.handleMouseEnter = this.handleMouseEnter.bind(this);
|
||||
this.handleMouseLeave = this.handleMouseLeave.bind(this);
|
||||
this.handleHoverAreaEnter = this.handleHoverAreaEnter.bind(this);
|
||||
this.handleHoverAreaLeave = this.handleHoverAreaLeave.bind(this);
|
||||
this.updateContainerMargin = this.updateContainerMargin.bind(this);
|
||||
this.handleDisplayModeToggle = this.handleDisplayModeToggle.bind(this);
|
||||
this.handleFolderListClick = this.handleFolderListClick.bind(this);
|
||||
@@ -70,9 +59,7 @@ export class SidebarManager {
|
||||
this.handleSidebarDrop = this.handleSidebarDrop.bind(this);
|
||||
this.handleCreateFolderSubmit = this.handleCreateFolderSubmit.bind(this);
|
||||
this.handleCreateFolderCancel = this.handleCreateFolderCancel.bind(this);
|
||||
this.handleMoreToggle = this.handleMoreToggle.bind(this);
|
||||
this.handleMoreDropdownItemClick = this.handleMoreDropdownItemClick.bind(this);
|
||||
this.handleDocumentClickForMore = this.handleDocumentClickForMore.bind(this);
|
||||
this.handleHideToggle = this.handleHideToggle.bind(this);
|
||||
this.getPageDisplayName = this.getPageDisplayName.bind(this);
|
||||
}
|
||||
|
||||
@@ -81,12 +68,6 @@ export class SidebarManager {
|
||||
}
|
||||
|
||||
async initialize(pageControls, options = {}) {
|
||||
const { forceInitialize = false } = options;
|
||||
|
||||
if (this.isDisabledBySetting && !forceInitialize) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up previous initialization if exists
|
||||
if (this.isInitialized) {
|
||||
this.cleanup();
|
||||
@@ -99,25 +80,15 @@ export class SidebarManager {
|
||||
|| pageControls?.sidebarApiClient
|
||||
|| getModelApiClient();
|
||||
|
||||
// Set initial sidebar state immediately (hidden by default)
|
||||
this.setInitialSidebarState();
|
||||
|
||||
this.setupEventHandlers();
|
||||
this.initializeDragAndDrop();
|
||||
this.updateSidebarTitle();
|
||||
this.restoreSidebarState();
|
||||
// Re-apply DOM visibility now that per-page state is known
|
||||
this.updateDomVisibility(!this.isDisabledBySetting);
|
||||
// Apply DOM visibility based on per-page state
|
||||
this.updateDomVisibility();
|
||||
await this.loadFolderTree();
|
||||
if (this.isDisabledBySetting && !forceInitialize) {
|
||||
this.cleanup();
|
||||
return;
|
||||
}
|
||||
this.restoreSelectedFolder();
|
||||
|
||||
// Apply final state with animation after everything is loaded
|
||||
this.applyFinalSidebarState();
|
||||
|
||||
// Update container margin based on initial sidebar state
|
||||
this.updateContainerMargin();
|
||||
|
||||
@@ -128,12 +99,6 @@ export class SidebarManager {
|
||||
cleanup() {
|
||||
if (!this.isInitialized) return;
|
||||
|
||||
// Clear any pending timeouts
|
||||
if (this.hoverTimeout) {
|
||||
clearTimeout(this.hoverTimeout);
|
||||
this.hoverTimeout = null;
|
||||
}
|
||||
|
||||
// Clean up event handlers
|
||||
this.removeEventHandlers();
|
||||
|
||||
@@ -151,11 +116,6 @@ export class SidebarManager {
|
||||
this.sidebarDragHandlersInitialized = false;
|
||||
}
|
||||
|
||||
const moreDropdown = document.getElementById('sidebarMoreDropdown');
|
||||
if (moreDropdown) {
|
||||
moreDropdown.classList.remove('open');
|
||||
}
|
||||
this.isMoreDropdownOpen = false;
|
||||
this.hideSidebarHiddenIndicator();
|
||||
|
||||
// Reset state
|
||||
@@ -165,7 +125,6 @@ export class SidebarManager {
|
||||
this.selectedPath = '';
|
||||
this.expandedNodes = new Set();
|
||||
this.openDropdown = null;
|
||||
this.isHovering = false;
|
||||
this.isDisabledByPage = false;
|
||||
this.apiClient = null;
|
||||
this.isInitialized = false;
|
||||
@@ -185,19 +144,13 @@ export class SidebarManager {
|
||||
}
|
||||
|
||||
removeEventHandlers() {
|
||||
const pinToggleBtn = document.getElementById('sidebarPinToggle');
|
||||
const collapseAllBtn = document.getElementById('sidebarCollapseAll');
|
||||
const folderTree = document.getElementById('sidebarFolderTree');
|
||||
const sidebarBreadcrumbNav = document.getElementById('sidebarBreadcrumbNav');
|
||||
const sidebarHeader = document.getElementById('sidebarHeader');
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
const hoverArea = document.getElementById('sidebarHoverArea');
|
||||
const displayModeToggleBtn = document.getElementById('sidebarDisplayModeToggle');
|
||||
const recursiveToggleBtn = document.getElementById('sidebarRecursiveToggle');
|
||||
|
||||
if (pinToggleBtn) {
|
||||
pinToggleBtn.removeEventListener('click', this.handlePinToggle);
|
||||
}
|
||||
if (collapseAllBtn) {
|
||||
collapseAllBtn.removeEventListener('click', this.handleCollapseAll);
|
||||
}
|
||||
@@ -212,14 +165,6 @@ export class SidebarManager {
|
||||
if (sidebarHeader) {
|
||||
sidebarHeader.removeEventListener('click', this.handleSidebarHeaderClick);
|
||||
}
|
||||
if (sidebar) {
|
||||
sidebar.removeEventListener('mouseenter', this.handleMouseEnter);
|
||||
sidebar.removeEventListener('mouseleave', this.handleMouseLeave);
|
||||
}
|
||||
if (hoverArea) {
|
||||
hoverArea.removeEventListener('mouseenter', this.handleHoverAreaEnter);
|
||||
hoverArea.removeEventListener('mouseleave', this.handleHoverAreaLeave);
|
||||
}
|
||||
|
||||
// Remove document click handler
|
||||
document.removeEventListener('click', this.handleDocumentClick);
|
||||
@@ -234,17 +179,10 @@ export class SidebarManager {
|
||||
recursiveToggleBtn.removeEventListener('click', this.handleRecursiveToggle);
|
||||
}
|
||||
|
||||
const moreToggle = document.getElementById('sidebarMoreToggle');
|
||||
if (moreToggle) {
|
||||
moreToggle.removeEventListener('click', this.handleMoreToggle);
|
||||
const hideToggle = document.getElementById('sidebarHideToggle');
|
||||
if (hideToggle) {
|
||||
hideToggle.removeEventListener('click', this.handleHideToggle);
|
||||
}
|
||||
|
||||
const moreDropdown = document.getElementById('sidebarMoreDropdown');
|
||||
if (moreDropdown) {
|
||||
moreDropdown.removeEventListener('click', this.handleMoreDropdownItemClick);
|
||||
}
|
||||
|
||||
document.removeEventListener('click', this.handleDocumentClickForMore);
|
||||
}
|
||||
|
||||
initializeDragAndDrop() {
|
||||
@@ -919,60 +857,6 @@ export class SidebarManager {
|
||||
this.currentDropTarget = null;
|
||||
}
|
||||
|
||||
async init() {
|
||||
this.apiClient = this.pageControls?.getSidebarApiClient?.()
|
||||
|| this.pageControls?.sidebarApiClient
|
||||
|| getModelApiClient();
|
||||
|
||||
// Set initial sidebar state immediately (hidden by default)
|
||||
this.setInitialSidebarState();
|
||||
|
||||
this.setupEventHandlers();
|
||||
this.initializeDragAndDrop();
|
||||
this.updateSidebarTitle();
|
||||
this.restoreSidebarState();
|
||||
await this.loadFolderTree();
|
||||
this.restoreSelectedFolder();
|
||||
|
||||
// Apply final state with animation after everything is loaded
|
||||
this.applyFinalSidebarState();
|
||||
|
||||
// Update container margin based on initial sidebar state
|
||||
this.updateContainerMargin();
|
||||
}
|
||||
|
||||
setInitialSidebarState() {
|
||||
if (this.isDisabledBySetting) return;
|
||||
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
const hoverArea = document.getElementById('sidebarHoverArea');
|
||||
|
||||
if (!sidebar || !hoverArea) return;
|
||||
|
||||
// Get stored pin state
|
||||
const isPinned = getStorageItem(`${this.pageType}_sidebarPinned`, true);
|
||||
this.isPinned = isPinned;
|
||||
|
||||
// Sidebar starts hidden by default (CSS handles this)
|
||||
// Just set up the hover area state
|
||||
if (window.innerWidth <= 1024) {
|
||||
hoverArea.classList.add('disabled');
|
||||
} else if (this.isPinned) {
|
||||
hoverArea.classList.add('disabled');
|
||||
} else {
|
||||
hoverArea.classList.remove('disabled');
|
||||
}
|
||||
}
|
||||
|
||||
applyFinalSidebarState() {
|
||||
if (this.isDisabledBySetting) return;
|
||||
|
||||
// Use requestAnimationFrame to ensure DOM is ready
|
||||
requestAnimationFrame(() => {
|
||||
this.updateAutoHideState();
|
||||
});
|
||||
}
|
||||
|
||||
updateSidebarTitle() {
|
||||
const sidebarTitle = document.getElementById('sidebarTitle');
|
||||
if (sidebarTitle) {
|
||||
@@ -987,12 +871,6 @@ export class SidebarManager {
|
||||
sidebarHeader.addEventListener('click', this.handleSidebarHeaderClick);
|
||||
}
|
||||
|
||||
// Pin toggle button
|
||||
const pinToggleBtn = document.getElementById('sidebarPinToggle');
|
||||
if (pinToggleBtn) {
|
||||
pinToggleBtn.addEventListener('click', this.handlePinToggle);
|
||||
}
|
||||
|
||||
// Collapse all button
|
||||
const collapseAllBtn = document.getElementById('sidebarCollapseAll');
|
||||
if (collapseAllBtn) {
|
||||
@@ -1018,34 +896,18 @@ export class SidebarManager {
|
||||
sidebarBreadcrumbNav.addEventListener('click', this.handleBreadcrumbClick);
|
||||
}
|
||||
|
||||
// Hover detection for auto-hide
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
const hoverArea = document.getElementById('sidebarHoverArea');
|
||||
|
||||
if (sidebar) {
|
||||
sidebar.addEventListener('mouseenter', this.handleMouseEnter);
|
||||
sidebar.addEventListener('mouseleave', this.handleMouseLeave);
|
||||
}
|
||||
|
||||
if (hoverArea) {
|
||||
hoverArea.addEventListener('mouseenter', this.handleHoverAreaEnter);
|
||||
hoverArea.addEventListener('mouseleave', this.handleHoverAreaLeave);
|
||||
}
|
||||
|
||||
// Close sidebar when clicking outside on mobile
|
||||
document.addEventListener('click', (e) => {
|
||||
if (window.innerWidth <= 1024 && this.isVisible) {
|
||||
if (window.innerWidth <= 1024) {
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
|
||||
if (sidebar && !sidebar.contains(e.target)) {
|
||||
this.hideSidebar();
|
||||
if (sidebar && !sidebar.contains(e.target) && !this.isDisabledByPage) {
|
||||
sidebar.classList.remove('visible');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handle window resize
|
||||
window.addEventListener('resize', () => {
|
||||
this.updateAutoHideState();
|
||||
this.updateContainerMargin();
|
||||
});
|
||||
|
||||
@@ -1074,18 +936,11 @@ export class SidebarManager {
|
||||
});
|
||||
}
|
||||
|
||||
// More options dropdown
|
||||
const moreToggle = document.getElementById('sidebarMoreToggle');
|
||||
if (moreToggle) {
|
||||
moreToggle.addEventListener('click', this.handleMoreToggle);
|
||||
// Dedicated hide sidebar button
|
||||
const hideToggle = document.getElementById('sidebarHideToggle');
|
||||
if (hideToggle) {
|
||||
hideToggle.addEventListener('click', this.handleHideToggle);
|
||||
}
|
||||
|
||||
const moreDropdown = document.getElementById('sidebarMoreDropdown');
|
||||
if (moreDropdown) {
|
||||
moreDropdown.addEventListener('click', this.handleMoreDropdownItemClick);
|
||||
}
|
||||
|
||||
document.addEventListener('click', this.handleDocumentClickForMore);
|
||||
}
|
||||
|
||||
handleDocumentClick(event) {
|
||||
@@ -1102,14 +957,9 @@ export class SidebarManager {
|
||||
}
|
||||
}
|
||||
|
||||
handlePinToggle(event) {
|
||||
handleHideToggle(event) {
|
||||
event.stopPropagation();
|
||||
this.isPinned = !this.isPinned;
|
||||
this.updateAutoHideState();
|
||||
this.updatePinButton();
|
||||
this.updateMoreDropdownLabels();
|
||||
this.saveSidebarState();
|
||||
this.updateContainerMargin();
|
||||
this.toggleHideOnThisPage();
|
||||
}
|
||||
|
||||
handleCollapseAll(event) {
|
||||
@@ -1119,102 +969,13 @@ export class SidebarManager {
|
||||
this.saveExpandedState();
|
||||
}
|
||||
|
||||
handleMouseEnter() {
|
||||
this.isHovering = true;
|
||||
if (this.hoverTimeout) {
|
||||
clearTimeout(this.hoverTimeout);
|
||||
this.hoverTimeout = null;
|
||||
}
|
||||
// ===== Sidebar visibility (per-page) and container margin =====
|
||||
|
||||
if (!this.isPinned) {
|
||||
this.showSidebar();
|
||||
}
|
||||
}
|
||||
|
||||
handleMouseLeave() {
|
||||
this.isHovering = false;
|
||||
if (!this.isPinned) {
|
||||
this.hoverTimeout = setTimeout(() => {
|
||||
if (!this.isHovering) {
|
||||
this.hideSidebar();
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
handleHoverAreaEnter() {
|
||||
if (!this.isPinned) {
|
||||
this.showSidebar();
|
||||
}
|
||||
}
|
||||
|
||||
handleHoverAreaLeave() {
|
||||
// Let the sidebar's mouse leave handler deal with hiding
|
||||
}
|
||||
|
||||
showSidebar() {
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
if (sidebar && !this.isPinned) {
|
||||
sidebar.classList.add('hover-active');
|
||||
this.isVisible = true;
|
||||
this.updateContainerMargin();
|
||||
}
|
||||
}
|
||||
|
||||
hideSidebar() {
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
if (sidebar && !this.isPinned) {
|
||||
sidebar.classList.remove('hover-active');
|
||||
this.isVisible = false;
|
||||
this.updateContainerMargin();
|
||||
}
|
||||
}
|
||||
|
||||
updateAutoHideState() {
|
||||
if (this.isDisabledBySetting || this.isDisabledByPage) return;
|
||||
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
const hoverArea = document.getElementById('sidebarHoverArea');
|
||||
|
||||
if (!sidebar || !hoverArea) return;
|
||||
|
||||
if (window.innerWidth <= 1024) {
|
||||
// Mobile: always use collapsed state
|
||||
sidebar.classList.remove('auto-hide', 'hover-active', 'visible');
|
||||
sidebar.classList.add('collapsed');
|
||||
hoverArea.classList.add('disabled');
|
||||
this.isVisible = false;
|
||||
} else if (this.isPinned) {
|
||||
// Desktop pinned: always visible
|
||||
sidebar.classList.remove('auto-hide', 'collapsed', 'hover-active');
|
||||
sidebar.classList.add('visible');
|
||||
hoverArea.classList.add('disabled');
|
||||
this.isVisible = true;
|
||||
} else {
|
||||
// Desktop auto-hide: use hover detection
|
||||
sidebar.classList.remove('collapsed', 'visible');
|
||||
sidebar.classList.add('auto-hide');
|
||||
hoverArea.classList.remove('disabled');
|
||||
|
||||
if (this.isHovering) {
|
||||
sidebar.classList.add('hover-active');
|
||||
this.isVisible = true;
|
||||
} else {
|
||||
sidebar.classList.remove('hover-active');
|
||||
this.isVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Update container margin when sidebar state changes
|
||||
this.updateContainerMargin();
|
||||
}
|
||||
|
||||
// New method to update container margin based on sidebar state
|
||||
updateContainerMargin() {
|
||||
const container = document.querySelector('.container');
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
|
||||
if (!container || !sidebar || this.isDisabledBySetting) return;
|
||||
if (!container || !sidebar) return;
|
||||
|
||||
// Always reset margin first — needed when transitioning from visible to hidden
|
||||
container.style.marginLeft = '';
|
||||
@@ -1222,194 +983,40 @@ export class SidebarManager {
|
||||
// When per-page disabled, skip adjustment but margin is already reset
|
||||
if (this.isDisabledByPage) return;
|
||||
|
||||
// Only adjust margin if sidebar is visible and pinned
|
||||
if ((this.isPinned || this.isHovering) && this.isVisible) {
|
||||
const sidebarWidth = sidebar.offsetWidth;
|
||||
const viewportWidth = window.innerWidth;
|
||||
const containerWidth = container.offsetWidth;
|
||||
// Sidebar is visible — adjust margin if we need room
|
||||
const sidebarWidth = sidebar.offsetWidth;
|
||||
const viewportWidth = window.innerWidth;
|
||||
const containerWidth = container.offsetWidth;
|
||||
|
||||
// Check if there's enough space for both sidebar and container
|
||||
// We need: sidebar width + container width + some padding < viewport width
|
||||
if (sidebarWidth + containerWidth + sidebarWidth > viewportWidth) {
|
||||
// Not enough space, push container to the right
|
||||
container.style.marginLeft = `${sidebarWidth + 10}px`;
|
||||
}
|
||||
if (sidebarWidth + containerWidth + sidebarWidth > viewportWidth) {
|
||||
container.style.marginLeft = `${sidebarWidth + 10}px`;
|
||||
}
|
||||
}
|
||||
|
||||
updateDomVisibility(enabled) {
|
||||
// Per-page disable adds on top of global setting
|
||||
const isVisible = enabled && !this.isDisabledByPage;
|
||||
updateDomVisibility() {
|
||||
const isHidden = this.isDisabledByPage;
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
const hoverArea = document.getElementById('sidebarHoverArea');
|
||||
|
||||
if (sidebar) {
|
||||
sidebar.classList.toggle('hidden-by-setting', !isVisible);
|
||||
sidebar.setAttribute('aria-hidden', (!isVisible).toString());
|
||||
sidebar.classList.toggle('visible', !isHidden);
|
||||
sidebar.classList.toggle('hidden-by-setting', isHidden);
|
||||
sidebar.setAttribute('aria-hidden', isHidden.toString());
|
||||
}
|
||||
|
||||
if (hoverArea) {
|
||||
hoverArea.classList.toggle('hidden-by-setting', !isVisible);
|
||||
if (!isVisible) {
|
||||
hoverArea.classList.add('disabled');
|
||||
}
|
||||
}
|
||||
|
||||
// Show or hide the "sidebar hidden" notification
|
||||
if (enabled && this.isDisabledByPage) {
|
||||
// Show or hide the "sidebar hidden" edge indicator
|
||||
if (isHidden) {
|
||||
this.showSidebarHiddenIndicator();
|
||||
} else {
|
||||
this.hideSidebarHiddenIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
async setSidebarEnabled(enabled) {
|
||||
this.isDisabledBySetting = !enabled;
|
||||
this.updateDomVisibility(enabled);
|
||||
|
||||
const shouldForceInitialization = !enabled && !this.isInitialized;
|
||||
const needsInitialization = !this.isInitialized || shouldForceInitialization;
|
||||
|
||||
if (this.lastPageControls && needsInitialization) {
|
||||
if (!this.initializationPromise) {
|
||||
this.initializationPromise = this.initialize(this.lastPageControls, {
|
||||
forceInitialize: shouldForceInitialization,
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Sidebar initialization failed:', error);
|
||||
})
|
||||
.finally(() => {
|
||||
this.initializationPromise = null;
|
||||
});
|
||||
}
|
||||
|
||||
await this.initializationPromise;
|
||||
} else if (this.initializationPromise) {
|
||||
await this.initializationPromise;
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
this.isHovering = false;
|
||||
this.isVisible = false;
|
||||
|
||||
const container = document.querySelector('.container');
|
||||
if (container) {
|
||||
container.style.marginLeft = '';
|
||||
}
|
||||
|
||||
if (this.isInitialized) {
|
||||
this.updateBreadcrumbs();
|
||||
this.updateSidebarHeader();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isInitialized) {
|
||||
this.updateAutoHideState();
|
||||
}
|
||||
}
|
||||
|
||||
updatePinButton() {
|
||||
const pinBtn = document.getElementById('sidebarPinToggle');
|
||||
if (pinBtn) {
|
||||
pinBtn.classList.toggle('active', this.isPinned);
|
||||
pinBtn.title = this.isPinned
|
||||
? translate('sidebar.unpinSidebar')
|
||||
: translate('sidebar.pinSidebar');
|
||||
}
|
||||
}
|
||||
|
||||
// ===== More Options Dropdown =====
|
||||
|
||||
handleMoreToggle(event) {
|
||||
event.stopPropagation();
|
||||
const dropdown = document.getElementById('sidebarMoreDropdown');
|
||||
if (!dropdown) return;
|
||||
|
||||
this.isMoreDropdownOpen = !dropdown.classList.contains('open');
|
||||
dropdown.classList.toggle('open', this.isMoreDropdownOpen);
|
||||
this.updateMoreDropdownLabels();
|
||||
}
|
||||
|
||||
handleMoreDropdownItemClick(event) {
|
||||
const item = event.target.closest('.sidebar-dropdown-item');
|
||||
if (!item) return;
|
||||
|
||||
const action = item.dataset.action;
|
||||
if (!action) return;
|
||||
|
||||
const dropdown = document.getElementById('sidebarMoreDropdown');
|
||||
if (dropdown) {
|
||||
dropdown.classList.remove('open');
|
||||
this.isMoreDropdownOpen = false;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case 'toggle-pin':
|
||||
this.handlePinToggle(event);
|
||||
break;
|
||||
case 'toggle-hide':
|
||||
this.toggleHideOnThisPage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
handleDocumentClickForMore(event) {
|
||||
const dropdown = document.getElementById('sidebarMoreDropdown');
|
||||
const toggle = document.getElementById('sidebarMoreToggle');
|
||||
if (!dropdown || !toggle) return;
|
||||
|
||||
if (!dropdown.contains(event.target) && !toggle.contains(event.target)) {
|
||||
dropdown.classList.remove('open');
|
||||
this.isMoreDropdownOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
updateMoreDropdownLabels() {
|
||||
const pinLabel = document.getElementById('sidebarMorePinLabel');
|
||||
if (pinLabel) {
|
||||
pinLabel.textContent = this.isPinned
|
||||
? translate('sidebar.unpinSidebar')
|
||||
: translate('sidebar.pinSidebar');
|
||||
}
|
||||
|
||||
const hideItem = document.querySelector('.sidebar-dropdown-item[data-action="toggle-hide"]');
|
||||
if (hideItem) {
|
||||
const hideIcon = hideItem.querySelector('i');
|
||||
const hideLabel = hideItem.querySelector('span');
|
||||
if (this.isDisabledByPage) {
|
||||
hideLabel.textContent = translate('sidebar.showSidebar');
|
||||
if (hideIcon) {
|
||||
hideIcon.className = 'fas fa-eye';
|
||||
}
|
||||
} else {
|
||||
hideLabel.textContent = translate('sidebar.hideOnThisPage');
|
||||
if (hideIcon) {
|
||||
hideIcon.className = 'fas fa-eye-slash';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toggleHideOnThisPage() {
|
||||
this.isDisabledByPage = !this.isDisabledByPage;
|
||||
setStorageItem(`${this.pageType}_sidebarDisabled`, this.isDisabledByPage);
|
||||
this.updateDomVisibility(!this.isDisabledBySetting);
|
||||
this.updateAutoHideState();
|
||||
this.updateDomVisibility();
|
||||
this.updateContainerMargin();
|
||||
this.updateMoreDropdownLabels();
|
||||
|
||||
if (!this.isDisabledByPage) {
|
||||
this.hideSidebarHiddenIndicator();
|
||||
} else {
|
||||
showToast(
|
||||
'sidebar.sidebarHiddenNotification',
|
||||
{ page: this.getPageDisplayName() },
|
||||
'info',
|
||||
`Sidebar hidden on ${this.getPageDisplayName()} page`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getPageDisplayName() {
|
||||
@@ -1733,11 +1340,6 @@ export class SidebarManager {
|
||||
|
||||
// Reload models with new filter
|
||||
await this.pageControls.resetAndReload();
|
||||
|
||||
// Auto-hide sidebar on mobile after selection
|
||||
if (window.innerWidth <= 1024) {
|
||||
this.hideSidebar();
|
||||
}
|
||||
}
|
||||
|
||||
handleFolderListClick(event) {
|
||||
@@ -2047,65 +1649,55 @@ export class SidebarManager {
|
||||
}
|
||||
}
|
||||
|
||||
toggleSidebar() {
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
const toggleBtn = document.querySelector('.sidebar-toggle-btn');
|
||||
|
||||
if (!sidebar) return;
|
||||
|
||||
this.isVisible = !this.isVisible;
|
||||
|
||||
if (this.isVisible) {
|
||||
sidebar.classList.remove('collapsed');
|
||||
sidebar.classList.add('visible');
|
||||
} else {
|
||||
sidebar.classList.remove('visible');
|
||||
sidebar.classList.add('collapsed');
|
||||
}
|
||||
|
||||
if (toggleBtn) {
|
||||
toggleBtn.classList.toggle('active', this.isVisible);
|
||||
}
|
||||
|
||||
this.saveSidebarState();
|
||||
}
|
||||
|
||||
closeSidebar() {
|
||||
const sidebar = document.getElementById('folderSidebar');
|
||||
const toggleBtn = document.querySelector('.sidebar-toggle-btn');
|
||||
|
||||
if (!sidebar) return;
|
||||
|
||||
this.isVisible = false;
|
||||
sidebar.classList.remove('visible');
|
||||
sidebar.classList.add('collapsed');
|
||||
|
||||
if (toggleBtn) {
|
||||
toggleBtn.classList.remove('active');
|
||||
}
|
||||
|
||||
this.saveSidebarState();
|
||||
}
|
||||
|
||||
restoreSidebarState() {
|
||||
const isPinned = getStorageItem(`${this.pageType}_sidebarPinned`, true);
|
||||
// Migration: old pin/unpin and global hide → per-page hide
|
||||
this._migrateOldSettings();
|
||||
|
||||
const expandedPaths = getStorageItem(`${this.pageType}_expandedNodes`, []);
|
||||
const displayMode = getStorageItem(`${this.pageType}_displayMode`, 'tree'); // 'tree' or 'list', default to 'tree'
|
||||
const recursiveSearchEnabled = getStorageItem(`${this.pageType}_recursiveSearch`, true);
|
||||
this.isDisabledByPage = getStorageItem(`${this.pageType}_sidebarDisabled`, false);
|
||||
|
||||
this.isPinned = isPinned;
|
||||
this.expandedNodes = new Set(expandedPaths);
|
||||
this.displayMode = displayMode;
|
||||
this.recursiveSearchEnabled = recursiveSearchEnabled;
|
||||
|
||||
this.updatePinButton();
|
||||
this.updateDisplayModeButton();
|
||||
this.updateCollapseAllButton();
|
||||
this.updateSearchRecursiveOption();
|
||||
this.updateRecursiveToggleButton();
|
||||
}
|
||||
|
||||
/**
|
||||
* One-time migration: old pin/unpin and global show_folder_sidebar → per-page hide
|
||||
* - sidebarPinned=false (was auto-hide) → sidebarDisabled=true for that page
|
||||
* - show_folder_sidebar=false (global) → sidebarDisabled=true for ALL pages
|
||||
*/
|
||||
_migrateOldSettings() {
|
||||
if (getStorageItem('_sidebar_migration_done')) return;
|
||||
|
||||
const PAGES = ['loras', 'recipes', 'checkpoints', 'embeddings'];
|
||||
|
||||
// 1. Migrate global hide setting to per-page
|
||||
if (state?.global?.settings?.show_folder_sidebar === false) {
|
||||
PAGES.forEach(p => setStorageItem(`${p}_sidebarDisabled`, true));
|
||||
}
|
||||
|
||||
// 2. Migrate unpinned (auto-hide) to per-page hide
|
||||
PAGES.forEach(p => {
|
||||
const wasPinned = getStorageItem(`${p}_sidebarPinned`, true);
|
||||
const alreadyDisabled = getStorageItem(`${p}_sidebarDisabled`, false);
|
||||
if (wasPinned === false && !alreadyDisabled) {
|
||||
// Was auto-hide → user didn't want sidebar taking space
|
||||
setStorageItem(`${p}_sidebarDisabled`, true);
|
||||
}
|
||||
// Clean up old keys
|
||||
localStorage.removeItem(`${p}_sidebarPinned`);
|
||||
});
|
||||
|
||||
setStorageItem('_sidebar_migration_done', true);
|
||||
}
|
||||
|
||||
restoreSelectedFolder() {
|
||||
const activeFolder = getStorageItem(`${this.pageType}_activeFolder`);
|
||||
if (activeFolder && typeof activeFolder === 'string') {
|
||||
@@ -2118,11 +1710,6 @@ export class SidebarManager {
|
||||
this.updateSidebarHeader();
|
||||
this.updateBreadcrumbs(); // Always update breadcrumbs
|
||||
}
|
||||
// Removed hidden class toggle since breadcrumbs are always visible now
|
||||
}
|
||||
|
||||
saveSidebarState() {
|
||||
setStorageItem(`${this.pageType}_sidebarPinned`, this.isPinned);
|
||||
}
|
||||
|
||||
saveExpandedState() {
|
||||
@@ -2134,7 +1721,7 @@ export class SidebarManager {
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
if (this.isDisabledBySetting || !this.isInitialized) {
|
||||
if (!this.isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,8 +93,7 @@ export class PageControls {
|
||||
async initSidebarManager() {
|
||||
try {
|
||||
this.sidebarManager.setHostPageControls(this);
|
||||
const shouldShowSidebar = state?.global?.settings?.show_folder_sidebar !== false;
|
||||
await this.sidebarManager.setSidebarEnabled(shouldShowSidebar);
|
||||
await this.sidebarManager.initialize(this);
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize SidebarManager:', error);
|
||||
}
|
||||
@@ -664,13 +663,6 @@ export class PageControls {
|
||||
}
|
||||
|
||||
this.updateActionButtonStates();
|
||||
|
||||
if (this.sidebarManager) {
|
||||
const shouldShowSidebar = !isExcludedView && state?.global?.settings?.show_folder_sidebar !== false;
|
||||
this.sidebarManager.setSidebarEnabled(shouldShowSidebar).catch((error) => {
|
||||
console.error('Failed to update sidebar visibility:', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
suspendInteractiveModes() {
|
||||
|
||||
@@ -15,7 +15,6 @@ 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';
|
||||
|
||||
const VALID_MATURE_BLUR_LEVELS = new Set(['PG13', 'R', 'X', 'XXX']);
|
||||
|
||||
@@ -884,12 +883,6 @@ 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) {
|
||||
@@ -2949,12 +2942,6 @@ export class SettingsManager {
|
||||
const showVersionOnCard = state.global.settings.show_version_on_card !== false;
|
||||
document.body.classList.toggle('hide-card-version', !showVersionOnCard);
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,8 +95,7 @@ class RecipeManager {
|
||||
async _initSidebar() {
|
||||
try {
|
||||
sidebarManager.setHostPageControls(this.pageControls);
|
||||
const shouldShowSidebar = state?.global?.settings?.show_folder_sidebar !== false;
|
||||
await sidebarManager.setSidebarEnabled(shouldShowSidebar);
|
||||
await sidebarManager.initialize(this.pageControls);
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize recipe sidebar:', error);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ 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',
|
||||
lora_syntax_format: 'legacy',
|
||||
model_card_footer_action: 'example_images',
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
<!-- Hover detection area -->
|
||||
<div class="sidebar-hover-area" id="sidebarHoverArea"></div>
|
||||
|
||||
<!-- Folder Navigation Sidebar -->
|
||||
<div class="folder-sidebar" id="folderSidebar">
|
||||
<div class="sidebar-header" id="sidebarHeader">
|
||||
@@ -15,23 +12,9 @@
|
||||
<button class="sidebar-action-btn" id="sidebarCollapseAll" title="{{ t('sidebar.collapseAll') }}">
|
||||
<i class="fas fa-compress-alt"></i>
|
||||
</button>
|
||||
<button class="sidebar-action-btn" id="sidebarPinToggle" title="{{ t('sidebar.unpinSidebar') }}">
|
||||
<i class="fas fa-thumbtack"></i>
|
||||
<button class="sidebar-action-btn" id="sidebarHideToggle" title="{{ t('sidebar.hideOnThisPage') }}">
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
</button>
|
||||
<button class="sidebar-action-btn" id="sidebarMoreToggle" title="{{ t('sidebar.moreOptions') }}">
|
||||
<i class="fas fa-ellipsis-v"></i>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Dropdown menu for more options -->
|
||||
<div class="sidebar-more-dropdown" id="sidebarMoreDropdown">
|
||||
<div class="sidebar-dropdown-item" data-action="toggle-pin">
|
||||
<i class="fas fa-thumbtack"></i>
|
||||
<span id="sidebarMorePinLabel">{{ t('sidebar.pinSidebar') }}</span>
|
||||
</div>
|
||||
<div class="sidebar-dropdown-item" data-action="toggle-hide">
|
||||
<i class="fas fa-eye-slash"></i>
|
||||
<span>{{ t('sidebar.hideOnThisPage') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-content">
|
||||
|
||||
@@ -480,24 +480,6 @@
|
||||
<div class="settings-subsection-header">
|
||||
<h4>{{ t('settings.sections.layoutSettings') }}</h4>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<div class="setting-row">
|
||||
<div class="setting-info">
|
||||
<label for="showFolderSidebar">
|
||||
{{ t('settings.layoutSettings.showFolderSidebar') }}
|
||||
<i class="fas fa-info-circle info-icon" data-tooltip="{{ t('settings.layoutSettings.showFolderSidebarHelp') }}"></i>
|
||||
</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>
|
||||
|
||||
<div class="setting-item">
|
||||
<div class="setting-row">
|
||||
<div class="setting-info">
|
||||
|
||||
@@ -20,7 +20,7 @@ const downloadManagerMock = {
|
||||
|
||||
const sidebarManagerMock = {
|
||||
setHostPageControls: vi.fn(),
|
||||
setSidebarEnabled: vi.fn(async () => {
|
||||
initialize: vi.fn(async () => {
|
||||
sidebarManagerMock.isInitialized = true;
|
||||
}),
|
||||
refresh: vi.fn(async () => {}),
|
||||
@@ -75,9 +75,6 @@ beforeEach(() => {
|
||||
performModelUpdateCheckMock.mockResolvedValue({ status: 'success', displayName: 'LoRA', records: [] });
|
||||
|
||||
sidebarManagerMock.isInitialized = false;
|
||||
sidebarManagerMock.setSidebarEnabled.mockImplementation(async (enabled) => {
|
||||
sidebarManagerMock.isInitialized = enabled;
|
||||
});
|
||||
|
||||
global.fetch = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
|
||||
@@ -72,12 +72,6 @@ vi.mock('../../../static/js/managers/BannerService.js', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('../../../static/js/components/SidebarManager.js', () => ({
|
||||
sidebarManager: {
|
||||
setSidebarEnabled: vi.fn().mockResolvedValue(),
|
||||
},
|
||||
}));
|
||||
|
||||
import { SettingsManager } from '../../../static/js/managers/SettingsManager.js';
|
||||
import { state } from '../../../static/js/state/index.js';
|
||||
|
||||
|
||||
@@ -83,6 +83,15 @@ vi.mock('../../../static/js/api/recipeApi.js', () => ({
|
||||
})),
|
||||
}));
|
||||
|
||||
vi.mock('../../../static/js/components/SidebarManager.js', () => ({
|
||||
sidebarManager: {
|
||||
setHostPageControls: vi.fn(),
|
||||
initialize: vi.fn(async () => {}),
|
||||
refresh: vi.fn(async () => {}),
|
||||
cleanup: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('RecipeManager', () => {
|
||||
let RecipeManager;
|
||||
let pageState;
|
||||
|
||||
Reference in New Issue
Block a user