Fix layout

This commit is contained in:
Will Miao
2025-03-13 20:37:23 +08:00
parent e7233c147d
commit 0b0caa1142
11 changed files with 175 additions and 75 deletions

View File

@@ -1,16 +1,19 @@
import { state } from '../state/index.js';
import { loadMoreLoras } from '../api/loraApi.js';
import { debounce } from './debounce.js';
export function initializeInfiniteScroll() {
if (state.observer) {
state.observer.disconnect();
}
const debouncedLoadMore = debounce(loadMoreLoras, 200);
state.observer = new IntersectionObserver(
(entries) => {
const target = entries[0];
if (target.isIntersecting && !state.isLoading && state.hasMore) {
loadMoreLoras();
debouncedLoadMore();
}
},
{ threshold: 0.1 }

View File

@@ -30,6 +30,34 @@ export class SearchManager {
// Initialize search options
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() {
@@ -103,16 +131,6 @@ export class SearchManager {
// Ensure at least one search option is selected
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
@@ -137,6 +155,8 @@ export class SearchManager {
if (this.searchOptionsPanel) {
const isHidden = this.searchOptionsPanel.classList.contains('hidden');
if (isHidden) {
// Update position before showing
this.updatePanelPositions();
this.searchOptionsPanel.classList.remove('hidden');
this.searchOptionsToggle.classList.add('active');
} else {
@@ -209,6 +229,9 @@ export class SearchManager {
this.isSearching = true;
state.loadingManager.showSimpleLoading('Searching...');
// Store current scroll position
const scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
state.currentPage = 1;
state.hasMore = true;
@@ -250,6 +273,14 @@ export class SearchManager {
state.hasMore = state.currentPage < data.total_pages;
state.currentPage++;
}
// Restore scroll position after content is loaded
setTimeout(() => {
window.scrollTo({
top: scrollPosition,
behavior: 'instant' // Use 'instant' to prevent animation
});
}, 10);
}
} catch (error) {
console.error('Search error:', error);
@@ -259,4 +290,23 @@ export class SearchManager {
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`;
}
}

View File

@@ -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() {
const folderTags = document.querySelector('.folder-tags');
const btn = document.querySelector('.toggle-folders-btn');
const isCollapsed = folderTags.classList.toggle('collapsed');
const toggleBtn = document.querySelector('.toggle-folders-btn i');
// 更新按钮提示文本
btn.title = isCollapsed ? 'Expand folder tags' : 'Collapse folder tags';
// 保存状态到 localStorage
localStorage.setItem('folderTagsCollapsed', isCollapsed);
if (folderTags) {
folderTags.classList.toggle('collapsed');
if (folderTags.classList.contains('collapsed')) {
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
@@ -128,10 +169,13 @@ export function initBackToTop() {
button.title = 'Back to top';
document.body.appendChild(button);
// Get the scrollable container
const scrollContainer = document.querySelector('.page-content');
// Show/hide button based on scroll position
const toggleBackToTop = () => {
const scrollThreshold = window.innerHeight * 0.75;
if (window.scrollY > scrollThreshold) {
const scrollThreshold = window.innerHeight * 0.3;
if (scrollContainer.scrollTop > scrollThreshold) {
button.classList.add('visible');
} else {
button.classList.remove('visible');
@@ -140,14 +184,14 @@ export function initBackToTop() {
// Smooth scroll to top
button.addEventListener('click', () => {
window.scrollTo({
scrollContainer.scrollTo({
top: 0,
behavior: 'smooth'
});
});
// Listen for scroll events
window.addEventListener('scroll', toggleBackToTop);
// Listen for scroll events on the scrollable container
scrollContainer.addEventListener('scroll', toggleBackToTop);
// Initial check
toggleBackToTop();