use std::path::PathBuf; use nomina_core::preset::NominaPreset; #[tauri::command] pub async fn save_preset(preset: NominaPreset) -> Result { 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::load(&PathBuf::from(path)).map_err(|e| e.to_string()) } #[tauri::command] pub async fn list_presets() -> Result, 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() }