mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 23:25:43 -03:00
Add nsfw browse control part 1
This commit is contained in:
@@ -2,6 +2,7 @@ import { showToast } from '../utils/uiHelpers.js';
|
||||
import { state } from '../state/index.js';
|
||||
import { showLoraModal } from './LoraModal.js';
|
||||
import { bulkManager } from '../managers/BulkManager.js';
|
||||
import { NSFW_LEVELS } from '../utils/constants.js';
|
||||
|
||||
export function createLoraCard(lora) {
|
||||
const card = document.createElement('div');
|
||||
@@ -27,6 +28,16 @@ export function createLoraCard(lora) {
|
||||
card.dataset.modelDescription = lora.modelDescription;
|
||||
}
|
||||
|
||||
// Store NSFW level if available
|
||||
const nsfwLevel = lora.preview_nsfw_level !== undefined ? lora.preview_nsfw_level : 0;
|
||||
card.dataset.nsfwLevel = nsfwLevel;
|
||||
|
||||
// Determine if the preview should be blurred based on NSFW level and user settings
|
||||
const shouldBlur = state.settings.blurMatureContent && nsfwLevel > NSFW_LEVELS.PG13;
|
||||
if (shouldBlur) {
|
||||
card.classList.add('nsfw-content');
|
||||
}
|
||||
|
||||
// Apply selection state if in bulk mode and this card is in the selected set
|
||||
if (state.bulkMode && state.selectedLoras.has(lora.file_path)) {
|
||||
card.classList.add('selected');
|
||||
@@ -36,8 +47,18 @@ export function createLoraCard(lora) {
|
||||
const previewUrl = lora.preview_url || '/loras_static/images/no-preview.png';
|
||||
const versionedPreviewUrl = version ? `${previewUrl}?t=${version}` : previewUrl;
|
||||
|
||||
// Determine NSFW warning text based on level
|
||||
let nsfwText = "Mature Content";
|
||||
if (nsfwLevel >= NSFW_LEVELS.XXX) {
|
||||
nsfwText = "XXX-rated Content";
|
||||
} else if (nsfwLevel >= NSFW_LEVELS.X) {
|
||||
nsfwText = "X-rated Content";
|
||||
} else if (nsfwLevel >= NSFW_LEVELS.R) {
|
||||
nsfwText = "R-rated Content";
|
||||
}
|
||||
|
||||
card.innerHTML = `
|
||||
<div class="card-preview">
|
||||
<div class="card-preview ${shouldBlur ? 'blurred' : ''}">
|
||||
${previewUrl.endsWith('.mp4') ?
|
||||
`<video controls autoplay muted loop>
|
||||
<source src="${versionedPreviewUrl}" type="video/mp4">
|
||||
@@ -45,7 +66,11 @@ export function createLoraCard(lora) {
|
||||
`<img src="${versionedPreviewUrl}" alt="${lora.model_name}">`
|
||||
}
|
||||
<div class="card-header">
|
||||
<span class="base-model-label" title="${lora.base_model}">
|
||||
${shouldBlur ?
|
||||
`<button class="toggle-blur-btn" title="Toggle blur">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>` : ''}
|
||||
<span class="base-model-label ${shouldBlur ? 'with-toggle' : ''}" title="${lora.base_model}">
|
||||
${lora.base_model}
|
||||
</span>
|
||||
<div class="card-actions">
|
||||
@@ -61,6 +86,14 @@ export function createLoraCard(lora) {
|
||||
</i>
|
||||
</div>
|
||||
</div>
|
||||
${shouldBlur ? `
|
||||
<div class="nsfw-overlay">
|
||||
<div class="nsfw-warning">
|
||||
<p>${nsfwText}</p>
|
||||
<button class="show-content-btn">Show</button>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
<div class="card-footer">
|
||||
<div class="model-info">
|
||||
<span class="model-name">${lora.model_name}</span>
|
||||
@@ -111,6 +144,52 @@ export function createLoraCard(lora) {
|
||||
}
|
||||
});
|
||||
|
||||
// Toggle blur button functionality
|
||||
const toggleBlurBtn = card.querySelector('.toggle-blur-btn');
|
||||
if (toggleBlurBtn) {
|
||||
toggleBlurBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const preview = card.querySelector('.card-preview');
|
||||
const isBlurred = preview.classList.toggle('blurred');
|
||||
const icon = toggleBlurBtn.querySelector('i');
|
||||
|
||||
// Update the icon based on blur state
|
||||
if (isBlurred) {
|
||||
icon.className = 'fas fa-eye';
|
||||
} else {
|
||||
icon.className = 'fas fa-eye-slash';
|
||||
}
|
||||
|
||||
// Toggle the overlay visibility
|
||||
const overlay = card.querySelector('.nsfw-overlay');
|
||||
if (overlay) {
|
||||
overlay.style.display = isBlurred ? 'flex' : 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Show content button functionality
|
||||
const showContentBtn = card.querySelector('.show-content-btn');
|
||||
if (showContentBtn) {
|
||||
showContentBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const preview = card.querySelector('.card-preview');
|
||||
preview.classList.remove('blurred');
|
||||
|
||||
// Update the toggle button icon
|
||||
const toggleBtn = card.querySelector('.toggle-blur-btn');
|
||||
if (toggleBtn) {
|
||||
toggleBtn.querySelector('i').className = 'fas fa-eye-slash';
|
||||
}
|
||||
|
||||
// Hide the overlay
|
||||
const overlay = card.querySelector('.nsfw-overlay');
|
||||
if (overlay) {
|
||||
overlay.style.display = 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Copy button click event
|
||||
card.querySelector('.fa-copy')?.addEventListener('click', async e => {
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { showToast } from '../utils/uiHelpers.js';
|
||||
import { state } from '../state/index.js';
|
||||
import { NSFW_LEVELS } from '../utils/constants.js';
|
||||
|
||||
export function showLoraModal(lora) {
|
||||
const escapedWords = lora.civitai?.trainedWords?.length ?
|
||||
@@ -153,27 +154,67 @@ function renderShowcaseContent(images) {
|
||||
Math.min(maxHeightPercent, aspectRatio)
|
||||
);
|
||||
|
||||
// Check if image should be blurred
|
||||
const nsfwLevel = img.nsfwLevel !== undefined ? img.nsfwLevel : 0;
|
||||
const shouldBlur = state.settings.blurMatureContent && nsfwLevel > NSFW_LEVELS.PG13;
|
||||
|
||||
// Determine NSFW warning text based on level
|
||||
let nsfwText = "Mature Content";
|
||||
if (nsfwLevel >= NSFW_LEVELS.XXX) {
|
||||
nsfwText = "XXX-rated Content";
|
||||
} else if (nsfwLevel >= NSFW_LEVELS.X) {
|
||||
nsfwText = "X-rated Content";
|
||||
} else if (nsfwLevel >= NSFW_LEVELS.R) {
|
||||
nsfwText = "R-rated Content";
|
||||
}
|
||||
|
||||
if (img.type === 'video') {
|
||||
return `
|
||||
<div class="media-wrapper" style="padding-bottom: ${heightPercent}%">
|
||||
<div class="media-wrapper ${shouldBlur ? 'nsfw-media-wrapper' : ''}" style="padding-bottom: ${heightPercent}%">
|
||||
${shouldBlur ? `
|
||||
<button class="toggle-blur-btn showcase-toggle-btn" title="Toggle blur">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
` : ''}
|
||||
<video controls autoplay muted loop crossorigin="anonymous"
|
||||
referrerpolicy="no-referrer" data-src="${img.url}"
|
||||
class="lazy">
|
||||
class="lazy ${shouldBlur ? 'blurred' : ''}">
|
||||
<source data-src="${img.url}" type="video/mp4">
|
||||
Your browser does not support video playback
|
||||
</video>
|
||||
${shouldBlur ? `
|
||||
<div class="nsfw-overlay">
|
||||
<div class="nsfw-warning">
|
||||
<p>${nsfwText}</p>
|
||||
<button class="show-content-btn">Show</button>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
return `
|
||||
<div class="media-wrapper" style="padding-bottom: ${heightPercent}%">
|
||||
<div class="media-wrapper ${shouldBlur ? 'nsfw-media-wrapper' : ''}" style="padding-bottom: ${heightPercent}%">
|
||||
${shouldBlur ? `
|
||||
<button class="toggle-blur-btn showcase-toggle-btn" title="Toggle blur">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
` : ''}
|
||||
<img data-src="${img.url}"
|
||||
alt="Preview"
|
||||
crossorigin="anonymous"
|
||||
referrerpolicy="no-referrer"
|
||||
width="${img.width}"
|
||||
height="${img.height}"
|
||||
class="lazy">
|
||||
alt="Preview"
|
||||
crossorigin="anonymous"
|
||||
referrerpolicy="no-referrer"
|
||||
width="${img.width}"
|
||||
height="${img.height}"
|
||||
class="lazy ${shouldBlur ? 'blurred' : ''}">
|
||||
${shouldBlur ? `
|
||||
<div class="nsfw-overlay">
|
||||
<div class="nsfw-warning">
|
||||
<p>${nsfwText}</p>
|
||||
<button class="show-content-btn">Show</button>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
`;
|
||||
}).join('')}
|
||||
@@ -585,6 +626,9 @@ export function toggleShowcase(element) {
|
||||
indicator.textContent = `Scroll or click to hide examples`;
|
||||
icon.classList.replace('fa-chevron-down', 'fa-chevron-up');
|
||||
initLazyLoading(carousel);
|
||||
|
||||
// Initialize NSFW content blur toggle handlers
|
||||
initNsfwBlurHandlers(carousel);
|
||||
} else {
|
||||
const count = carousel.querySelectorAll('.media-wrapper').length;
|
||||
indicator.textContent = `Scroll or click to show ${count} examples`;
|
||||
@@ -592,6 +636,57 @@ export function toggleShowcase(element) {
|
||||
}
|
||||
}
|
||||
|
||||
// New function to initialize blur toggle handlers for showcase images/videos
|
||||
function initNsfwBlurHandlers(container) {
|
||||
// Handle toggle blur buttons
|
||||
const toggleButtons = container.querySelectorAll('.toggle-blur-btn');
|
||||
toggleButtons.forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const wrapper = btn.closest('.media-wrapper');
|
||||
const media = wrapper.querySelector('img, video');
|
||||
const isBlurred = media.classList.toggle('blurred');
|
||||
const icon = btn.querySelector('i');
|
||||
|
||||
// Update the icon based on blur state
|
||||
if (isBlurred) {
|
||||
icon.className = 'fas fa-eye';
|
||||
} else {
|
||||
icon.className = 'fas fa-eye-slash';
|
||||
}
|
||||
|
||||
// Toggle the overlay visibility
|
||||
const overlay = wrapper.querySelector('.nsfw-overlay');
|
||||
if (overlay) {
|
||||
overlay.style.display = isBlurred ? 'flex' : 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Handle "Show" buttons in overlays
|
||||
const showButtons = container.querySelectorAll('.show-content-btn');
|
||||
showButtons.forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const wrapper = btn.closest('.media-wrapper');
|
||||
const media = wrapper.querySelector('img, video');
|
||||
media.classList.remove('blurred');
|
||||
|
||||
// Update the toggle button icon
|
||||
const toggleBtn = wrapper.querySelector('.toggle-blur-btn');
|
||||
if (toggleBtn) {
|
||||
toggleBtn.querySelector('i').className = 'fas fa-eye-slash';
|
||||
}
|
||||
|
||||
// Hide the overlay
|
||||
const overlay = wrapper.querySelector('.nsfw-overlay');
|
||||
if (overlay) {
|
||||
overlay.style.display = 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Add lazy loading initialization
|
||||
function initLazyLoading(container) {
|
||||
const lazyElements = container.querySelectorAll('.lazy');
|
||||
|
||||
Reference in New Issue
Block a user