From fb2b69b787a8fa7229ed55ff7c9201f4a9437216 Mon Sep 17 00:00:00 2001 From: Will Miao <13051207myq@gmail.com> Date: Fri, 5 Sep 2025 09:27:45 +0800 Subject: [PATCH] feat(tags): refactor preset tags to constants for better maintainability --- static/js/components/shared/ModelTags.js | 9 +- static/js/managers/BulkManager.js | 124 +++++++++++++++++++---- static/js/utils/constants.js | 7 ++ 3 files changed, 113 insertions(+), 27 deletions(-) diff --git a/static/js/components/shared/ModelTags.js b/static/js/components/shared/ModelTags.js index ca958d6a..08ae6900 100644 --- a/static/js/components/shared/ModelTags.js +++ b/static/js/components/shared/ModelTags.js @@ -4,14 +4,7 @@ */ import { showToast } from '../../utils/uiHelpers.js'; import { getModelApiClient } from '../../api/modelApiFactory.js'; -import { translate } from '../../utils/i18nHelpers.js'; - -// Preset tag suggestions -const PRESET_TAGS = [ - 'character', 'style', 'concept', 'clothing', - 'poses', 'background', 'vehicle', 'buildings', - 'objects', 'animal' -]; +import { PRESET_TAGS } from '../../utils/constants.js'; // Create a named function so we can remove it later let saveTagsHandler = null; diff --git a/static/js/managers/BulkManager.js b/static/js/managers/BulkManager.js index 3b4116f2..7ecdadcf 100644 --- a/static/js/managers/BulkManager.js +++ b/static/js/managers/BulkManager.js @@ -4,6 +4,7 @@ import { updateCardsForBulkMode } from '../components/shared/ModelCard.js'; import { modalManager } from './ModalManager.js'; import { getModelApiClient } from '../api/modelApiFactory.js'; import { MODEL_TYPES, MODEL_CONFIG } from '../api/apiConfig.js'; +import { PRESET_TAGS } from '../utils/constants.js'; export class BulkManager { constructor() { @@ -437,13 +438,6 @@ export class BulkManager { } initializeBulkTagsInterface() { - // Import preset tags from ModelTags.js - const PRESET_TAGS = [ - 'character', 'style', 'concept', 'clothing', - 'poses', 'background', 'vehicle', 'buildings', - 'objects', 'animal' - ]; - // Setup tag input behavior const tagInput = document.querySelector('.bulk-metadata-input'); if (tagInput) { @@ -452,6 +446,8 @@ export class BulkManager { e.preventDefault(); this.addBulkTag(e.target.value.trim()); e.target.value = ''; + // Update dropdown to show added indicator + this.updateBulkSuggestionsDropdown(); } }); } @@ -496,19 +492,30 @@ export class BulkManager { container.className = 'metadata-suggestions-container'; presetTags.forEach(tag => { - const item = document.createElement('div'); - item.className = 'metadata-suggestion-item'; - item.title = tag; - item.innerHTML = `${tag}`; + // Check if tag is already added + const existingTags = this.getBulkExistingTags(); + const isAdded = existingTags.includes(tag); - item.addEventListener('click', () => { - this.addBulkTag(tag); - const input = document.querySelector('.bulk-metadata-input'); - if (input) { - input.value = tag; - input.focus(); - } - }); + const item = document.createElement('div'); + item.className = `metadata-suggestion-item ${isAdded ? 'already-added' : ''}`; + item.title = tag; + item.innerHTML = ` + ${tag} + ${isAdded ? '' : ''} + `; + + if (!isAdded) { + item.addEventListener('click', () => { + this.addBulkTag(tag); + const input = document.querySelector('.bulk-metadata-input'); + if (input) { + input.value = tag; + input.focus(); + } + // Update dropdown to show added indicator + this.updateBulkSuggestionsDropdown(); + }); + } container.appendChild(item); }); @@ -560,11 +567,81 @@ export class BulkManager { deleteBtn.addEventListener('click', (e) => { e.stopPropagation(); newTag.remove(); + // Update dropdown to show/hide added indicator + this.updateBulkSuggestionsDropdown(); }); tagsContainer.appendChild(newTag); } + /** + * Get existing tags in the bulk tags container + * @returns {Array} Array of existing tag strings + */ + getBulkExistingTags() { + const tagsContainer = document.getElementById('bulkTagsItems'); + if (!tagsContainer) return []; + + const currentTags = tagsContainer.querySelectorAll('.metadata-item'); + return Array.from(currentTags).map(tag => tag.dataset.tag); + } + + /** + * Update status of items in the bulk suggestions dropdown + */ + updateBulkSuggestionsDropdown() { + const dropdown = document.querySelector('.metadata-suggestions-dropdown'); + if (!dropdown) return; + + // Get all current tags + const existingTags = this.getBulkExistingTags(); + + // Update status of each item in dropdown + dropdown.querySelectorAll('.metadata-suggestion-item').forEach(item => { + const tagText = item.querySelector('.metadata-suggestion-text').textContent; + const isAdded = existingTags.includes(tagText); + + if (isAdded) { + item.classList.add('already-added'); + + // Add indicator if it doesn't exist + let indicator = item.querySelector('.added-indicator'); + if (!indicator) { + indicator = document.createElement('span'); + indicator.className = 'added-indicator'; + indicator.innerHTML = ''; + item.appendChild(indicator); + } + + // Remove click event + item.onclick = null; + item.removeEventListener('click', item._clickHandler); + } else { + // Re-enable items that are no longer in the list + item.classList.remove('already-added'); + + // Remove indicator if it exists + const indicator = item.querySelector('.added-indicator'); + if (indicator) indicator.remove(); + + // Restore click event if not already set + if (!item._clickHandler) { + item._clickHandler = () => { + this.addBulkTag(tagText); + const input = document.querySelector('.bulk-metadata-input'); + if (input) { + input.value = tagText; + input.focus(); + } + // Update dropdown to show added indicator + this.updateBulkSuggestionsDropdown(); + }; + item.addEventListener('click', item._clickHandler); + } + } + }); + } + async saveBulkTags(mode = 'append') { const tagElements = document.querySelectorAll('#bulkTagsItems .metadata-item'); const tags = Array.from(tagElements).map(tag => tag.dataset.tag); @@ -647,6 +724,15 @@ export class BulkManager { if (replaceBtn) { replaceBtn.replaceWith(replaceBtn.cloneNode(true)); } + + // Remove the suggestions dropdown + const tagForm = document.querySelector('#bulkAddTagsModal .metadata-add-form'); + if (tagForm) { + const dropdown = tagForm.querySelector('.metadata-suggestions-dropdown'); + if (dropdown) { + dropdown.remove(); + } + } } } diff --git a/static/js/utils/constants.js b/static/js/utils/constants.js index 9f440aa5..196de1fc 100644 --- a/static/js/utils/constants.js +++ b/static/js/utils/constants.js @@ -163,3 +163,10 @@ export const NODE_TYPE_ICONS = { // Default ComfyUI node color when bgcolor is null export const DEFAULT_NODE_COLOR = "#353535"; + +// Preset tag suggestions +export const PRESET_TAGS = [ + 'character', 'style', 'concept', 'clothing', + 'poses', 'background', 'vehicle', 'buildings', + 'objects', 'animal' +];