From a9250aad4938a0da355be9f160cfe9ee0f879a4c Mon Sep 17 00:00:00 2001 From: Sam Sartor Date: Sat, 28 Sep 2024 19:25:48 -0600 Subject: [PATCH] full-screen app css --- src/app.rs | 222 ++++++++++++++++++++++++++++++++++++++++------------- src/lib.rs | 1 + 2 files changed, 171 insertions(+), 52 deletions(-) diff --git a/src/app.rs b/src/app.rs index 317c2cb..febb898 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,10 +1,9 @@ #![allow(non_snake_case)] -use std::collections::{BTreeMap, BTreeSet, HashMap}; - use dioxus::prelude::*; use ordermap::OrderSet; use sir::{css, global_css}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; pub type ChannelId = u32; pub type UserId = u32; @@ -13,6 +12,7 @@ pub enum ConnectionState { Disconnected, Connecting, Connected, + Failed(String), } #[derive(Debug)] @@ -150,12 +150,13 @@ pub fn ChatView() -> Element { let server = STATE.server.read(); let mut draft = use_signal(|| "".to_string()); - let chat_history_box = css!( + let chat_history = css!( " - margin: 16px; - border: solid black 1px; + overflow-y: auto; + flex: 1 0 0; " ); + let chat_message = css!( " display: flex; @@ -165,12 +166,14 @@ pub fn ChatView() -> Element { align-items: center; " ); + let chat_box = css!( " display: flex; flex-direction: row; - margin: 16px; + padding: 16px; gap: 8px; + border-top: solid black 1px; input { flex-grow: 1; @@ -190,7 +193,7 @@ pub fn ChatView() -> Element { rsx!( div { - class: "{chat_history_box}", + class: "{chat_history}", for chat in server.chat.iter() { div { class: "{chat_message}", @@ -202,22 +205,22 @@ pub fn ChatView() -> Element { } } } - div { - class: "{chat_box}", - input { - placeholder: "say something", - value: "{draft.read()}", - oninput: move |evt| draft.set(evt.value().clone()), - onkeypress: move |evt: Event| { - if evt.code() == Code::Enter && evt.modifiers().is_empty() { - do_send(); - } + } + div { + class: "{chat_box}", + input { + placeholder: "say something", + value: "{draft.read()}", + oninput: move |evt| draft.set(evt.value().clone()), + onkeypress: move |evt: Event| { + if evt.code() == Code::Enter && evt.modifiers().is_empty() { + do_send(); } } - button { - onclick: move |_| do_send(), - "Send" - } + } + button { + onclick: move |_| do_send(), + "Send" } } ) @@ -225,73 +228,188 @@ pub fn ChatView() -> Element { #[component] pub fn ServerView() -> Element { + let net: Coroutine = use_coroutine_handle(); let server = STATE.server.read(); + let grid = css!( + " + display: grid; + grid-template-rows: auto 1fr; + grid-template-columns: 1fr 1fr; + height: 100%; + background-color: white; + + gap: 4px; + padding: 4px; + " + ); + let channel_box = css!( " padding: 16px; - margin: 16px; border: solid black 1px; + grid-row: 2; + overflow: auto; + " + ); + + let chat_box = css!( + " + border: solid black 1px; + grid-row: 2; + display: flex; + flex-direction: column; + " + ); + + let top_bar = css!( + " + padding: 16px; + border: solid black 1px; + grid-row: 1; + grid-column: span 2; + + button { + padding: 8px; + } " ); rsx!( div { - class: "framed_box {channel_box}", - for (id, state) in server.channels.iter() { - if state.parent.is_none() { - Channel { id: *id } + class: "{grid}", + div { + class: "{top_bar}", + button { + onclick: move |_| net.send(Disconnect), + "Disconnect" + } + + } + div { + class: "{channel_box}", + for (id, state) in server.channels.iter() { + if state.parent.is_none() { + Channel { id: *id } + } } } + div { + class: "{chat_box}", + ChatView {} + } } - ChatView {} ) } -pub fn app() -> Element { - let net = use_coroutine(|rx: UnboundedReceiver| super::network_entrypoint(rx)); +#[component] +pub fn LoginView() -> Element { + let net: Coroutine = use_coroutine_handle(); let mut username = use_signal(|| "".to_string()); let default_address = option_env!("MUMBLEWEB2_WEBTRANSPORT_SERVER_ADDRESS").unwrap_or(""); let mut address = use_signal(|| default_address.to_string()); + let error = css!( + " + color: red; + pre { + color: black; + } + " + ); + + let login_box = css!( + " + max-width: 50vw; + min-width: 640px; + align-self: center; + padding: 16px; + background-color: white; + + display: flex; + flex-direction: column; + gap: 16px; + + input,button { + padding: 8px; + } + " + ); + + let do_connect = move |_| { + net.send(Connect{address: address.read().clone(), username: username.read().clone(), hash: "[39, 96, 204, 127, 26, 59, 35, 209, 197, 103, 192, 6, 3, 98, 203, 228, 124, 46, 247, 72, 44, 224, 123, 238, 218, 140, 128, 100, 115, 14, 23, 233]".to_string()}) + }; let status = &STATE.status; + let bottom = match &*status.read() { + Disconnected => rsx! { + button { + onclick: do_connect.clone(), + "Connect!" + } + }, + Connecting => rsx! { + "Connecting..." + }, + Failed(msg) => rsx!( + button { + onclick: do_connect.clone(), + "Reconnect!" + } + div { + class: "{error}", + "Failed to connect:" + pre { + "{msg}" + } + } + ), + Connected => unreachable!(), + }; rsx!( - sir::AppStyle { } div { + class: "{login_box}", input { placeholder: "username", value: "{username.read()}", autofocus: "true", oninput: move |evt| username.set(evt.value().clone()), } - br {} input { placeholder: "server address", value: "{address.read()}", autofocus: "true", oninput: move |evt| address.set(evt.value().clone()), } - br {} - match *status.read() { - Disconnected => rsx!{ - button { - onclick: move |event| net.send(Connect{address: address.read().clone(), username: username.read().clone(), hash: "[39, 96, 204, 127, 26, 59, 35, 209, 197, 103, 192, 6, 3, 98, 203, 228, 124, 46, 247, 72, 44, 224, 123, 238, 218, 140, 128, 100, 115, 14, 23, 233]".to_string()}), - "Connect!" - } - }, - Connecting => rsx!{ - "Connecting..." - }, - Connected => rsx!{ - button { - onclick: move |event| net.send(Disconnect), - "Disconnect" - } - br {} - ServerView {} - } - } - br {} + {bottom} + } + ) +} + +pub fn app() -> Element { + use_coroutine(|rx: UnboundedReceiver| super::network_entrypoint(rx)); + + global_css!( + " + body { + margin: 0; + } + + #main { + height: 100vh; + display: flex; + flex-direction: column; + justify-content: space-around; + background-color: grey; + overflow: auto; + } + " + ); + + rsx!( + sir::AppStyle { } + match *STATE.status.read() { + Connected => rsx!(ServerView {}), + _ => rsx!(LoginView {}), } ) } diff --git a/src/lib.rs b/src/lib.rs index 412dee3..4678ce7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -354,6 +354,7 @@ pub async fn network_entrypoint(mut event_rx: UnboundedReceiver) { }; if let Err(error) = network_connect(address, username, &mut event_rx).await { + *STATE.status.write() = ConnectionState::Failed(format!("{error:?}")); console::error_1(&error); } }