Add filters - checkpoint

This commit is contained in:
Will Miao
2025-03-05 19:07:11 +08:00
parent 879df0d563
commit c17f2c885a
6 changed files with 428 additions and 8 deletions

View File

@@ -24,6 +24,7 @@ import { DownloadManager } from './managers/DownloadManager.js';
import { SettingsManager, toggleApiKeyVisibility } from './managers/SettingsManager.js';
import { LoraContextMenu } from './components/ContextMenu.js';
import { moveManager } from './managers/MoveManager.js';
import { FilterManager } from './managers/FilterManager.js';
// Export all functions that need global access
window.loadMoreLoras = loadMoreLoras;
@@ -53,6 +54,7 @@ document.addEventListener('DOMContentLoaded', () => {
state.loadingManager = new LoadingManager();
modalManager.initialize(); // Initialize modalManager after DOM is loaded
window.downloadManager = new DownloadManager(); // Move this after modalManager initialization
window.filterManager = new FilterManager(); // Initialize filter manager
initializeInfiniteScroll();
initializeEventListeners();
lazyLoadImages();

View File

@@ -0,0 +1,159 @@
import { BASE_MODELS, BASE_MODEL_CLASSES } from '../utils/constants.js';
import { state } from '../state/index.js';
import { showToast } from '../utils/uiHelpers.js';
export class FilterManager {
constructor() {
this.filters = {
baseModel: []
};
this.filterPanel = document.getElementById('filterPanel');
this.filterButton = document.getElementById('filterButton');
this.activeFiltersCount = document.getElementById('activeFiltersCount');
this.initialize();
}
initialize() {
// Create base model filter tags
this.createBaseModelTags();
// Close filter panel when clicking outside
document.addEventListener('click', (e) => {
if (!this.filterPanel.contains(e.target) &&
e.target !== this.filterButton &&
!this.filterButton.contains(e.target) &&
!this.filterPanel.classList.contains('hidden')) {
this.closeFilterPanel();
}
});
// Initialize active filters from localStorage if available
this.loadFiltersFromStorage();
}
createBaseModelTags() {
const baseModelTagsContainer = document.getElementById('baseModelTags');
if (!baseModelTagsContainer) return;
baseModelTagsContainer.innerHTML = '';
Object.entries(BASE_MODELS).forEach(([key, value]) => {
const tag = document.createElement('div');
tag.className = `filter-tag base-model-tag ${BASE_MODEL_CLASSES[value]}`;
tag.dataset.baseModel = value;
tag.innerHTML = value;
// Add click handler to toggle selection
tag.addEventListener('click', () => {
tag.classList.toggle('active');
if (tag.classList.contains('active')) {
if (!this.filters.baseModel.includes(value)) {
this.filters.baseModel.push(value);
}
} else {
this.filters.baseModel = this.filters.baseModel.filter(model => model !== value);
}
this.updateActiveFiltersCount();
});
baseModelTagsContainer.appendChild(tag);
});
}
toggleFilterPanel() {
this.filterPanel.classList.toggle('hidden');
// Mark selected filters
if (!this.filterPanel.classList.contains('hidden')) {
this.updateTagSelections();
}
}
closeFilterPanel() {
this.filterPanel.classList.add('hidden');
}
updateTagSelections() {
// Update base model tags
const baseModelTags = document.querySelectorAll('.base-model-tag');
baseModelTags.forEach(tag => {
const baseModel = tag.dataset.baseModel;
if (this.filters.baseModel.includes(baseModel)) {
tag.classList.add('active');
} else {
tag.classList.remove('active');
}
});
}
updateActiveFiltersCount() {
const totalActiveFilters = this.filters.baseModel.length;
if (totalActiveFilters > 0) {
this.activeFiltersCount.textContent = totalActiveFilters;
this.activeFiltersCount.style.display = 'inline-flex';
} else {
this.activeFiltersCount.style.display = 'none';
}
}
applyFilters() {
// Save filters to localStorage
localStorage.setItem('loraFilters', JSON.stringify(this.filters));
// Apply filters to cards (will be implemented later)
showToast('Filters applied', 'success');
// Close the filter panel
this.closeFilterPanel();
// Update filter button to show active state
if (this.hasActiveFilters()) {
this.filterButton.classList.add('active');
} else {
this.filterButton.classList.remove('active');
}
}
clearFilters() {
// Clear all filters
this.filters = {
baseModel: []
};
// Update UI
this.updateTagSelections();
this.updateActiveFiltersCount();
// Remove from localStorage
localStorage.removeItem('loraFilters');
this.filterButton.classList.remove('active');
showToast('All filters cleared', 'info');
}
loadFiltersFromStorage() {
const savedFilters = localStorage.getItem('loraFilters');
if (savedFilters) {
try {
this.filters = JSON.parse(savedFilters);
this.updateTagSelections();
this.updateActiveFiltersCount();
if (this.hasActiveFilters()) {
this.filterButton.classList.add('active');
}
} catch (error) {
console.error('Error loading filters from storage:', error);
}
}
}
hasActiveFilters() {
return this.filters.baseModel.length > 0;
}
}

View File

@@ -7,5 +7,8 @@ export const state = {
loadingManager: null,
observer: null,
previewVersions: new Map(),
searchManager: null // 添加 searchManager
searchManager: null,
filters: {
baseModel: []
}
};

View File

@@ -0,0 +1,24 @@
export const BASE_MODELS = {
SD_1_5: "SD1.5",
SD_2_0: "SD2.0",
SD_2_1: "SD2.1",
SDXL: "SDXL",
FLUX_1_D: "Flux.1 D",
IL: "IL",
PONY: "Pony",
HUNYUAN_VIDEO: "Hunyuan Video",
UNKNOWN: "Unknown"
};
// Base model display names and their corresponding class names (for styling)
export const BASE_MODEL_CLASSES = {
[BASE_MODELS.SD_1_5]: "sd-1-5",
[BASE_MODELS.SD_2_0]: "sd-2-0",
[BASE_MODELS.SD_2_1]: "sd-2-1",
[BASE_MODELS.SDXL]: "sdxl",
[BASE_MODELS.FLUX_1_D]: "flux",
[BASE_MODELS.IL]: "il",
[BASE_MODELS.PONY]: "pony",
[BASE_MODELS.HUNYUAN_VIDEO]: "hunyuan",
[BASE_MODELS.UNKNOWN]: "unknown"
};