fix(recipes): polish deleted-LoRA reconnect panel UI

- fix .reconnect-input overflow (calc(100% - 20px) -> border-box 100%)
- replace nested-card border/background with a dashed top separator
- route reconnect copy through translate(); add recipes.resources
  .reconnectInstructions/reconnectExample/reconnectPlaceholder keys
  and translate them in all 9 locales
- show reconnect failures inline in the panel (role=alert) instead of
  a transient toast; errors clear on input/show/hide
- drop dead .reconnect-instructions code CSS; add regression test
This commit is contained in:
Will Miao
2026-08-29 18:09:33 +08:00
parent fc9088bfd6
commit 6e31da7a70
13 changed files with 116 additions and 27 deletions
+18 -18
View File
@@ -966,14 +966,14 @@
/* Deleted badge is a pure status indicator; the reconnect action lives on
an explicit ghost button in the item's action row. */
/* LoRA reconnect container */
/* LoRA reconnect container: an inline extension of the item, not a nested
card — a dashed separator reads lighter than another bordered box inside
an already bordered item. */
.lora-reconnect-container {
display: none;
flex-direction: column;
background: var(--lora-surface);
border: 1px solid var(--border-color);
border-radius: var(--border-radius-xs);
padding: 12px;
border-top: 1px dashed var(--border-color);
padding-top: 10px;
margin-top: 10px;
gap: 10px;
}
@@ -1001,18 +1001,6 @@
font-size: 0.85em;
}
.reconnect-instructions code {
background: rgba(0, 0, 0, 0.1);
padding: 2px 4px;
border-radius: 3px;
font-family: var(--font-mono);
font-size: 0.9em;
}
[data-theme="dark"] .reconnect-instructions code {
background: rgba(255, 255, 255, 0.1);
}
.reconnect-form {
display: flex;
flex-direction: column;
@@ -1020,7 +1008,8 @@
}
.reconnect-input {
width: calc(100% - 20px);
box-sizing: border-box;
width: 100%;
padding: 8px 10px;
border: 1px solid var(--border-color);
border-radius: var(--border-radius-xs);
@@ -1029,6 +1018,17 @@
font-size: 0.9em;
}
.reconnect-error {
display: none;
margin: 0;
color: var(--lora-error);
font-size: 0.85em;
}
.reconnect-error.active {
display: block;
}
.reconnect-actions {
display: flex;
justify-content: flex-end;
+32 -9
View File
@@ -963,16 +963,17 @@ class RecipeModal {
${isDeleted || lora.hashInvalid ? `
<div class="lora-reconnect-container" data-lora-index="${loraIndex}">
<div class="reconnect-instructions">
<p>Enter LoRA Syntax or Name to Reconnect:</p>
<small>Example: <code>&lt;lora:Boris_Vallejo_BV_flux_D:1&gt;</code> or just <code>Boris_Vallejo_BV_flux_D</code></small>
<p>${escapeHtml(translate('recipes.resources.reconnectInstructions', {}, 'Enter LoRA syntax or name to reconnect:'))}</p>
<small>${escapeHtml(translate('recipes.resources.reconnectExample', {}, 'Example: <lora:name:1> or just the name'))}</small>
</div>
<div class="reconnect-form">
<input type="text" class="reconnect-input" placeholder="Enter LoRA name or syntax">
<input type="text" class="reconnect-input" placeholder="${escapeHtml(translate('recipes.resources.reconnectPlaceholder', {}, 'Enter LoRA name or syntax'))}">
<div class="reconnect-actions">
<button class="reconnect-cancel-btn">Cancel</button>
<button class="reconnect-confirm-btn">Reconnect</button>
<button class="reconnect-cancel-btn">${escapeHtml(translate('common.cancel', {}, 'Cancel'))}</button>
<button class="reconnect-confirm-btn">${escapeHtml(translate('recipes.resources.reconnect', {}, 'Reconnect'))}</button>
</div>
</div>
<p class="reconnect-error" role="alert"></p>
</div>` : ''}
</div>
</div>
@@ -1660,6 +1661,9 @@ class RecipeModal {
// Add keydown handlers to reconnect inputs
const reconnectInputs = document.querySelectorAll('.reconnect-input');
reconnectInputs.forEach(input => {
input.addEventListener('input', () => {
this.clearReconnectError(input.closest('.lora-reconnect-container'));
});
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
const container = input.closest('.lora-reconnect-container');
@@ -1683,6 +1687,7 @@ class RecipeModal {
const container = document.querySelector(`.lora-reconnect-container[data-lora-index="${loraIndex}"]`);
if (container) {
container.classList.add('active');
this.clearReconnectError(container);
const input = container.querySelector('.reconnect-input');
input.focus();
}
@@ -1691,14 +1696,33 @@ class RecipeModal {
hideReconnectInput(container) {
if (container && container.classList.contains('active')) {
container.classList.remove('active');
this.clearReconnectError(container);
const input = container.querySelector('.reconnect-input');
if (input) input.value = '';
}
}
showReconnectError(container, message) {
const error = container && container.querySelector('.reconnect-error');
if (error) {
error.textContent = message;
error.classList.add('active');
}
}
clearReconnectError(container) {
const error = container && container.querySelector('.reconnect-error');
if (error) {
error.textContent = '';
error.classList.remove('active');
}
}
async reconnectLora(loraIndex, inputValue) {
const container = document.querySelector(`.lora-reconnect-container[data-lora-index="${loraIndex}"]`);
if (!inputValue || !inputValue.trim()) {
showToast('toast.recipes.enterLoraName', {}, 'error');
this.showReconnectError(container, translate('toast.recipes.enterLoraName', {}, 'Please enter a LoRA name or syntax'));
return;
}
@@ -1729,7 +1753,6 @@ class RecipeModal {
if (result.success) {
// Hide the reconnect input
const container = document.querySelector(`.lora-reconnect-container[data-lora-index="${loraIndex}"]`);
this.hideReconnectInput(container);
// Update the current recipe with the updated lora data
@@ -1747,11 +1770,11 @@ class RecipeModal {
loras: this.currentRecipe.loras
});
} else {
showToast('toast.recipes.reconnectFailed', { message: result.error }, 'error');
this.showReconnectError(container, translate('toast.recipes.reconnectFailed', { message: result.error }, `Error reconnecting LoRA: ${result.error}`));
}
} catch (error) {
console.error('Error reconnecting LoRA:', error);
showToast('toast.recipes.reconnectFailed', { message: error.message }, 'error');
this.showReconnectError(container, translate('toast.recipes.reconnectFailed', { message: error.message }, `Error reconnecting LoRA: ${error.message}`));
} finally {
state.loadingManager.hide();
}