feat(ui): add configurable model card footer action, fixes #249

This commit is contained in:
Will Miao
2025-10-17 08:43:35 +08:00
parent 52bf93e430
commit 6d9be814a5
16 changed files with 120 additions and 13 deletions

View File

@@ -101,7 +101,8 @@
"checkpointNameCopied": "Checkpoint-Name kopiert",
"toggleBlur": "Unschärfe umschalten",
"show": "Anzeigen",
"openExampleImages": "Beispielbilder-Ordner öffnen"
"openExampleImages": "Beispielbilder-Ordner öffnen",
"replacePreview": "Vorschau ersetzen"
},
"nsfw": {
"matureContent": "Nicht jugendfreie Inhalte",
@@ -240,6 +241,12 @@
"always": "Kopf- und Fußzeilen sind immer sichtbar",
"hover": "Kopf- und Fußzeilen erscheinen nur beim Darüberfahren mit der Maus"
},
"modelCardFooterAction": "Aktion der Modellkarten-Schaltfläche",
"modelCardFooterActionOptions": {
"exampleImages": "Beispielbilder öffnen",
"replacePreview": "Vorschau ersetzen"
},
"modelCardFooterActionHelp": "Wähle aus, was die Schaltfläche unten rechts auf der Karte ausführt.",
"modelNameDisplay": "Anzeige des Modellnamens",
"modelNameDisplayOptions": {
"modelName": "Modellname",

View File

@@ -101,7 +101,8 @@
"checkpointNameCopied": "Checkpoint name copied",
"toggleBlur": "Toggle blur",
"show": "Show",
"openExampleImages": "Open Example Images Folder"
"openExampleImages": "Open Example Images Folder",
"replacePreview": "Replace Preview"
},
"nsfw": {
"matureContent": "Mature Content",
@@ -240,6 +241,12 @@
"always": "Headers and footers are always visible",
"hover": "Headers and footers only appear when hovering over a card"
},
"modelCardFooterAction": "Model Card Button Action",
"modelCardFooterActionOptions": {
"exampleImages": "Open Example Images",
"replacePreview": "Replace Preview"
},
"modelCardFooterActionHelp": "Choose what the bottom-right card button does.",
"modelNameDisplay": "Model Name Display",
"modelNameDisplayOptions": {
"modelName": "Model Name",

View File

@@ -101,7 +101,8 @@
"checkpointNameCopied": "Nombre del checkpoint copiado",
"toggleBlur": "Alternar difuminado",
"show": "Mostrar",
"openExampleImages": "Abrir carpeta de imágenes de ejemplo"
"openExampleImages": "Abrir carpeta de imágenes de ejemplo",
"replacePreview": "Reemplazar vista previa"
},
"nsfw": {
"matureContent": "Contenido para adultos",
@@ -240,6 +241,12 @@
"always": "Los encabezados y pies de página siempre son visibles",
"hover": "Los encabezados y pies de página solo aparecen al pasar el ratón sobre una tarjeta"
},
"modelCardFooterAction": "Acción del botón de tarjeta de modelo",
"modelCardFooterActionOptions": {
"exampleImages": "Abrir imágenes de ejemplo",
"replacePreview": "Reemplazar vista previa"
},
"modelCardFooterActionHelp": "Elige qué hace el botón en la esquina inferior derecha de la tarjeta.",
"modelNameDisplay": "Visualización del nombre del modelo",
"modelNameDisplayOptions": {
"modelName": "Nombre del modelo",

View File

@@ -101,7 +101,8 @@
"checkpointNameCopied": "Nom du checkpoint copié",
"toggleBlur": "Basculer le flou",
"show": "Afficher",
"openExampleImages": "Ouvrir le dossier d'images d'exemple"
"openExampleImages": "Ouvrir le dossier d'images d'exemple",
"replacePreview": "Remplacer l'aperçu"
},
"nsfw": {
"matureContent": "Contenu pour adultes",
@@ -240,6 +241,12 @@
"always": "Les en-têtes et pieds de page sont toujours visibles",
"hover": "Les en-têtes et pieds de page n'apparaissent qu'au survol d'une carte"
},
"modelCardFooterAction": "Action du bouton de carte de modèle",
"modelCardFooterActionOptions": {
"exampleImages": "Ouvrir les images d'exemple",
"replacePreview": "Remplacer l'aperçu"
},
"modelCardFooterActionHelp": "Choisissez ce que fait le bouton en bas à droite de la carte.",
"modelNameDisplay": "Affichage du nom du modèle",
"modelNameDisplayOptions": {
"modelName": "Nom du modèle",

View File

@@ -101,7 +101,8 @@
"checkpointNameCopied": "שם Checkpoint הועתק",
"toggleBlur": "הפעל/כבה טשטוש",
"show": "הצג",
"openExampleImages": "פתח תיקיית תמונות דוגמה"
"openExampleImages": "פתח תיקיית תמונות דוגמה",
"replacePreview": "החלף תצוגה מקדימה"
},
"nsfw": {
"matureContent": "תוכן למבוגרים",
@@ -240,6 +241,12 @@
"always": "כותרות עליונות ותחתונות תמיד גלויות",
"hover": "כותרות עליונות ותחתונות מופיעות רק בעת ריחוף מעל כרטיס"
},
"modelCardFooterAction": "פעולת כפתור כרטיס מודל",
"modelCardFooterActionOptions": {
"exampleImages": "פתח תמונות דוגמה",
"replacePreview": "החלף תצוגה מקדימה"
},
"modelCardFooterActionHelp": "בחר מה עושה הכפתור בפינה הימנית התחתונה של הכרטיס.",
"modelNameDisplay": "תצוגת שם מודל",
"modelNameDisplayOptions": {
"modelName": "שם מודל",

View File

@@ -101,7 +101,8 @@
"checkpointNameCopied": "checkpointの名前をコピーしました",
"toggleBlur": "ぼかしの切り替え",
"show": "表示",
"openExampleImages": "例画像フォルダを開く"
"openExampleImages": "例画像フォルダを開く",
"replacePreview": "プレビューを置換"
},
"nsfw": {
"matureContent": "成人向けコンテンツ",
@@ -240,6 +241,12 @@
"always": "ヘッダーとフッターが常に表示されます",
"hover": "カードにホバーしたときのみヘッダーとフッターが表示されます"
},
"modelCardFooterAction": "モデルカードボタンのアクション",
"modelCardFooterActionOptions": {
"exampleImages": "例画像を開く",
"replacePreview": "プレビューを置換"
},
"modelCardFooterActionHelp": "カード右下のボタンが何をするかを選択します。",
"modelNameDisplay": "モデル名表示",
"modelNameDisplayOptions": {
"modelName": "モデル名",

View File

@@ -101,7 +101,8 @@
"checkpointNameCopied": "Checkpoint 이름 복사됨",
"toggleBlur": "블러 토글",
"show": "보기",
"openExampleImages": "예시 이미지 폴더 열기"
"openExampleImages": "예시 이미지 폴더 열기",
"replacePreview": "미리보기 교체"
},
"nsfw": {
"matureContent": "성인 콘텐츠",
@@ -240,6 +241,12 @@
"always": "헤더와 푸터가 항상 보입니다",
"hover": "카드에 마우스를 올렸을 때만 헤더와 푸터가 나타납니다"
},
"modelCardFooterAction": "모델 카드 버튼 동작",
"modelCardFooterActionOptions": {
"exampleImages": "예시 이미지 열기",
"replacePreview": "미리보기 교체"
},
"modelCardFooterActionHelp": "카드 우측 하단 버튼이 수행할 작업을 선택하세요.",
"modelNameDisplay": "모델명 표시",
"modelNameDisplayOptions": {
"modelName": "모델명",

View File

@@ -101,7 +101,8 @@
"checkpointNameCopied": "Имя checkpoint скопировано",
"toggleBlur": "Переключить размытие",
"show": "Показать",
"openExampleImages": "Открыть папку с примерами"
"openExampleImages": "Открыть папку с примерами",
"replacePreview": "Заменить превью"
},
"nsfw": {
"matureContent": "Контент для взрослых",
@@ -240,6 +241,12 @@
"always": "Заголовки и подписи всегда видны",
"hover": "Заголовки и подписи появляются только при наведении на карточку"
},
"modelCardFooterAction": "Действие кнопки карточки модели",
"modelCardFooterActionOptions": {
"exampleImages": "Открыть примеры изображений",
"replacePreview": "Заменить превью"
},
"modelCardFooterActionHelp": "Выберите, что делает кнопка в правом нижнем углу карточки.",
"modelNameDisplay": "Отображение названия модели",
"modelNameDisplayOptions": {
"modelName": "Название модели",

View File

@@ -101,7 +101,8 @@
"checkpointNameCopied": "检查点名称已复制",
"toggleBlur": "切换模糊",
"show": "显示",
"openExampleImages": "打开示例图片文件夹"
"openExampleImages": "打开示例图片文件夹",
"replacePreview": "替换预览"
},
"nsfw": {
"matureContent": "成熟内容",
@@ -240,6 +241,12 @@
"always": "标题和底部始终显示",
"hover": "仅在悬停卡片时显示标题和底部"
},
"modelCardFooterAction": "模型卡片按钮操作",
"modelCardFooterActionOptions": {
"exampleImages": "打开示例图片",
"replacePreview": "替换预览"
},
"modelCardFooterActionHelp": "选择右下角卡片按钮的功能。",
"modelNameDisplay": "模型名称显示",
"modelNameDisplayOptions": {
"modelName": "模型名称",

View File

@@ -101,7 +101,8 @@
"checkpointNameCopied": "Checkpoint 名稱已複製",
"toggleBlur": "切換模糊",
"show": "顯示",
"openExampleImages": "開啟範例圖片資料夾"
"openExampleImages": "開啟範例圖片資料夾",
"replacePreview": "更換預覽圖"
},
"nsfw": {
"matureContent": "成熟內容",
@@ -240,6 +241,12 @@
"always": "標題與頁腳始終可見",
"hover": "標題與頁腳僅在滑鼠懸停時顯示"
},
"modelCardFooterAction": "模型卡片按鈕操作",
"modelCardFooterActionOptions": {
"exampleImages": "開啟範例圖片",
"replacePreview": "更換預覽圖"
},
"modelCardFooterActionHelp": "選擇右下角卡片按鈕的功能。",
"modelNameDisplay": "模型名稱顯示",
"modelNameDisplayOptions": {
"modelName": "模型名稱",

View File

@@ -163,6 +163,7 @@ class SettingsHandler:
"show_only_sfw",
"compact_mode",
"priority_tags",
"model_card_footer_action",
"model_name_display",
)

View File

@@ -46,6 +46,7 @@ DEFAULT_SETTINGS: Dict[str, Any] = {
"compact_mode": False,
"priority_tags": DEFAULT_PRIORITY_TAG_CONFIG.copy(),
"model_name_display": "model_name",
"model_card_footer_action": "example_images",
}
@@ -317,6 +318,7 @@ class SettingsManager:
'cardInfoDisplay': 'card_info_display',
'includeTriggerWords': 'include_trigger_words',
'compactMode': 'compact_mode',
'modelCardFooterAction': 'model_card_footer_action',
}
updated = False

View File

@@ -491,7 +491,13 @@ export function createModelCard(model, modelType) {
// Generate UI text with i18n support
const toggleBlurTitle = translate('modelCard.actions.toggleBlur', {}, 'Toggle blur');
const showButtonText = translate('modelCard.actions.show', {}, 'Show');
const openExampleImagesTitle = translate('modelCard.actions.openExampleImages', {}, 'Open Example Images Folder');
const footerActionSetting = state.global.settings.model_card_footer_action || 'example_images';
const footerActionTitle = footerActionSetting === 'replace_preview'
? translate('modelCard.actions.replacePreview', {}, 'Replace Preview')
: translate('modelCard.actions.openExampleImages', {}, 'Open Example Images Folder');
const footerActionIcon = footerActionSetting === 'replace_preview'
? 'fas fa-image'
: 'fas fa-folder-open';
card.innerHTML = `
<div class="card-preview ${shouldBlur ? 'blurred' : ''}">
@@ -525,8 +531,8 @@ export function createModelCard(model, modelType) {
${model.civitai?.name ? `<span class="version-name">${model.civitai.name}</span>` : ''}
</div>
<div class="card-actions">
<i class="fas fa-folder-open"
title="${openExampleImagesTitle}">
<i class="${footerActionIcon}"
title="${footerActionTitle}">
</i>
</div>
</div>

View File

@@ -290,6 +290,12 @@ export class SettingsManager {
cardInfoDisplaySelect.value = state.global.settings.card_info_display || 'always';
}
// Set model card footer action
const modelCardFooterActionSelect = document.getElementById('modelCardFooterAction');
if (modelCardFooterActionSelect) {
modelCardFooterActionSelect.value = state.global.settings.model_card_footer_action || 'example_images';
}
// Set model name display setting
const modelNameDisplaySelect = document.getElementById('modelNameDisplay');
if (modelNameDisplaySelect) {
@@ -1221,6 +1227,10 @@ export class SettingsManager {
if (settingKey === 'model_name_display') {
this.reloadContent();
}
if (settingKey === 'model_card_footer_action') {
this.reloadContent();
}
} catch (error) {
showToast('toast.settings.settingSaveFailed', { message: error.message }, 'error');
}

View File

@@ -27,6 +27,7 @@ const DEFAULT_SETTINGS_BASE = Object.freeze({
display_density: 'default',
card_info_display: 'always',
model_name_display: 'model_name',
model_card_footer_action: 'example_images',
include_trigger_words: false,
compact_mode: false,
priority_tags: { ...DEFAULT_PRIORITY_TAG_CONFIG },

View File

@@ -172,6 +172,23 @@
</ul>
</div>
</div>
<div class="setting-item">
<div class="setting-row">
<div class="setting-info">
<label for="modelCardFooterAction">{{ t('settings.layoutSettings.modelCardFooterAction') }}</label>
</div>
<div class="setting-control select-control">
<select id="modelCardFooterAction" onchange="settingsManager.saveSelectSetting('modelCardFooterAction', 'model_card_footer_action')">
<option value="example_images">{{ t('settings.layoutSettings.modelCardFooterActionOptions.exampleImages') }}</option>
<option value="replace_preview">{{ t('settings.layoutSettings.modelCardFooterActionOptions.replacePreview') }}</option>
</select>
</div>
</div>
<div class="input-help">
{{ t('settings.layoutSettings.modelCardFooterActionHelp') }}
</div>
</div>
<!-- Language Selection -->
<div class="setting-item">