diff --git a/src/api.ts b/src/api.ts index cefc5b5..d3725eb 100644 --- a/src/api.ts +++ b/src/api.ts @@ -303,12 +303,41 @@ export class DiscourseAPI { if (data && data.tags) { const canCreateTags = await this.checkCanCreateTags(); + + // 处理所有标签(包括tag_groups中的标签) + const allTags = new Map(); + + // 添加普通标签 data.tags.forEach((tag: any) => { - tags.push({ + allTags.set(tag.name, { name: tag.name, count: tag.count || 0 }); + }); + + // 添加tag_groups中的标签 + if (data.extras && data.extras.tag_groups) { + data.extras.tag_groups.forEach((group: any) => { + if (group.tags) { + group.tags.forEach((tag: any) => { + // 如果标签已存在,取较大的count值 + const existing = allTags.get(tag.name); + if (existing) { + existing.count = Math.max(existing.count, tag.count || 0); + } else { + allTags.set(tag.name, { name: tag.name, count: tag.count || 0 }); + } + }); + } + }); + } + + // 按count数量排序,转换为最终格式 + const sortedTags = Array.from(allTags.values()) + .sort((a, b) => b.count - a.count) + .map(tag => ({ name: tag.name, canCreate: canCreateTags - }); - }); + })); + + tags.push(...sortedTags); } return tags; diff --git a/src/ui.ts b/src/ui.ts index 95a2706..485f1f3 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -82,6 +82,7 @@ export class SelectCategoryModal extends Modal { removeBtn.onclick = () => { selectedTags.delete(tag); updateSelectedTags(); + showDefaultTags(); // 重新显示网格,让移除的标签重新出现 }; }); }; @@ -101,18 +102,47 @@ export class SelectCategoryModal extends Modal { // 创建标签建议容器 const tagSuggestions = tagInputContainer.createEl('div', { cls: 'tag-suggestions' }); + // 创建默认标签网格容器 + const defaultTagsGrid = tagInputContainer.createEl('div', { cls: 'default-tags-grid' }); + + // 显示默认标签网格 + const showDefaultTags = () => { + defaultTagsGrid.empty(); + const availableTags = this.tags.filter(tag => !selectedTags.has(tag.name)).slice(0, 20); + + if (availableTags.length > 0) { + availableTags.forEach(tag => { + const tagEl = defaultTagsGrid.createEl('span', { + cls: 'grid-tag', + text: tag.name + }); + tagEl.onclick = () => { + selectedTags.add(tag.name); + updateSelectedTags(); + showDefaultTags(); // 重新显示网格,移除已选标签 + }; + }); + } + }; + + // 初始化显示默认标签网格 + showDefaultTags(); + // 处理输入事件,显示匹配的标签 tagInput.oninput = () => { const value = tagInput.value.toLowerCase(); - tagSuggestions.empty(); if (value) { + // 有输入时隐藏默认网格,显示搜索结果 + defaultTagsGrid.style.display = 'none'; + tagSuggestions.empty(); + const matches = this.tags .filter(tag => tag.name.toLowerCase().includes(value) && !selectedTags.has(tag.name) ) - .slice(0, 10); + .slice(0, 20); // 搜索结果显示更多 if (matches.length > 0) { // 获取输入框位置和宽度 @@ -126,6 +156,7 @@ export class SelectCategoryModal extends Modal { tagSuggestions.style.top = `${inputRect.bottom + 4}px`; tagSuggestions.style.left = `${inputRect.left}px`; tagSuggestions.style.width = `${Math.min(inputRect.width, maxWidth)}px`; + tagSuggestions.style.display = 'block'; matches.forEach(tag => { const suggestion = tagSuggestions.createEl('div', { @@ -135,11 +166,20 @@ export class SelectCategoryModal extends Modal { suggestion.onclick = () => { selectedTags.add(tag.name); tagInput.value = ''; - tagSuggestions.empty(); + tagSuggestions.style.display = 'none'; + defaultTagsGrid.style.display = 'grid'; updateSelectedTags(); + showDefaultTags(); }; }); + } else { + tagSuggestions.style.display = 'none'; } + } else { + // 无输入时显示默认网格,隐藏搜索结果 + tagSuggestions.style.display = 'none'; + defaultTagsGrid.style.display = 'grid'; + showDefaultTags(); } }; @@ -153,16 +193,19 @@ export class SelectCategoryModal extends Modal { if (existingTag) { selectedTags.add(existingTag.name); updateSelectedTags(); + showDefaultTags(); } else if (this.canCreateTags) { selectedTags.add(value); updateSelectedTags(); + showDefaultTags(); } else { // 显示权限提示 new Notice(t('PERMISSION_ERROR'), 3000); } } tagInput.value = ''; - tagSuggestions.empty(); + tagSuggestions.style.display = 'none'; + defaultTagsGrid.style.display = 'grid'; } }; @@ -170,7 +213,8 @@ export class SelectCategoryModal extends Modal { tagInput.onblur = () => { // 延迟隐藏,以便可以点击建议 setTimeout(() => { - tagSuggestions.empty(); + tagSuggestions.style.display = 'none'; + defaultTagsGrid.style.display = 'grid'; }, 200); }; diff --git a/styles.css b/styles.css index 0f564ff..d69fcde 100644 --- a/styles.css +++ b/styles.css @@ -199,42 +199,91 @@ If your plugin does not need CSS, delete this file. .discourse-sync-modal .tag { display: inline-flex; align-items: center; - gap: 4px; - padding: 4px 8px; background-color: var(--interactive-accent); color: var(--text-on-accent); + padding: 4px 8px; border-radius: var(--radius-s); font-size: 12px; font-weight: 500; + cursor: pointer; transition: all 0.2s ease; - border: 1px solid var(--interactive-accent); + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .discourse-sync-modal .tag:hover { background-color: var(--interactive-accent-hover); - border-color: var(--interactive-accent-hover); + transform: translateY(-1px); + box-shadow: var(--shadow-s); } .discourse-sync-modal .remove-tag { + margin-left: 6px; cursor: pointer; + font-weight: bold; font-size: 14px; - width: 16px; - height: 16px; + line-height: 1; + opacity: 0.8; + transition: opacity 0.2s ease; display: inline-flex; align-items: center; justify-content: center; + width: 16px; + height: 16px; border-radius: 50%; - background-color: var(--background-modifier-hover); - margin-left: 4px; - transition: all 0.2s ease; - opacity: 0.7; + background-color: rgba(255, 255, 255, 0.2); } .discourse-sync-modal .remove-tag:hover { - background-color: var(--background-modifier-error); - color: var(--text-on-accent); opacity: 1; - transform: scale(1.1); + background-color: rgba(255, 255, 255, 0.3); +} + +/* 默认标签网格样式 */ +.discourse-sync-modal .default-tags-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); + gap: 6px; + margin-top: 8px; + padding: 8px; + background-color: var(--background-secondary); + border-radius: var(--radius-s); + border: 1px solid var(--background-modifier-border); +} + +.discourse-sync-modal .grid-tag { + display: inline-flex; + align-items: center; + justify-content: center; + background-color: var(--background-primary); + color: var(--text-normal); + padding: 6px 8px; + border-radius: var(--radius-s); + font-size: 11px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; + border: 1px solid var(--background-modifier-border); + text-align: center; + min-height: 28px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.discourse-sync-modal .grid-tag:hover { + background-color: var(--interactive-accent); + color: var(--text-on-accent); + border-color: var(--interactive-accent); + transform: translateY(-1px); + box-shadow: var(--shadow-s); +} + +.discourse-sync-modal .grid-tag:active { + transform: translateY(0); + box-shadow: var(--shadow-xs); } .discourse-sync-modal input[type="text"] {