/// 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}" } } } }