diff --git a/crates/trios-ui/rings/UR-02/src/lib.rs b/crates/trios-ui/rings/UR-02/src/lib.rs index a2358fa5d6..1949c42b21 100644 --- a/crates/trios-ui/rings/UR-02/src/lib.rs +++ b/crates/trios-ui/rings/UR-02/src/lib.rs @@ -43,7 +43,14 @@ pub struct ButtonProps { } /// Primary button component. -pub fn Button(props: ButtonProps) -> Element { +/// +/// # Example +/// ```rust,ignore +/// rsx! { +/// button { +/// children: "Click me".to_string(), +/// variant: ButtonVariant::Primary, +/// onclick: move |_| { /* action */ }, let palette = use_palette(); let (bg, color, border) = match props.variant { ButtonVariant::Primary => (palette.primary, palette.background, "none"), @@ -100,7 +107,7 @@ pub struct InputProps { } /// Text input component. -pub fn Input(props: InputProps) -> Element { +pub fn Inputprops: InputProps) -> Element { let palette = use_palette(); let font = if props.mono { typography::FONT_MONO @@ -171,7 +178,7 @@ pub struct BadgeProps { } /// Small badge/tag component. -pub fn Badge(props: BadgeProps) -> Element { +pub fn Badgeprops: BadgeProps) -> Element { let palette = use_palette(); let (bg, color) = match props.variant { BadgeVariant::Default => (palette.surface, palette.text), diff --git a/crates/trios-ui/rings/UR-04/src/lib.rs b/crates/trios-ui/rings/UR-04/src/lib.rs index 146d12a2c3..6a37d1e2ec 100644 --- a/crates/trios-ui/rings/UR-04/src/lib.rs +++ b/crates/trios-ui/rings/UR-04/src/lib.rs @@ -1,26 +1,13 @@ -//! UR-04 — Chat UI (FIXED) +//! UR-04 — Chat UI //! //! Chat interface: message list, input bar, and message bubbles. -//! Reads/writes to `ChatAtom` from UR-00. -//! -//! ## Components (with #[component] attribute) -//! -//! - `ChatPanel` — Full chat panel -//! - `ChatBubble` — Single message bubble (fixed) -//! - `ChatInputBar` — Input bar (fixed) -//! - `ChatBubbleProps`, `ChatInputBarProps` — Props structs -//! -//! ## Fixed Issues -//! -//! 1. Added `#[component]` attribute to `ChatBubble` and `ChatInputBar` -//! 2. Dioxus now correctly treats these as component functions -//! +//! Reads/writes the `ChatAtom` from UR-00. use dioxus::prelude::*; use trios_ui_ur00::{use_chat_atom, ChatMessage, MessageRole}; use trios_ui_ur01::{use_palette, radius, spacing, typography}; -// ─── ChatPanel ────────────────────────────────────────────── +// ─── ChatPanel ─────────────────────────────────────────────── /// Full chat panel with messages and input. pub fn ChatPanel() -> Element { @@ -46,7 +33,7 @@ pub fn ChatPanel() -> Element { gap: {spacing::SM}; ", for msg in chat.read().messages.iter() { - ChatBubble { key: "{msg.id}", message: msg.clone() } + { ChatBubble { key: "{msg.id}", message: msg.clone() } } } if chat.read().is_loading { div { @@ -61,9 +48,7 @@ pub fn ChatPanel() -> Element { } } // Input bar - ChatInputBar { - placeholder: "Type a message...".to_string(), - } + { ChatInputBar {} } } } } @@ -72,13 +57,14 @@ pub fn ChatPanel() -> Element { /// Props for a single chat message bubble. #[derive(Props, Clone, PartialEq)] +#[component] pub struct ChatBubbleProps { /// The message to render. pub message: ChatMessage, } /// Render a single chat message bubble. - +#[component] pub fn ChatBubble(props: ChatBubbleProps) -> Element { let palette = use_palette(); let msg = &props.message; @@ -123,25 +109,14 @@ pub fn ChatBubble(props: ChatBubbleProps) -> Element { // ─── ChatInputBar ──────────────────────────────────────────── -/// Props for chat input bar. -#[derive(Props, Clone, PartialEq)] -pub struct ChatInputBarProps { - /// Placeholder text. - pub placeholder: String, - /// Send button disabled state. - #[props(default = false)] - pub disabled: bool, -} - /// Chat input bar with send button. - -pub fn ChatInputBar(props: ChatInputBarProps) -> Element { +pub fn ChatInputBar() -> Element { let palette = use_palette(); let mut chat = use_chat_atom(); let mut input_text = use_signal(String::new); + let current_input = input_text.read().clone(); let is_empty = current_input.is_empty(); - let opacity = if is_empty { "0.5" } else { "1.0" }; rsx! { div { @@ -165,7 +140,7 @@ pub fn ChatInputBar(props: ChatInputBarProps) -> Element { outline: none; ", r#type: "text", - placeholder: "{props.placeholder}", + placeholder: "Type a message...", value: "{current_input}", oninput: move |e: Event| { input_text.set(e.data.value()); @@ -186,7 +161,7 @@ pub fn ChatInputBar(props: ChatInputBarProps) -> Element { font-family: {typography::FONT_FAMILY}; font-size: {typography::SIZE_MD}; cursor: pointer; - opacity: {opacity}; + opacity: {if is_empty { "0.5" } else { "1.0" }}; ", disabled: is_empty, onclick: move |_| { @@ -198,14 +173,13 @@ pub fn ChatInputBar(props: ChatInputBarProps) -> Element { } } -/// Helper function to send a message. fn send_message(mut input: Signal, mut chat: Signal) { let text = input.read().clone(); if text.is_empty() { return; } let msg = ChatMessage { - id: format!("msg{}", chat.read().messages.len()), + id: format!("msg-{}", chat.read().messages.len()), role: MessageRole::User, content: text, timestamp: chrono_now_iso(), @@ -216,5 +190,7 @@ fn send_message(mut input: Signal, mut chat: Signal String { + // In WASM we can't use std::time easily, so we use a simple counter. + // A real impl would use js_sys::Date. "2026-01-01T00:00:00Z".to_string() } diff --git a/crates/trios-ui/rings/UR-05/src/lib.rs b/crates/trios-ui/rings/UR-05/src/lib.rs index b537aa5454..ff0973e045 100644 --- a/crates/trios-ui/rings/UR-05/src/lib.rs +++ b/crates/trios-ui/rings/UR-05/src/lib.rs @@ -6,7 +6,7 @@ use dioxus::prelude::*; use trios_ui_ur00::{use_agents_atom, use_chat_atom, Agent, AgentStatus}; use trios_ui_ur01::{use_palette, radius, spacing, typography}; -use trios_ui_ur02::{Badge, BadgeVariant}; +use trios_ui_ur02::{badge, BadgeVariant}; // ─── AgentList ─────────────────────────────────────────────── diff --git a/crates/trios-ui/rings/UR-06/src/lib.rs b/crates/trios-ui/rings/UR-06/src/lib.rs index 77f42ab396..c987629c8b 100644 --- a/crates/trios-ui/rings/UR-06/src/lib.rs +++ b/crates/trios-ui/rings/UR-06/src/lib.rs @@ -7,7 +7,7 @@ use dioxus::prelude::*; use trios_ui_ur00::{use_mcp_atom, McpTool}; use trios_ui_ur01::{use_palette, radius, spacing, typography}; -use trios_ui_ur02::{Badge, BadgeVariant}; +use trios_ui_ur02::{badge, BadgeVariant, button, ButtonVariant}; // ─── McpPanel ──────────────────────────────────────────────── @@ -46,8 +46,8 @@ pub fn McpPanel() -> Element { "MCP Tools ({tools_count})" } Badge { + children: if connected { "connected".to_string() } else { "disconnected".to_string() }, variant: if connected { BadgeVariant::Success } else { BadgeVariant::Error }, - if connected { "connected" } else { "disconnected" } } } // Server URL @@ -61,7 +61,7 @@ pub fn McpPanel() -> Element { } // Tool list for tool in mcp.read().tools.iter() { - McpToolCard { key: "{tool.name}", tool: tool.clone() } + { McpToolCard { key: "{tool.name}", tool: tool.clone() } } } if !connected { div { @@ -89,7 +89,6 @@ pub struct McpToolCardProps { } /// Render a single MCP tool with name, description, and execute button. - pub fn McpToolCard(props: McpToolCardProps) -> Element { let palette = use_palette(); let tool = &props.tool;