Refactor panel position management and enhance recipe card handling

- Removed redundant updatePanelPositions calls from various components and centralized the logic in the uiHelpers.js for better maintainability.
- Introduced appendRecipeCards function in RecipeManager to streamline the addition of recipe cards from search results.
- Cleaned up unused code related to search input handling and recipe loading, improving overall code clarity and performance.
- Updated HeaderManager and SearchManager to utilize the new updatePanelPositions function, ensuring consistent panel positioning across the application.
This commit is contained in:
Will Miao
2025-03-20 09:54:13 +08:00
parent caf5b1528c
commit a88b0239eb
9 changed files with 56 additions and 202 deletions

View File

@@ -101,53 +101,4 @@ export class HeaderManager {
}); });
} }
} }
}
// Helper method to update panel positions (can be called from window resize handlers)
updatePanelPositions() {
if (this.searchManager && typeof this.searchManager.updatePanelPositions === 'function') {
this.searchManager.updatePanelPositions();
} else {
const searchOptionsPanel = document.getElementById('searchOptionsPanel');
const filterPanel = document.getElementById('filterPanel');
if (!searchOptionsPanel && !filterPanel) return;
// Get the header element
const header = document.querySelector('.app-header');
if (!header) return;
// Calculate the position based on the bottom of the header
const headerRect = header.getBoundingClientRect();
const topPosition = headerRect.bottom + 5; // Add 5px padding
// Set the positions
if (searchOptionsPanel) {
searchOptionsPanel.style.top = `${topPosition}px`;
}
if (filterPanel) {
filterPanel.style.top = `${topPosition}px`;
}
// Adjust panel horizontal position based on the search container
const searchContainer = document.querySelector('.header-search');
if (searchContainer) {
const searchRect = searchContainer.getBoundingClientRect();
// Position the search options panel aligned with the search container
if (searchOptionsPanel) {
searchOptionsPanel.style.right = `${window.innerWidth - searchRect.right}px`;
}
// Position the filter panel aligned with the filter button
if (filterPanel) {
const filterButton = document.getElementById('filterButton');
if (filterButton) {
const filterRect = filterButton.getBoundingClientRect();
filterPanel.style.right = `${window.innerWidth - filterRect.right}px`;
}
}
}
}
}
}

View File

@@ -5,7 +5,7 @@ import { modalManager } from './managers/ModalManager.js';
import { updateService } from './managers/UpdateService.js'; import { updateService } from './managers/UpdateService.js';
import { HeaderManager } from './components/Header.js'; import { HeaderManager } from './components/Header.js';
import { SettingsManager } from './managers/SettingsManager.js'; import { SettingsManager } from './managers/SettingsManager.js';
import { showToast, initTheme, initBackToTop, updatePanelPositions, lazyLoadImages } from './utils/uiHelpers.js'; import { showToast, initTheme, initBackToTop, lazyLoadImages } from './utils/uiHelpers.js';
import { initializeInfiniteScroll } from './utils/infiniteScroll.js'; import { initializeInfiniteScroll } from './utils/infiniteScroll.js';
// Core application class // Core application class
@@ -30,12 +30,6 @@ export class AppCore {
initTheme(); initTheme();
initBackToTop(); initBackToTop();
// Set up event listeners
window.addEventListener('resize', updatePanelPositions);
// Initial positioning
updatePanelPositions();
// Mark as initialized // Mark as initialized
this.initialized = true; this.initialized = true;
@@ -66,9 +60,6 @@ export class AppCore {
initializeInfiniteScroll(pageType); initializeInfiniteScroll(pageType);
} }
// Update panel positions
updatePanelPositions();
return this; return this;
} }
} }

View File

@@ -1,6 +1,6 @@
import { BASE_MODELS, BASE_MODEL_CLASSES } from '../utils/constants.js'; import { BASE_MODELS, BASE_MODEL_CLASSES } from '../utils/constants.js';
import { state, getCurrentPageState } from '../state/index.js'; import { state, getCurrentPageState } from '../state/index.js';
import { showToast } from '../utils/uiHelpers.js'; import { showToast, updatePanelPositions } from '../utils/uiHelpers.js';
import { resetAndReload } from '../api/loraApi.js'; import { resetAndReload } from '../api/loraApi.js';
export class FilterManager { export class FilterManager {
@@ -155,11 +155,7 @@ export class FilterManager {
if (isHidden) { if (isHidden) {
// Update panel positions before showing // Update panel positions before showing
if (window.searchManager && typeof window.searchManager.updatePanelPositions === 'function') {
window.searchManager.updatePanelPositions();
} else if (typeof updatePanelPositions === 'function') {
updatePanelPositions(); updatePanelPositions();
}
this.filterPanel.classList.remove('hidden'); this.filterPanel.classList.remove('hidden');
this.filterButton.classList.add('active'); this.filterButton.classList.add('active');

View File

@@ -1,4 +1,4 @@
import { showToast } from '../utils/uiHelpers.js'; import { showToast, updatePanelPositions } from '../utils/uiHelpers.js';
export class RecipeFilterManager { export class RecipeFilterManager {
constructor() { constructor() {
@@ -165,11 +165,7 @@ export class RecipeFilterManager {
if (isHidden) { if (isHidden) {
// Update panel positions before showing // Update panel positions before showing
if (window.searchManager && typeof window.searchManager.updatePanelPositions === 'function') {
window.searchManager.updatePanelPositions();
} else if (typeof updatePanelPositions === 'function') {
updatePanelPositions(); updatePanelPositions();
}
this.filterPanel.classList.remove('hidden'); this.filterPanel.classList.remove('hidden');
this.filterButton.classList.add('active'); this.filterButton.classList.add('active');

View File

@@ -33,10 +33,7 @@ export class RecipeSearchManager extends SearchManager {
const grid = document.getElementById('recipeGrid'); const grid = document.getElementById('recipeGrid');
if (!searchTerm) { if (!searchTerm) {
if (state) { window.recipeManager.loadRecipes();
state.pages.recipes.currentPage = 1;
}
this.resetAndReloadRecipes();
return; return;
} }
@@ -112,34 +109,12 @@ export class RecipeSearchManager extends SearchManager {
} }
} }
resetAndReloadRecipes() {
if (window.recipeManager && typeof window.recipeManager.loadRecipes === 'function') {
window.recipeManager.loadRecipes();
} else {
// Fallback to reloading the page
window.location.reload();
}
}
appendRecipeCards(recipes) { appendRecipeCards(recipes) {
// This function would be implemented in the recipes page
// Similar to appendLoraCards for loras
const grid = document.getElementById('recipeGrid'); const grid = document.getElementById('recipeGrid');
if (!grid) return; if (!grid) return;
if (typeof window.appendRecipeCards === 'function') { // Create data object in the format expected by the RecipeManager
window.appendRecipeCards(recipes); const data = { items: recipes, has_more: false };
} else { window.recipeManager.updateRecipesGrid(data, false);
// Fallback implementation
recipes.forEach(recipe => {
const card = document.createElement('div');
card.className = 'recipe-card';
card.innerHTML = `
<h3>${recipe.name}</h3>
<p>${recipe.description || 'No description'}</p>
`;
grid.appendChild(card);
});
}
} }
} }

View File

@@ -1,3 +1,4 @@
import { updatePanelPositions } from "../utils/uiHelpers.js";
/** /**
* SearchManager - Handles search functionality across different pages * SearchManager - Handles search functionality across different pages
* Each page can extend or customize this base functionality * Each page can extend or customize this base functionality
@@ -27,11 +28,10 @@ export class SearchManager {
this.initEventListeners(); this.initEventListeners();
this.loadSearchPreferences(); this.loadSearchPreferences();
// Initialize panel positions updatePanelPositions();
this.updatePanelPositions();
// Add resize listener // Add resize listener
window.addEventListener('resize', this.updatePanelPositions.bind(this)); window.addEventListener('resize', updatePanelPositions);
} }
initEventListeners() { initEventListeners() {
@@ -161,7 +161,7 @@ export class SearchManager {
const isHidden = this.searchOptionsPanel.classList.contains('hidden'); const isHidden = this.searchOptionsPanel.classList.contains('hidden');
if (isHidden) { if (isHidden) {
// Update position before showing // Update position before showing
this.updatePanelPositions(); updatePanelPositions();
this.searchOptionsPanel.classList.remove('hidden'); this.searchOptionsPanel.classList.remove('hidden');
this.searchOptionsToggle.classList.add('active'); this.searchOptionsToggle.classList.add('active');
@@ -267,56 +267,6 @@ export class SearchManager {
return options; return options;
} }
updatePanelPositions() {
const searchOptionsPanel = document.getElementById('searchOptionsPanel');
const filterPanel = document.getElementById('filterPanel');
if (!searchOptionsPanel && !filterPanel) return;
// Get the header element
const header = document.querySelector('.app-header');
if (!header) return;
// Calculate the position based on the bottom of the header
const headerRect = header.getBoundingClientRect();
const topPosition = headerRect.bottom + 5; // Add 5px padding
// Set the positions
if (searchOptionsPanel) {
searchOptionsPanel.style.top = `${topPosition}px`;
// Make sure the panel is visible when positioned
if (!searchOptionsPanel.classList.contains('hidden') &&
window.getComputedStyle(searchOptionsPanel).display === 'none') {
searchOptionsPanel.style.display = 'block';
}
}
if (filterPanel) {
filterPanel.style.top = `${topPosition}px`;
}
// Adjust panel horizontal position based on the search container
const searchContainer = document.querySelector('.header-search');
if (searchContainer) {
const searchRect = searchContainer.getBoundingClientRect();
// Position the search options panel aligned with the search container
if (searchOptionsPanel) {
searchOptionsPanel.style.right = `${window.innerWidth - searchRect.right}px`;
}
// Position the filter panel aligned with the filter button
if (filterPanel) {
const filterButton = document.getElementById('filterButton');
if (filterButton) {
const filterRect = filterButton.getBoundingClientRect();
filterPanel.style.right = `${window.innerWidth - filterRect.right}px`;
}
}
}
}
performSearch() { performSearch() {
const query = this.searchInput.value.trim(); const query = this.searchInput.value.trim();
const options = this.getActiveSearchOptions(); const options = this.getActiveSearchOptions();

View File

@@ -59,6 +59,12 @@ class RecipeManager {
window.importRecipes = () => this.importRecipes(); window.importRecipes = () => this.importRecipes();
window.importManager = this.importManager; window.importManager = this.importManager;
window.loadMoreRecipes = () => this.loadMoreRecipes(); window.loadMoreRecipes = () => this.loadMoreRecipes();
// Add appendRecipeCards function for the search manager to use
window.appendRecipeCards = (recipes) => {
const data = { items: recipes, has_more: false };
this.updateRecipesGrid(data, false);
};
} }
initEventListeners() { initEventListeners() {
@@ -70,28 +76,6 @@ class RecipeManager {
this.loadRecipes(); this.loadRecipes();
}); });
} }
// Search input
const searchInput = document.getElementById('searchInput');
if (searchInput) {
let debounceTimeout;
searchInput.addEventListener('input', () => {
clearTimeout(debounceTimeout);
debounceTimeout = setTimeout(() => {
this.pageState.filters.search = searchInput.value;
this.loadRecipes();
}, 300);
});
}
// Import button
const importButton = document.querySelector('button[onclick="importRecipes()"]');
if (importButton) {
importButton.onclick = (e) => {
e.preventDefault();
this.importManager.showImportModal();
};
}
} }
async loadRecipes(resetPage = true) { async loadRecipes(resetPage = true) {

View File

@@ -106,20 +106,45 @@ export function updatePanelPositions() {
const searchOptionsPanel = document.getElementById('searchOptionsPanel'); const searchOptionsPanel = document.getElementById('searchOptionsPanel');
const filterPanel = document.getElementById('filterPanel'); const filterPanel = document.getElementById('filterPanel');
if (!searchOptionsPanel || !filterPanel) return; if (!searchOptionsPanel && !filterPanel) return;
// Get the controls container // Get the header element
const controls = document.querySelector('.controls'); const header = document.querySelector('.app-header');
if (!controls) return; if (!header) return;
// Calculate the position based on the bottom of the controls container // Calculate the position based on the bottom of the header
const controlsRect = controls.getBoundingClientRect(); const headerRect = header.getBoundingClientRect();
const topPosition = controlsRect.bottom + 10; // Add 10px padding const topPosition = headerRect.bottom + 5; // Add 5px padding
// Set the positions // Set the positions
if (searchOptionsPanel) {
searchOptionsPanel.style.top = `${topPosition}px`; searchOptionsPanel.style.top = `${topPosition}px`;
}
if (filterPanel) {
filterPanel.style.top = `${topPosition}px`; filterPanel.style.top = `${topPosition}px`;
} }
// Adjust panel horizontal position based on the search container
const searchContainer = document.querySelector('.header-search');
if (searchContainer) {
const searchRect = searchContainer.getBoundingClientRect();
// Position the search options panel aligned with the search container
if (searchOptionsPanel) {
searchOptionsPanel.style.right = `${window.innerWidth - searchRect.right}px`;
}
// Position the filter panel aligned with the filter button
if (filterPanel) {
const filterButton = document.getElementById('filterButton');
if (filterButton) {
const filterRect = filterButton.getBoundingClientRect();
filterPanel.style.right = `${window.innerWidth - filterRect.right}px`;
}
}
}
}
// Update the toggleFolderTags function // Update the toggleFolderTags function
export function toggleFolderTags() { export function toggleFolderTags() {
@@ -144,11 +169,7 @@ export function toggleFolderTags() {
// Update panel positions after toggling // Update panel positions after toggling
// Use a small delay to ensure the DOM has updated // Use a small delay to ensure the DOM has updated
setTimeout(() => { setTimeout(() => {
if (window.searchManager && typeof window.searchManager.updatePanelPositions === 'function') {
window.searchManager.updatePanelPositions();
} else if (typeof updatePanelPositions === 'function') {
updatePanelPositions(); updatePanelPositions();
}
}, 50); }, 50);
} }
} }

View File

@@ -77,13 +77,3 @@
{% block main_script %} {% block main_script %}
<script type="module" src="/loras_static/js/recipes.js"></script> <script type="module" src="/loras_static/js/recipes.js"></script>
{% endblock %} {% endblock %}
{% block additional_scripts %}
<script>
// Refresh recipes
function refreshRecipes() {
// Will be implemented in recipes.js
window.location.reload();
}
</script>
{% endblock %}