diff --git a/locales/de.json b/locales/de.json index 21bbb0f3..db6a6e82 100644 --- a/locales/de.json +++ b/locales/de.json @@ -127,6 +127,10 @@ "checkError": "Fehler beim Überprüfen der Beispielbilder", "missingHash": "Fehlende Modell-Hash-Informationen.", "noRemoteImagesAvailable": "Keine Remote-Beispielbilder für dieses Modell auf Civitai verfügbar" + }, + "badges": { + "update": "Update", + "updateAvailable": "Update verfügbar" } }, "globalContextMenu": { diff --git a/locales/en.json b/locales/en.json index e8d76aa7..e43296d0 100644 --- a/locales/en.json +++ b/locales/en.json @@ -127,6 +127,10 @@ "checkError": "Error checking for example images", "missingHash": "Missing model hash information.", "noRemoteImagesAvailable": "No remote example images available for this model on Civitai" + }, + "badges": { + "update": "Update", + "updateAvailable": "Update available" } }, "globalContextMenu": { diff --git a/locales/es.json b/locales/es.json index 53b10dfc..fd1dc6c4 100644 --- a/locales/es.json +++ b/locales/es.json @@ -127,6 +127,10 @@ "checkError": "Error al verificar imágenes de ejemplo", "missingHash": "Falta información del hash del modelo.", "noRemoteImagesAvailable": "No hay imágenes de ejemplo remotas disponibles para este modelo en Civitai" + }, + "badges": { + "update": "Actualización", + "updateAvailable": "Actualización disponible" } }, "globalContextMenu": { diff --git a/locales/fr.json b/locales/fr.json index dc14d6e4..71890fcb 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -127,6 +127,10 @@ "checkError": "Erreur lors de la vérification des images d'exemple", "missingHash": "Informations de hachage du modèle manquantes.", "noRemoteImagesAvailable": "Aucune image d'exemple distante disponible pour ce modèle sur Civitai" + }, + "badges": { + "update": "Mise à jour", + "updateAvailable": "Mise à jour disponible" } }, "globalContextMenu": { diff --git a/locales/he.json b/locales/he.json index 6e4b5940..4c5308f0 100644 --- a/locales/he.json +++ b/locales/he.json @@ -127,6 +127,10 @@ "checkError": "שגיאה בבדיקת תמונות דוגמה", "missingHash": "חסר מידע hash של המודל.", "noRemoteImagesAvailable": "אין תמונות דוגמה מרוחקות זמינות למודל זה ב-Civitai" + }, + "badges": { + "update": "עדכון", + "updateAvailable": "עדכון זמין" } }, "globalContextMenu": { diff --git a/locales/ja.json b/locales/ja.json index 84ae2124..136c21e4 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -127,6 +127,10 @@ "checkError": "例画像の確認中にエラーが発生しました", "missingHash": "モデルハッシュ情報がありません。", "noRemoteImagesAvailable": "このモデルのCivitaiでのリモート例画像は利用できません" + }, + "badges": { + "update": "アップデート", + "updateAvailable": "アップデートがあります" } }, "globalContextMenu": { diff --git a/locales/ko.json b/locales/ko.json index 088e67b4..14903ef9 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -127,6 +127,10 @@ "checkError": "예시 이미지 확인 중 오류", "missingHash": "모델 해시 정보가 없습니다.", "noRemoteImagesAvailable": "Civitai에서 이 모델의 원격 예시 이미지를 사용할 수 없습니다" + }, + "badges": { + "update": "업데이트", + "updateAvailable": "업데이트 가능" } }, "globalContextMenu": { diff --git a/locales/ru.json b/locales/ru.json index 0021f803..b72c91b1 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -127,6 +127,10 @@ "checkError": "Ошибка проверки примеров изображений", "missingHash": "Отсутствует хеш модели.", "noRemoteImagesAvailable": "Нет удаленных примеров изображений для этой модели на Civitai" + }, + "badges": { + "update": "Обновление", + "updateAvailable": "Доступно обновление" } }, "globalContextMenu": { diff --git a/locales/zh-CN.json b/locales/zh-CN.json index d33b0eb9..be002614 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -127,6 +127,10 @@ "checkError": "检查示例图片时出错", "missingHash": "缺少模型哈希信息。", "noRemoteImagesAvailable": "此模型在 Civitai 上没有远程示例图片" + }, + "badges": { + "update": "更新", + "updateAvailable": "有可用更新" } }, "globalContextMenu": { diff --git a/locales/zh-TW.json b/locales/zh-TW.json index 04c82bbe..0ce1a382 100644 --- a/locales/zh-TW.json +++ b/locales/zh-TW.json @@ -127,6 +127,10 @@ "checkError": "檢查範例圖片時發生錯誤", "missingHash": "缺少模型雜湊資訊。", "noRemoteImagesAvailable": "此模型在 Civitai 上無遠端範例圖片" + }, + "badges": { + "update": "更新", + "updateAvailable": "有可用更新" } }, "globalContextMenu": { diff --git a/static/css/base.css b/static/css/base.css index fc479161..ed1599ba 100644 --- a/static/css/base.css +++ b/static/css/base.css @@ -53,6 +53,9 @@ html, body { --lora-error: oklch(75% 0.32 29); --lora-warning: oklch(var(--lora-warning-l) var(--lora-warning-c) var(--lora-warning-h)); --lora-success: oklch(var(--lora-success-l) var(--lora-success-c) var(--lora-success-h)); + --badge-update-bg: oklch(72% 0.2 220); + --badge-update-text: oklch(28% 0.03 220); + --badge-update-glow: oklch(72% 0.2 220 / 0.28); /* Spacing Scale */ --space-1: calc(8px * 1); @@ -100,6 +103,9 @@ html[data-theme="light"] { --lora-border: oklch(90% 0.02 256 / 0.15); --lora-text: oklch(98% 0.02 256); --lora-warning: oklch(75% 0.25 80); /* Modified to be used with oklch() */ + --badge-update-bg: oklch(62% 0.18 220); + --badge-update-text: oklch(98% 0.02 240); + --badge-update-glow: oklch(62% 0.18 220 / 0.4); } body { diff --git a/static/css/components/card.css b/static/css/components/card.css index cf63df36..01f57c9c 100644 --- a/static/css/components/card.css +++ b/static/css/components/card.css @@ -296,6 +296,18 @@ min-height: 20px; } +.card-header-info { + display: flex; + align-items: center; + gap: 6px; + flex: 1; + min-width: 0; +} + +.card-header-info .base-model-label { + flex-shrink: 1; +} + .card-actions i { margin-left: var(--space-1); cursor: pointer; @@ -422,6 +434,7 @@ border-radius: var(--border-radius-xs); backdrop-filter: blur(2px); font-size: 0.85em; + line-height: 1.2; } /* Style for version name */ @@ -575,4 +588,26 @@ 15% { opacity: 1; transform: translateY(0); } 85% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(0); } - } \ No newline at end of file + } + +.model-card.has-update { + border-color: color-mix(in oklab, var(--badge-update-bg) 60%, transparent); + box-shadow: 0 0 0 1px color-mix(in oklab, var(--badge-update-bg) 45%, transparent); +} + +.model-update-badge { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 2px 10px; + border-radius: var(--border-radius-xs); + background: var(--badge-update-bg); + color: var(--badge-update-text); + font-size: 0.7rem; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + box-shadow: 0 4px 12px var(--badge-update-glow); + border: 1px solid color-mix(in oklab, var(--badge-update-bg) 55%, transparent); + white-space: nowrap; +} diff --git a/static/js/components/shared/ModelCard.js b/static/js/components/shared/ModelCard.js index aa777292..633e2825 100644 --- a/static/js/components/shared/ModelCard.js +++ b/static/js/components/shared/ModelCard.js @@ -432,6 +432,8 @@ export function createModelCard(model, modelType) { card.dataset.notes = model.notes || ''; card.dataset.base_model = model.base_model || 'Unknown'; card.dataset.favorite = model.favorite ? 'true' : 'false'; + const hasUpdateAvailable = Boolean(model.update_available); + card.dataset.update_available = hasUpdateAvailable ? 'true' : 'false'; // LoRA specific data if (modelType === MODEL_TYPES.LORA) { @@ -507,6 +509,9 @@ export function createModelCard(model, modelType) { // Get favorite status from model data const isFavorite = model.favorite === true; + if (hasUpdateAvailable) { + card.classList.add('has-update'); + } // Generate action icons based on model type with i18n support const favoriteTitle = isFavorite ? @@ -531,6 +536,8 @@ export function createModelCard(model, modelType) { copyTitle = translate('modelCard.actions.copyLoRASyntax', {}, 'Copy value'); } + const updateBadgeLabel = translate('modelCard.badges.update', {}, 'Update'); + const updateBadgeTooltip = translate('modelCard.badges.updateAvailable', {}, 'Update available'); const actionIcons = ` @@ -568,9 +575,16 @@ export function createModelCard(model, modelType) { `` : ''} - - ${model.base_model} - +
+ + ${model.base_model} + + ${hasUpdateAvailable ? ` + + ${updateBadgeLabel} + + ` : ''} +
${actionIcons}