initial project scaffold
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.
This commit is contained in:
72
crates/nomina-app/src/commands/presets.rs
Normal file
72
crates/nomina-app/src/commands/presets.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
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()
|
||||
}
|
||||
Reference in New Issue
Block a user