mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-06-19 08:52:05 -03:00
feat(license-icons): add second set of license icons matching current CivitAI design
- Add 5 new Tabler SVG icons (currency-dollar, brush, user, git-merge, license) - Implement Set 2 rendering in ModelModal.js (standalone UI) with green/red permission indicators and preview_tooltip.js (ComfyUI widget) - Add use_new_license_icons setting (default: true) with toggle in settings UI - ComfyUI tooltip reads setting directly from preview-url API response to eliminate race conditions and respect standalone settings changes - Remove the now-unused separate ComfyUI setting loramanager.license_icon_style - Add CSS for both standalone (lora-modal.css) and widget (lm_styles.css) - i18n: translate licenseIcons keys into all 10 supported languages - Fix test to use classic style explicitly for continued coverage
This commit is contained in:
@@ -72,6 +72,10 @@
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.modal-header-actions .license-permissions {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.license-restrictions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -95,6 +99,41 @@
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* Set 2 — New style permission indicators */
|
||||
.license-permissions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.license-icon-new {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: inline-block;
|
||||
border-radius: 4px;
|
||||
background-color: var(--text-muted);
|
||||
-webkit-mask: var(--license-icon-image) center/contain no-repeat;
|
||||
mask: var(--license-icon-image) center/contain no-repeat;
|
||||
transition: background-color 0.2s ease, transform 0.2s ease;
|
||||
cursor: default;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
.license-icon-new.allowed {
|
||||
background-color: var(--color-success, #40c057);
|
||||
outline-color: color-mix(in oklch, var(--color-success, #40c057) 30%, transparent);
|
||||
}
|
||||
|
||||
.license-icon-new.denied {
|
||||
background-color: var(--color-error, #fa5252);
|
||||
outline-color: color-mix(in oklch, var(--color-error, #fa5252) 30%, transparent);
|
||||
}
|
||||
|
||||
.license-icon-new:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* Info Grid */
|
||||
.info-grid {
|
||||
display: grid;
|
||||
|
||||
1
static/images/tabler/brush.svg
Normal file
1
static/images/tabler/brush.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-brush"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M3 21v-4a4 4 0 1 1 4 4h-4" /><path d="M21 3a16 16 0 0 0 -12.8 10.2" /><path d="M21 3a16 16 0 0 1 -10.2 12.8" /><path d="M10.6 9a9 9 0 0 1 4.4 4.4" /></svg>
|
||||
|
After Width: | Height: | Size: 460 B |
1
static/images/tabler/currency-dollar.svg
Normal file
1
static/images/tabler/currency-dollar.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-currency-dollar"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M16.7 8a3 3 0 0 0 -2.7 -2h-4a3 3 0 0 0 0 6h4a3 3 0 0 1 0 6h-4a3 3 0 0 1 -2.7 -2" /><path d="M12 3v3m0 12v3" /></svg>
|
||||
|
After Width: | Height: | Size: 431 B |
1
static/images/tabler/git-merge.svg
Normal file
1
static/images/tabler/git-merge.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-git-merge"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 18a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /><path d="M5 6a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /><path d="M15 12a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /><path d="M7 8l0 8" /><path d="M7 8a4 4 0 0 0 4 4h4" /></svg>
|
||||
|
After Width: | Height: | Size: 501 B |
1
static/images/tabler/license.svg
Normal file
1
static/images/tabler/license.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-license"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M15 21h-9a3 3 0 0 1 -3 -3v-1h10v2a2 2 0 0 0 4 0v-14a2 2 0 1 1 2 2h-2m2 -4h-11a3 3 0 0 0 -3 3v11" /><path d="M9 7l4 0" /><path d="M9 11l4 0" /></svg>
|
||||
|
After Width: | Height: | Size: 455 B |
1
static/images/tabler/user.svg
Normal file
1
static/images/tabler/user.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-user"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0" /><path d="M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2" /></svg>
|
||||
|
After Width: | Height: | Size: 401 B |
@@ -234,6 +234,95 @@ function renderLicenseIcons(modelData) {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
// ── Set 2 (new CivitAI-style) permission icons ──
|
||||
|
||||
const NEW_LICENSE_ICON_CONFIG = [
|
||||
{
|
||||
key: 'commercial',
|
||||
icon: 'currency-dollar.svg',
|
||||
allowedFn: (license) => {
|
||||
const uses = license.allowCommercialUse || [];
|
||||
return uses.includes('Image') || uses.includes('Sell');
|
||||
},
|
||||
labelAllowed: 'Commercial use allowed',
|
||||
labelDenied: 'No commercial use'
|
||||
},
|
||||
{
|
||||
key: 'genServices',
|
||||
icon: 'brush.svg',
|
||||
allowedFn: (license) => {
|
||||
const uses = license.allowCommercialUse || [];
|
||||
return uses.includes('RentCivit') || uses.includes('Rent');
|
||||
},
|
||||
labelAllowed: 'Generation services allowed',
|
||||
labelDenied: 'No generation services'
|
||||
},
|
||||
{
|
||||
key: 'credit',
|
||||
icon: 'user.svg',
|
||||
allowedFn: (license) => !!license.allowNoCredit,
|
||||
labelAllowed: 'No credit required',
|
||||
labelDenied: 'Creator credit required'
|
||||
},
|
||||
{
|
||||
key: 'derivatives',
|
||||
icon: 'git-merge.svg',
|
||||
allowedFn: (license) => !!license.allowDerivatives,
|
||||
labelAllowed: 'Merges allowed',
|
||||
labelDenied: 'No merges allowed'
|
||||
},
|
||||
{
|
||||
key: 'relicense',
|
||||
icon: 'license.svg',
|
||||
allowedFn: (license) => !!license.allowDifferentLicense,
|
||||
labelAllowed: 'Different permissions allowed on merges',
|
||||
labelDenied: 'Same permissions required on merges'
|
||||
}
|
||||
];
|
||||
|
||||
function createNewLicenseIconMarkup(icon, allowed, label) {
|
||||
const safeLabel = escapeAttribute(label);
|
||||
const iconPath = `/loras_static/images/tabler/${icon}`;
|
||||
const stateClass = allowed ? 'allowed' : 'denied';
|
||||
return `<span class="license-icon-new ${stateClass}" role="img" aria-label="${safeLabel}" title="${safeLabel}" style="--license-icon-image: url('${iconPath}')"></span>`;
|
||||
}
|
||||
|
||||
function renderNewLicenseIcons(modelData) {
|
||||
const license = modelData?.civitai?.model;
|
||||
if (!license) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const icons = [];
|
||||
NEW_LICENSE_ICON_CONFIG.forEach((config) => {
|
||||
if (config.key === 'credit' && !hasLicenseField(license, 'allowNoCredit')) {
|
||||
return;
|
||||
}
|
||||
if (config.key === 'derivatives' && !hasLicenseField(license, 'allowDerivatives')) {
|
||||
return;
|
||||
}
|
||||
if (config.key === 'relicense' && !hasLicenseField(license, 'allowDifferentLicense')) {
|
||||
return;
|
||||
}
|
||||
if ((config.key === 'commercial' || config.key === 'genServices') && !hasLicenseField(license, 'allowCommercialUse')) {
|
||||
return;
|
||||
}
|
||||
const allowed = config.allowedFn(license);
|
||||
const label = allowed ? config.labelAllowed : config.labelDenied;
|
||||
icons.push(createNewLicenseIconMarkup(config.icon, allowed, label));
|
||||
});
|
||||
|
||||
if (!icons.length) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const containerLabel = translate('modals.model.license.restrictionsLabel', {}, 'License permissions');
|
||||
const safeContainerLabel = escapeAttribute(containerLabel);
|
||||
return `<div class="license-permissions" aria-label="${safeContainerLabel}" role="group">
|
||||
${icons.join('\n ')}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the model modal with the given model data
|
||||
* @param {Object} model - Model data object
|
||||
@@ -264,7 +353,10 @@ export async function showModelModal(model, modelType) {
|
||||
};
|
||||
const escapedFilePathAttr = escapeAttribute(modelWithFullData.file_path || '');
|
||||
const escapedFolderPath = escapeHtml((modelWithFullData.file_path || '').replace(/[^/]+$/, '') || 'N/A');
|
||||
const licenseIcons = renderLicenseIcons(modelWithFullData);
|
||||
const useNewIcons = state.global.settings.use_new_license_icons !== false;
|
||||
const licenseIcons = useNewIcons
|
||||
? renderNewLicenseIcons(modelWithFullData)
|
||||
: renderLicenseIcons(modelWithFullData);
|
||||
const viewOnCivitaiAction = modelWithFullData.from_civitai ? `
|
||||
<div class="civitai-view" title="${translate('modals.model.actions.viewOnCivitai', {}, 'View on Civitai')}" data-action="view-civitai" data-filepath="${escapedFilePathAttr}">
|
||||
<i class="fas fa-globe"></i> ${translate('modals.model.actions.viewOnCivitaiText', {}, 'View on Civitai')}
|
||||
|
||||
@@ -1003,6 +1003,12 @@ export class SettingsManager {
|
||||
|
||||
this.loadDownloadBackendSettings();
|
||||
this.loadProxySettings();
|
||||
|
||||
// Set license icon style
|
||||
const useNewLicenseIconsCheckbox = document.getElementById('useNewLicenseIcons');
|
||||
if (useNewLicenseIconsCheckbox) {
|
||||
useNewLicenseIconsCheckbox.checked = state.global.settings.use_new_license_icons !== false;
|
||||
}
|
||||
}
|
||||
|
||||
loadDownloadBackendSettings() {
|
||||
@@ -2947,6 +2953,10 @@ export class SettingsManager {
|
||||
const showVersionOnCard = state.global.settings.show_version_on_card !== false;
|
||||
document.body.classList.toggle('hide-card-version', !showVersionOnCard);
|
||||
|
||||
// Apply license icon style
|
||||
const useNewLicenseIcons = state.global.settings.use_new_license_icons !== false;
|
||||
document.body.classList.toggle('use-new-license-icons', useNewLicenseIcons);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ const DEFAULT_SETTINGS_BASE = Object.freeze({
|
||||
backup_auto_enabled: true,
|
||||
backup_retention_count: 5,
|
||||
strip_lora_on_copy: false,
|
||||
use_new_license_icons: true,
|
||||
});
|
||||
|
||||
export function createDefaultSettings() {
|
||||
|
||||
Reference in New Issue
Block a user