mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-24 14:42:11 -03:00
Refactor LoRA template with modular components and script updates
This commit is contained in:
8
static/js/utils/debounce.js
Normal file
8
static/js/utils/debounce.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Debounce function
|
||||
export function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function(...args) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => func.apply(this, args), wait);
|
||||
};
|
||||
}
|
||||
29
static/js/utils/infiniteScroll.js
Normal file
29
static/js/utils/infiniteScroll.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { state } from '../state/index.js';
|
||||
import { loadMoreLoras } from '../api/loraApi.js';
|
||||
|
||||
export function initializeInfiniteScroll() {
|
||||
if (state.observer) {
|
||||
state.observer.disconnect();
|
||||
}
|
||||
|
||||
state.observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
const target = entries[0];
|
||||
if (target.isIntersecting && !state.isLoading && state.hasMore) {
|
||||
loadMoreLoras();
|
||||
}
|
||||
},
|
||||
{ threshold: 0.1 }
|
||||
);
|
||||
|
||||
const existingSentinel = document.getElementById('scroll-sentinel');
|
||||
if (existingSentinel) {
|
||||
state.observer.observe(existingSentinel);
|
||||
} else {
|
||||
const sentinel = document.createElement('div');
|
||||
sentinel.id = 'scroll-sentinel';
|
||||
sentinel.style.height = '10px';
|
||||
document.getElementById('loraGrid').appendChild(sentinel);
|
||||
state.observer.observe(sentinel);
|
||||
}
|
||||
}
|
||||
56
static/js/utils/modalUtils.js
Normal file
56
static/js/utils/modalUtils.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import { modalManager } from '../managers/ModalManager.js';
|
||||
|
||||
let pendingDeletePath = null;
|
||||
|
||||
export function showDeleteModal(filePath) {
|
||||
event.stopPropagation();
|
||||
pendingDeletePath = filePath;
|
||||
|
||||
const card = document.querySelector(`.lora-card[data-filepath="${filePath}"]`);
|
||||
const modelName = card.dataset.name;
|
||||
const modal = modalManager.getModal('deleteModal').element;
|
||||
const modelInfo = modal.querySelector('.delete-model-info');
|
||||
|
||||
modelInfo.innerHTML = `
|
||||
<strong>Model:</strong> ${modelName}
|
||||
<br>
|
||||
<strong>File:</strong> ${filePath}
|
||||
`;
|
||||
|
||||
modalManager.showModal('deleteModal');
|
||||
}
|
||||
|
||||
export async function confirmDelete() {
|
||||
if (!pendingDeletePath) return;
|
||||
|
||||
const modal = document.getElementById('deleteModal');
|
||||
const card = document.querySelector(`.lora-card[data-filepath="${pendingDeletePath}"]`);
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/delete_model', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
file_path: pendingDeletePath
|
||||
})
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
if (card) {
|
||||
card.remove();
|
||||
}
|
||||
closeDeleteModal();
|
||||
} else {
|
||||
const error = await response.text();
|
||||
alert(`Failed to delete model: ${error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
alert(`Error deleting model: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function closeDeleteModal() {
|
||||
modalManager.closeModal('deleteModal');
|
||||
}
|
||||
88
static/js/utils/uiHelpers.js
Normal file
88
static/js/utils/uiHelpers.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import { state } from '../state/index.js';
|
||||
import { resetAndReload } from '../api/loraApi.js';
|
||||
|
||||
export function showToast(message, type = 'info') {
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.textContent = message;
|
||||
document.body.append(toast);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
toast.classList.add('show');
|
||||
setTimeout(() => toast.remove(), 2300);
|
||||
});
|
||||
}
|
||||
|
||||
export function lazyLoadImages() {
|
||||
const observer = new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting && entry.target.dataset.src) {
|
||||
entry.target.src = entry.target.dataset.src;
|
||||
observer.unobserve(entry.target);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));
|
||||
}
|
||||
|
||||
export function restoreFolderFilter() {
|
||||
const activeFolder = localStorage.getItem('activeFolder');
|
||||
const folderTag = activeFolder && document.querySelector(`.tag[data-folder="${activeFolder}"]`);
|
||||
if (folderTag) {
|
||||
folderTag.classList.add('active');
|
||||
filterByFolder(activeFolder);
|
||||
}
|
||||
}
|
||||
|
||||
export function initTheme() {
|
||||
document.body.dataset.theme = localStorage.getItem('theme') || 'dark';
|
||||
}
|
||||
|
||||
export function toggleTheme() {
|
||||
const theme = document.body.dataset.theme === 'light' ? 'dark' : 'light';
|
||||
document.body.dataset.theme = theme;
|
||||
localStorage.setItem('theme', theme);
|
||||
}
|
||||
|
||||
export function toggleFolder(tag) {
|
||||
const tagElement = (tag instanceof HTMLElement) ? tag : this;
|
||||
const folder = tagElement.dataset.folder;
|
||||
const wasActive = tagElement.classList.contains('active');
|
||||
|
||||
document.querySelectorAll('.folder-tags .tag').forEach(t => {
|
||||
t.classList.remove('active');
|
||||
});
|
||||
|
||||
if (!wasActive) {
|
||||
tagElement.classList.add('active');
|
||||
state.activeFolder = folder;
|
||||
} else {
|
||||
state.activeFolder = null;
|
||||
}
|
||||
|
||||
resetAndReload();
|
||||
}
|
||||
|
||||
export function copyTriggerWord(word) {
|
||||
navigator.clipboard.writeText(word).then(() => {
|
||||
const toast = document.createElement('div');
|
||||
toast.className = 'toast toast-copy';
|
||||
toast.textContent = 'Copied!';
|
||||
document.body.appendChild(toast);
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
toast.classList.add('show');
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
setTimeout(() => toast.remove(), 300);
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function filterByFolder(folderPath) {
|
||||
document.querySelectorAll('.lora-card').forEach(card => {
|
||||
card.style.display = card.dataset.folder === folderPath ? '' : 'none';
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user