完善图片视频添加预览功能

This commit is contained in:
2026-07-10 14:41:54 +08:00
parent aefe72b864
commit 266a7ffacd
25 changed files with 713 additions and 12 deletions

View File

@@ -6,6 +6,7 @@ use std::sync::Mutex;
use tauri::menu::{MenuBuilder, MenuItemBuilder, SubmenuBuilder};
use tauri::{Emitter, Manager};
use tauri_plugin_dialog::DialogExt;
use base64::Engine;
#[derive(Debug, Clone, serde::Serialize)]
struct DirEntry {
@@ -55,6 +56,59 @@ fn is_hidden_entry(entry: &fs::DirEntry) -> bool {
}
}
/// Returns the companion hidden resources directory path for a markdown file.
/// Example: `notes/doc.md` → `notes/.doc`
fn resources_dir_path(file_path: &str) -> Option<String> {
let path = std::path::Path::new(file_path);
if path.extension().map_or(true, |ext| ext != "md") {
return None;
}
let stem = path.file_stem()?.to_str()?;
let parent = path.parent()?;
let dir_name = format!(".{}", stem);
Some(parent.join(dir_name).to_string_lossy().to_string())
}
/// On Windows, set the hidden attribute on a directory so it doesn't clutter
/// the file manager.
#[cfg(windows)]
fn hide_windows_dir(dir_path: &str) {
let _ = std::process::Command::new("attrib")
.args(["+h", dir_path])
.output();
}
/// Ensure a directory exists, and hide it on Windows when the name starts with `.`.
fn ensure_resources_dir(dir_path: &str) -> std::io::Result<()> {
fs::create_dir_all(dir_path)?;
#[cfg(windows)]
{
let name = std::path::Path::new(dir_path)
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("");
if name.starts_with('.') {
hide_windows_dir(dir_path);
}
}
Ok(())
}
#[tauri::command]
fn save_media_file(path: String, data: String) -> Result<(), String> {
let bytes = base64::engine::general_purpose::STANDARD
.decode(&data)
.map_err(|e| format!("解码失败: {}", e))?;
if let Some(parent) = std::path::Path::new(&path).parent() {
let parent_str = parent.to_string_lossy().to_string();
ensure_resources_dir(&parent_str)
.map_err(|e| format!("无法创建目录: {}", e))?;
}
fs::write(&path, &bytes).map_err(|e| format!("无法写入文件: {}", e))
}
#[tauri::command]
fn pick_folder(app: tauri::AppHandle) -> Option<String> {
app.dialog()
@@ -200,7 +254,14 @@ fn create_file(path: String) -> Result<(), String> {
if let Some(parent) = PathBuf::from(&path).parent() {
fs::create_dir_all(parent).map_err(|e| format!("无法创建父目录: {}", e))?;
}
fs::write(&path, "").map_err(|e| format!("无法创建文件: {}", e))
fs::write(&path, "").map_err(|e| format!("无法创建文件: {}", e))?;
// Create companion hidden resources directory for markdown files.
if let Some(res_dir) = resources_dir_path(&path) {
ensure_resources_dir(&res_dir).map_err(|e| format!("无法创建资源文件夹: {}", e))?;
}
Ok(())
}
#[tauri::command]
@@ -209,7 +270,17 @@ fn delete_entry(path: String) -> Result<(), String> {
if p.is_dir() {
fs::remove_dir_all(&p).map_err(|e| format!("无法删除文件夹: {}", e))
} else if p.is_file() {
fs::remove_file(&p).map_err(|e| format!("无法删除文件: {}", e))
fs::remove_file(&p).map_err(|e| format!("无法删除文件: {}", e))?;
// If this was a markdown file, also remove its companion resources directory.
if let Some(res_dir) = resources_dir_path(&path) {
let res = PathBuf::from(&res_dir);
if res.is_dir() {
let _ = fs::remove_dir_all(&res);
}
}
Ok(())
} else {
Err("路径不存在".to_string())
}
@@ -222,6 +293,21 @@ fn rename_entry(path: String, new_name: String) -> Result<String, String> {
.parent()
.ok_or_else(|| "无法获取父目录".to_string())?;
let new_path = parent.join(&new_name);
// If this is a markdown file, rename its companion resources directory first.
if let Some(old_res_dir) = resources_dir_path(&path) {
let old_res = PathBuf::from(&old_res_dir);
if old_res.is_dir() {
let new_res_dir = resources_dir_path(&new_path.to_string_lossy());
if let Some(new_res) = new_res_dir {
let new_res_path = PathBuf::from(&new_res);
if new_res_path != old_res {
let _ = fs::rename(&old_res, &new_res_path);
}
}
}
}
fs::rename(&p, &new_path).map_err(|e| format!("无法重命名: {}", e))?;
Ok(new_path.to_string_lossy().to_string())
}
@@ -249,7 +335,8 @@ pub fn run() {
create_folder,
create_file,
delete_entry,
rename_entry
rename_entry,
save_media_file
])
.setup(|app| {
// ---- File menu ----