feat(ui): add adaptive expand/collapse for Additional Notes section (#962)

This commit is contained in:
Will Miao
2026-06-08 20:52:41 +08:00
parent e3c812367e
commit c0e2578640
12 changed files with 154 additions and 19 deletions

View File

@@ -1225,7 +1225,9 @@
},
"notes": {
"saved": "Notizen erfolgreich gespeichert",
"saveFailed": "Fehler beim Speichern der Notizen"
"saveFailed": "Fehler beim Speichern der Notizen",
"showMore": "Mehr anzeigen",
"showLess": "Weniger anzeigen"
},
"usageTips": {
"addPresetParameter": "Voreingestellten Parameter hinzufügen...",

View File

@@ -1225,7 +1225,9 @@
},
"notes": {
"saved": "Notes saved successfully",
"saveFailed": "Failed to save notes"
"saveFailed": "Failed to save notes",
"showMore": "Show more",
"showLess": "Show less"
},
"usageTips": {
"addPresetParameter": "Add preset parameter...",

View File

@@ -1225,7 +1225,9 @@
},
"notes": {
"saved": "Notas guardadas exitosamente",
"saveFailed": "Error al guardar notas"
"saveFailed": "Error al guardar notas",
"showMore": "Mostrar más",
"showLess": "Mostrar menos"
},
"usageTips": {
"addPresetParameter": "Añadir parámetro preestablecido...",

View File

@@ -1225,7 +1225,9 @@
},
"notes": {
"saved": "Notes sauvegardées avec succès",
"saveFailed": "Échec de la sauvegarde des notes"
"saveFailed": "Échec de la sauvegarde des notes",
"showMore": "Afficher plus",
"showLess": "Afficher moins"
},
"usageTips": {
"addPresetParameter": "Ajouter un paramètre prédéfini...",

View File

@@ -1225,7 +1225,9 @@
},
"notes": {
"saved": "הערות נשמרו בהצלחה",
"saveFailed": "שמירת ההערות נכשלה"
"saveFailed": "שמירת ההערות נכשלה",
"showMore": "הצג עוד",
"showLess": "הצג פחות"
},
"usageTips": {
"addPresetParameter": "הוסף פרמטר קבוע מראש...",

View File

@@ -1225,7 +1225,9 @@
},
"notes": {
"saved": "メモが正常に保存されました",
"saveFailed": "メモの保存に失敗しました"
"saveFailed": "メモの保存に失敗しました",
"showMore": "もっと見る",
"showLess": "折りたたむ"
},
"usageTips": {
"addPresetParameter": "プリセットパラメータを追加...",

View File

@@ -1225,7 +1225,9 @@
},
"notes": {
"saved": "메모가 성공적으로 저장됨",
"saveFailed": "메모 저장 실패"
"saveFailed": "메모 저장 실패",
"showMore": "더 보기",
"showLess": "접기"
},
"usageTips": {
"addPresetParameter": "프리셋 매개변수 추가...",

View File

@@ -1225,7 +1225,9 @@
},
"notes": {
"saved": "Заметки успешно сохранены",
"saveFailed": "Не удалось сохранить заметки"
"saveFailed": "Не удалось сохранить заметки",
"showMore": "Показать больше",
"showLess": "Свернуть"
},
"usageTips": {
"addPresetParameter": "Добавить предустановленный параметр...",

View File

@@ -1225,7 +1225,9 @@
},
"notes": {
"saved": "备注保存成功",
"saveFailed": "备注保存失败"
"saveFailed": "备注保存失败",
"showMore": "展开",
"showLess": "收起"
},
"usageTips": {
"addPresetParameter": "添加预设参数...",

View File

@@ -1225,7 +1225,9 @@
},
"notes": {
"saved": "備註已儲存",
"saveFailed": "儲存備註失敗"
"saveFailed": "儲存備註失敗",
"showMore": "展開",
"showLess": "收起"
},
"usageTips": {
"addPresetParameter": "新增預設參數...",

View File

@@ -140,14 +140,66 @@
/* Add specific styles for notes content */
.info-item.notes .editable-field [contenteditable] {
height: 60px; /* Keep initial modal layout stable regardless of note length */
min-height: 60px; /* Increase height for multiple lines */
max-height: 420px; /* Limit maximum height */
overflow: auto; /* Enable scrolling and resize handle for long content */
resize: vertical; /* Allow manual vertical resizing */
white-space: pre-wrap; /* Preserve line breaks */
line-height: 1.5; /* Improve readability */
padding: 8px 12px; /* Slightly increase padding */
min-height: 60px;
white-space: pre-wrap;
line-height: 1.5;
padding: 8px 12px;
}
/* Notes expand/collapse — collapsed by default; only applies when JS detects long content */
.info-item.notes .editable-field {
position: relative;
max-height: none;
overflow: visible;
}
.info-item.notes .editable-field.collapsed {
max-height: 80px;
overflow: hidden;
}
/* Gradient fade overlay hint when collapsed */
.info-item.notes .editable-field.collapsed::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 28px;
background: linear-gradient(transparent, var(--bg-color));
pointer-events: none;
}
/* Notes header row — label left, toggle button right */
.notes-header {
display: flex;
align-items: center;
justify-content: space-between;
}
/* Toggle button — icon only, inline with the label */
.notes-toggle-btn {
display: none; /* shown by JS when content exceeds threshold */
align-items: center;
justify-content: center;
width: 26px;
height: 26px;
padding: 0;
border: none;
background: none;
color: var(--lora-accent);
cursor: pointer;
border-radius: 4px;
transition: background 0.15s;
flex-shrink: 0;
}
.notes-toggle-btn:hover {
background: rgba(66, 153, 225, 0.1);
}
.notes-toggle-btn i {
font-size: 0.85em;
}
.file-path {

View File

@@ -510,7 +510,12 @@ export async function showModelModal(model, modelType) {
</div>
${typeSpecificContent}
<div class="info-item notes">
<label>${translate('modals.model.metadata.additionalNotes', {}, 'Additional Notes')} <i class="fas fa-info-circle notes-hint" title="${translate('modals.model.metadata.notesHint', {}, 'Press Enter to save, Shift+Enter for new line')}"></i></label>
<div class="notes-header">
<label>${translate('modals.model.metadata.additionalNotes', {}, 'Additional Notes')} <i class="fas fa-info-circle notes-hint" title="${translate('modals.model.metadata.notesHint', {}, 'Press Enter to save, Shift+Enter for new line')}"></i></label>
<button class="notes-toggle-btn" style="display:none" title="${translate('modals.model.notes.showMore', {}, 'Show more')}">
<i class="fas fa-chevron-down"></i>
</button>
</div>
<div class="editable-field">
<div class="notes-content" contenteditable="true" spellcheck="false">${modelWithFullData.notes || translate('modals.model.metadata.addNotesPlaceholder', {}, 'Add your notes here...')}</div>
</div>
@@ -837,12 +842,70 @@ function setupEditableFields(filePath, modelType) {
});
}
// Setup adaptive expand/collapse for notes
setupNotesExpand();
// LoRA specific field setup
if (modelType === 'loras') {
setupLoraSpecificFields(filePath);
}
}
/**
* Adaptive expand/collapse for the Additional Notes section.
* Measures content height synchronously after render (before first paint,
* so no visual flash). If notes fit within ~4 lines, no toggle is shown.
* If they exceed the threshold, the field collapses with a gradient fade
* and a "Show more" button appears.
*/
function setupNotesExpand() {
const notesContainer = document.querySelector('.info-item.notes');
if (!notesContainer) return;
const notesField = notesContainer.querySelector('.editable-field');
const notesContent = notesContainer.querySelector('.notes-content');
const toggleBtn = notesContainer.querySelector('.notes-toggle-btn');
if (!notesField || !notesContent || !toggleBtn) return;
const placeholderText = translate('modals.model.metadata.addNotesPlaceholder', {}, 'Add your notes here...');
const content = notesContent.textContent || '';
const isEmpty = !content.trim() || content === placeholderText;
if (isEmpty) {
return;
}
// CSS default has no constraints, so scrollHeight reflects full content
const contentHeight = notesContent.scrollHeight;
const collapsedThreshold = 95; // ~4 lines
if (contentHeight <= collapsedThreshold) {
return;
}
// Long content — collapse and show toggle
notesField.classList.add('collapsed');
toggleBtn.style.display = 'inline-flex';
toggleBtn.title = translate('modals.model.notes.showMore', {}, 'Show more');
const toggleIcon = toggleBtn.querySelector('i');
toggleBtn.addEventListener('click', function onClick() {
const isCollapsed = notesField.classList.contains('collapsed');
if (isCollapsed) {
notesField.classList.remove('collapsed');
toggleBtn.title = translate('modals.model.notes.showLess', {}, 'Show less');
toggleIcon.className = 'fas fa-chevron-up';
notesField.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
} else {
notesField.classList.add('collapsed');
toggleBtn.title = translate('modals.model.notes.showMore', {}, 'Show more');
toggleIcon.className = 'fas fa-chevron-down';
}
});
}
function setupLoraSpecificFields(filePath) {
const presetSelector = document.getElementById('preset-selector');
const presetValue = document.getElementById('preset-value');