M0-M11 狩夜人笔记初始实现:11里程碑+86测试
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
// 文件约定常量
|
||||
export const MD_EXT = '.md';
|
||||
export const ATTACHMENTS_DIR = '.attachments';
|
||||
export const TMP_SUFFIX = '.dsh-tmp';
|
||||
export const RECENT_VAULT_MAX = 5;
|
||||
export const SEARCH_RESULT_MAX = 100;
|
||||
export const DEFAULT_VAULT_NAME = 'notes';
|
||||
@@ -0,0 +1,7 @@
|
||||
// @hunter/shared — 主进程与渲染进程共享的类型与常量
|
||||
export * from './types/ipc.js';
|
||||
export * from './types/vault.js';
|
||||
export * from './types/doc.js';
|
||||
export * from './types/search.js';
|
||||
export * from './types/graph.js';
|
||||
export * from './constants.js';
|
||||
@@ -0,0 +1,18 @@
|
||||
// 文档元数据白名单(仅 4 个业务字段)
|
||||
export interface DocMeta {
|
||||
title?: string;
|
||||
tags?: string[];
|
||||
star?: boolean;
|
||||
links?: string[];
|
||||
}
|
||||
|
||||
export interface ReadDocResult {
|
||||
meta: DocMeta;
|
||||
body: string;
|
||||
}
|
||||
|
||||
export interface WriteDocPayload {
|
||||
path: string;
|
||||
meta: DocMeta;
|
||||
body: string;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface GraphNode { id: string; title: string; basePath: string; star: boolean; group: string; color: string; }
|
||||
export interface GraphEdge { source: string; target: string; }
|
||||
export interface GraphData { nodes: GraphNode[]; edges: GraphEdge[]; }
|
||||
@@ -0,0 +1,69 @@
|
||||
import type { TreeNode, VaultMeta } from './vault.js';
|
||||
import type { SearchHit, TagStat } from './search.js';
|
||||
import type { GraphData } from './graph.js';
|
||||
import type { DocMeta, ReadDocResult, WriteDocPayload } from './doc.js';
|
||||
|
||||
// ===== IPC 通道命名 =====
|
||||
export const IPC = {
|
||||
vaultList: 'vault:list',
|
||||
vaultSwitch: 'vault:switch',
|
||||
vaultSetDefault: 'vault:set-default',
|
||||
vaultPick: 'vault:pick',
|
||||
treeList: 'tree:list',
|
||||
treeRefresh: 'tree:refresh',
|
||||
fileCreate: 'file:create',
|
||||
fileRename: 'file:rename',
|
||||
fileMove: 'file:move',
|
||||
fileDelete: 'file:delete',
|
||||
fileImport: 'file:import',
|
||||
docRead: 'doc:read',
|
||||
docWrite: 'doc:write',
|
||||
docReveal: 'doc:reveal',
|
||||
search: 'search',
|
||||
tagStats: 'tag:stats',
|
||||
graph: 'graph',
|
||||
winMinimize: 'win:minimize',
|
||||
winMaximize: 'win:maximize',
|
||||
winClose: 'win:close',
|
||||
copyMd: 'doc:copy-md',
|
||||
printPdf: 'doc:print-pdf',
|
||||
} as const;
|
||||
export type IpcChannel = (typeof IPC)[keyof typeof IPC];
|
||||
|
||||
// ===== 请求/响应类型映射 =====
|
||||
export interface IpcMap {
|
||||
[IPC.vaultList]: { args: void; result: VaultMeta };
|
||||
[IPC.vaultSwitch]: { args: { root: string }; result: VaultMeta };
|
||||
[IPC.vaultSetDefault]: { args: { root: string }; result: void };
|
||||
[IPC.vaultPick]: { args: void; result: VaultMeta | null };
|
||||
[IPC.treeList]: { args: void; result: TreeNode[] };
|
||||
[IPC.treeRefresh]: { args: void; result: TreeNode[] };
|
||||
[IPC.fileCreate]: { args: { basePath: string; name: string; isFolder: boolean }; result: { path: string } };
|
||||
[IPC.fileRename]: { args: { from: string; toName: string }; result: { path: string } };
|
||||
[IPC.fileMove]: { args: { src: string; destDir: string }; result: { path: string } };
|
||||
[IPC.fileDelete]: { args: { path: string; recursive: boolean }; result: void };
|
||||
[IPC.fileImport]: { args: { sources: string[]; destDir: string }; result: { ok: string[]; failed: { path: string; reason: string }[] } };
|
||||
[IPC.docRead]: { args: { path: string }; result: ReadDocResult };
|
||||
[IPC.docWrite]: { args: WriteDocPayload; result: void };
|
||||
[IPC.docReveal]: { args: { path: string }; result: void };
|
||||
[IPC.search]: { args: { query: string }; result: SearchHit[] };
|
||||
[IPC.tagStats]: { args: void; result: TagStat[] };
|
||||
[IPC.graph]: { args: void; result: GraphData };
|
||||
[IPC.winMinimize]: { args: void; result: void };
|
||||
[IPC.winMaximize]: { args: void; result: void };
|
||||
[IPC.winClose]: { args: void; result: void };
|
||||
[IPC.copyMd]: { args: { path: string }; result: string };
|
||||
[IPC.printPdf]: { args: void; result: void };
|
||||
}
|
||||
|
||||
// 类型安全的 invoke 帮助器签名(preload 暴露 + 渲染层使用)
|
||||
export type Invoke = <K extends keyof IpcMap>(
|
||||
channel: K,
|
||||
args: IpcMap[K]['args'],
|
||||
) => Promise<IpcMap[K]['result']>;
|
||||
|
||||
// 渲染层通过 preload 拿到的受限 API
|
||||
export interface BridgeApi {
|
||||
invoke: Invoke;
|
||||
send: <K extends keyof IpcMap>(channel: K, args: IpcMap[K]['args']) => void;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export interface SearchHit { path: string; title: string; snippet: string; }
|
||||
export interface TagStat { tag: string; count: number; }
|
||||
@@ -0,0 +1,19 @@
|
||||
export interface VaultMeta {
|
||||
currentRoot: string;
|
||||
recents: string[];
|
||||
defaultRoot: string;
|
||||
}
|
||||
|
||||
export type TreeNodeType = 'folder' | 'doc';
|
||||
|
||||
export interface TreeNode {
|
||||
/** 相对库根路径,作为稳定 id */
|
||||
path: string;
|
||||
type: TreeNodeType;
|
||||
/** 显示名(doc 去除 .md) */
|
||||
name: string;
|
||||
parent: string;
|
||||
/** doc 的所在目录相对路径;folder 为自身 */
|
||||
basePath: string;
|
||||
mtime: number;
|
||||
}
|
||||
Reference in New Issue
Block a user