Dioxus (ui-dioxus/): 2,169 lines, WebView mode (same wry as Tauri), Catppuccin theme, 12 components, agor-core integration, compiles clean. Evolution path — keeps xterm.js, gradual migration from Tauri. GPUI (ui-gpui/): 2,490 lines, GPU-accelerated rendering, alacritty_terminal for native terminal, 17 files, Catppuccin palette, demo data. Revolution path — pure Rust UI, 120fps target, no WebView. Both are standalone (not in workspace), share agor-core backend. Created for side-by-side comparison to inform framework decision.
151 lines
5.5 KiB
Rust
151 lines
5.5 KiB
Rust
/// Settings panel — drawer that slides out from the sidebar.
|
|
///
|
|
/// Mirrors the Svelte app's SettingsTab.svelte: theme selection, font controls,
|
|
/// provider configuration. Uses the same drawer pattern (18rem wide,
|
|
/// mantle background).
|
|
|
|
use dioxus::prelude::*;
|
|
|
|
#[component]
|
|
pub fn SettingsPanel() -> Element {
|
|
let mut theme = use_signal(|| "Catppuccin Mocha".to_string());
|
|
let mut ui_font = use_signal(|| "Inter".to_string());
|
|
let mut term_font = use_signal(|| "JetBrains Mono".to_string());
|
|
let mut default_shell = use_signal(|| "/bin/bash".to_string());
|
|
|
|
rsx! {
|
|
div { class: "drawer-panel",
|
|
div { class: "drawer-title", "Settings" }
|
|
|
|
// Appearance section
|
|
div { class: "settings-section",
|
|
div { class: "settings-section-title", "Appearance" }
|
|
|
|
div { class: "settings-row",
|
|
span { class: "settings-label", "Theme" }
|
|
select {
|
|
class: "settings-select",
|
|
value: "{theme}",
|
|
onchange: move |e| theme.set(e.value()),
|
|
option { value: "Catppuccin Mocha", "Catppuccin Mocha" }
|
|
option { value: "Catppuccin Macchiato", "Catppuccin Macchiato" }
|
|
option { value: "Tokyo Night", "Tokyo Night" }
|
|
option { value: "Dracula", "Dracula" }
|
|
option { value: "Nord", "Nord" }
|
|
}
|
|
}
|
|
|
|
div { class: "settings-row",
|
|
span { class: "settings-label", "UI Font" }
|
|
select {
|
|
class: "settings-select",
|
|
value: "{ui_font}",
|
|
onchange: move |e| ui_font.set(e.value()),
|
|
option { value: "Inter", "Inter" }
|
|
option { value: "system-ui", "System UI" }
|
|
option { value: "IBM Plex Sans", "IBM Plex Sans" }
|
|
}
|
|
}
|
|
|
|
div { class: "settings-row",
|
|
span { class: "settings-label", "Terminal Font" }
|
|
select {
|
|
class: "settings-select",
|
|
value: "{term_font}",
|
|
onchange: move |e| term_font.set(e.value()),
|
|
option { value: "JetBrains Mono", "JetBrains Mono" }
|
|
option { value: "Fira Code", "Fira Code" }
|
|
option { value: "Cascadia Code", "Cascadia Code" }
|
|
}
|
|
}
|
|
}
|
|
|
|
// Defaults section
|
|
div { class: "settings-section",
|
|
div { class: "settings-section-title", "Defaults" }
|
|
|
|
div { class: "settings-row",
|
|
span { class: "settings-label", "Shell" }
|
|
select {
|
|
class: "settings-select",
|
|
value: "{default_shell}",
|
|
onchange: move |e| default_shell.set(e.value()),
|
|
option { value: "/bin/bash", "/bin/bash" }
|
|
option { value: "/bin/zsh", "/bin/zsh" }
|
|
option { value: "/usr/bin/fish", "/usr/bin/fish" }
|
|
}
|
|
}
|
|
}
|
|
|
|
// Providers section
|
|
div { class: "settings-section",
|
|
div { class: "settings-section-title", "Providers" }
|
|
|
|
ProviderCard {
|
|
name: "Claude",
|
|
model: "claude-sonnet-4-20250514",
|
|
status: "Available",
|
|
accent: "var(--ctp-mauve)",
|
|
}
|
|
ProviderCard {
|
|
name: "Codex",
|
|
model: "gpt-5.4",
|
|
status: "Available",
|
|
accent: "var(--ctp-green)",
|
|
}
|
|
ProviderCard {
|
|
name: "Ollama",
|
|
model: "qwen3:8b",
|
|
status: "Not running",
|
|
accent: "var(--ctp-peach)",
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[component]
|
|
fn ProviderCard(
|
|
name: String,
|
|
model: String,
|
|
status: String,
|
|
accent: String,
|
|
) -> Element {
|
|
let is_available = status == "Available";
|
|
|
|
let badge_bg = if is_available {
|
|
"color-mix(in srgb, var(--ctp-green) 15%, transparent)"
|
|
} else {
|
|
"color-mix(in srgb, var(--ctp-overlay0) 15%, transparent)"
|
|
};
|
|
let badge_color = if is_available {
|
|
"var(--ctp-green)"
|
|
} else {
|
|
"var(--ctp-overlay0)"
|
|
};
|
|
let badge_style = format!(
|
|
"font-size: 0.625rem; padding: 0.0625rem 0.3125rem; border-radius: 0.1875rem; background: {badge_bg}; color: {badge_color};"
|
|
);
|
|
|
|
rsx! {
|
|
div {
|
|
style: "background: var(--ctp-surface0); border-radius: 0.375rem; padding: 0.5rem 0.75rem; margin-bottom: 0.5rem;",
|
|
|
|
div {
|
|
style: "display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.25rem;",
|
|
span {
|
|
style: "font-weight: 600; font-size: 0.8125rem; color: {accent};",
|
|
"{name}"
|
|
}
|
|
span {
|
|
style: "{badge_style}",
|
|
"{status}"
|
|
}
|
|
}
|
|
div {
|
|
style: "font-size: 0.6875rem; color: var(--ctp-overlay1); font-family: var(--term-font-family);",
|
|
"{model}"
|
|
}
|
|
}
|
|
}
|
|
}
|