From ef567a449ecdefd2bf4ce5aaf69ba0db74154f9a Mon Sep 17 00:00:00 2001 From: Dariusz L Date: Sun, 26 Apr 2026 02:55:09 +0200 Subject: [PATCH] Add token visibility toggles and CivitAI help Add UI and behavior for showing/hiding API tokens: new CSS (.ml-options-input-row, .ml-options-visibility-btn), visibility buttons next to CivitAI, CivitAI session and HuggingFace inputs, and JS helpers (getVisibilityIcon, syncVisibilityToggle, bindVisibilityToggle) to toggle input type and update button state/aria attributes. Introduce an inline help button and expandable help panel with step-by-step instructions for obtaining the __Secure-civitai-token and an "Open CivitAI" action. Remove the Clear Tokens button from the actions and its previous handler. Overall improves UX for managing and understanding token usage while keeping tokens stored locally. --- web/linker.js | 151 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 134 insertions(+), 17 deletions(-) diff --git a/web/linker.js b/web/linker.js index fcceb47..2be801b 100644 --- a/web/linker.js +++ b/web/linker.js @@ -2760,6 +2760,11 @@ class LinkerManagerDialog extends ComfyDialog { color: var(--ml-text-muted); line-height: 1.45; } + .ml-options-input-row { + display: flex; + align-items: center; + gap: 8px; + } .ml-options-input { width: 100%; padding: 10px 12px; @@ -2774,6 +2779,34 @@ class LinkerManagerDialog extends ComfyDialog { border-color: rgba(78,161,255,0.45); box-shadow: 0 0 0 3px rgba(78,161,255,0.12); } + .ml-options-visibility-btn { + width: 38px; + min-width: 38px; + height: 38px; + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid var(--ml-border); + border-radius: 10px; + background: rgba(255,255,255,0.04); + color: var(--ml-text-muted); + cursor: pointer; + transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease; + } + .ml-options-visibility-btn:hover { + background: rgba(255,255,255,0.08); + color: var(--ml-text); + border-color: rgba(78,161,255,0.35); + } + .ml-options-visibility-btn[aria-pressed="true"] { + color: var(--ml-text); + border-color: rgba(78,161,255,0.35); + } + .ml-options-visibility-btn svg { + width: 18px; + height: 18px; + display: block; + } .ml-options-actions { display: flex; gap: 8px; @@ -3598,23 +3631,62 @@ class LinkerManagerDialog extends ComfyDialog {
- +
+ + +
Used for direct CivitAI downloads that otherwise return HTTP 401 or 403.
- - + +
+ + +
Used only for CivitAI web search (civitai.red) to include results available to your logged-in session, including NSFW. Keep it private.
+
- +
+ + +
Used for gated HuggingFace repos that need authorization during download.
-
Saved only on this machine.
@@ -3624,9 +3696,52 @@ class LinkerManagerDialog extends ComfyDialog { const civitaiInput = this.contentElement.querySelector('#ml-options-civitai'); const civitaiSessionInput = this.contentElement.querySelector('#ml-options-civitai-session'); const hfInput = this.contentElement.querySelector('#ml-options-hf'); + const civitaiToggle = this.contentElement.querySelector('#ml-options-civitai-toggle'); + const civitaiSessionToggle = this.contentElement.querySelector('#ml-options-civitai-session-toggle'); + const hfToggle = this.contentElement.querySelector('#ml-options-hf-toggle'); const status = this.contentElement.querySelector('#ml-options-status'); const saveBtn = this.contentElement.querySelector('#ml-options-save'); - const clearBtn = this.contentElement.querySelector('#ml-options-clear'); + const civitaiHelpBtn = this.contentElement.querySelector('#ml-options-civitai-help'); + const civitaiHelpPanel = this.contentElement.querySelector('#ml-options-civitai-help-panel'); + const openCivitaiBtn = this.contentElement.querySelector('#ml-options-open-civitai'); + + const getVisibilityIcon = (visible) => visible + ? ` + + ` + : ` + + `; + + const syncVisibilityToggle = (input, button) => { + if (!input || !button) return; + const visible = input.type === 'text'; + button.innerHTML = getVisibilityIcon(visible); + button.style.color = visible ? 'var(--ml-text)' : 'var(--ml-text-muted)'; + button.setAttribute('aria-pressed', visible ? 'true' : 'false'); + button.setAttribute('title', visible ? 'Hide value' : 'Show value'); + }; + + const bindVisibilityToggle = (input, button) => { + if (!input || !button) return; + syncVisibilityToggle(input, button); + button.addEventListener('click', () => { + input.type = input.type === 'password' ? 'text' : 'password'; + syncVisibilityToggle(input, button); + }); + }; + + bindVisibilityToggle(civitaiInput, civitaiToggle); + bindVisibilityToggle(civitaiSessionInput, civitaiSessionToggle); + bindVisibilityToggle(hfInput, hfToggle); if (saveBtn) { saveBtn.addEventListener('click', async () => { @@ -3639,17 +3754,19 @@ class LinkerManagerDialog extends ComfyDialog { }); } - if (clearBtn) { - clearBtn.addEventListener('click', async () => { - localStorage.removeItem('modelLinker.civitaiApiKey'); - localStorage.removeItem('modelLinker.civitaiSessionToken'); - localStorage.removeItem('modelLinker.huggingFaceToken'); - if (civitaiInput) civitaiInput.value = ''; - if (civitaiSessionInput) civitaiSessionInput.value = ''; - if (hfInput) hfInput.value = ''; - await this.clearSearchCaches(); - if (status) status.textContent = 'Tokens cleared.'; - this.showNotification('API tokens cleared and search cache reset', 'info'); + if (civitaiHelpBtn && civitaiHelpPanel) { + civitaiHelpBtn.addEventListener('click', () => { + const isHidden = civitaiHelpPanel.style.display === 'none'; + civitaiHelpPanel.style.display = isHidden ? 'block' : 'none'; + civitaiHelpBtn.textContent = isHidden + ? 'Hide CivitAI Token Instructions' + : 'How To Get CivitAI Session Token'; + }); + } + + if (openCivitaiBtn) { + openCivitaiBtn.addEventListener('click', () => { + window.open('https://civitai.red', '_blank', 'noopener,noreferrer'); }); } }