Obsidian Templater 插件的实用代码片段,用于模板中的交互式数据输入。

工具类型与分类选择器

在创建工具卡片时,通过多级弹窗让用户依次选择工具类型和对应分类,支持多选。选中的结果格式化为 wikilink 数组,供模板 frontmatter 使用。

使用场景

  • 适用于 tp-卡片-工具 这类需要填写 tool_types / tool_categories 的模板。
  • 依赖 Dataview 与 Templater:dv.pages("#tool/type") 读取工具类型,tp.system.suggester 负责交互式选择。
  • 片段会在每次选择后从候选列表中移除已选项,避免重复选择;按 ESC 结束当前层级选择。

输出结果

最终得到两个数组:selectedTypesselectedCategories。数组元素会被格式化为 "[[名称]]",可以直接拼入 YAML frontmatter 的列表字段。

// tool types and categories
let types = await dv.pages("#tool/type")
    .sort(p => p.tool_type_id)
    .map(p => p.file.name)
    .array();
let categories = await dv.pages("#tool/category")
    .sort(p => [p.tool_type_id, p.tool_category_id])
    .groupBy(p => p.tool_type_id)
    .map(p => p.rows.map(r => r.file.name).array())
    .array();
const typeCategories = Object.fromEntries(types.map((t, i) => [t, categories[i]]));
let selectMoreTypes = true;
let selectedTypes = [];
let selectedCategories = [];
while (selectMoreTypes) {
    let selectedType = await tp.system.suggester(types, types, false,
        "[Select tool type (ESC when finished)] - " + selectedTypes.join(", ")
    );
    if (!selectedType) {
        break;
    }
    selectedTypes.push(selectedType);
    types = types.filter(t => t !== selectedType);
 
    let currentCategories = typeCategories[selectedType];
    while (true) {
        let selectedCategory = await tp.system.suggester(currentCategories, currentCategories, false,
            "[Select tool category (ESC when finished)] - " + selectedCategories.join(", ")
        );
        if (!selectedCategory) {
            break;
        }
        selectedCategories.push(selectedCategory);
        currentCategories = currentCategories.filter(c => c !== selectedCategory);
    }
}
selectedTypes = selectedTypes.map(t => `"[[${t}]]"`);
selectedCategories = selectedCategories.map(c => `"[[${c}]]"`);