Rust workspace with nomina-core (rename engine) and nomina-app (Tauri v2 shell). React/TypeScript frontend with tabbed rule panels, virtual-scrolled file list, and Zustand state management. All 9 rule types implemented with 25 passing tests.
73 lines
2.0 KiB
Rust
73 lines
2.0 KiB
Rust
use std::path::PathBuf;
|
|
|
|
use nomina_core::preset::NominaPreset;
|
|
|
|
#[tauri::command]
|
|
pub async fn save_preset(preset: NominaPreset) -> Result<String, String> {
|
|
let dir = get_presets_dir();
|
|
std::fs::create_dir_all(&dir).map_err(|e| e.to_string())?;
|
|
|
|
let filename = format!("{}.nomina", sanitize_filename(&preset.name));
|
|
let path = dir.join(&filename);
|
|
preset.save(&path).map_err(|e| e.to_string())?;
|
|
|
|
Ok(path.to_string_lossy().to_string())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn load_preset(path: String) -> Result<NominaPreset, String> {
|
|
NominaPreset::load(&PathBuf::from(path)).map_err(|e| e.to_string())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn list_presets() -> Result<Vec<PresetInfo>, String> {
|
|
let dir = get_presets_dir();
|
|
if !dir.exists() {
|
|
return Ok(Vec::new());
|
|
}
|
|
|
|
let mut presets = Vec::new();
|
|
let entries = std::fs::read_dir(&dir).map_err(|e| e.to_string())?;
|
|
|
|
for entry in entries {
|
|
let entry = match entry {
|
|
Ok(e) => e,
|
|
Err(_) => continue,
|
|
};
|
|
let path = entry.path();
|
|
if path.extension().map(|e| e == "nomina").unwrap_or(false) {
|
|
if let Ok(preset) = NominaPreset::load(&path) {
|
|
presets.push(PresetInfo {
|
|
name: preset.name,
|
|
description: preset.description,
|
|
path: path.to_string_lossy().to_string(),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(presets)
|
|
}
|
|
|
|
#[derive(Debug, serde::Serialize)]
|
|
pub struct PresetInfo {
|
|
pub name: String,
|
|
pub description: String,
|
|
pub path: String,
|
|
}
|
|
|
|
fn get_presets_dir() -> PathBuf {
|
|
let dirs = directories::ProjectDirs::from("com", "nomina", "Nomina")
|
|
.expect("failed to get app data directory");
|
|
dirs.data_dir().join("presets")
|
|
}
|
|
|
|
fn sanitize_filename(name: &str) -> String {
|
|
name.chars()
|
|
.map(|c| match c {
|
|
'<' | '>' | ':' | '"' | '/' | '\\' | '|' | '?' | '*' => '_',
|
|
_ => c,
|
|
})
|
|
.collect()
|
|
}
|