diff --git a/web/css/linker-main.css b/web/css/linker-main.css index 59970f1..3603c3a 100644 --- a/web/css/linker-main.css +++ b/web/css/linker-main.css @@ -2371,6 +2371,16 @@ box-shadow: none; cursor: not-allowed; } +.ml-btn.ml-footer-btn.ml-btn-is-disabled, +.ml-btn.ml-btn-primary.ml-footer-btn.ml-btn-is-disabled, +.ml-btn.ml-btn-download.ml-footer-btn.ml-btn-is-disabled { + opacity: 1; + color: rgba(255,255,255,0.34); + background: rgba(255,255,255,0.016); + border-color: rgba(255,255,255,0.055); + box-shadow: none; + cursor: not-allowed; +} /* Tabs */ .ml-tabs { diff --git a/web/linker.js b/web/linker.js index d84ceaa..3c4fd14 100644 --- a/web/linker.js +++ b/web/linker.js @@ -5030,13 +5030,21 @@ class LinkerManagerDialog extends ComfyDialog { updateApplyPendingButton() { if (!this.applyPendingBtn) return; const count = this.pendingResolutions?.length || 0; + const isEmpty = count === 0; + const tooltip = count > 0 + ? `Apply ${count} queued model link${count > 1 ? 's' : ''} to the current workflow.` + : 'Apply the model links you selected from local matches or search results.'; this.applyPendingBtn.textContent = `Apply Selected (${count})`; - this.applyPendingBtn.disabled = count === 0; + this.setTooltip(this.applyPendingBtn, tooltip); + this.applyPendingBtn.setAttribute('aria-disabled', String(isEmpty)); + this.applyPendingBtn.classList.toggle('ml-btn-is-disabled', isEmpty); } createFooter() { // Store reference to download all button so we can update its text this.downloadAllButton = $el("button.ml-btn.ml-btn-download.ml-footer-btn", { + "data-tooltip": "Download every missing model that has a known download source.", + "aria-label": "Download all missing models", onclick: () => this.handleDownloadAllClick() }, [ $el("span.ml-btn-icon", { textContent: "☁" }), @@ -5045,6 +5053,8 @@ class LinkerManagerDialog extends ComfyDialog { // Auto-resolve button (secondary style) this.autoResolveButton = $el("button.ml-btn.ml-btn-secondary.ml-footer-btn", { + "data-tooltip": "Automatically link all missing models with a 100% local match.", + "aria-label": "Auto-link all 100 percent local matches", onclick: () => this.autoResolve100Percent() }, [ $el("span.ml-btn-icon", { textContent: "🔗" }), @@ -5054,9 +5064,24 @@ class LinkerManagerDialog extends ComfyDialog { // Apply pending resolutions button this.applyPendingBtn = $el("button.ml-btn.ml-btn-primary.ml-footer-btn", { id: "apply-pending-resolutions", + "data-tooltip": "Apply the model links you selected from local matches or search results.", + "aria-label": "Apply selected model links", + "aria-disabled": "true", textContent: "Apply Selected (0)", - onclick: () => this.applyPendingResolutions() + onclick: () => { + if ((this.pendingResolutions?.length || 0) === 0) return; + this.applyPendingResolutions(); + } }); + this.applyPendingBtn.classList.add('ml-btn-is-disabled'); + this.downloadAllButton.setAttribute('aria-label', 'Download all missing models'); + this.autoResolveButton.setAttribute('aria-label', 'Auto-link all 100 percent local matches'); + this.applyPendingBtn.setAttribute('aria-label', 'Apply selected model links'); + this.applyPendingBtn.setAttribute('aria-disabled', 'true'); + + this.setTooltip(this.downloadAllButton, 'Download every missing model that has a known download source.'); + this.setTooltip(this.autoResolveButton, 'Automatically link all missing models with a 100% local match.'); + this.setTooltip(this.applyPendingBtn, 'Apply the model links you selected from local matches or search results.'); return $el("div.ml-footer", {}, [ this.autoResolveButton, @@ -5126,10 +5151,20 @@ class LinkerManagerDialog extends ComfyDialog { const activeCount = Object.keys(this.activeDownloads).length; if (activeCount > 0) { this.downloadAllButton.innerHTML = `✕ Cancel All (${activeCount})`; + this.downloadAllButton.setAttribute( + 'data-tooltip', + `Cancel ${activeCount} active download${activeCount > 1 ? 's' : ''}.` + ); + this.downloadAllButton.setAttribute('aria-label', 'Cancel all active downloads'); this.downloadAllButton.classList.remove('ml-btn-download'); this.downloadAllButton.classList.add('ml-btn-danger'); } else { this.downloadAllButton.innerHTML = `☁ Download All Missing`; + this.downloadAllButton.setAttribute( + 'data-tooltip', + 'Download every missing model that has a known download source.' + ); + this.downloadAllButton.setAttribute('aria-label', 'Download all missing models'); this.downloadAllButton.classList.remove('ml-btn-danger'); this.downloadAllButton.classList.add('ml-btn-download'); }