Compare commits

...

2 Commits

Author SHA1 Message Date
wood chen
6acd9bcc01
Merge pull request #25 from cumany/main
支持标签组功能,支持直接从列表多选标签。
2025-07-13 03:26:46 +08:00
cumany
951eba6bc5 支持标签组功能,支持直接从列表多选标签。 2025-07-12 16:51:52 +08:00
3 changed files with 143 additions and 21 deletions

View File

@ -303,12 +303,41 @@ export class DiscourseAPI {
if (data && data.tags) {
const canCreateTags = await this.checkCanCreateTags();
// 处理所有标签包括tag_groups中的标签
const allTags = new Map<string, { name: string; count: number }>();
// 添加普通标签
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;

View File

@ -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);
};

View File

@ -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"] {