overhaul settings: split into routed sub-tabs, add server logs, changelog, reusable setting components

- Rename Server tab to Settings with horizontal sub-tab navigation (General, Generation, GPU, Logs, Changelog)
- All sub-tabs are proper routes under /settings/* with /server redirect for backwards compat
- General: connection settings, link cards (docs + discord), API reference card, app updates
- Generation: auto-chunking, crossfade, normalize, autoplay as SettingRow components
- GPU: info card with platform-aware icons (Apple logo for MPS), CUDA management, explainer text
- Logs: real-time server log viewer piped from Tauri sidecar via event system (Tauri-only)
- Changelog: parsed from CHANGELOG.md at build time via Vite virtual module plugin
- New reusable SettingRow/SettingSection components for consistent settings layout
- New Toggle (switch) UI component replacing checkboxes in settings
- Toast viewport now offsets when audio player is open
- Sidebar stays active on settings sub-routes (fuzzy matching)
This commit is contained in:
James Pine
2026-03-16 09:31:14 -07:00
parent e0a798dc0d
commit 2c63dfff25
30 changed files with 1879 additions and 60 deletions
+22 -3
View File
@@ -413,6 +413,10 @@ async fn start_server(
tauri_plugin_shell::process::CommandEvent::Stdout(line) => {
let line_str = String::from_utf8_lossy(&line);
println!("Server output: {}", line_str);
let _ = app.emit("server-log", serde_json::json!({
"stream": "stdout",
"line": line_str.trim_end(),
}));
if line_str.contains("Uvicorn running") || line_str.contains("Application startup complete") {
println!("Server is ready!");
@@ -422,6 +426,10 @@ async fn start_server(
tauri_plugin_shell::process::CommandEvent::Stderr(line) => {
let line_str = String::from_utf8_lossy(&line).to_string();
eprintln!("Server: {}", line_str);
let _ = app.emit("server-log", serde_json::json!({
"stream": "stderr",
"line": line_str.trim_end(),
}));
// Collect error lines for debugging
if line_str.contains("ERROR") || line_str.contains("Error") || line_str.contains("Failed") {
@@ -482,15 +490,26 @@ async fn start_server(
}
}
// Spawn task to continue reading output
// Spawn task to continue reading output and emit to frontend
let app_handle = app.clone();
tokio::spawn(async move {
while let Some(event) = rx.recv().await {
match event {
tauri_plugin_shell::process::CommandEvent::Stdout(line) => {
println!("Server: {}", String::from_utf8_lossy(&line));
let line_str = String::from_utf8_lossy(&line);
println!("Server: {}", line_str);
let _ = app_handle.emit("server-log", serde_json::json!({
"stream": "stdout",
"line": line_str.trim_end(),
}));
}
tauri_plugin_shell::process::CommandEvent::Stderr(line) => {
eprintln!("Server error: {}", String::from_utf8_lossy(&line));
let line_str = String::from_utf8_lossy(&line);
eprintln!("Server error: {}", line_str);
let _ = app_handle.emit("server-log", serde_json::json!({
"stream": "stderr",
"line": line_str.trim_end(),
}));
}
_ => {}
}