完善功能
This commit is contained in:
@@ -189,3 +189,106 @@ MarkdownEditor.vue
|
||||
| 块 hover | `bg-[#faf9f6]` 微暖灰,提示可点击 |
|
||||
| 编辑 textarea | `bg-[#faf9f6]`,`border-[#bf6a3b]`,`font-mono` |
|
||||
| 缩放 | `calc(1rem * var(--editor-zoom, 1))` CSS 变量,由 App.vue 的 Ctrl+滚轮 控制 |
|
||||
|
||||
## 粘贴图片/文件功能
|
||||
|
||||
### 概述
|
||||
|
||||
支持在编辑区域(edit 模式和 mixed 模式)中通过 `Ctrl+V` 粘贴剪贴板中的图片或文件。媒体文件自动拷贝到与 markdown 文件同级的隐藏资源文件夹中,编辑区域插入 markdown 图片语法引用。
|
||||
|
||||
### 隐藏资源文件夹约定
|
||||
|
||||
```
|
||||
工作目录/
|
||||
├── doc.md ← markdown 文档
|
||||
└── .doc/ ← 隐藏资源文件夹(. + 文件名 stem)
|
||||
├── 20260710_140530_a1b2.png
|
||||
└── 20260710_140531_c3d4.png
|
||||
```
|
||||
|
||||
| 规则 | 说明 |
|
||||
|---|---|
|
||||
| 命名 | `{md文件名}` → `.{stem}/`(如 `test.md` → `.test/`) |
|
||||
| 可见性 | macOS/Linux:`.` 开头自动隐藏;Windows:Rust 端调用 `attrib +h` 设置隐藏属性 |
|
||||
| 生命周期 | 随 md 文件创建/删除/重命名自动联动 |
|
||||
| 引用方式 | markdown 中使用相对路径 `` |
|
||||
|
||||
### 整体流程
|
||||
|
||||
```
|
||||
用户 Ctrl+V 粘贴图片
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ textarea @paste 事件 │
|
||||
│ 检查 clipboardData.items │
|
||||
│ ├─ image/png, image/jpeg, ... │ ← 截图粘贴
|
||||
│ └─ kind === 'file' │ ← 文件管理器复制粘贴
|
||||
│ │
|
||||
│ 如有媒体项 → e.preventDefault() │
|
||||
│ 无媒体项 → 走浏览器默认文本粘贴 │
|
||||
└──────────────────┬──────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 前端 processPaste() │
|
||||
│ ├─ FileReader.readAsDataURL(blob) │
|
||||
│ ├─ 去掉 "data:xxx;base64," 前缀 │
|
||||
│ ├─ invoke("save_media_file", { │
|
||||
│ │ path: ".doc/20260710_xxx.png", │
|
||||
│ │ data: "base64string" │
|
||||
│ │ }) │
|
||||
│ └─ 光标处插入  │
|
||||
└──────────────────┬──────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Rust save_media_file │
|
||||
│ ├─ base64 decode → Vec<u8> │
|
||||
│ ├─ ensure_resources_dir() 创建目录 │
|
||||
│ │ └─ Windows: attrib +h 隐藏 │
|
||||
│ └─ fs::write() 写入文件 │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 前端关键函数
|
||||
|
||||
| 函数 | 位置 | 说明 |
|
||||
|---|---|---|
|
||||
| `processPaste()` | `MarkdownEditor.vue` | 核心粘贴处理:检测剪贴板媒体 → 生成文件名 → 调 Rust 保存 → 拼接 markdown 语法 |
|
||||
| `blobToBase64()` | 同上 | FileReader 读取 blob 为去前缀 base64 字符串 |
|
||||
| `generateMediaFilename()` | 同上 | `YYYYMMDD_HHmmss_随机4位.ext` |
|
||||
| `imageExtFromMime()` | 同上 | MIME type → 文件扩展名映射 |
|
||||
| `onEditorPaste()` | 同上 | edit 模式 textarea 的 paste handler |
|
||||
| `onBlockPaste()` | 同上 | mixed 模式 block textarea 的 paste handler |
|
||||
|
||||
### Rust 端关键函数
|
||||
|
||||
| 命令/函数 | 位置 | 说明 |
|
||||
|---|---|---|
|
||||
| `save_media_file(path, data)` | `lib.rs` | base64 解码 → 创建目录(+Windows 隐藏) → 写入文件 |
|
||||
| `resources_dir_path(file_path)` | 同上 | `a/b/doc.md` → `a/b/.doc`(仅 .md 文件) |
|
||||
| `ensure_resources_dir(dir_path)` | 同上 | 创建目录 + Windows `attrib +h` 隐藏 |
|
||||
| `hide_windows_dir(dir_path)` | 同上 | `#[cfg(windows)]` 调用 `attrib +h` |
|
||||
|
||||
### 生命周期联动
|
||||
|
||||
| 操作 | Rust 行为 | 前端行为 |
|
||||
|---|---|---|
|
||||
| 新建 `doc.md` | `create_file` 同时调用 `ensure_resources_dir` 创建 `.doc/` | 无额外操作 |
|
||||
| 删除 `doc.md` | `delete_entry` 检查并删除 `.doc/`(如存在) | App.vue 关闭文件引用 |
|
||||
| 重命名 `doc.md` → `new.md` | `rename_entry` 检查并重命名 `.doc/` → `.new/` | App.vue 更新 `currentFilePath` |
|
||||
| 粘贴图片时目录被删 | `save_media_file` → `ensure_resources_dir` 自动重建 `.doc/` | 正常写入 |
|
||||
|
||||
### 编辑模式兼容
|
||||
|
||||
paste 事件同时绑定在两种模式的 textarea 上:
|
||||
|
||||
- **edit 模式**:`@paste="onEditorPaste"` — 操作 `props.modelValue` + `editorTextareaRef`
|
||||
- **mixed 模式**:`@paste="onBlockPaste"` — 操作 `editingSource` + `blockTextareaRef`(包含空文档和 block 编辑两种场景)
|
||||
|
||||
粘贴后的 markdown 语法统一为:
|
||||
```markdown
|
||||

|
||||
```
|
||||
多张图片粘贴时用换行分隔。视频文件使用相同的 `` 语法,由 `remarkLocalMedia` 插件根据扩展名自动转为 `<video>` 标签。
|
||||
|
||||
Reference in New Issue
Block a user