mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-06-19 00:42: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:
@@ -314,6 +314,7 @@
|
|||||||
"downloads": "Downloads",
|
"downloads": "Downloads",
|
||||||
"videoSettings": "Video-Einstellungen",
|
"videoSettings": "Video-Einstellungen",
|
||||||
"layoutSettings": "Layout-Einstellungen",
|
"layoutSettings": "Layout-Einstellungen",
|
||||||
|
"licenseIcons": "Lizenzsymbole",
|
||||||
"misc": "Verschiedenes",
|
"misc": "Verschiedenes",
|
||||||
"backup": "Backups",
|
"backup": "Backups",
|
||||||
"folderSettings": "Standard-Roots",
|
"folderSettings": "Standard-Roots",
|
||||||
@@ -594,6 +595,10 @@
|
|||||||
"label": "Früher Zugriff Updates ausblenden",
|
"label": "Früher Zugriff Updates ausblenden",
|
||||||
"help": "Nur Early-Access-Updates"
|
"help": "Nur Early-Access-Updates"
|
||||||
},
|
},
|
||||||
|
"licenseIcons": {
|
||||||
|
"useNewStyle": "Aktualisierte Lizenzsymbole verwenden",
|
||||||
|
"useNewStyleHelp": "Lizenzberechtigungen mit farbigen Indikatoren (neuer Stil) oder nur Einschränkungssymbolen (klassischer Stil) anzeigen. Orientiert sich am aktuellen CivitAI-Design."
|
||||||
|
},
|
||||||
"misc": {
|
"misc": {
|
||||||
"includeTriggerWords": "Trigger Words in LoRA-Syntax einschließen",
|
"includeTriggerWords": "Trigger Words in LoRA-Syntax einschließen",
|
||||||
"includeTriggerWordsHelp": "Trainierte Trigger Words beim Kopieren der LoRA-Syntax in die Zwischenablage einschließen",
|
"includeTriggerWordsHelp": "Trainierte Trigger Words beim Kopieren der LoRA-Syntax in die Zwischenablage einschließen",
|
||||||
|
|||||||
@@ -314,6 +314,7 @@
|
|||||||
"downloads": "Downloads",
|
"downloads": "Downloads",
|
||||||
"videoSettings": "Video Settings",
|
"videoSettings": "Video Settings",
|
||||||
"layoutSettings": "Layout Settings",
|
"layoutSettings": "Layout Settings",
|
||||||
|
"licenseIcons": "License Icons",
|
||||||
"misc": "Miscellaneous",
|
"misc": "Miscellaneous",
|
||||||
"backup": "Backups",
|
"backup": "Backups",
|
||||||
"folderSettings": "Default Roots",
|
"folderSettings": "Default Roots",
|
||||||
@@ -594,6 +595,10 @@
|
|||||||
"label": "Hide Early Access Updates",
|
"label": "Hide Early Access Updates",
|
||||||
"help": "When enabled, models with only early access updates will not show 'Update available' badge"
|
"help": "When enabled, models with only early access updates will not show 'Update available' badge"
|
||||||
},
|
},
|
||||||
|
"licenseIcons": {
|
||||||
|
"useNewStyle": "Use updated license icons",
|
||||||
|
"useNewStyleHelp": "Display license permissions with colored indicators (new style) or restriction-only icons (classic style). Mirroring the current CivitAI design."
|
||||||
|
},
|
||||||
"misc": {
|
"misc": {
|
||||||
"includeTriggerWords": "Include Trigger Words in LoRA Syntax",
|
"includeTriggerWords": "Include Trigger Words in LoRA Syntax",
|
||||||
"includeTriggerWordsHelp": "Include trained trigger words when copying LoRA syntax to clipboard",
|
"includeTriggerWordsHelp": "Include trained trigger words when copying LoRA syntax to clipboard",
|
||||||
|
|||||||
@@ -314,6 +314,7 @@
|
|||||||
"downloads": "Descargas",
|
"downloads": "Descargas",
|
||||||
"videoSettings": "Configuración de video",
|
"videoSettings": "Configuración de video",
|
||||||
"layoutSettings": "Configuración de diseño",
|
"layoutSettings": "Configuración de diseño",
|
||||||
|
"licenseIcons": "Iconos de licencia",
|
||||||
"misc": "Varios",
|
"misc": "Varios",
|
||||||
"backup": "Copias de seguridad",
|
"backup": "Copias de seguridad",
|
||||||
"folderSettings": "Raíces predeterminadas",
|
"folderSettings": "Raíces predeterminadas",
|
||||||
@@ -594,6 +595,10 @@
|
|||||||
"label": "Ocultar actualizaciones de acceso temprano",
|
"label": "Ocultar actualizaciones de acceso temprano",
|
||||||
"help": "Solo actualizaciones de acceso temprano"
|
"help": "Solo actualizaciones de acceso temprano"
|
||||||
},
|
},
|
||||||
|
"licenseIcons": {
|
||||||
|
"useNewStyle": "Usar iconos de licencia actualizados",
|
||||||
|
"useNewStyleHelp": "Mostrar permisos de licencia con indicadores de color (nuevo estilo) o solo iconos de restricción (estilo clásico). Refleja el diseño actual de CivitAI."
|
||||||
|
},
|
||||||
"misc": {
|
"misc": {
|
||||||
"includeTriggerWords": "Incluir palabras clave en la sintaxis de LoRA",
|
"includeTriggerWords": "Incluir palabras clave en la sintaxis de LoRA",
|
||||||
"includeTriggerWordsHelp": "Incluir palabras clave entrenadas al copiar la sintaxis de LoRA al portapapeles",
|
"includeTriggerWordsHelp": "Incluir palabras clave entrenadas al copiar la sintaxis de LoRA al portapapeles",
|
||||||
|
|||||||
@@ -314,6 +314,7 @@
|
|||||||
"downloads": "Téléchargements",
|
"downloads": "Téléchargements",
|
||||||
"videoSettings": "Paramètres vidéo",
|
"videoSettings": "Paramètres vidéo",
|
||||||
"layoutSettings": "Paramètres d'affichage",
|
"layoutSettings": "Paramètres d'affichage",
|
||||||
|
"licenseIcons": "Icônes de licence",
|
||||||
"misc": "Divers",
|
"misc": "Divers",
|
||||||
"backup": "Sauvegardes",
|
"backup": "Sauvegardes",
|
||||||
"folderSettings": "Racines par défaut",
|
"folderSettings": "Racines par défaut",
|
||||||
@@ -594,6 +595,10 @@
|
|||||||
"label": "Masquer les mises à jour en accès anticipé",
|
"label": "Masquer les mises à jour en accès anticipé",
|
||||||
"help": "Seulement les mises à jour en accès anticipé"
|
"help": "Seulement les mises à jour en accès anticipé"
|
||||||
},
|
},
|
||||||
|
"licenseIcons": {
|
||||||
|
"useNewStyle": "Utiliser les icônes de licence mises à jour",
|
||||||
|
"useNewStyleHelp": "Afficher les permissions de licence avec des indicateurs colorés (nouveau style) ou des icônes de restriction uniquement (style classique). Reprend le design actuel de CivitAI."
|
||||||
|
},
|
||||||
"misc": {
|
"misc": {
|
||||||
"includeTriggerWords": "Inclure les mots-clés dans la syntaxe LoRA",
|
"includeTriggerWords": "Inclure les mots-clés dans la syntaxe LoRA",
|
||||||
"includeTriggerWordsHelp": "Inclure les mots-clés d'entraînement lors de la copie de la syntaxe LoRA dans le presse-papiers",
|
"includeTriggerWordsHelp": "Inclure les mots-clés d'entraînement lors de la copie de la syntaxe LoRA dans le presse-papiers",
|
||||||
|
|||||||
@@ -314,6 +314,7 @@
|
|||||||
"downloads": "הורדות",
|
"downloads": "הורדות",
|
||||||
"videoSettings": "הגדרות וידאו",
|
"videoSettings": "הגדרות וידאו",
|
||||||
"layoutSettings": "הגדרות פריסה",
|
"layoutSettings": "הגדרות פריסה",
|
||||||
|
"licenseIcons": "סמלי רישיון",
|
||||||
"misc": "שונות",
|
"misc": "שונות",
|
||||||
"backup": "גיבויים",
|
"backup": "גיבויים",
|
||||||
"folderSettings": "תיקיות ברירת מחדל",
|
"folderSettings": "תיקיות ברירת מחדל",
|
||||||
@@ -594,6 +595,10 @@
|
|||||||
"label": "הסתר עדכוני גישה מוקדמת",
|
"label": "הסתר עדכוני גישה מוקדמת",
|
||||||
"help": "רק עדכוני גישה מוקדמת"
|
"help": "רק עדכוני גישה מוקדמת"
|
||||||
},
|
},
|
||||||
|
"licenseIcons": {
|
||||||
|
"useNewStyle": "השתמש בסמלי רישיון מעודכנים",
|
||||||
|
"useNewStyleHelp": "הצג הרשאות רישיון עם מחוונים צבעוניים (סגנון חדש) או סמלי הגבלה בלבד (סגנון קלאסי). משקף את העיצוב העדכני של CivitAI."
|
||||||
|
},
|
||||||
"misc": {
|
"misc": {
|
||||||
"includeTriggerWords": "כלול מילות טריגר בתחביר LoRA",
|
"includeTriggerWords": "כלול מילות טריגר בתחביר LoRA",
|
||||||
"includeTriggerWordsHelp": "כלול מילות טריגר מאומנות בעת העתקת תחביר LoRA ללוח",
|
"includeTriggerWordsHelp": "כלול מילות טריגר מאומנות בעת העתקת תחביר LoRA ללוח",
|
||||||
|
|||||||
@@ -314,6 +314,7 @@
|
|||||||
"downloads": "ダウンロード",
|
"downloads": "ダウンロード",
|
||||||
"videoSettings": "動画設定",
|
"videoSettings": "動画設定",
|
||||||
"layoutSettings": "レイアウト設定",
|
"layoutSettings": "レイアウト設定",
|
||||||
|
"licenseIcons": "ライセンスアイコン",
|
||||||
"misc": "その他",
|
"misc": "その他",
|
||||||
"backup": "バックアップ",
|
"backup": "バックアップ",
|
||||||
"folderSettings": "デフォルトルート",
|
"folderSettings": "デフォルトルート",
|
||||||
@@ -594,6 +595,10 @@
|
|||||||
"label": "早期アクセス更新を非表示",
|
"label": "早期アクセス更新を非表示",
|
||||||
"help": "早期アクセスのみの更新"
|
"help": "早期アクセスのみの更新"
|
||||||
},
|
},
|
||||||
|
"licenseIcons": {
|
||||||
|
"useNewStyle": "更新されたライセンスアイコンを使用",
|
||||||
|
"useNewStyleHelp": "カラーインジケーター付きでライセンス許可を表示(新スタイル)するか、制限のみのアイコンを表示(クラシックスタイル)します。現在のCivitAIデザインを反映しています。"
|
||||||
|
},
|
||||||
"misc": {
|
"misc": {
|
||||||
"includeTriggerWords": "LoRA構文にトリガーワードを含める",
|
"includeTriggerWords": "LoRA構文にトリガーワードを含める",
|
||||||
"includeTriggerWordsHelp": "LoRA構文をクリップボードにコピーする際、学習済みトリガーワードを含めます",
|
"includeTriggerWordsHelp": "LoRA構文をクリップボードにコピーする際、学習済みトリガーワードを含めます",
|
||||||
|
|||||||
@@ -314,6 +314,7 @@
|
|||||||
"downloads": "다운로드",
|
"downloads": "다운로드",
|
||||||
"videoSettings": "비디오 설정",
|
"videoSettings": "비디오 설정",
|
||||||
"layoutSettings": "레이아웃 설정",
|
"layoutSettings": "레이아웃 설정",
|
||||||
|
"licenseIcons": "라이선스 아이콘",
|
||||||
"misc": "기타",
|
"misc": "기타",
|
||||||
"backup": "백업",
|
"backup": "백업",
|
||||||
"folderSettings": "기본 루트",
|
"folderSettings": "기본 루트",
|
||||||
@@ -594,6 +595,10 @@
|
|||||||
"label": "얼리 액세스 업데이트 숨기기",
|
"label": "얼리 액세스 업데이트 숨기기",
|
||||||
"help": "얼리 액세스 업데이트만"
|
"help": "얼리 액세스 업데이트만"
|
||||||
},
|
},
|
||||||
|
"licenseIcons": {
|
||||||
|
"useNewStyle": "업데이트된 라이선스 아이콘 사용",
|
||||||
|
"useNewStyleHelp": "색상 표시기가 있는 라이선스 권한(새 스타일) 또는 제한 전용 아이콘(클래식 스타일)을 표시합니다. 현재 CivitAI 디자인을 반영합니다."
|
||||||
|
},
|
||||||
"misc": {
|
"misc": {
|
||||||
"includeTriggerWords": "LoRA 문법에 트리거 단어 포함",
|
"includeTriggerWords": "LoRA 문법에 트리거 단어 포함",
|
||||||
"includeTriggerWordsHelp": "LoRA 문법을 클립보드에 복사할 때 학습된 트리거 단어를 포함합니다",
|
"includeTriggerWordsHelp": "LoRA 문법을 클립보드에 복사할 때 학습된 트리거 단어를 포함합니다",
|
||||||
|
|||||||
@@ -314,6 +314,7 @@
|
|||||||
"downloads": "Загрузки",
|
"downloads": "Загрузки",
|
||||||
"videoSettings": "Настройки видео",
|
"videoSettings": "Настройки видео",
|
||||||
"layoutSettings": "Настройки макета",
|
"layoutSettings": "Настройки макета",
|
||||||
|
"licenseIcons": "Значки лицензии",
|
||||||
"misc": "Разное",
|
"misc": "Разное",
|
||||||
"backup": "Резервные копии",
|
"backup": "Резервные копии",
|
||||||
"folderSettings": "Корневые папки",
|
"folderSettings": "Корневые папки",
|
||||||
@@ -594,6 +595,10 @@
|
|||||||
"label": "Скрыть обновления раннего доступа",
|
"label": "Скрыть обновления раннего доступа",
|
||||||
"help": "Только обновления раннего доступа"
|
"help": "Только обновления раннего доступа"
|
||||||
},
|
},
|
||||||
|
"licenseIcons": {
|
||||||
|
"useNewStyle": "Использовать обновлённые значки лицензии",
|
||||||
|
"useNewStyleHelp": "Отображать разрешения лицензии с цветными индикаторами (новый стиль) или только значки ограничений (классический стиль). Соответствует текущему дизайну CivitAI."
|
||||||
|
},
|
||||||
"misc": {
|
"misc": {
|
||||||
"includeTriggerWords": "Включать триггерные слова в синтаксис LoRA",
|
"includeTriggerWords": "Включать триггерные слова в синтаксис LoRA",
|
||||||
"includeTriggerWordsHelp": "Включать обученные триггерные слова при копировании синтаксиса LoRA в буфер обмена",
|
"includeTriggerWordsHelp": "Включать обученные триггерные слова при копировании синтаксиса LoRA в буфер обмена",
|
||||||
|
|||||||
@@ -314,6 +314,7 @@
|
|||||||
"downloads": "下载",
|
"downloads": "下载",
|
||||||
"videoSettings": "视频设置",
|
"videoSettings": "视频设置",
|
||||||
"layoutSettings": "布局设置",
|
"layoutSettings": "布局设置",
|
||||||
|
"licenseIcons": "许可协议图标",
|
||||||
"misc": "其他",
|
"misc": "其他",
|
||||||
"backup": "备份",
|
"backup": "备份",
|
||||||
"folderSettings": "默认根目录",
|
"folderSettings": "默认根目录",
|
||||||
@@ -594,6 +595,10 @@
|
|||||||
"label": "隐藏抢先体验更新",
|
"label": "隐藏抢先体验更新",
|
||||||
"help": "抢先体验更新"
|
"help": "抢先体验更新"
|
||||||
},
|
},
|
||||||
|
"licenseIcons": {
|
||||||
|
"useNewStyle": "使用新版许可协议图标",
|
||||||
|
"useNewStyleHelp": "以彩色指示器显示许可权限(新样式),或仅显示限制图标(经典样式)。与当前 CivitAI 设计保持一致。"
|
||||||
|
},
|
||||||
"misc": {
|
"misc": {
|
||||||
"includeTriggerWords": "复制 LoRA 语法时包含触发词",
|
"includeTriggerWords": "复制 LoRA 语法时包含触发词",
|
||||||
"includeTriggerWordsHelp": "复制 LoRA 语法到剪贴板时包含训练触发词",
|
"includeTriggerWordsHelp": "复制 LoRA 语法到剪贴板时包含训练触发词",
|
||||||
|
|||||||
@@ -314,6 +314,7 @@
|
|||||||
"downloads": "下載",
|
"downloads": "下載",
|
||||||
"videoSettings": "影片設定",
|
"videoSettings": "影片設定",
|
||||||
"layoutSettings": "版面設定",
|
"layoutSettings": "版面設定",
|
||||||
|
"licenseIcons": "許可協議圖標",
|
||||||
"misc": "其他",
|
"misc": "其他",
|
||||||
"backup": "備份",
|
"backup": "備份",
|
||||||
"folderSettings": "預設根目錄",
|
"folderSettings": "預設根目錄",
|
||||||
@@ -594,6 +595,10 @@
|
|||||||
"label": "隱藏搶先體驗更新",
|
"label": "隱藏搶先體驗更新",
|
||||||
"help": "搶先體驗更新"
|
"help": "搶先體驗更新"
|
||||||
},
|
},
|
||||||
|
"licenseIcons": {
|
||||||
|
"useNewStyle": "使用新版許可協議圖標",
|
||||||
|
"useNewStyleHelp": "以彩色指示器顯示許可權限(新樣式),或僅顯示限制圖標(經典樣式)。與當前 CivitAI 設計保持一致。"
|
||||||
|
},
|
||||||
"misc": {
|
"misc": {
|
||||||
"includeTriggerWords": "在 LoRA 語法中包含觸發詞",
|
"includeTriggerWords": "在 LoRA 語法中包含觸發詞",
|
||||||
"includeTriggerWordsHelp": "複製 LoRA 語法到剪貼簿時包含訓練觸發詞",
|
"includeTriggerWordsHelp": "複製 LoRA 語法到剪貼簿時包含訓練觸發詞",
|
||||||
|
|||||||
@@ -1272,6 +1272,14 @@ class ModelQueryHandler:
|
|||||||
license_flags = (model_data or {}).get("license_flags")
|
license_flags = (model_data or {}).get("license_flags")
|
||||||
if license_flags is not None:
|
if license_flags is not None:
|
||||||
response_payload["license_flags"] = int(license_flags)
|
response_payload["license_flags"] = int(license_flags)
|
||||||
|
# Include the user's license icon style preference so the
|
||||||
|
# ComfyUI tooltip can pick the right set without a separate
|
||||||
|
# API call.
|
||||||
|
try:
|
||||||
|
settings = get_settings_manager()
|
||||||
|
response_payload["use_new_license_icons"] = settings.get("use_new_license_icons", True)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
return web.json_response(response_payload)
|
return web.json_response(response_payload)
|
||||||
return web.json_response(
|
return web.json_response(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ DEFAULT_SETTINGS: Dict[str, Any] = {
|
|||||||
"download_skip_base_models": [],
|
"download_skip_base_models": [],
|
||||||
"backup_auto_enabled": True,
|
"backup_auto_enabled": True,
|
||||||
"backup_retention_count": 5,
|
"backup_retention_count": 5,
|
||||||
|
"use_new_license_icons": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,10 @@
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-header-actions .license-permissions {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.license-restrictions {
|
.license-restrictions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -95,6 +99,41 @@
|
|||||||
transform: translateY(-1px);
|
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 */
|
||||||
.info-grid {
|
.info-grid {
|
||||||
display: 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>`;
|
</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
|
* Display the model modal with the given model data
|
||||||
* @param {Object} model - Model data object
|
* @param {Object} model - Model data object
|
||||||
@@ -264,7 +353,10 @@ export async function showModelModal(model, modelType) {
|
|||||||
};
|
};
|
||||||
const escapedFilePathAttr = escapeAttribute(modelWithFullData.file_path || '');
|
const escapedFilePathAttr = escapeAttribute(modelWithFullData.file_path || '');
|
||||||
const escapedFolderPath = escapeHtml((modelWithFullData.file_path || '').replace(/[^/]+$/, '') || 'N/A');
|
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 ? `
|
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}">
|
<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')}
|
<i class="fas fa-globe"></i> ${translate('modals.model.actions.viewOnCivitaiText', {}, 'View on Civitai')}
|
||||||
|
|||||||
@@ -1003,6 +1003,12 @@ export class SettingsManager {
|
|||||||
|
|
||||||
this.loadDownloadBackendSettings();
|
this.loadDownloadBackendSettings();
|
||||||
this.loadProxySettings();
|
this.loadProxySettings();
|
||||||
|
|
||||||
|
// Set license icon style
|
||||||
|
const useNewLicenseIconsCheckbox = document.getElementById('useNewLicenseIcons');
|
||||||
|
if (useNewLicenseIconsCheckbox) {
|
||||||
|
useNewLicenseIconsCheckbox.checked = state.global.settings.use_new_license_icons !== false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadDownloadBackendSettings() {
|
loadDownloadBackendSettings() {
|
||||||
@@ -2947,6 +2953,10 @@ export class SettingsManager {
|
|||||||
const showVersionOnCard = state.global.settings.show_version_on_card !== false;
|
const showVersionOnCard = state.global.settings.show_version_on_card !== false;
|
||||||
document.body.classList.toggle('hide-card-version', !showVersionOnCard);
|
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_auto_enabled: true,
|
||||||
backup_retention_count: 5,
|
backup_retention_count: 5,
|
||||||
strip_lora_on_copy: false,
|
strip_lora_on_copy: false,
|
||||||
|
use_new_license_icons: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function createDefaultSettings() {
|
export function createDefaultSettings() {
|
||||||
|
|||||||
@@ -592,6 +592,30 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- License Icons -->
|
||||||
|
<div class="settings-subsection">
|
||||||
|
<div class="settings-subsection-header">
|
||||||
|
<h4>{{ t('settings.sections.licenseIcons') }}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="setting-item">
|
||||||
|
<div class="setting-row">
|
||||||
|
<div class="setting-info">
|
||||||
|
<label for="useNewLicenseIcons">
|
||||||
|
{{ t('settings.licenseIcons.useNewStyle') }}
|
||||||
|
<i class="fas fa-info-circle info-icon" data-tooltip="{{ t('settings.licenseIcons.useNewStyleHelp') }}"></i>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="setting-control">
|
||||||
|
<label class="toggle-switch">
|
||||||
|
<input type="checkbox" id="useNewLicenseIcons"
|
||||||
|
onchange="settingsManager.saveToggleSetting('useNewLicenseIcons', 'use_new_license_icons')">
|
||||||
|
<span class="toggle-slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Miscellaneous -->
|
<!-- Miscellaneous -->
|
||||||
<div class="settings-subsection">
|
<div class="settings-subsection">
|
||||||
<div class="settings-subsection-header">
|
<div class="settings-subsection-header">
|
||||||
|
|||||||
@@ -101,14 +101,19 @@ vi.mock(API_FACTORY, () => ({
|
|||||||
|
|
||||||
describe('Model modal license rendering', () => {
|
describe('Model modal license rendering', () => {
|
||||||
let getModelApiClient;
|
let getModelApiClient;
|
||||||
|
let state;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
document.body.innerHTML = '';
|
document.body.innerHTML = '';
|
||||||
({ getModelApiClient } = await import(API_FACTORY));
|
({ getModelApiClient } = await import(API_FACTORY));
|
||||||
getModelApiClient.mockReset();
|
getModelApiClient.mockReset();
|
||||||
|
// Import state and force classic icons for this test
|
||||||
|
const stateModule = await import('../../../static/js/state/index.js');
|
||||||
|
state = stateModule.state;
|
||||||
|
state.global.settings.use_new_license_icons = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles aggregated commercial strings without extra restrictions', async () => {
|
it('handles aggregated commercial strings without extra restrictions (classic style)', async () => {
|
||||||
const fetchModelMetadata = vi.fn().mockResolvedValue(null);
|
const fetchModelMetadata = vi.fn().mockResolvedValue(null);
|
||||||
getModelApiClient.mockReturnValue({
|
getModelApiClient.mockReturnValue({
|
||||||
fetchModelMetadata,
|
fetchModelMetadata,
|
||||||
|
|||||||
@@ -73,6 +73,40 @@
|
|||||||
mask: var(--license-icon-image) center/contain no-repeat;
|
mask: var(--license-icon-image) center/contain no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set 2 — new style license overlay */
|
||||||
|
.lm-tooltip__license-overlay-new {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
left: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 5px 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(10, 10, 14, 0.78);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
max-width: calc(100% - 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lm-tooltip__license-icon-new {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 3px;
|
||||||
|
-webkit-mask: var(--license-icon-image) center/contain no-repeat;
|
||||||
|
mask: var(--license-icon-image) center/contain no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lm-tooltip__license-icon-new.allowed {
|
||||||
|
background-color: #40c057;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lm-tooltip__license-icon-new.denied {
|
||||||
|
background-color: #fa5252;
|
||||||
|
}
|
||||||
|
|
||||||
.lm-loras-container {
|
.lm-loras-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ const LICENSE_FLAG_BITS = {
|
|||||||
allowRelicense: 1 << 6,
|
allowRelicense: 1 << 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ── Set 1 (classic) icon definitions ──
|
||||||
|
|
||||||
const LICENSE_ICON_COPY = {
|
const LICENSE_ICON_COPY = {
|
||||||
credit: "Creator credit required",
|
credit: "Creator credit required",
|
||||||
image: "No selling generated content",
|
image: "No selling generated content",
|
||||||
@@ -29,6 +31,51 @@ const COMMERCIAL_ICON_CONFIG = [
|
|||||||
{ bit: LICENSE_FLAG_BITS.allowSellingModels, icon: "shopping-cart-off.svg", label: LICENSE_ICON_COPY.sell },
|
{ bit: LICENSE_FLAG_BITS.allowSellingModels, icon: "shopping-cart-off.svg", label: LICENSE_ICON_COPY.sell },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// ── Set 2 (new CivitAI-style) icon definitions ──
|
||||||
|
|
||||||
|
const LNI = LICENSE_ICON_PATH; // alias for brevity
|
||||||
|
|
||||||
|
const NEW_LICENSE_ICON_COPY = {
|
||||||
|
commercial: { allowed: "Commercial use allowed", denied: "No commercial use" },
|
||||||
|
genServices: { allowed: "Generation services allowed", denied: "No generation services" },
|
||||||
|
credit: { allowed: "No credit required", denied: "Creator credit required" },
|
||||||
|
derivatives: { allowed: "Merges allowed", denied: "No merges allowed" },
|
||||||
|
relicense: { allowed: "Different permissions allowed on merges", denied: "Same permissions required on merges" },
|
||||||
|
};
|
||||||
|
|
||||||
|
const NEW_ICON_CONFIG = [
|
||||||
|
{
|
||||||
|
bitCombo: [LICENSE_FLAG_BITS.allowOnImages, LICENSE_FLAG_BITS.allowSellingModels],
|
||||||
|
icon: "currency-dollar.svg",
|
||||||
|
labelKey: "commercial",
|
||||||
|
allowedFn: (flags) => (flags & LICENSE_FLAG_BITS.allowOnImages) !== 0 || (flags & LICENSE_FLAG_BITS.allowSellingModels) !== 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bitCombo: [LICENSE_FLAG_BITS.allowOnCivitai, LICENSE_FLAG_BITS.allowRental],
|
||||||
|
icon: "brush.svg",
|
||||||
|
labelKey: "genServices",
|
||||||
|
allowedFn: (flags) => (flags & LICENSE_FLAG_BITS.allowOnCivitai) !== 0 || (flags & LICENSE_FLAG_BITS.allowRental) !== 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bitCombo: [LICENSE_FLAG_BITS.allowNoCredit],
|
||||||
|
icon: "user.svg",
|
||||||
|
labelKey: "credit",
|
||||||
|
allowedFn: (flags) => (flags & LICENSE_FLAG_BITS.allowNoCredit) !== 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bitCombo: [LICENSE_FLAG_BITS.allowDerivatives],
|
||||||
|
icon: "git-merge.svg",
|
||||||
|
labelKey: "derivatives",
|
||||||
|
allowedFn: (flags) => (flags & LICENSE_FLAG_BITS.allowDerivatives) !== 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bitCombo: [LICENSE_FLAG_BITS.allowRelicense],
|
||||||
|
icon: "license.svg",
|
||||||
|
labelKey: "relicense",
|
||||||
|
allowedFn: (flags) => (flags & LICENSE_FLAG_BITS.allowRelicense) !== 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
function parseLicenseFlags(value) {
|
function parseLicenseFlags(value) {
|
||||||
if (typeof value === "number") {
|
if (typeof value === "number") {
|
||||||
return Number.isFinite(value) ? value : null;
|
return Number.isFinite(value) ? value : null;
|
||||||
@@ -78,6 +125,81 @@ function createLicenseIconElement({ icon, label }) {
|
|||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Set 2 (new style) helpers ──
|
||||||
|
|
||||||
|
function buildNewLicenseIconData(licenseFlags) {
|
||||||
|
if (licenseFlags == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NEW_ICON_CONFIG.map((config) => {
|
||||||
|
const allowed = config.allowedFn(licenseFlags);
|
||||||
|
const label = allowed
|
||||||
|
? NEW_LICENSE_ICON_COPY[config.labelKey].allowed
|
||||||
|
: NEW_LICENSE_ICON_COPY[config.labelKey].denied;
|
||||||
|
return {
|
||||||
|
icon: config.icon,
|
||||||
|
label,
|
||||||
|
allowed,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createNewLicenseIconElement({ icon, label, allowed }) {
|
||||||
|
const element = document.createElement("span");
|
||||||
|
element.className = `lm-tooltip__license-icon-new ${allowed ? "allowed" : "denied"}`;
|
||||||
|
element.setAttribute("role", "img");
|
||||||
|
element.setAttribute("aria-label", label);
|
||||||
|
element.title = label;
|
||||||
|
element.style.setProperty("--license-icon-image", `url('${LICENSE_ICON_PATH}${icon}')`);
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LICENSE_ICON_STORAGE_KEY = "lm_license_icon_new_style";
|
||||||
|
|
||||||
|
// Module-level cache: null = not yet initialized
|
||||||
|
let _useNewIconsCached = null;
|
||||||
|
|
||||||
|
// Fetch the setting from the LoRA Manager backend API via the proper
|
||||||
|
// ComfyUI api helper (handles base URL, credentials, etc.).
|
||||||
|
// Stores the result in both the in-memory cache and localStorage so the
|
||||||
|
// value survives page reloads even before the API responds.
|
||||||
|
async function _fetchLicenseIconSetting() {
|
||||||
|
try {
|
||||||
|
const response = await api.fetchApi("/lm/settings");
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
const value = data.use_new_license_icons !== false;
|
||||||
|
_useNewIconsCached = value;
|
||||||
|
try { localStorage.setItem(LICENSE_ICON_STORAGE_KEY, String(value)); } catch (_) {}
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
// API not available; cached/localStorage fallback stays in place
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUseNewLicenseIcons() {
|
||||||
|
// 1) In-memory cache hit
|
||||||
|
if (_useNewIconsCached !== null) {
|
||||||
|
return _useNewIconsCached;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) localStorage — survives page reloads
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem(LICENSE_ICON_STORAGE_KEY);
|
||||||
|
if (stored !== null) {
|
||||||
|
_useNewIconsCached = stored === "true";
|
||||||
|
// Refresh from API in background for next time
|
||||||
|
_fetchLicenseIconSetting();
|
||||||
|
return _useNewIconsCached;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
// 3) First-ever run: kick off API fetch, default to new style
|
||||||
|
_fetchLicenseIconSetting();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lightweight preview tooltip that can display images or videos for different model types.
|
* Lightweight preview tooltip that can display images or videos for different model types.
|
||||||
*/
|
*/
|
||||||
@@ -101,6 +223,10 @@ export class PreviewTooltip {
|
|||||||
|
|
||||||
ensureLmStyles();
|
ensureLmStyles();
|
||||||
|
|
||||||
|
// Pre-fetch license icon style from LM backend so the tooltip
|
||||||
|
// respects the standalone settings toggle as early as possible.
|
||||||
|
_fetchLicenseIconSetting();
|
||||||
|
|
||||||
this.element = document.createElement("div");
|
this.element = document.createElement("div");
|
||||||
this.element.className = "lm-tooltip";
|
this.element.className = "lm-tooltip";
|
||||||
document.body.appendChild(this.element);
|
document.body.appendChild(this.element);
|
||||||
@@ -135,6 +261,7 @@ export class PreviewTooltip {
|
|||||||
previewUrl: data.preview_url,
|
previewUrl: data.preview_url,
|
||||||
displayName: data.display_name ?? modelName,
|
displayName: data.display_name ?? modelName,
|
||||||
licenseFlags: parseLicenseFlags(data.license_flags),
|
licenseFlags: parseLicenseFlags(data.license_flags),
|
||||||
|
useNewLicenseIcons: data.use_new_license_icons,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +277,7 @@ export class PreviewTooltip {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const { previewUrl, displayName, licenseFlags } = raw;
|
const { previewUrl, displayName, licenseFlags, useNewLicenseIcons } = raw;
|
||||||
if (!previewUrl) {
|
if (!previewUrl) {
|
||||||
throw new Error("No preview URL available");
|
throw new Error("No preview URL available");
|
||||||
}
|
}
|
||||||
@@ -161,6 +288,7 @@ export class PreviewTooltip {
|
|||||||
? displayName
|
? displayName
|
||||||
: this.displayNameFormatter(modelName),
|
: this.displayNameFormatter(modelName),
|
||||||
licenseFlags: parseLicenseFlags(licenseFlags),
|
licenseFlags: parseLicenseFlags(licenseFlags),
|
||||||
|
useNewLicenseIcons,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +310,7 @@ export class PreviewTooltip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.currentModelName = modelName;
|
this.currentModelName = modelName;
|
||||||
const { previewUrl, displayName, licenseFlags } = await this.resolvePreviewData(
|
const { previewUrl, displayName, licenseFlags, useNewLicenseIcons } = await this.resolvePreviewData(
|
||||||
modelName
|
modelName
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -211,7 +339,7 @@ export class PreviewTooltip {
|
|||||||
nameLabel.className = "lm-tooltip__label";
|
nameLabel.className = "lm-tooltip__label";
|
||||||
|
|
||||||
mediaContainer.appendChild(mediaElement);
|
mediaContainer.appendChild(mediaElement);
|
||||||
this.renderLicenseOverlay(mediaContainer, licenseFlags);
|
this.renderLicenseOverlay(mediaContainer, licenseFlags, useNewLicenseIcons);
|
||||||
mediaContainer.appendChild(nameLabel);
|
mediaContainer.appendChild(nameLabel);
|
||||||
this.element.appendChild(mediaContainer);
|
this.element.appendChild(mediaContainer);
|
||||||
|
|
||||||
@@ -293,16 +421,25 @@ export class PreviewTooltip {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLicenseOverlay(container, licenseFlags) {
|
renderLicenseOverlay(container, licenseFlags, useNewLicenseIcons) {
|
||||||
const icons = buildLicenseIconData(licenseFlags);
|
const useNew = useNewLicenseIcons !== undefined ? useNewLicenseIcons : getUseNewLicenseIcons();
|
||||||
|
const icons = useNew
|
||||||
|
? buildNewLicenseIconData(licenseFlags)
|
||||||
|
: buildLicenseIconData(licenseFlags);
|
||||||
if (!icons.length) {
|
if (!icons.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const overlay = document.createElement("div");
|
const overlay = document.createElement("div");
|
||||||
overlay.className = "lm-tooltip__license-overlay";
|
overlay.className = useNew
|
||||||
|
? "lm-tooltip__license-overlay-new"
|
||||||
|
: "lm-tooltip__license-overlay";
|
||||||
icons.forEach((descriptor) => {
|
icons.forEach((descriptor) => {
|
||||||
overlay.appendChild(createLicenseIconElement(descriptor));
|
overlay.appendChild(
|
||||||
|
useNew
|
||||||
|
? createNewLicenseIconElement(descriptor)
|
||||||
|
: createLicenseIconElement(descriptor)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
container.appendChild(overlay);
|
container.appendChild(overlay);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user