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:
Will Miao
2025-03-19 16:15:18 +08:00
parent f9c54690b0
commit 7924e4000c
5 changed files with 164 additions and 134 deletions

View File

@@ -706,9 +706,10 @@ function initLazyLoading(container) {
}
export function setupShowcaseScroll() {
// Change from modal-content to window/document level
// Add event listener to document for wheel events
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;
const showcase = modalContent.querySelector('.showcase-section');
@@ -725,24 +726,52 @@ export function setupShowcaseScroll() {
event.preventDefault();
}
}
}, { passive: false }); // Add passive: false option here
}, { passive: false });
// Keep the existing scroll tracking code
const modalContent = document.querySelector('.modal-content');
if (modalContent) {
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');
// Use MutationObserver instead of deprecated DOMNodeInserted
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type === 'childList' && mutation.addedNodes.length) {
// Check if loraModal content was added
const loraModal = document.getElementById('loraModal');
if (loraModal && loraModal.querySelector('.modal-content')) {
setupBackToTopButton(loraModal.querySelector('.modal-content'));
}
}
});
}
});
// 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) {
const modalContent = button.closest('.modal-content');
if (modalContent) {

View File

@@ -111,13 +111,11 @@ export class RecipeSearchManager extends SearchManager {
}
resetAndReloadRecipes() {
// This function would be implemented in the recipes page
// Similar to resetAndReload for loras
if (typeof window.loadRecipes === 'function') {
window.loadRecipes();
if (window.recipeManager && typeof window.recipeManager.loadRecipes === 'function') {
window.recipeManager.loadRecipes();
} else {
// Fallback to reloading the page
window.location.reload();
window.location.reload();
}
}

View 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')">&times;</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')">&times;</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>

View File

@@ -1,6 +1,3 @@
<!-- Model details Modal -->
<div id="loraModal" class="modal"></div>
<!-- Delete Confirmation Modal -->
<div id="deleteModal" class="modal delete-modal">
<div class="modal-content delete-modal-content">
@@ -14,118 +11,6 @@
</div>
</div>
<!-- Download from URL Modal -->
<div id="downloadModal" class="modal">
<div class="modal-content">
<button class="close" onclick="modalManager.closeModal('downloadModal')">&times;</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')">&times;</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 -->
<div id="settingsModal" class="modal">
<div class="modal-content settings-modal">

View File

@@ -11,6 +11,10 @@
{% 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 additional_components %}
{% include 'components/lora_modals.html' %}
{% endblock %}
{% block content %}
{% include 'components/controls.html' %}
<!-- Lora卡片容器 -->