full-screen app css

This commit is contained in:
2024-09-28 19:25:48 -06:00
parent faf3cd3df7
commit a9250aad49
2 changed files with 171 additions and 52 deletions
+170 -52
View File
@@ -1,10 +1,9 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use std::collections::{BTreeMap, BTreeSet, HashMap};
use dioxus::prelude::*; use dioxus::prelude::*;
use ordermap::OrderSet; use ordermap::OrderSet;
use sir::{css, global_css}; use sir::{css, global_css};
use std::collections::{BTreeMap, BTreeSet, HashMap};
pub type ChannelId = u32; pub type ChannelId = u32;
pub type UserId = u32; pub type UserId = u32;
@@ -13,6 +12,7 @@ pub enum ConnectionState {
Disconnected, Disconnected,
Connecting, Connecting,
Connected, Connected,
Failed(String),
} }
#[derive(Debug)] #[derive(Debug)]
@@ -150,12 +150,13 @@ pub fn ChatView() -> Element {
let server = STATE.server.read(); let server = STATE.server.read();
let mut draft = use_signal(|| "".to_string()); let mut draft = use_signal(|| "".to_string());
let chat_history_box = css!( let chat_history = css!(
" "
margin: 16px; overflow-y: auto;
border: solid black 1px; flex: 1 0 0;
" "
); );
let chat_message = css!( let chat_message = css!(
" "
display: flex; display: flex;
@@ -165,12 +166,14 @@ pub fn ChatView() -> Element {
align-items: center; align-items: center;
" "
); );
let chat_box = css!( let chat_box = css!(
" "
display: flex; display: flex;
flex-direction: row; flex-direction: row;
margin: 16px; padding: 16px;
gap: 8px; gap: 8px;
border-top: solid black 1px;
input { input {
flex-grow: 1; flex-grow: 1;
@@ -190,7 +193,7 @@ pub fn ChatView() -> Element {
rsx!( rsx!(
div { div {
class: "{chat_history_box}", class: "{chat_history}",
for chat in server.chat.iter() { for chat in server.chat.iter() {
div { div {
class: "{chat_message}", class: "{chat_message}",
@@ -202,22 +205,22 @@ pub fn ChatView() -> Element {
} }
} }
} }
div { }
class: "{chat_box}", div {
input { class: "{chat_box}",
placeholder: "say something", input {
value: "{draft.read()}", placeholder: "say something",
oninput: move |evt| draft.set(evt.value().clone()), value: "{draft.read()}",
onkeypress: move |evt: Event<KeyboardData>| { oninput: move |evt| draft.set(evt.value().clone()),
if evt.code() == Code::Enter && evt.modifiers().is_empty() { onkeypress: move |evt: Event<KeyboardData>| {
do_send(); if evt.code() == Code::Enter && evt.modifiers().is_empty() {
} do_send();
} }
} }
button { }
onclick: move |_| do_send(), button {
"Send" onclick: move |_| do_send(),
} "Send"
} }
} }
) )
@@ -225,73 +228,188 @@ pub fn ChatView() -> Element {
#[component] #[component]
pub fn ServerView() -> Element { pub fn ServerView() -> Element {
let net: Coroutine<Command> = use_coroutine_handle();
let server = STATE.server.read(); 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!( let channel_box = css!(
" "
padding: 16px; padding: 16px;
margin: 16px;
border: solid black 1px; 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!( rsx!(
div { div {
class: "framed_box {channel_box}", class: "{grid}",
for (id, state) in server.channels.iter() { div {
if state.parent.is_none() { class: "{top_bar}",
Channel { id: *id } 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 { #[component]
let net = use_coroutine(|rx: UnboundedReceiver<Command>| super::network_entrypoint(rx)); pub fn LoginView() -> Element {
let net: Coroutine<Command> = use_coroutine_handle();
let mut username = use_signal(|| "".to_string()); let mut username = use_signal(|| "".to_string());
let default_address = option_env!("MUMBLEWEB2_WEBTRANSPORT_SERVER_ADDRESS").unwrap_or(""); let default_address = option_env!("MUMBLEWEB2_WEBTRANSPORT_SERVER_ADDRESS").unwrap_or("");
let mut address = use_signal(|| default_address.to_string()); 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 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!( rsx!(
sir::AppStyle { }
div { div {
class: "{login_box}",
input { input {
placeholder: "username", placeholder: "username",
value: "{username.read()}", value: "{username.read()}",
autofocus: "true", autofocus: "true",
oninput: move |evt| username.set(evt.value().clone()), oninput: move |evt| username.set(evt.value().clone()),
} }
br {}
input { input {
placeholder: "server address", placeholder: "server address",
value: "{address.read()}", value: "{address.read()}",
autofocus: "true", autofocus: "true",
oninput: move |evt| address.set(evt.value().clone()), oninput: move |evt| address.set(evt.value().clone()),
} }
br {} {bottom}
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!" pub fn app() -> Element {
} use_coroutine(|rx: UnboundedReceiver<Command>| super::network_entrypoint(rx));
},
Connecting => rsx!{ global_css!(
"Connecting..." "
}, body {
Connected => rsx!{ margin: 0;
button { }
onclick: move |event| net.send(Disconnect),
"Disconnect" #main {
} height: 100vh;
br {} display: flex;
ServerView {} flex-direction: column;
} justify-content: space-around;
} background-color: grey;
br {} overflow: auto;
}
"
);
rsx!(
sir::AppStyle { }
match *STATE.status.read() {
Connected => rsx!(ServerView {}),
_ => rsx!(LoginView {}),
} }
) )
} }
+1
View File
@@ -354,6 +354,7 @@ pub async fn network_entrypoint(mut event_rx: UnboundedReceiver<Command>) {
}; };
if let Err(error) = network_connect(address, username, &mut event_rx).await { if let Err(error) = network_connect(address, username, &mut event_rx).await {
*STATE.status.write() = ConnectionState::Failed(format!("{error:?}"));
console::error_1(&error); console::error_1(&error);
} }
} }