add /config endpoint, add docker proxy setup, and style chat box

This commit is contained in:
2025-07-13 19:33:55 -06:00
parent 74fe399cdc
commit 1793504467
12 changed files with 561 additions and 94 deletions
+129 -37
View File
@@ -3,9 +3,11 @@
use base64::{display::Base64Display, prelude::BASE64_URL_SAFE};
use dioxus::prelude::*;
use mime_guess::Mime;
use mumble_web2_common::GuiConfig;
use ordermap::OrderSet;
use sir::{css, global_css};
use std::collections::HashMap;
use tracing::error;
use crate::{imp, CONFIG};
@@ -279,6 +281,13 @@ pub fn ChatView() -> Element {
let server = STATE.server.read();
let mut draft = use_signal(|| "".to_string());
let chat_panel = css!(
"
display: flex;
flex-direction: column;
"
);
let chat_history = css!(
"
overflow-y: auto;
@@ -296,18 +305,44 @@ pub fn ChatView() -> Element {
"
);
let chat_box_wrapper = css!(
"
padding: 16px;
border-top: solid var(--line-color) var(--line-width);
"
);
let chat_box = css!(
"
display: flex;
flex-direction: row;
padding: 16px;
gap: 8px;
border-top: solid var(--line-color) var(--line-width);
gap: 16px;
background-color: var(--light-bg-color);
padding-top: 16px;
padding-bottom: 16px;
padding-left: 8px;
padding-right: 16px;
border-radius: 8px;
input {
color: white;
background-color: var(--light-bg-color);
font-size: larger;
flex-grow: 1;
padding: 8px;
border: none;
}
input:focus {
outline: none;
}
"
);
@@ -322,49 +357,88 @@ pub fn ChatView() -> Element {
rsx!(
div {
class: "{chat_history}",
for chat in server.chat.iter() {
div {
class: "{chat_message}",
if let Some(sender) = chat.sender.and_then(|u| server.users.get(&u)) {
UserPill {
name: sender.name.clone(),
icon: UserIcon::None,
isself: false,
class: "{chat_panel}",
div {
class: "{chat_history}",
for chat in server.chat.iter() {
div {
class: "{chat_message}",
if let Some(sender) = chat.sender.and_then(|u| server.users.get(&u)) {
UserPill {
name: sender.name.clone(),
icon: UserIcon::None,
isself: false,
}
}
span {
dangerous_inner_html: "{chat.dangerous_html}",
}
}
span {
dangerous_inner_html: "{chat.dangerous_html}",
}
}
}
}
div {
class: "{chat_box}",
input {
placeholder: "say something",
value: "{draft.read()}",
oninput: move |evt| draft.set(evt.value().clone()),
onkeypress: move |evt: Event<KeyboardData>| {
if evt.code() == Code::Enter && evt.modifiers().is_empty() {
do_send();
div {
class: "{chat_box_wrapper}",
div {
class: "{chat_box}",
input {
placeholder: "say something",
value: "{draft.read()}",
oninput: move |evt| draft.set(evt.value().clone()),
onkeypress: move |evt: Event<KeyboardData>| {
if evt.code() == Code::Enter && evt.modifiers().is_empty() {
do_send();
}
}
}
div {
span {
onclick: move |_| pick_and_send_file(&net),
class: "material-symbols-outlined",
style: "color: rgba(255, 255, 255, 0.5); font-variation-settings: 'FILL' 1, 'wght' 700, 'GRAD' 0, 'opsz' 48; vertical-align: middle; font-size: 35px; user-select: none;",
"attach_file",
}
}
div {
span {
onclick: move |_| do_send(),
class: "material-symbols-outlined",
style: "color: rgba(255, 255, 255, 0.5); font-variation-settings: 'FILL' 1, 'wght' 700, 'GRAD' 0, 'opsz' 48; vertical-align: middle; font-size: 35px; user-select: none;",
"send",
}
}
}
}
button {
onclick: move |_| pick_and_send_file(&net),
"File"
}
button {
onclick: move |_| do_send(),
"Send"
//button {
// onclick: move |_| do_send(),
// "Send"
//}
}
}
)
}
// true => rsx!(span { class: "material-symbols-outlined", style: "{button_style}", "mic_off"}),
//Connecting => rsx! {
// div {
// class: "{connecting_status}",
// span {
// class: "material-symbols-outlined",
// style: "vertical-align: middle; font-size: 30px;",
// "signal_cellular_alt_2_bar"
// }
// span {
// style: "width: 5px; display: inline-block;"
// }
// span {
// style: "vertical-align: middle; font-size: 30px;",
// "Connecting"
// }
// }
//},
#[component]
pub fn ControlView() -> Element {
let config_future = use_resource(|| CONFIG.get());
let net: Coroutine<Command> = use_coroutine_handle();
let status = &STATE.status;
let server = STATE.server.read();
@@ -382,7 +456,12 @@ pub fn ControlView() -> Element {
};
let current_channel_name = server.channels[&channel].name.clone();
let Some(proxy_url) = &CONFIG.proxy_url else {
let Some(proxy_url) = config_future
.read_unchecked()
.as_ref()
.and_then(|gui_config| gui_config.proxy_url.clone())
else {
return rsx!();
};
@@ -675,7 +754,7 @@ pub fn ServerView() -> Element {
let chat_box = css!(
"
display: flex;
flex-direction: column;
flex-direction: row;
grid-area: chat;
border-left: solid var(--line-color) var(--line-width);
@@ -727,7 +806,15 @@ pub fn ServerView() -> Element {
#[component]
pub fn LoginView() -> Element {
let net: Coroutine<Command> = use_coroutine_handle();
let default_address = CONFIG.proxy_url.as_deref().unwrap_or("");
let config_future = use_resource(|| CONFIG.get());
let default_address = &*config_future
.read_unchecked()
.as_ref()
.and_then(|gui_config| gui_config.proxy_url.clone())
.unwrap_or("".to_string());
let mut address = use_signal(|| default_address.to_string());
let previous_username = imp::load_username();
@@ -840,6 +927,11 @@ pub fn LoginView() -> Element {
pub fn app() -> Element {
use_coroutine(|rx: UnboundedReceiver<Command>| super::network_entrypoint(rx));
use_future(|| async move {
if let Err(err) = imp::load_config().await {
error!("{}", err)
}
});
global_css!(
"