diff --git a/web/css/autocomplete-plus.css b/web/css/autocomplete-plus.css index 30852c8..62d37aa 100644 --- a/web/css/autocomplete-plus.css +++ b/web/css/autocomplete-plus.css @@ -5,7 +5,8 @@ --autocomplete-plus-text-color-cat-copyright: var(--p-purple-600); --autocomplete-plus-text-color-cat-character: var(--p-green-600); --autocomplete-plus-text-color-cat-meta: var(--p-yellow-600); - --autocomplete-plus-text-color-cat-unknown: var(--p-grey-600); + --autocomplete-plus-text-color-cat-unknown: var(--p-gray-600); + --autocomplete-plus-text-color-disabled: var(--p-gray-600); /* Selected color */ --autocomplete-plus-text-color-cat-general-selected: var(--p-blue-200); @@ -13,7 +14,7 @@ --autocomplete-plus-text-color-cat-copyright-selected: var(--p-purple-200); --autocomplete-plus-text-color-cat-character-selected: var(--p-green-200); --autocomplete-plus-text-color-cat-meta-selected: var(--p-yellow-200); - --autocomplete-plus-text-color-cat-unknown-selected: var(--p-grey-200); + --autocomplete-plus-text-color-cat-unknown-selected: var(--p-gray-200); } /* Dark Theme */ @@ -23,7 +24,8 @@ body.dark-theme { --autocomplete-plus-text-color-cat-copyright: var(--p-purple-400); --autocomplete-plus-text-color-cat-character: var(--p-green-400); --autocomplete-plus-text-color-cat-meta: var(--p-yellow-400); - --autocomplete-plus-text-color-cat-unknown: var(--p-grey-400); + --autocomplete-plus-text-color-cat-unknown: var(--p-gray-500); + --autocomplete-plus-text-color-disabled: var(--p-gray-500); /* Selected color */ --autocomplete-plus-text-color-cat-general-selected: var(--p-blue-200); @@ -31,7 +33,7 @@ body.dark-theme { --autocomplete-plus-text-color-cat-copyright-selected: var(--p-purple-200); --autocomplete-plus-text-color-cat-character-selected: var(--p-green-200); --autocomplete-plus-text-color-cat-meta-selected: var(--p-yellow-200); - --autocomplete-plus-text-color-cat-unknown-selected: var(--p-grey-200); + --autocomplete-plus-text-color-cat-unknown-selected: var(--p-gray-200); } #autocomplete-plus-list { @@ -210,6 +212,10 @@ body.dark-theme { white-space: nowrap; } +.related-tag-name.related-tag-already-exists { + color: var(--autocomplete-plus-text-color-disabled); +} + .related-tag-alias { overflow: hidden; color: var(--descrip-text); diff --git a/web/js/related-tags.js b/web/js/related-tags.js index 8e03a7a..af86864 100644 --- a/web/js/related-tags.js +++ b/web/js/related-tags.js @@ -425,6 +425,7 @@ class RelatedTagsUI { this.header.appendChild(tagNameSpan); if (!autoCompleteData.initialized) { + // Show loading message const messageDiv = document.createElement('div'); messageDiv.className = 'related-tags-loading-message'; messageDiv.textContent = `Initializing cooccurrence data... [${autoCompleteData.baseLoadingProgress.cooccurrence}%]`; @@ -433,15 +434,19 @@ class RelatedTagsUI { } if (!this.relatedTags || this.relatedTags.length === 0) { + // Show no related tags message const messageCell = document.createElement('div'); messageCell.textContent = 'No related tags found'; this.tagsContainer.appendChild(messageCell); return; } + const existingTagsInTextarea = this.#extractTagsFromTextArea(); + // Create tag rows this.relatedTags.forEach(tagData => { - const tagRow = this.#createTagElement(tagData); + const isExisting = existingTagsInTextarea.has(normalizeTagToSearch(tagData.tag)); + const tagRow = this.#createTagElement(tagData, isExisting); this.tagsContainer.appendChild(tagRow); }); } @@ -449,9 +454,10 @@ class RelatedTagsUI { /** * Creates an HTML table row for a related tag. * @param {TagData} tagData The tag data to display + * @param {boolean} isExisting Whether the tag already exists in the textarea * @returns {HTMLTableRowElement} The tag row element */ - #createTagElement(tagData) { + #createTagElement(tagData, isExisting) { const categoryText = TagCategory[tagData.category] || "unknown"; const tagRow = document.createElement('div'); @@ -464,6 +470,11 @@ class RelatedTagsUI { tagNameCell.className = 'related-tag-name'; tagNameCell.textContent = tagData.tag; + // grayout tag name if it already exists + if (isExisting) { + tagNameCell.classList.add('related-tag-already-exists'); + } + // Alias cell (middle column) const aliasCell = document.createElement('span'); aliasCell.className = 'related-tag-alias'; @@ -628,6 +639,22 @@ class RelatedTagsUI { return area; } + + /** + * Extracts existing tags from the textarea. + * @returns {Set} Set of existing tags in the textarea + */ + #extractTagsFromTextArea() { + const existingTagsInTextarea = new Set(); + if (this.target && this.target.value) { + const tagPositions = findAllTagPositions(this.target.value); + tagPositions.forEach(pos => { + existingTagsInTextarea.add(normalizeTagToSearch(pos.tag)); + }); + } + return existingTagsInTextarea; + } + } // --- RelatedTags Event Handling Class ---