feat: Implement Canvas file export functionality and enhance Markdown export process
- Added support for exporting `.canvas` files by rendering them to images and generating corresponding `.canvas.md` files. - Updated the export logic to handle both Markdown and Canvas files, including file type checks and notifications. - Improved resource management by ensuring assets are copied correctly and links are updated in the exported content. - Refactored settings to change default export paths from 'docs' to 'wiki' for better organization. - Created detailed implementation notes and flowcharts to document the export processes and core functionalities.
This commit is contained in:
70
src/main.ts
70
src/main.ts
@@ -23,7 +23,7 @@ export default class vitepressExporterPlugin extends Plugin {
|
||||
this.registerEvent(
|
||||
// @ts-ignore
|
||||
this.app.workspace.on("file-menu", (menu: Menu, file: TFile) => {
|
||||
if (file.extension === "md") {
|
||||
if (file.extension === "md" || file.extension === "canvas") {
|
||||
|
||||
menu.addItem((item: MenuItem) => {
|
||||
item
|
||||
@@ -80,8 +80,8 @@ export default class vitepressExporterPlugin extends Plugin {
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeFile.extension !== 'md') {
|
||||
new Notice('Current file is not a Markdown file');
|
||||
if (activeFile.extension !== 'md' && activeFile.extension !== 'canvas') {
|
||||
new Notice('Current file is not a Markdown or canvas file');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,11 @@ export default class vitepressExporterPlugin extends Plugin {
|
||||
|
||||
// 导出单个笔记
|
||||
async exportNote(file: TFile) {
|
||||
if (file.extension === 'canvas') {
|
||||
await this.exportCanvasFile(file);
|
||||
return;
|
||||
}
|
||||
|
||||
const { vault } = this.app;
|
||||
|
||||
// 使用 binary 模式读取文件以保留原始格式(包括行尾空格)
|
||||
@@ -129,6 +134,63 @@ export default class vitepressExporterPlugin extends Plugin {
|
||||
console.warn(`Exported ${file.name} to ${docsPath}`);
|
||||
}
|
||||
|
||||
// 导出 canvas 文件
|
||||
async exportCanvasFile(file: TFile) {
|
||||
const { vault } = this.app;
|
||||
|
||||
// 1. 渲染 canvas 为图片
|
||||
const renderedImage = await this.renderCanvas(file);
|
||||
if (!renderedImage) {
|
||||
new Notice(`Failed to render canvas: ${file.name}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 保存图片到 assetsPath (扁平化存储)
|
||||
const imageFileName = file.name + '.png';
|
||||
const imagePath = `${this.settings.assetsPath}/${imageFileName}`;
|
||||
|
||||
// 确保目标目录存在
|
||||
await vault.adapter.mkdir(this.settings.assetsPath);
|
||||
|
||||
// 写入渲染的图片
|
||||
await vault.adapter.writeBinary(imagePath, renderedImage.buffer);
|
||||
|
||||
console.debug(`Successfully rendered canvas: ${file.path} -> ${imagePath}`);
|
||||
|
||||
// 3. 计算 .canvas.md 文件的输出路径(复用现有逻辑)
|
||||
const fileNameWithoutExt = file.name.replace('.canvas', '');
|
||||
const filePathWithoutExt = file.path.replace('.canvas', '');
|
||||
|
||||
let docsPath: string;
|
||||
if (this.settings.preserveFolderStructure && this.settings.nestNoteFolder) {
|
||||
// 保留文件夹 + 嵌套: notes/some-note.canvas > docs/notes/some-note.canvas/index.md
|
||||
docsPath = `${this.settings.docsPath}/${filePathWithoutExt}.canvas/index.md`;
|
||||
} else if (this.settings.preserveFolderStructure) {
|
||||
// 保留文件夹结构: notes/some-note.canvas > docs/notes/some-note.canvas.md
|
||||
docsPath = `${this.settings.docsPath}/${filePathWithoutExt}.md`;
|
||||
} else if (this.settings.nestNoteFolder) {
|
||||
// 嵌套文件夹: notes/some-note.canvas > docs/some-note.canvas/index.md
|
||||
docsPath = `${this.settings.docsPath}/${fileNameWithoutExt}.canvas/index.md`;
|
||||
} else {
|
||||
// 默认: notes/some-note.canvas > docs/some-note.canvas.md
|
||||
docsPath = `${this.settings.docsPath}/${fileNameWithoutExt}.canvas.md`;
|
||||
}
|
||||
|
||||
// 4. 确保 .canvas.md 目标目录存在
|
||||
const targetDir = docsPath.substring(0, docsPath.lastIndexOf('/'));
|
||||
await vault.adapter.mkdir(targetDir);
|
||||
|
||||
// 5. 生成 .canvas.md 内容
|
||||
const content = `<Viewer src="/${imageFileName}" />`;
|
||||
|
||||
// 6. 写入 .canvas.md 文件
|
||||
const contentBuffer = new TextEncoder().encode(content);
|
||||
await vault.adapter.writeBinary(docsPath, contentBuffer.buffer);
|
||||
|
||||
console.warn(`Exported ${file.name} to ${docsPath}`);
|
||||
new Notice(`Exported ${file.name} to ${docsPath}`);
|
||||
}
|
||||
|
||||
// 处理资源文件
|
||||
async processAssets(content: string, sourceFile: TFile): Promise<string> {
|
||||
const { vault, metadataCache } = this.app;
|
||||
@@ -188,7 +250,7 @@ export default class vitepressExporterPlugin extends Plugin {
|
||||
if (canvasFile instanceof TFile) {
|
||||
const renderedImage = await this.renderCanvas(canvasFile);
|
||||
if (renderedImage) {
|
||||
const imageFileName = canvasFile.name.replace('.canvas', '.png');
|
||||
const imageFileName = canvasFile.name + '.png';
|
||||
// 图片保存到 docs/assets/
|
||||
const imagePath = `${this.settings.assetsPath}/${imageFileName}`;
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ export interface vitepressExporterSettings {
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: vitepressExporterSettings = {
|
||||
docsPath: 'docs',
|
||||
assetsPath: 'docs/public',
|
||||
docsPath: 'wiki',
|
||||
assetsPath: 'wiki/public',
|
||||
nestNoteFolder: true,
|
||||
preserveFolderStructure: true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user