mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 15:15:44 -03:00
Enhance settings modal with video autoplay on hover option and improve layout. Fixes https://github.com/willmiao/ComfyUI-Lora-Manager/issues/92
This commit is contained in:
@@ -196,7 +196,7 @@ body.modal-open {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.settings-modal {
|
.settings-modal {
|
||||||
max-width: 500px;
|
max-width: 650px; /* Further increased from 600px for more space */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Settings Links */
|
/* Settings Links */
|
||||||
@@ -266,14 +266,22 @@ body.modal-open {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* API key input specific styles */
|
||||||
.api-key-input {
|
.api-key-input {
|
||||||
|
width: 100%; /* Take full width of parent */
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.api-key-input input {
|
.api-key-input input {
|
||||||
padding-right: 40px;
|
width: 100%;
|
||||||
|
padding: 6px 40px 6px 10px; /* Add left padding */
|
||||||
|
height: 32px;
|
||||||
|
border-radius: var(--border-radius-xs);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
background-color: var(--lora-surface);
|
||||||
|
color: var(--text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.api-key-input .toggle-visibility {
|
.api-key-input .toggle-visibility {
|
||||||
@@ -294,8 +302,10 @@ body.modal-open {
|
|||||||
.input-help {
|
.input-help {
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
opacity: 0.8;
|
opacity: 0.7;
|
||||||
margin-top: 4px;
|
margin-top: 8px; /* Space between control and help */
|
||||||
|
line-height: 1.4;
|
||||||
|
width: 100%; /* Full width */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 统一各个 section 的样式 */
|
/* 统一各个 section 的样式 */
|
||||||
@@ -341,8 +351,8 @@ body.modal-open {
|
|||||||
|
|
||||||
.setting-item {
|
.setting-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column; /* Changed to column for help text placement */
|
||||||
margin-bottom: var(--space-2);
|
margin-bottom: var(--space-3); /* Increased to provide more spacing between items */
|
||||||
padding: var(--space-1);
|
padding: var(--space-1);
|
||||||
border-radius: var(--border-radius-xs);
|
border-radius: var(--border-radius-xs);
|
||||||
}
|
}
|
||||||
@@ -355,35 +365,52 @@ body.modal-open {
|
|||||||
background: rgba(255, 255, 255, 0.05);
|
background: rgba(255, 255, 255, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-info {
|
/* Control row with label and input together */
|
||||||
margin-bottom: var(--space-1);
|
.setting-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.setting-info {
|
||||||
|
margin-bottom: 0;
|
||||||
|
width: 35%; /* Increased from 30% to prevent wrapping */
|
||||||
|
flex-shrink: 0; /* Prevent shrinking */
|
||||||
|
}
|
||||||
|
|
||||||
.setting-info label {
|
.setting-info label {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: 4px;
|
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
margin-bottom: 0;
|
||||||
|
white-space: nowrap; /* Prevent label wrapping */
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-control {
|
.setting-control {
|
||||||
width: 100%;
|
width: 60%; /* Decreased slightly from 65% */
|
||||||
margin-bottom: var(--space-1);
|
margin-bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end; /* Right-align all controls */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Select Control Styles */
|
/* Select Control Styles */
|
||||||
.select-control {
|
.select-control {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.select-control select {
|
.select-control select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
max-width: 100%; /* Increased from 200px */
|
||||||
padding: 6px 10px;
|
padding: 6px 10px;
|
||||||
border-radius: var(--border-radius-xs);
|
border-radius: var(--border-radius-xs);
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
background-color: var(--lora-surface);
|
background-color: var(--lora-surface);
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
font-size: 0.95em;
|
font-size: 0.95em;
|
||||||
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fix dark theme select dropdown text color */
|
/* Fix dark theme select dropdown text color */
|
||||||
@@ -409,6 +436,7 @@ body.modal-open {
|
|||||||
width: 50px;
|
width: 50px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
margin-left: auto; /* Push to right side */
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-switch input {
|
.toggle-switch input {
|
||||||
@@ -458,15 +486,6 @@ input:checked + .toggle-slider:before {
|
|||||||
width: 22px;
|
width: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update input help styles */
|
|
||||||
.input-help {
|
|
||||||
font-size: 0.85em;
|
|
||||||
color: var(--text-color);
|
|
||||||
opacity: 0.7;
|
|
||||||
margin-top: 4px;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Blur effect for NSFW content */
|
/* Blur effect for NSFW content */
|
||||||
.nsfw-blur {
|
.nsfw-blur {
|
||||||
filter: blur(12px);
|
filter: blur(12px);
|
||||||
|
|||||||
@@ -57,10 +57,15 @@ export function createLoraCard(lora) {
|
|||||||
nsfwText = "R-rated Content";
|
nsfwText = "R-rated Content";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if autoplayOnHover is enabled for video previews
|
||||||
|
const autoplayOnHover = state.global.settings.autoplayOnHover || false;
|
||||||
|
const isVideo = previewUrl.endsWith('.mp4');
|
||||||
|
const videoAttrs = autoplayOnHover ? 'controls muted loop' : 'controls autoplay muted loop';
|
||||||
|
|
||||||
card.innerHTML = `
|
card.innerHTML = `
|
||||||
<div class="card-preview ${shouldBlur ? 'blurred' : ''}">
|
<div class="card-preview ${shouldBlur ? 'blurred' : ''}">
|
||||||
${previewUrl.endsWith('.mp4') ?
|
${isVideo ?
|
||||||
`<video controls autoplay muted loop>
|
`<video ${videoAttrs}>
|
||||||
<source src="${versionedPreviewUrl}" type="video/mp4">
|
<source src="${versionedPreviewUrl}" type="video/mp4">
|
||||||
</video>` :
|
</video>` :
|
||||||
`<img src="${versionedPreviewUrl}" alt="${lora.model_name}">`
|
`<img src="${versionedPreviewUrl}" alt="${lora.model_name}">`
|
||||||
@@ -246,6 +251,26 @@ export function createLoraCard(lora) {
|
|||||||
actionGroup.style.display = 'none';
|
actionGroup.style.display = 'none';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add autoplayOnHover handlers for video elements if needed
|
||||||
|
const videoElement = card.querySelector('video');
|
||||||
|
if (videoElement && autoplayOnHover) {
|
||||||
|
const cardPreview = card.querySelector('.card-preview');
|
||||||
|
|
||||||
|
// Remove autoplay attribute and pause initially
|
||||||
|
videoElement.removeAttribute('autoplay');
|
||||||
|
videoElement.pause();
|
||||||
|
|
||||||
|
// Add mouse events to trigger play/pause
|
||||||
|
cardPreview.addEventListener('mouseenter', () => {
|
||||||
|
videoElement.play();
|
||||||
|
});
|
||||||
|
|
||||||
|
cardPreview.addEventListener('mouseleave', () => {
|
||||||
|
videoElement.pause();
|
||||||
|
videoElement.currentTime = 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { LoadingManager } from './managers/LoadingManager.js';
|
|||||||
import { modalManager } from './managers/ModalManager.js';
|
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, 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';
|
||||||
import { migrateStorageItems } from './utils/storageHelpers.js';
|
import { migrateStorageItems } from './utils/storageHelpers.js';
|
||||||
@@ -26,7 +26,7 @@ export class AppCore {
|
|||||||
modalManager.initialize();
|
modalManager.initialize();
|
||||||
updateService.initialize();
|
updateService.initialize();
|
||||||
window.modalManager = modalManager;
|
window.modalManager = modalManager;
|
||||||
window.settingsManager = new SettingsManager();
|
window.settingsManager = settingsManager;
|
||||||
|
|
||||||
// Initialize UI components
|
// Initialize UI components
|
||||||
window.headerManager = new HeaderManager();
|
window.headerManager = new HeaderManager();
|
||||||
@@ -76,4 +76,4 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
export const appCore = new AppCore();
|
export const appCore = new AppCore();
|
||||||
|
|
||||||
// Export common utilities for global use
|
// Export common utilities for global use
|
||||||
export { showToast, lazyLoadImages, initializeInfiniteScroll };
|
export { showToast, lazyLoadImages, initializeInfiniteScroll };
|
||||||
@@ -65,6 +65,12 @@ export class SettingsManager {
|
|||||||
// Sync with state (backend will set this via template)
|
// Sync with state (backend will set this via template)
|
||||||
state.global.settings.show_only_sfw = showOnlySFWCheckbox.checked;
|
state.global.settings.show_only_sfw = showOnlySFWCheckbox.checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set video autoplay on hover setting
|
||||||
|
const autoplayOnHoverCheckbox = document.getElementById('autoplayOnHover');
|
||||||
|
if (autoplayOnHoverCheckbox) {
|
||||||
|
autoplayOnHoverCheckbox.checked = state.global.settings.autoplayOnHover || false;
|
||||||
|
}
|
||||||
|
|
||||||
// Load default lora root
|
// Load default lora root
|
||||||
await this.loadLoraRoots();
|
await this.loadLoraRoots();
|
||||||
@@ -120,11 +126,170 @@ export class SettingsManager {
|
|||||||
this.isOpen = !this.isOpen;
|
this.isOpen = !this.isOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auto-save methods for different control types
|
||||||
|
|
||||||
|
// For toggle switches
|
||||||
|
async saveToggleSetting(elementId, settingKey) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (!element) return;
|
||||||
|
|
||||||
|
const value = element.checked;
|
||||||
|
|
||||||
|
// Update frontend state
|
||||||
|
if (settingKey === 'blur_mature_content') {
|
||||||
|
state.global.settings.blurMatureContent = value;
|
||||||
|
} else if (settingKey === 'show_only_sfw') {
|
||||||
|
state.global.settings.show_only_sfw = value;
|
||||||
|
} else if (settingKey === 'autoplay_on_hover') {
|
||||||
|
state.global.settings.autoplayOnHover = value;
|
||||||
|
} else {
|
||||||
|
// For any other settings that might be added in the future
|
||||||
|
state.global.settings[settingKey] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save to localStorage
|
||||||
|
setStorageItem('settings', state.global.settings);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// For backend settings, make API call
|
||||||
|
if (['show_only_sfw', 'blur_mature_content', 'autoplay_on_hover'].includes(settingKey)) {
|
||||||
|
const payload = {};
|
||||||
|
payload[settingKey] = value;
|
||||||
|
|
||||||
|
const response = await fetch('/api/settings', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to save setting');
|
||||||
|
}
|
||||||
|
|
||||||
|
showToast(`${settingKey.replace(/_/g, ' ')} updated`, 'success');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply frontend settings immediately
|
||||||
|
this.applyFrontendSettings();
|
||||||
|
|
||||||
|
if (settingKey === 'show_only_sfw') {
|
||||||
|
this.reloadContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
showToast('Failed to save setting: ' + error.message, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For select dropdowns
|
||||||
|
async saveSelectSetting(elementId, settingKey) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (!element) return;
|
||||||
|
|
||||||
|
const value = element.value;
|
||||||
|
|
||||||
|
// Update frontend state
|
||||||
|
if (settingKey === 'default_lora_root') {
|
||||||
|
state.global.settings.default_loras_root = value;
|
||||||
|
} else {
|
||||||
|
// For any other settings that might be added in the future
|
||||||
|
state.global.settings[settingKey] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save to localStorage
|
||||||
|
setStorageItem('settings', state.global.settings);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// For backend settings, make API call
|
||||||
|
const payload = {};
|
||||||
|
payload[settingKey] = value;
|
||||||
|
|
||||||
|
const response = await fetch('/api/settings', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to save setting');
|
||||||
|
}
|
||||||
|
|
||||||
|
showToast(`${settingKey.replace(/_/g, ' ')} updated`, 'success');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
showToast('Failed to save setting: ' + error.message, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For input fields
|
||||||
|
async saveInputSetting(elementId, settingKey) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (!element) return;
|
||||||
|
|
||||||
|
const value = element.value;
|
||||||
|
|
||||||
|
// For API key or other inputs that need to be saved on backend
|
||||||
|
try {
|
||||||
|
// Check if value has changed from existing value
|
||||||
|
const currentValue = state.global.settings[settingKey] || '';
|
||||||
|
if (value === currentValue) {
|
||||||
|
return; // No change, exit early
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update state
|
||||||
|
state.global.settings[settingKey] = value;
|
||||||
|
|
||||||
|
// Save to localStorage if appropriate
|
||||||
|
if (!settingKey.includes('api_key')) { // Don't store API keys in localStorage for security
|
||||||
|
setStorageItem('settings', state.global.settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For backend settings, make API call
|
||||||
|
const payload = {};
|
||||||
|
payload[settingKey] = value;
|
||||||
|
|
||||||
|
const response = await fetch('/api/settings', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(payload)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to save setting');
|
||||||
|
}
|
||||||
|
|
||||||
|
showToast(`${settingKey.replace(/_/g, ' ')} updated`, 'success');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
showToast('Failed to save setting: ' + error.message, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async reloadContent() {
|
||||||
|
if (this.currentPage === 'loras') {
|
||||||
|
// Reload the loras without updating folders
|
||||||
|
await resetAndReload(false);
|
||||||
|
} else if (this.currentPage === 'recipes') {
|
||||||
|
// Reload the recipes without updating folders
|
||||||
|
await window.recipeManager.loadRecipes();
|
||||||
|
} else if (this.currentPage === 'checkpoints') {
|
||||||
|
// Reload the checkpoints without updating folders
|
||||||
|
await window.checkpointsManager.loadCheckpoints();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async saveSettings() {
|
async saveSettings() {
|
||||||
// Get frontend settings from UI
|
// Get frontend settings from UI
|
||||||
const blurMatureContent = document.getElementById('blurMatureContent').checked;
|
const blurMatureContent = document.getElementById('blurMatureContent').checked;
|
||||||
const showOnlySFW = document.getElementById('showOnlySFW').checked;
|
const showOnlySFW = document.getElementById('showOnlySFW').checked;
|
||||||
const defaultLoraRoot = document.getElementById('defaultLoraRoot').value;
|
const defaultLoraRoot = document.getElementById('defaultLoraRoot').value;
|
||||||
|
const autoplayOnHover = document.getElementById('autoplayOnHover').checked;
|
||||||
|
|
||||||
// Get backend settings
|
// Get backend settings
|
||||||
const apiKey = document.getElementById('civitaiApiKey').value;
|
const apiKey = document.getElementById('civitaiApiKey').value;
|
||||||
@@ -133,6 +298,7 @@ export class SettingsManager {
|
|||||||
state.global.settings.blurMatureContent = blurMatureContent;
|
state.global.settings.blurMatureContent = blurMatureContent;
|
||||||
state.global.settings.show_only_sfw = showOnlySFW;
|
state.global.settings.show_only_sfw = showOnlySFW;
|
||||||
state.global.settings.default_loras_root = defaultLoraRoot;
|
state.global.settings.default_loras_root = defaultLoraRoot;
|
||||||
|
state.global.settings.autoplayOnHover = autoplayOnHover;
|
||||||
|
|
||||||
// Save settings to localStorage
|
// Save settings to localStorage
|
||||||
setStorageItem('settings', state.global.settings);
|
setStorageItem('settings', state.global.settings);
|
||||||
@@ -186,11 +352,42 @@ export class SettingsManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Apply autoplay setting to existing videos in card previews
|
||||||
|
const autoplayOnHover = state.global.settings.autoplayOnHover;
|
||||||
|
document.querySelectorAll('.card-preview video').forEach(video => {
|
||||||
|
// Remove previous event listeners by cloning and replacing the element
|
||||||
|
const videoParent = video.parentElement;
|
||||||
|
const videoClone = video.cloneNode(true);
|
||||||
|
|
||||||
|
if (autoplayOnHover) {
|
||||||
|
// Pause video initially and set up mouse events for hover playback
|
||||||
|
videoClone.removeAttribute('autoplay');
|
||||||
|
videoClone.pause();
|
||||||
|
|
||||||
|
// Add mouse events to the parent element
|
||||||
|
videoParent.onmouseenter = () => videoClone.play();
|
||||||
|
videoParent.onmouseleave = () => {
|
||||||
|
videoClone.pause();
|
||||||
|
videoClone.currentTime = 0;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Use default autoplay behavior
|
||||||
|
videoClone.setAttribute('autoplay', '');
|
||||||
|
videoParent.onmouseenter = null;
|
||||||
|
videoParent.onmouseleave = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
videoParent.replaceChild(videoClone, video);
|
||||||
|
});
|
||||||
|
|
||||||
// For show_only_sfw, there's no immediate action needed as it affects content loading
|
// For show_only_sfw, there's no immediate action needed as it affects content loading
|
||||||
// The setting will take effect on next reload
|
// The setting will take effect on next reload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create singleton instance
|
||||||
|
export const settingsManager = new SettingsManager();
|
||||||
|
|
||||||
// Helper function for toggling API key visibility
|
// Helper function for toggling API key visibility
|
||||||
export function toggleApiKeyVisibility(button) {
|
export function toggleApiKeyVisibility(button) {
|
||||||
const input = button.parentElement.querySelector('input');
|
const input = button.parentElement.querySelector('input');
|
||||||
|
|||||||
@@ -17,16 +17,24 @@
|
|||||||
<button class="close" onclick="modalManager.closeModal('settingsModal')">×</button>
|
<button class="close" onclick="modalManager.closeModal('settingsModal')">×</button>
|
||||||
<h2>Settings</h2>
|
<h2>Settings</h2>
|
||||||
<div class="settings-form">
|
<div class="settings-form">
|
||||||
<div class="input-group">
|
<div class="setting-item api-key-item">
|
||||||
<label for="civitaiApiKey">Civitai API Key:</label>
|
<div class="setting-row">
|
||||||
<div class="api-key-input">
|
<div class="setting-info">
|
||||||
<input type="password"
|
<label for="civitaiApiKey">Civitai API Key:</label>
|
||||||
id="civitaiApiKey"
|
</div>
|
||||||
placeholder="Enter your Civitai API key"
|
<div class="setting-control">
|
||||||
value="{{ settings.get('civitai_api_key', '') }}" />
|
<div class="api-key-input">
|
||||||
<button class="toggle-visibility" onclick="toggleApiKeyVisibility(this)">
|
<input type="password"
|
||||||
<i class="fas fa-eye"></i>
|
id="civitaiApiKey"
|
||||||
</button>
|
placeholder="Enter your Civitai API key"
|
||||||
|
value="{{ settings.get('civitai_api_key', '') }}"
|
||||||
|
onblur="settingsManager.saveInputSetting('civitaiApiKey', 'civitai_api_key')"
|
||||||
|
onkeydown="if(event.key === 'Enter') { this.blur(); }" />
|
||||||
|
<button class="toggle-visibility" onclick="toggleApiKeyVisibility(this)">
|
||||||
|
<i class="fas fa-eye"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-help">
|
<div class="input-help">
|
||||||
Used for authentication when downloading models from Civitai
|
Used for authentication when downloading models from Civitai
|
||||||
@@ -37,32 +45,61 @@
|
|||||||
<h3>Content Filtering</h3>
|
<h3>Content Filtering</h3>
|
||||||
|
|
||||||
<div class="setting-item">
|
<div class="setting-item">
|
||||||
<div class="setting-info">
|
<div class="setting-row">
|
||||||
<label for="blurMatureContent">Blur NSFW Content</label>
|
<div class="setting-info">
|
||||||
<div class="input-help">
|
<label for="blurMatureContent">Blur NSFW Content</label>
|
||||||
Blur mature (NSFW) content preview images
|
</div>
|
||||||
|
<div class="setting-control">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="blurMatureContent" checked
|
||||||
|
onchange="settingsManager.saveToggleSetting('blurMatureContent', 'blur_mature_content')">
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-control">
|
<div class="input-help">
|
||||||
<label class="toggle-switch">
|
Blur mature (NSFW) content preview images
|
||||||
<input type="checkbox" id="blurMatureContent" checked>
|
|
||||||
<span class="toggle-slider"></span>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="setting-item">
|
<div class="setting-item">
|
||||||
<div class="setting-info">
|
<div class="setting-row">
|
||||||
<label for="showOnlySFW">Show Only SFW Results</label>
|
<div class="setting-info">
|
||||||
<div class="input-help">
|
<label for="showOnlySFW">Show Only SFW Results</label>
|
||||||
Filter out all NSFW content when browsing and searching
|
</div>
|
||||||
|
<div class="setting-control">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="showOnlySFW" value="{{ settings.get('show_only_sfw', False) }}" {% if settings.get('show_only_sfw', False) %}checked{% endif %}
|
||||||
|
onchange="settingsManager.saveToggleSetting('showOnlySFW', 'show_only_sfw')">
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="setting-control">
|
<div class="input-help">
|
||||||
<label class="toggle-switch">
|
Filter out all NSFW content when browsing and searching
|
||||||
<input type="checkbox" id="showOnlySFW" value="{{ settings.get('show_only_sfw', False) }}" {% if settings.get('show_only_sfw', False) %}checked{% endif %}>
|
</div>
|
||||||
<span class="toggle-slider"></span>
|
</div>
|
||||||
</label>
|
</div>
|
||||||
|
|
||||||
|
<!-- Add Video Settings Section -->
|
||||||
|
<div class="settings-section">
|
||||||
|
<h3>Video Settings</h3>
|
||||||
|
|
||||||
|
<div class="setting-item">
|
||||||
|
<div class="setting-row">
|
||||||
|
<div class="setting-info">
|
||||||
|
<label for="autoplayOnHover">Autoplay Videos on Hover</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-control">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="autoplayOnHover"
|
||||||
|
onchange="settingsManager.saveToggleSetting('autoplayOnHover', 'autoplay_on_hover')">
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input-help">
|
||||||
|
Only play video previews when hovering over them
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -72,14 +109,16 @@
|
|||||||
<h3>Folder Settings</h3>
|
<h3>Folder Settings</h3>
|
||||||
|
|
||||||
<div class="setting-item">
|
<div class="setting-item">
|
||||||
<div class="setting-info">
|
<div class="setting-row">
|
||||||
<label for="defaultLoraRoot">Default LoRA Root</label>
|
<div class="setting-info">
|
||||||
</div>
|
<label for="defaultLoraRoot">Default LoRA Root</label>
|
||||||
<div class="setting-control select-control">
|
</div>
|
||||||
<select id="defaultLoraRoot">
|
<div class="setting-control select-control">
|
||||||
<option value="">No Default</option>
|
<select id="defaultLoraRoot" onchange="settingsManager.saveSelectSetting('defaultLoraRoot', 'default_lora_root')">
|
||||||
<!-- Options will be loaded dynamically -->
|
<option value="">No Default</option>
|
||||||
</select>
|
<!-- Options will be loaded dynamically -->
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-help">
|
<div class="input-help">
|
||||||
Set the default LoRA root directory for downloads, imports and moves
|
Set the default LoRA root directory for downloads, imports and moves
|
||||||
@@ -87,18 +126,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-actions">
|
|
||||||
<button class="primary-btn" onclick="settingsManager.saveSettings()">Save</button>
|
|
||||||
</div>
|
|
||||||
<!-- Add the new links section -->
|
|
||||||
<div class="settings-links">
|
|
||||||
<a href="https://github.com/willmiao/ComfyUI-Lora-Manager" target="_blank" class="settings-link" title="GitHub Repository">
|
|
||||||
<i class="fab fa-github"></i>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/willmiao/ComfyUI-Lora-Manager/issues/new" target="_blank" class="settings-link" title="Report Issue">
|
|
||||||
<i class="fas fa-bug"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user