mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 23:25:43 -03:00
Refactor LoraModal and RecipeSearchManager for improved functionality and performance
- Updated LoraModal to enhance lazy loading and scroll behavior, utilizing MutationObserver for dynamic content changes and adding a new helper function for the back-to-top button. - Modified RecipeSearchManager to ensure proper recipe loading through the window.recipeManager object, improving reliability in recipe reloading. - Added additional components to loras.html for better modularity and organization of the modal structure.
This commit is contained in:
@@ -706,9 +706,10 @@ function initLazyLoading(container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function setupShowcaseScroll() {
|
export function setupShowcaseScroll() {
|
||||||
// Change from modal-content to window/document level
|
// Add event listener to document for wheel events
|
||||||
document.addEventListener('wheel', (event) => {
|
document.addEventListener('wheel', (event) => {
|
||||||
const modalContent = document.querySelector('.modal-content');
|
// Find the active modal content
|
||||||
|
const modalContent = document.querySelector('#loraModal .modal-content');
|
||||||
if (!modalContent) return;
|
if (!modalContent) return;
|
||||||
|
|
||||||
const showcase = modalContent.querySelector('.showcase-section');
|
const showcase = modalContent.querySelector('.showcase-section');
|
||||||
@@ -725,24 +726,52 @@ export function setupShowcaseScroll() {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, { passive: false }); // Add passive: false option here
|
}, { passive: false });
|
||||||
|
|
||||||
// Keep the existing scroll tracking code
|
// Use MutationObserver instead of deprecated DOMNodeInserted
|
||||||
const modalContent = document.querySelector('.modal-content');
|
const observer = new MutationObserver((mutations) => {
|
||||||
if (modalContent) {
|
for (const mutation of mutations) {
|
||||||
modalContent.addEventListener('scroll', () => {
|
if (mutation.type === 'childList' && mutation.addedNodes.length) {
|
||||||
const backToTopBtn = modalContent.querySelector('.back-to-top');
|
// Check if loraModal content was added
|
||||||
if (backToTopBtn) {
|
const loraModal = document.getElementById('loraModal');
|
||||||
if (modalContent.scrollTop > 300) {
|
if (loraModal && loraModal.querySelector('.modal-content')) {
|
||||||
backToTopBtn.classList.add('visible');
|
setupBackToTopButton(loraModal.querySelector('.modal-content'));
|
||||||
} else {
|
|
||||||
backToTopBtn.classList.remove('visible');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start observing the document body for changes
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
|
||||||
|
// Also try to set up the button immediately in case the modal is already open
|
||||||
|
const modalContent = document.querySelector('#loraModal .modal-content');
|
||||||
|
if (modalContent) {
|
||||||
|
setupBackToTopButton(modalContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New helper function to set up the back to top button
|
||||||
|
function setupBackToTopButton(modalContent) {
|
||||||
|
// Remove any existing scroll listeners to avoid duplicates
|
||||||
|
modalContent.onscroll = null;
|
||||||
|
|
||||||
|
// Add new scroll listener
|
||||||
|
modalContent.addEventListener('scroll', () => {
|
||||||
|
const backToTopBtn = modalContent.querySelector('.back-to-top');
|
||||||
|
if (backToTopBtn) {
|
||||||
|
if (modalContent.scrollTop > 300) {
|
||||||
|
backToTopBtn.classList.add('visible');
|
||||||
|
} else {
|
||||||
|
backToTopBtn.classList.remove('visible');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Trigger a scroll event to check initial position
|
||||||
|
modalContent.dispatchEvent(new Event('scroll'));
|
||||||
|
}
|
||||||
|
|
||||||
export function scrollToTop(button) {
|
export function scrollToTop(button) {
|
||||||
const modalContent = button.closest('.modal-content');
|
const modalContent = button.closest('.modal-content');
|
||||||
if (modalContent) {
|
if (modalContent) {
|
||||||
|
|||||||
@@ -111,10 +111,8 @@ export class RecipeSearchManager extends SearchManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resetAndReloadRecipes() {
|
resetAndReloadRecipes() {
|
||||||
// This function would be implemented in the recipes page
|
if (window.recipeManager && typeof window.recipeManager.loadRecipes === 'function') {
|
||||||
// Similar to resetAndReload for loras
|
window.recipeManager.loadRecipes();
|
||||||
if (typeof window.loadRecipes === 'function') {
|
|
||||||
window.loadRecipes();
|
|
||||||
} else {
|
} else {
|
||||||
// Fallback to reloading the page
|
// Fallback to reloading the page
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
|
|||||||
114
templates/components/lora_modals.html
Normal file
114
templates/components/lora_modals.html
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
<!-- Model details Modal -->
|
||||||
|
<div id="loraModal" class="modal"></div>
|
||||||
|
|
||||||
|
<!-- Download from URL Modal -->
|
||||||
|
<div id="downloadModal" class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<button class="close" onclick="modalManager.closeModal('downloadModal')">×</button>
|
||||||
|
<h2>Download LoRA from URL</h2>
|
||||||
|
|
||||||
|
<!-- Step 1: URL Input -->
|
||||||
|
<div class="download-step" id="urlStep">
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="loraUrl">Civitai URL:</label>
|
||||||
|
<input type="text" id="loraUrl" placeholder="https://civitai.com/models/..." />
|
||||||
|
<div class="error-message" id="urlError"></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-actions">
|
||||||
|
<button class="primary-btn" onclick="downloadManager.validateAndFetchVersions()">Next</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Step 2: Version Selection -->
|
||||||
|
<div class="download-step" id="versionStep" style="display: none;">
|
||||||
|
<div class="version-list" id="versionList">
|
||||||
|
<!-- Versions will be inserted here dynamically -->
|
||||||
|
</div>
|
||||||
|
<div class="modal-actions">
|
||||||
|
<button class="secondary-btn" onclick="downloadManager.backToUrl()">Back</button>
|
||||||
|
<button class="primary-btn" onclick="downloadManager.proceedToLocation()">Next</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Step 3: Location Selection -->
|
||||||
|
<div class="download-step" id="locationStep" style="display: none;">
|
||||||
|
<div class="location-selection">
|
||||||
|
<!-- Move path preview to top -->
|
||||||
|
<div class="path-preview">
|
||||||
|
<label>Download Location Preview:</label>
|
||||||
|
<div class="path-display" id="targetPathDisplay">
|
||||||
|
<span class="path-text">Select a LoRA root directory</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<label>Select LoRA Root:</label>
|
||||||
|
<select id="loraRoot"></select>
|
||||||
|
</div>
|
||||||
|
<div class="input-group">
|
||||||
|
<label>Target Folder:</label>
|
||||||
|
<div class="folder-browser" id="folderBrowser">
|
||||||
|
{% for folder in folders %}
|
||||||
|
{% if folder %}
|
||||||
|
<div class="folder-item" data-folder="{{ folder }}">
|
||||||
|
{{ folder }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="newFolder">New Folder (optional):</label>
|
||||||
|
<input type="text" id="newFolder" placeholder="Enter folder name" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-actions">
|
||||||
|
<button class="secondary-btn" onclick="downloadManager.backToVersions()">Back</button>
|
||||||
|
<button class="primary-btn" onclick="downloadManager.startDownload()">Download</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Move Model Modal -->
|
||||||
|
<div id="moveModal" class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2 id="moveModalTitle">Move Model</h2>
|
||||||
|
<span class="close" onclick="modalManager.closeModal('moveModal')">×</span>
|
||||||
|
</div>
|
||||||
|
<div class="location-selection">
|
||||||
|
<div class="path-preview">
|
||||||
|
<label>Target Location Preview:</label>
|
||||||
|
<div class="path-display" id="moveTargetPathDisplay">
|
||||||
|
<span class="path-text">Select a LoRA root directory</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-group">
|
||||||
|
<label>Select LoRA Root:</label>
|
||||||
|
<select id="moveLoraRoot"></select>
|
||||||
|
</div>
|
||||||
|
<div class="input-group">
|
||||||
|
<label>Target Folder:</label>
|
||||||
|
<div class="folder-browser" id="moveFolderBrowser">
|
||||||
|
{% for folder in folders %}
|
||||||
|
{% if folder %}
|
||||||
|
<div class="folder-item" data-folder="{{ folder }}">
|
||||||
|
{{ folder }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="moveNewFolder">New Folder (optional):</label>
|
||||||
|
<input type="text" id="moveNewFolder" placeholder="Enter folder name" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-actions">
|
||||||
|
<button class="cancel-btn" onclick="modalManager.closeModal('moveModal')">Cancel</button>
|
||||||
|
<button class="primary-btn" onclick="moveManager.moveModel()">Move</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
<!-- Model details Modal -->
|
|
||||||
<div id="loraModal" class="modal"></div>
|
|
||||||
|
|
||||||
<!-- Delete Confirmation Modal -->
|
<!-- Delete Confirmation Modal -->
|
||||||
<div id="deleteModal" class="modal delete-modal">
|
<div id="deleteModal" class="modal delete-modal">
|
||||||
<div class="modal-content delete-modal-content">
|
<div class="modal-content delete-modal-content">
|
||||||
@@ -14,118 +11,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Download from URL Modal -->
|
|
||||||
<div id="downloadModal" class="modal">
|
|
||||||
<div class="modal-content">
|
|
||||||
<button class="close" onclick="modalManager.closeModal('downloadModal')">×</button>
|
|
||||||
<h2>Download LoRA from URL</h2>
|
|
||||||
|
|
||||||
<!-- Step 1: URL Input -->
|
|
||||||
<div class="download-step" id="urlStep">
|
|
||||||
<div class="input-group">
|
|
||||||
<label for="loraUrl">Civitai URL:</label>
|
|
||||||
<input type="text" id="loraUrl" placeholder="https://civitai.com/models/..." />
|
|
||||||
<div class="error-message" id="urlError"></div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-actions">
|
|
||||||
<button class="primary-btn" onclick="downloadManager.validateAndFetchVersions()">Next</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Step 2: Version Selection -->
|
|
||||||
<div class="download-step" id="versionStep" style="display: none;">
|
|
||||||
<div class="version-list" id="versionList">
|
|
||||||
<!-- Versions will be inserted here dynamically -->
|
|
||||||
</div>
|
|
||||||
<div class="modal-actions">
|
|
||||||
<button class="secondary-btn" onclick="downloadManager.backToUrl()">Back</button>
|
|
||||||
<button class="primary-btn" onclick="downloadManager.proceedToLocation()">Next</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Step 3: Location Selection -->
|
|
||||||
<div class="download-step" id="locationStep" style="display: none;">
|
|
||||||
<div class="location-selection">
|
|
||||||
<!-- Move path preview to top -->
|
|
||||||
<div class="path-preview">
|
|
||||||
<label>Download Location Preview:</label>
|
|
||||||
<div class="path-display" id="targetPathDisplay">
|
|
||||||
<span class="path-text">Select a LoRA root directory</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="input-group">
|
|
||||||
<label>Select LoRA Root:</label>
|
|
||||||
<select id="loraRoot"></select>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<label>Target Folder:</label>
|
|
||||||
<div class="folder-browser" id="folderBrowser">
|
|
||||||
{% for folder in folders %}
|
|
||||||
{% if folder %}
|
|
||||||
<div class="folder-item" data-folder="{{ folder }}">
|
|
||||||
{{ folder }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<label for="newFolder">New Folder (optional):</label>
|
|
||||||
<input type="text" id="newFolder" placeholder="Enter folder name" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-actions">
|
|
||||||
<button class="secondary-btn" onclick="downloadManager.backToVersions()">Back</button>
|
|
||||||
<button class="primary-btn" onclick="downloadManager.startDownload()">Download</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Move Model Modal -->
|
|
||||||
<div id="moveModal" class="modal">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h2 id="moveModalTitle">Move Model</h2>
|
|
||||||
<span class="close" onclick="modalManager.closeModal('moveModal')">×</span>
|
|
||||||
</div>
|
|
||||||
<div class="location-selection">
|
|
||||||
<div class="path-preview">
|
|
||||||
<label>Target Location Preview:</label>
|
|
||||||
<div class="path-display" id="moveTargetPathDisplay">
|
|
||||||
<span class="path-text">Select a LoRA root directory</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="input-group">
|
|
||||||
<label>Select LoRA Root:</label>
|
|
||||||
<select id="moveLoraRoot"></select>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<label>Target Folder:</label>
|
|
||||||
<div class="folder-browser" id="moveFolderBrowser">
|
|
||||||
{% for folder in folders %}
|
|
||||||
{% if folder %}
|
|
||||||
<div class="folder-item" data-folder="{{ folder }}">
|
|
||||||
{{ folder }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="input-group">
|
|
||||||
<label for="moveNewFolder">New Folder (optional):</label>
|
|
||||||
<input type="text" id="moveNewFolder" placeholder="Enter folder name" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-actions">
|
|
||||||
<button class="cancel-btn" onclick="modalManager.closeModal('moveModal')">Cancel</button>
|
|
||||||
<button class="primary-btn" onclick="moveManager.moveModel()">Move</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Settings Modal -->
|
<!-- Settings Modal -->
|
||||||
<div id="settingsModal" class="modal">
|
<div id="settingsModal" class="modal">
|
||||||
<div class="modal-content settings-modal">
|
<div class="modal-content settings-modal">
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
{% block init_message %}Scanning and building LoRA cache. This may take a few minutes...{% endblock %}
|
{% block init_message %}Scanning and building LoRA cache. This may take a few minutes...{% endblock %}
|
||||||
{% block init_check_url %}/api/loras?page=1&page_size=1{% endblock %}
|
{% block init_check_url %}/api/loras?page=1&page_size=1{% endblock %}
|
||||||
|
|
||||||
|
{% block additional_components %}
|
||||||
|
{% include 'components/lora_modals.html' %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% include 'components/controls.html' %}
|
{% include 'components/controls.html' %}
|
||||||
<!-- Lora卡片容器 -->
|
<!-- Lora卡片容器 -->
|
||||||
|
|||||||
Reference in New Issue
Block a user