QuickAdd 脚本 - 利用 Canvas 平铺笔记
前言
在 Obsidian 中文论坛看到这篇 在Excalidraw中列出某笔记所有二级Heading - 经验分享 - Obsidian 中文论坛 ,我就想用 Canvas 来平铺一下,这样笔记可以全局预览和编辑。
实现过程和效果
- 获取当前笔记路径
- 提取所有标题 (可选范围,即标题参数),暂定二级标题
- 设定间距、宽度、高度参数
- 循环排列即生成 JSON 数据
- 生成 canvas 即可
我是固定一个 Canvas 用来编辑,我这边直接随便设置的一个 未命名.canvas
,可以 2 种模式可以相互转换,转换的参数通过代码参数来调节。
Quickadd 配置 Macro 代码
将下述脚本放在 Quickadd 的配置文件夹下,保存为 convertMdToCanvas.js
文件,在 Quickadd 插件设置添加 Macro 动作:
在 Scripts 中选择对应的 convertMdToCanvas
脚本,点击添加即可:
QuickAdd Macro 脚本
const path = require('path');
const fs = require('fs');
// 获取笔记的基本路径
const file = app.workspace.getActiveFile();
const fileFullPath = app.vault.adapter.getFullPath(file.path);
module.exports = {
entry: async (QuickAdd, settings, params) => {
// 可调节的参数
// 大纲等级
const level = Number(settings["level"]);
// 卡片参数
const width = Number(settings["width"]);
const height = Number(settings["height"]);
// 卡片间隔
const space = Number(settings["space"]);
// 每行卡片的数量限制
const limit = Number(settings["limit"]);
// 基于库的相对路径的Canvas
const canvasPath = settings["canvasPath"];
const canvasData = {
nodes: [],
edges: []
};
if (file.extension === 'md') {
console.log("开始获取二级标题");
const { heads, counts } = getHeadings(fileFullPath, level);
console.log(heads);
let x = 0;
let y = 0;
let n = 1;
let nodes = [];
const length = heads.length;
for (let i = 1; i <= length; i++) {
const node = {
id: "",
type: "file",
file: file.path,
subpath: "",
x: 0,
y: 0,
width: width,
height: height,
};
node.subpath = heads[i - 1];
node.id = String(i);
node.x = x;
node.y = y;
node.color = String(counts[i - 1]-1)
console.log([heads[i - 1], x, y]);
x += width + space;
if (i >= limit * n) {
y += height + space;
x = 0;
n = n + 1;
}
console.log([heads[i - 1], node.x, y]);
nodes.push(node);
}
canvasData.nodes = nodes;
console.log(canvasData);
const canvasFile = app.vault.getAbstractFileByPath(canvasPath);
const canvasJson = JSON.stringify(canvasData, null, 2);
if (canvasFile) {
app.vault.modify(canvasFile, canvasJson);
app.workspace.activeLeaf.openFile(canvasFile);
} else {
canvasFile = app.vault.create(canvasPath, canvasJson);
app.workspace.activeLeaf.openFile(canvasFile);
}
// 尝试重新加载缩略图
setTimeout(() => {
try {
app.commands.executeCommandById("canvas-minimap:reload");
} catch (error) {
console.log(error);
}
}, 1000);
} else if (file.extension === 'canvas') {
fs.readFile(fileFullPath, 'utf8', (err, data) => {
if (err) throw err;
const canvasData = JSON.parse(data);
// 获取nodes中的object.file
canvasData.nodes;
const mdFilePath = canvasData.nodes[0].file;
app.workspace.activeLeaf.openFile(app.vault.getAbstractFileByPath(mdFilePath));
});
}
},
settings: {
name: "Convert md to canvas",
author: "熊猫别熬夜",
options: {
"canvasPath": {
type: "text",
defaultValue: "MdToCanvas.canvas",
placeholder: "相对路径",
description: "设置Canvas路径,可以嵌套子文件夹",
},
"level": {
type: "dropdown",
defaultValue: 2,
options: [2, 3, 4, 5, 6],
description: "设置平铺的大纲等级,每个等级对应不同颜色",
},
"width": {
type: "text",
defaultValue: "1080",
placeholder: "卡片参数",
description: "卡片宽度",
},
"height": {
type: "text",
defaultValue: "1000",
placeholder: "卡片参数",
description: "卡片高度",
},
"limit": {
type: "text",
defaultValue: "3",
placeholder: "每行卡片数量",
description: "每行卡片数量",
},
"space": {
type: "text",
defaultValue: "250",
placeholder: "卡片间隔",
description: "卡片之间的间隔",
},
}
}
};
function getHeadings(fileFullPath, level) {
// 读取文件内容
const fileContent = fs.readFileSync(fileFullPath, 'utf-8');
// 使用正则表达式提取指定级别的标题
const regex = new RegExp(`^#{2,${level}}\\s(.+)`, 'gm');
const heads = [];
let head;
let counts = [];
while ((head = regex.exec(fileContent)) !== null) {
heads.push("#" + head[1]);
counts.push(head[0].match(/#/g).length);
}
return { heads, counts };
}
可调整的参数
配合 Canvas Minimal 插件
另外推荐 Canvas Minimal,可以给 Canvas 生成缩略图并点击可跳转。
References
讨论
若阁下有独到的见解或新颖的想法,诚邀您在文章下方留言,与大家共同探讨。
反馈交流
其他渠道
版权声明
版权声明:所有 PKMer 文章如果需要转载,请附上原文出处链接。