mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 15:15:44 -03:00
Fix layout
This commit is contained in:
@@ -1,11 +0,0 @@
|
|||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<!-- ...existing code... -->
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{% include 'components/header.html' %}
|
|
||||||
<!-- ...existing code... -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<!-- ...existing code... -->
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{% include 'components/header.html' %}
|
|
||||||
<!-- ...existing code... -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<!-- ...existing code... -->
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{% include 'components/header.html' %}
|
|
||||||
<!-- ...existing code... -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
.modal {
|
.modal {
|
||||||
display: none;
|
display: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 48px; /* Start below the header */
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: calc(100% - 48px); /* Adjust height to exclude header */
|
||||||
background: rgba(0, 0, 0, 0.2); /* 调整为更淡的半透明黑色 */
|
background: rgba(0, 0, 0, 0.2); /* 调整为更淡的半透明黑色 */
|
||||||
z-index: var(--z-modal);
|
z-index: var(--z-modal);
|
||||||
overflow: hidden; /* 改为 hidden,防止双滚动条 */
|
overflow: hidden; /* 改为 hidden,防止双滚动条 */
|
||||||
@@ -24,7 +24,7 @@ body.modal-open {
|
|||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
height: auto;
|
height: auto;
|
||||||
max-height: 90vh;
|
max-height: 90vh;
|
||||||
margin: 2rem auto;
|
margin: 1rem auto; /* Reduce top margin from 5rem to 1rem */
|
||||||
background: var(--lora-surface);
|
background: var(--lora-surface);
|
||||||
border-radius: var(--border-radius-base);
|
border-radius: var(--border-radius-base);
|
||||||
padding: var(--space-3);
|
padding: var(--space-3);
|
||||||
|
|||||||
@@ -144,10 +144,9 @@
|
|||||||
|
|
||||||
/* Filter Panel Styles */
|
/* Filter Panel Styles */
|
||||||
.filter-panel {
|
.filter-panel {
|
||||||
position: absolute;
|
position: fixed;
|
||||||
top: 140px; /* Adjust to be closer to the filter button */
|
|
||||||
right: 20px;
|
right: 20px;
|
||||||
width: 300px;
|
width: 320px;
|
||||||
background-color: var(--card-bg);
|
background-color: var(--card-bg);
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
border-radius: var(--border-radius-base);
|
border-radius: var(--border-radius-base);
|
||||||
@@ -312,7 +311,7 @@
|
|||||||
width: calc(100% - 40px);
|
width: calc(100% - 40px);
|
||||||
left: 20px;
|
left: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
top: 140px;
|
top: 160px; /* Adjusted for mobile layout */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,10 +350,9 @@
|
|||||||
|
|
||||||
/* Search Options Panel */
|
/* Search Options Panel */
|
||||||
.search-options-panel {
|
.search-options-panel {
|
||||||
position: absolute;
|
position: fixed;
|
||||||
top: 140px;
|
right: 20px;
|
||||||
right: 65px; /* Position it closer to the search options button */
|
width: 280px;
|
||||||
width: 280px; /* Slightly wider to accommodate tags better */
|
|
||||||
background-color: var(--card-bg);
|
background-color: var(--card-bg);
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
border-radius: var(--border-radius-base);
|
border-radius: var(--border-radius-base);
|
||||||
@@ -507,4 +505,15 @@ input:checked + .slider:before {
|
|||||||
|
|
||||||
.slider.round:before {
|
.slider.round:before {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile adjustments */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.search-options-panel,
|
||||||
|
.filter-panel {
|
||||||
|
width: calc(100% - 40px);
|
||||||
|
left: 20px;
|
||||||
|
right: 20px;
|
||||||
|
top: 160px; /* Adjusted for mobile layout */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
overflow-y: auto; /* Enable scrolling here */
|
overflow-y: auto; /* Enable scrolling here */
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ import {
|
|||||||
openCivitai,
|
openCivitai,
|
||||||
toggleFolderTags,
|
toggleFolderTags,
|
||||||
initFolderTagsVisibility,
|
initFolderTagsVisibility,
|
||||||
initBackToTop
|
initBackToTop,
|
||||||
|
updatePanelPositions
|
||||||
} from './utils/uiHelpers.js';
|
} from './utils/uiHelpers.js';
|
||||||
import { initializeInfiniteScroll } from './utils/infiniteScroll.js';
|
import { initializeInfiniteScroll } from './utils/infiniteScroll.js';
|
||||||
import { showDeleteModal, confirmDelete, closeDeleteModal } from './utils/modalUtils.js';
|
import { showDeleteModal, confirmDelete, closeDeleteModal } from './utils/modalUtils.js';
|
||||||
@@ -56,6 +57,7 @@ window.toggleApiKeyVisibility = toggleApiKeyVisibility;
|
|||||||
window.moveManager = moveManager;
|
window.moveManager = moveManager;
|
||||||
window.toggleShowcase = toggleShowcase;
|
window.toggleShowcase = toggleShowcase;
|
||||||
window.scrollToTop = scrollToTop;
|
window.scrollToTop = scrollToTop;
|
||||||
|
window.updatePanelPositions = updatePanelPositions;
|
||||||
|
|
||||||
// Export bulk manager methods to window
|
// Export bulk manager methods to window
|
||||||
window.toggleBulkMode = () => bulkManager.toggleBulkMode();
|
window.toggleBulkMode = () => bulkManager.toggleBulkMode();
|
||||||
@@ -96,6 +98,12 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
|
|
||||||
// Initialize the bulk manager
|
// Initialize the bulk manager
|
||||||
bulkManager.initialize();
|
bulkManager.initialize();
|
||||||
|
|
||||||
|
// Initial positioning
|
||||||
|
updatePanelPositions();
|
||||||
|
|
||||||
|
// Update positions on window resize
|
||||||
|
window.addEventListener('resize', updatePanelPositions);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize event listeners
|
// Initialize event listeners
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export class FilterManager {
|
|||||||
this.filterPanel = document.getElementById('filterPanel');
|
this.filterPanel = document.getElementById('filterPanel');
|
||||||
this.filterButton = document.getElementById('filterButton');
|
this.filterButton = document.getElementById('filterButton');
|
||||||
this.activeFiltersCount = document.getElementById('activeFiltersCount');
|
this.activeFiltersCount = document.getElementById('activeFiltersCount');
|
||||||
|
this.tagsLoaded = false;
|
||||||
|
|
||||||
this.initialize();
|
this.initialize();
|
||||||
}
|
}
|
||||||
@@ -140,20 +141,35 @@ export class FilterManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleFilterPanel() {
|
toggleFilterPanel() {
|
||||||
const wasHidden = this.filterPanel.classList.contains('hidden');
|
if (this.filterPanel) {
|
||||||
|
const isHidden = this.filterPanel.classList.contains('hidden');
|
||||||
this.filterPanel.classList.toggle('hidden');
|
|
||||||
|
if (isHidden) {
|
||||||
// If the panel is being opened, load the top tags and update selections
|
// Update panel positions before showing
|
||||||
if (wasHidden) {
|
if (window.searchManager && typeof window.searchManager.updatePanelPositions === 'function') {
|
||||||
this.loadTopTags();
|
window.searchManager.updatePanelPositions();
|
||||||
this.updateTagSelections();
|
} else if (typeof updatePanelPositions === 'function') {
|
||||||
|
updatePanelPositions();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.filterPanel.classList.remove('hidden');
|
||||||
|
this.filterButton.classList.add('active');
|
||||||
|
|
||||||
|
// Load tags if they haven't been loaded yet
|
||||||
|
if (!this.tagsLoaded) {
|
||||||
|
this.loadTopTags();
|
||||||
|
this.tagsLoaded = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.closeFilterPanel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closeFilterPanel() {
|
closeFilterPanel() {
|
||||||
this.filterPanel.classList.add('hidden');
|
this.filterPanel.classList.add('hidden');
|
||||||
|
this.filterButton.classList.remove('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTagSelections() {
|
updateTagSelections() {
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import { state } from '../state/index.js';
|
import { state } from '../state/index.js';
|
||||||
import { loadMoreLoras } from '../api/loraApi.js';
|
import { loadMoreLoras } from '../api/loraApi.js';
|
||||||
|
import { debounce } from './debounce.js';
|
||||||
|
|
||||||
export function initializeInfiniteScroll() {
|
export function initializeInfiniteScroll() {
|
||||||
if (state.observer) {
|
if (state.observer) {
|
||||||
state.observer.disconnect();
|
state.observer.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const debouncedLoadMore = debounce(loadMoreLoras, 200);
|
||||||
|
|
||||||
state.observer = new IntersectionObserver(
|
state.observer = new IntersectionObserver(
|
||||||
(entries) => {
|
(entries) => {
|
||||||
const target = entries[0];
|
const target = entries[0];
|
||||||
if (target.isIntersecting && !state.isLoading && state.hasMore) {
|
if (target.isIntersecting && !state.isLoading && state.hasMore) {
|
||||||
loadMoreLoras();
|
debouncedLoadMore();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ threshold: 0.1 }
|
{ threshold: 0.1 }
|
||||||
|
|||||||
@@ -30,6 +30,34 @@ export class SearchManager {
|
|||||||
|
|
||||||
// Initialize search options
|
// Initialize search options
|
||||||
this.initSearchOptions();
|
this.initSearchOptions();
|
||||||
|
|
||||||
|
// Add global click handler to close panels when clicking outside
|
||||||
|
document.addEventListener('click', (e) => {
|
||||||
|
// Close search options panel when clicking outside
|
||||||
|
if (this.searchOptionsPanel &&
|
||||||
|
!this.searchOptionsPanel.contains(e.target) &&
|
||||||
|
e.target !== this.searchOptionsToggle &&
|
||||||
|
!this.searchOptionsToggle.contains(e.target)) {
|
||||||
|
this.closeSearchOptionsPanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close filter panel when clicking outside (if filterManager exists)
|
||||||
|
const filterPanel = document.getElementById('filterPanel');
|
||||||
|
const filterButton = document.getElementById('filterButton');
|
||||||
|
if (filterPanel &&
|
||||||
|
!filterPanel.contains(e.target) &&
|
||||||
|
e.target !== filterButton &&
|
||||||
|
!filterButton.contains(e.target) &&
|
||||||
|
window.filterManager) {
|
||||||
|
window.filterManager.closeFilterPanel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize panel positions
|
||||||
|
this.updatePanelPositions();
|
||||||
|
|
||||||
|
// Add resize listener
|
||||||
|
window.addEventListener('resize', this.updatePanelPositions.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
initSearchOptions() {
|
initSearchOptions() {
|
||||||
@@ -103,16 +131,6 @@ export class SearchManager {
|
|||||||
|
|
||||||
// Ensure at least one search option is selected
|
// Ensure at least one search option is selected
|
||||||
this.validateSearchOptions();
|
this.validateSearchOptions();
|
||||||
|
|
||||||
// Close panel when clicking outside
|
|
||||||
document.addEventListener('click', (e) => {
|
|
||||||
if (this.searchOptionsPanel &&
|
|
||||||
!this.searchOptionsPanel.contains(e.target) &&
|
|
||||||
e.target !== this.searchOptionsToggle &&
|
|
||||||
!this.searchOptionsToggle.contains(e.target)) {
|
|
||||||
this.closeSearchOptionsPanel();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add method to validate search options
|
// Add method to validate search options
|
||||||
@@ -137,6 +155,8 @@ export class SearchManager {
|
|||||||
if (this.searchOptionsPanel) {
|
if (this.searchOptionsPanel) {
|
||||||
const isHidden = this.searchOptionsPanel.classList.contains('hidden');
|
const isHidden = this.searchOptionsPanel.classList.contains('hidden');
|
||||||
if (isHidden) {
|
if (isHidden) {
|
||||||
|
// Update position before showing
|
||||||
|
this.updatePanelPositions();
|
||||||
this.searchOptionsPanel.classList.remove('hidden');
|
this.searchOptionsPanel.classList.remove('hidden');
|
||||||
this.searchOptionsToggle.classList.add('active');
|
this.searchOptionsToggle.classList.add('active');
|
||||||
} else {
|
} else {
|
||||||
@@ -209,6 +229,9 @@ export class SearchManager {
|
|||||||
this.isSearching = true;
|
this.isSearching = true;
|
||||||
state.loadingManager.showSimpleLoading('Searching...');
|
state.loadingManager.showSimpleLoading('Searching...');
|
||||||
|
|
||||||
|
// Store current scroll position
|
||||||
|
const scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
|
||||||
|
|
||||||
state.currentPage = 1;
|
state.currentPage = 1;
|
||||||
state.hasMore = true;
|
state.hasMore = true;
|
||||||
|
|
||||||
@@ -250,6 +273,14 @@ export class SearchManager {
|
|||||||
state.hasMore = state.currentPage < data.total_pages;
|
state.hasMore = state.currentPage < data.total_pages;
|
||||||
state.currentPage++;
|
state.currentPage++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore scroll position after content is loaded
|
||||||
|
setTimeout(() => {
|
||||||
|
window.scrollTo({
|
||||||
|
top: scrollPosition,
|
||||||
|
behavior: 'instant' // Use 'instant' to prevent animation
|
||||||
|
});
|
||||||
|
}, 10);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Search error:', error);
|
console.error('Search error:', error);
|
||||||
@@ -259,4 +290,23 @@ export class SearchManager {
|
|||||||
state.loadingManager.hide();
|
state.loadingManager.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updatePanelPositions() {
|
||||||
|
const searchOptionsPanel = document.getElementById('searchOptionsPanel');
|
||||||
|
const filterPanel = document.getElementById('filterPanel');
|
||||||
|
|
||||||
|
if (!searchOptionsPanel || !filterPanel) return;
|
||||||
|
|
||||||
|
// Get the controls container
|
||||||
|
const controls = document.querySelector('.controls');
|
||||||
|
if (!controls) return;
|
||||||
|
|
||||||
|
// Calculate the position based on the bottom of the controls container
|
||||||
|
const controlsRect = controls.getBoundingClientRect();
|
||||||
|
const topPosition = controlsRect.bottom + 10; // Add 10px padding
|
||||||
|
|
||||||
|
// Set the positions
|
||||||
|
searchOptionsPanel.style.top = `${topPosition}px`;
|
||||||
|
filterPanel.style.top = `${topPosition}px`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -98,16 +98,57 @@ export function openCivitai(modelName) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamically positions the search options panel and filter panel
|
||||||
|
* based on the current layout and folder tags container height
|
||||||
|
*/
|
||||||
|
export function updatePanelPositions() {
|
||||||
|
const searchOptionsPanel = document.getElementById('searchOptionsPanel');
|
||||||
|
const filterPanel = document.getElementById('filterPanel');
|
||||||
|
|
||||||
|
if (!searchOptionsPanel || !filterPanel) return;
|
||||||
|
|
||||||
|
// Get the controls container
|
||||||
|
const controls = document.querySelector('.controls');
|
||||||
|
if (!controls) return;
|
||||||
|
|
||||||
|
// Calculate the position based on the bottom of the controls container
|
||||||
|
const controlsRect = controls.getBoundingClientRect();
|
||||||
|
const topPosition = controlsRect.bottom + 10; // Add 10px padding
|
||||||
|
|
||||||
|
// Set the positions
|
||||||
|
searchOptionsPanel.style.top = `${topPosition}px`;
|
||||||
|
filterPanel.style.top = `${topPosition}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the toggleFolderTags function
|
||||||
export function toggleFolderTags() {
|
export function toggleFolderTags() {
|
||||||
const folderTags = document.querySelector('.folder-tags');
|
const folderTags = document.querySelector('.folder-tags');
|
||||||
const btn = document.querySelector('.toggle-folders-btn');
|
const toggleBtn = document.querySelector('.toggle-folders-btn i');
|
||||||
const isCollapsed = folderTags.classList.toggle('collapsed');
|
|
||||||
|
|
||||||
// 更新按钮提示文本
|
if (folderTags) {
|
||||||
btn.title = isCollapsed ? 'Expand folder tags' : 'Collapse folder tags';
|
folderTags.classList.toggle('collapsed');
|
||||||
|
|
||||||
// 保存状态到 localStorage
|
if (folderTags.classList.contains('collapsed')) {
|
||||||
localStorage.setItem('folderTagsCollapsed', isCollapsed);
|
toggleBtn.className = 'fas fa-chevron-down';
|
||||||
|
toggleBtn.parentElement.title = 'Expand folder tags';
|
||||||
|
localStorage.setItem('folderTagsCollapsed', 'true');
|
||||||
|
} else {
|
||||||
|
toggleBtn.className = 'fas fa-chevron-up';
|
||||||
|
toggleBtn.parentElement.title = 'Collapse folder tags';
|
||||||
|
localStorage.setItem('folderTagsCollapsed', 'false');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update panel positions after toggling
|
||||||
|
// Use a small delay to ensure the DOM has updated
|
||||||
|
setTimeout(() => {
|
||||||
|
if (window.searchManager && typeof window.searchManager.updatePanelPositions === 'function') {
|
||||||
|
window.searchManager.updatePanelPositions();
|
||||||
|
} else if (typeof updatePanelPositions === 'function') {
|
||||||
|
updatePanelPositions();
|
||||||
|
}
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add this to your existing initialization code
|
// Add this to your existing initialization code
|
||||||
@@ -128,10 +169,13 @@ export function initBackToTop() {
|
|||||||
button.title = 'Back to top';
|
button.title = 'Back to top';
|
||||||
document.body.appendChild(button);
|
document.body.appendChild(button);
|
||||||
|
|
||||||
|
// Get the scrollable container
|
||||||
|
const scrollContainer = document.querySelector('.page-content');
|
||||||
|
|
||||||
// Show/hide button based on scroll position
|
// Show/hide button based on scroll position
|
||||||
const toggleBackToTop = () => {
|
const toggleBackToTop = () => {
|
||||||
const scrollThreshold = window.innerHeight * 0.75;
|
const scrollThreshold = window.innerHeight * 0.3;
|
||||||
if (window.scrollY > scrollThreshold) {
|
if (scrollContainer.scrollTop > scrollThreshold) {
|
||||||
button.classList.add('visible');
|
button.classList.add('visible');
|
||||||
} else {
|
} else {
|
||||||
button.classList.remove('visible');
|
button.classList.remove('visible');
|
||||||
@@ -140,14 +184,14 @@ export function initBackToTop() {
|
|||||||
|
|
||||||
// Smooth scroll to top
|
// Smooth scroll to top
|
||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
window.scrollTo({
|
scrollContainer.scrollTo({
|
||||||
top: 0,
|
top: 0,
|
||||||
behavior: 'smooth'
|
behavior: 'smooth'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for scroll events
|
// Listen for scroll events on the scrollable container
|
||||||
window.addEventListener('scroll', toggleBackToTop);
|
scrollContainer.addEventListener('scroll', toggleBackToTop);
|
||||||
|
|
||||||
// Initial check
|
// Initial check
|
||||||
toggleBackToTop();
|
toggleBackToTop();
|
||||||
|
|||||||
Reference in New Issue
Block a user