use crate::i18n::{t, Locale}; use dioxus::prelude::*; /// Chat input bar with a textarea and send button. /// /// Enter sends the message; Shift+Enter inserts a newline. /// The input is disabled during streaming. /// /// # Arguments /// /// * `input_text` - Two-way bound input text signal /// * `on_send` - Callback fired with the message text when sent /// * `is_streaming` - Whether to disable the input (streaming in progress) #[component] pub fn ChatInputBar( input_text: Signal, on_send: EventHandler, is_streaming: bool, ) -> Element { let locale = use_context::>(); let l = *locale.read(); let mut input = input_text; rsx! { div { class: "chat-input-bar", textarea { class: "chat-input", placeholder: "{t(l, \"chat.type_message\")}", disabled: is_streaming, rows: "1", value: "{input}", oninput: move |e: Event| { input.set(e.value()); }, onkeypress: move |e: Event| { // Enter sends, Shift+Enter adds newline if e.key() == Key::Enter && !e.modifiers().shift() { e.prevent_default(); let text = input.read().trim().to_string(); if !text.is_empty() { on_send.call(text); input.set(String::new()); } } }, } button { class: "btn-primary chat-send-btn", disabled: is_streaming || input.read().trim().is_empty(), onclick: move |_| { let text = input.read().trim().to_string(); if !text.is_empty() { on_send.call(text); input.set(String::new()); } }, if is_streaming { // Stop icon during streaming dioxus_free_icons::Icon { icon: dioxus_free_icons::icons::fa_solid_icons::FaStop, width: 16, height: 16, } } else { dioxus_free_icons::Icon { icon: dioxus_free_icons::icons::fa_solid_icons::FaPaperPlane, width: 16, height: 16, } } } } } }