mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-22 13:42:12 -03:00
Refactor model name editing functionality in LoraModal; update styles for improved user interaction and accessibility
This commit is contained in:
@@ -593,56 +593,60 @@
|
||||
|
||||
/* Model name field styles - complete replacement */
|
||||
.model-name-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
width: calc(100% - 40px); /* Reduce width to avoid overlap with close button */
|
||||
position: relative; /* Add position relative for absolute positioning of save button */
|
||||
display: none;
|
||||
}
|
||||
|
||||
.model-name-field h2 {
|
||||
/* New Model Name Header Styles */
|
||||
.model-name-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: calc(100% - 40px); /* Avoid overlap with close button */
|
||||
position: relative;
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
|
||||
.model-name-content {
|
||||
margin: 0;
|
||||
padding: var(--space-1);
|
||||
border-radius: var(--border-radius-xs);
|
||||
transition: background-color 0.2s;
|
||||
flex: 1;
|
||||
font-size: 1.5em !important; /* Increased and forced size */
|
||||
font-weight: 600; /* Make it bolder */
|
||||
min-height: 1.5em;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid transparent;
|
||||
font-size: 1.5em !important;
|
||||
font-weight: 600;
|
||||
line-height: 1.2;
|
||||
color: var(--text-color); /* Ensure correct color */
|
||||
}
|
||||
|
||||
.model-name-field h2:hover {
|
||||
background: oklch(var(--lora-accent) / 0.1);
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.model-name-field h2:focus {
|
||||
color: var(--text-color);
|
||||
border: 1px solid transparent;
|
||||
outline: none;
|
||||
background: var(--bg-color);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.model-name-content:focus {
|
||||
border: 1px solid var(--lora-accent);
|
||||
background: var(--bg-color);
|
||||
}
|
||||
|
||||
.model-name-field .save-btn {
|
||||
position: absolute;
|
||||
right: 10px; /* Position closer to the end of the field */
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
.edit-model-name-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--text-color);
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
cursor: pointer;
|
||||
padding: 2px 5px;
|
||||
border-radius: var(--border-radius-xs);
|
||||
transition: all 0.2s ease;
|
||||
margin-left: var(--space-1);
|
||||
}
|
||||
|
||||
.model-name-field:hover .save-btn,
|
||||
.model-name-field h2:focus ~ .save-btn {
|
||||
opacity: 1;
|
||||
.edit-model-name-btn.visible,
|
||||
.model-name-header:hover .edit-model-name-btn {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* Ensure close button is accessible */
|
||||
.modal-content .close {
|
||||
z-index: 10; /* Ensure close button is above other elements */
|
||||
.edit-model-name-btn:hover {
|
||||
opacity: 0.8 !important;
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .edit-model-name-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
/* Tab System Styling */
|
||||
|
||||
@@ -10,10 +10,10 @@ export function showLoraModal(lora) {
|
||||
<div class="modal-content">
|
||||
<button class="close" onclick="modalManager.closeModal('loraModal')">×</button>
|
||||
<header class="modal-header">
|
||||
<div class="editable-field model-name-field">
|
||||
<div class="model-name-header">
|
||||
<h2 class="model-name-content" contenteditable="true" spellcheck="false">${lora.model_name}</h2>
|
||||
<button class="save-btn" onclick="saveModelName('${lora.file_path}')">
|
||||
<i class="fas fa-save"></i>
|
||||
<button class="edit-model-name-btn" title="Edit model name">
|
||||
<i class="fas fa-pencil-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
${renderCompactTags(lora.tags || [])}
|
||||
@@ -122,6 +122,7 @@ export function showLoraModal(lora) {
|
||||
setupTabSwitching();
|
||||
setupTagTooltip();
|
||||
setupTriggerWordsEditMode();
|
||||
setupModelNameEditing();
|
||||
|
||||
// If we have a model ID but no description, fetch it
|
||||
if (lora.civitai?.modelId && !lora.modelDescription) {
|
||||
@@ -405,61 +406,18 @@ function setupEditableFields() {
|
||||
|
||||
editableFields.forEach(field => {
|
||||
field.addEventListener('focus', function() {
|
||||
if (this.textContent === 'Add your notes here...' ||
|
||||
this.textContent === 'Save usage tips here..') {
|
||||
if (this.textContent === 'Add your notes here...') {
|
||||
this.textContent = '';
|
||||
}
|
||||
});
|
||||
|
||||
field.addEventListener('blur', function() {
|
||||
if (this.textContent.trim() === '') {
|
||||
if (this.classList.contains('model-name-content')) {
|
||||
// Restore original model name if empty
|
||||
const filePath = document.querySelector('.modal-content')
|
||||
.querySelector('.file-path').textContent +
|
||||
document.querySelector('.modal-content')
|
||||
.querySelector('#file-name').textContent + '.safetensors';
|
||||
const loraCard = document.querySelector(`.lora-card[data-filepath="${filePath}"]`);
|
||||
if (loraCard) {
|
||||
this.textContent = loraCard.dataset.model_name;
|
||||
}
|
||||
} else if (this.classList.contains('usage-tips-content')) {
|
||||
this.textContent = 'Save usage tips here..';
|
||||
} else {
|
||||
if (this.classList.contains('notes-content')) {
|
||||
this.textContent = 'Add your notes here...';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Add input validation for model name
|
||||
if (field.classList.contains('model-name-content')) {
|
||||
field.addEventListener('input', function() {
|
||||
// Limit model name length
|
||||
if (this.textContent.length > 100) {
|
||||
this.textContent = this.textContent.substring(0, 100);
|
||||
// Place cursor at the end
|
||||
const range = document.createRange();
|
||||
const sel = window.getSelection();
|
||||
range.setStart(this.childNodes[0], 100);
|
||||
range.collapse(true);
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
|
||||
showToast('Model name is limited to 100 characters', 'warning');
|
||||
}
|
||||
});
|
||||
|
||||
field.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
const filePath = document.querySelector('.modal-content')
|
||||
.querySelector('.file-path').textContent +
|
||||
document.querySelector('.modal-content')
|
||||
.querySelector('#file-name').textContent + '.safetensors';
|
||||
saveModelName(filePath);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const presetSelector = document.getElementById('preset-selector');
|
||||
@@ -473,7 +431,7 @@ function setupEditableFields() {
|
||||
presetValue.style.display = 'inline-block';
|
||||
presetValue.min = selected.includes('strength') ? 0 : 1;
|
||||
presetValue.max = selected.includes('strength') ? 1 : 12;
|
||||
presetValue.step = selected.includes('strength') ? 0.01 : 1;
|
||||
presetValue.step = selected.includes('strength') ? 0.5 : 1;
|
||||
if (selected === 'clip_skip') {
|
||||
presetValue.type = 'number';
|
||||
presetValue.step = 1;
|
||||
@@ -795,7 +753,7 @@ export function scrollToTop(button) {
|
||||
}
|
||||
|
||||
function parsePresets(usageTips) {
|
||||
if (!usageTips || usageTips === 'Save usage tips here..') return {};
|
||||
if (!usageTips) return {};
|
||||
try {
|
||||
return JSON.parse(usageTips);
|
||||
} catch {
|
||||
@@ -852,17 +810,6 @@ function formatFileSize(bytes) {
|
||||
return `${size.toFixed(1)} ${units[unitIndex]}`;
|
||||
}
|
||||
|
||||
// Add tag copy functionality
|
||||
window.copyTag = async function(tag) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(tag);
|
||||
showToast('Tag copied to clipboard', 'success');
|
||||
} catch (err) {
|
||||
console.error('Copy failed:', err);
|
||||
showToast('Copy failed', 'error');
|
||||
}
|
||||
};
|
||||
|
||||
// New function to render compact tags with tooltip
|
||||
function renderCompactTags(tags) {
|
||||
if (!tags || tags.length === 0) return '';
|
||||
@@ -1161,4 +1108,90 @@ window.copyTriggerWord = async function(word) {
|
||||
console.error('Copy failed:', err);
|
||||
showToast('Copy failed', 'error');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// New function to handle model name editing
|
||||
function setupModelNameEditing() {
|
||||
const modelNameContent = document.querySelector('.model-name-content');
|
||||
const editBtn = document.querySelector('.edit-model-name-btn');
|
||||
|
||||
if (!modelNameContent || !editBtn) return;
|
||||
|
||||
// Show edit button on hover
|
||||
const modelNameHeader = document.querySelector('.model-name-header');
|
||||
modelNameHeader.addEventListener('mouseenter', () => {
|
||||
editBtn.classList.add('visible');
|
||||
});
|
||||
|
||||
modelNameHeader.addEventListener('mouseleave', () => {
|
||||
if (!modelNameContent.getAttribute('data-editing')) {
|
||||
editBtn.classList.remove('visible');
|
||||
}
|
||||
});
|
||||
|
||||
// Handle edit button click
|
||||
editBtn.addEventListener('click', () => {
|
||||
modelNameContent.setAttribute('data-editing', 'true');
|
||||
modelNameContent.focus();
|
||||
|
||||
// Place cursor at the end
|
||||
const range = document.createRange();
|
||||
const sel = window.getSelection();
|
||||
if (modelNameContent.childNodes.length > 0) {
|
||||
range.setStart(modelNameContent.childNodes[0], modelNameContent.textContent.length);
|
||||
range.collapse(true);
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
}
|
||||
|
||||
editBtn.classList.add('visible');
|
||||
});
|
||||
|
||||
// Handle focus out
|
||||
modelNameContent.addEventListener('blur', function() {
|
||||
this.removeAttribute('data-editing');
|
||||
editBtn.classList.remove('visible');
|
||||
|
||||
if (this.textContent.trim() === '') {
|
||||
// Restore original model name if empty
|
||||
const filePath = document.querySelector('.modal-content')
|
||||
.querySelector('.file-path').textContent +
|
||||
document.querySelector('.modal-content')
|
||||
.querySelector('#file-name').textContent + '.safetensors';
|
||||
const loraCard = document.querySelector(`.lora-card[data-filepath="${filePath}"]`);
|
||||
if (loraCard) {
|
||||
this.textContent = loraCard.dataset.model_name;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handle enter key
|
||||
modelNameContent.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
const filePath = document.querySelector('.modal-content')
|
||||
.querySelector('.file-path').textContent +
|
||||
document.querySelector('.modal-content')
|
||||
.querySelector('#file-name').textContent + '.safetensors';
|
||||
saveModelName(filePath);
|
||||
this.blur();
|
||||
}
|
||||
});
|
||||
|
||||
// Limit model name length
|
||||
modelNameContent.addEventListener('input', function() {
|
||||
// Limit model name length
|
||||
if (this.textContent.length > 100) {
|
||||
this.textContent = this.textContent.substring(0, 100);
|
||||
// Place cursor at the end
|
||||
const range = document.createRange();
|
||||
const sel = window.getSelection();
|
||||
range.setStart(this.childNodes[0], 100);
|
||||
range.collapse(true);
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
|
||||
showToast('Model name is limited to 100 characters', 'warning');
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user