feat(M2): FR-E6 链接气泡+图片入库——LinkBubbleMenu(编辑/移除href);ImageView 节点视图(相对路径转 vaultasset:// 协议展示);assetPickImage/assetWrite IPC + .attachments 入库;剪贴板粘贴图片入库;工具栏 链接/图片/网图 按钮;CSP 放行 vaultasset:;editor-link-image E2E 3 项
This commit is contained in:
@@ -119,6 +119,24 @@ export class FileService {
|
||||
return destRel;
|
||||
}
|
||||
|
||||
// FR-E6:导入本地图片到 .attachments,返回库内相对路径(POSIX)
|
||||
async importAsset(srcAbs: string): Promise<string> {
|
||||
await fs.mkdir(nodePath.join(this.root, ATTACHMENTS_DIR), { recursive: true });
|
||||
const finalName = await dedupeName(this.root, ATTACHMENTS_DIR, sanitizeName(nodePath.basename(srcAbs)));
|
||||
const destRel = joinRel(ATTACHMENTS_DIR, finalName);
|
||||
await fs.copyFile(srcAbs, this.abs(destRel));
|
||||
return destRel;
|
||||
}
|
||||
|
||||
// FR-E6:写入图片字节(base64)到 .attachments,返回库内相对路径(剪贴板粘贴入库)
|
||||
async writeAsset(name: string, dataBase64: string): Promise<string> {
|
||||
await fs.mkdir(nodePath.join(this.root, ATTACHMENTS_DIR), { recursive: true });
|
||||
const finalName = await dedupeName(this.root, ATTACHMENTS_DIR, sanitizeName(name));
|
||||
const destRel = joinRel(ATTACHMENTS_DIR, finalName);
|
||||
await fs.writeFile(this.abs(destRel), Buffer.from(dataBase64, 'base64'));
|
||||
return destRel;
|
||||
}
|
||||
|
||||
async readDoc(path: string): Promise<ReadDocResult> {
|
||||
const abs = this.abs(path);
|
||||
const raw = await fs.readFile(abs, 'utf8');
|
||||
|
||||
@@ -46,6 +46,17 @@ export class VaultService {
|
||||
return result.filePaths[0];
|
||||
}
|
||||
|
||||
// FR-E6:选择本地图片并导入 .attachments,返回库内相对路径(null=取消)
|
||||
async pickImage(): Promise<string | null> {
|
||||
if (!this.fileService) throw new Error('vault not initialized');
|
||||
const r = await dialog.showOpenDialog({
|
||||
properties: ['openFile'],
|
||||
filters: [{ name: '图片', extensions: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'bmp', 'ico'] }],
|
||||
});
|
||||
if (r.canceled || r.filePaths.length === 0) return null;
|
||||
return this.fileService.importAsset(r.filePaths[0]);
|
||||
}
|
||||
|
||||
async switch(root: string): Promise<VaultMeta> {
|
||||
// 校验是存在的目录
|
||||
const stat = await fs.stat(root).catch(() => null);
|
||||
|
||||
Reference in New Issue
Block a user