user control box with some styling

This commit is contained in:
2025-04-06 18:08:09 -06:00
parent dd65b238d1
commit 74fe399cdc
3 changed files with 307 additions and 62 deletions
+2 -4
View File
@@ -1,6 +1,6 @@
[workspace]
resolver = "2"
members = [ "common","gui", "proxy"]
members = ["common", "gui", "proxy"]
[workspace.dependencies]
serde = { version = "1.0.214", features = ["derive"] }
@@ -11,9 +11,7 @@ mumble-web2-common = { path = "common" }
version = "0.5.0"
package = "mumble-protocol-2x"
default-features = false
features = [
"asynchronous-codec",
]
features = ["asynchronous-codec"]
[profile]
+14 -4
View File
@@ -53,13 +53,13 @@ web-sys = { version = "0.3.72", features = [
"AudioDataCopyToOptions",
"AudioSampleFormat",
"Storage",
], optional = true}
], optional = true }
gloo-timers = { version = "0.3.0", features = ["futures"], optional = true }
tracing-web = { version = "0.1.3", optional = true }
# Desktop Dependecies
# ===================
dioxus-desktop = { version = "0.6.3", optional = true}
dioxus-desktop = { version = "0.6.3", optional = true }
tokio = { version = "1.41.1", features = ["net", "rt"], optional = true }
tokio-rustls = { version = "0.26.0", optional = true }
opus = { version = "0.3.0", optional = true }
@@ -82,7 +82,9 @@ ordermap = "0.5.3"
html-purifier = "0.3.0"
markdown = "0.3.0"
futures-channel = "0.3.30"
sir = { git = "https://gitlab.com/samsartor/sir", features = ["dioxus"] } # dioxus 0.6
sir = { git = "https://gitlab.com/samsartor/sir", features = [
"dioxus",
] } # dioxus 0.6
mumble-web2-common = { workspace = true }
serde = { workspace = true }
tracing-subscriber = { version = "0.3.18", features = ["ansi"] }
@@ -107,4 +109,12 @@ web = [
"gloo-timers",
"tracing-web",
]
desktop = ["dioxus/desktop", "tokio", "tokio-rustls", "tracing-subscriber/env-filter", "opus", "cpal", "dasp_ring_buffer"]
desktop = [
"dioxus/desktop",
"tokio",
"tokio-rustls",
"tracing-subscriber/env-filter",
"opus",
"cpal",
"dasp_ring_buffer",
]
+291 -54
View File
@@ -363,6 +363,269 @@ pub fn ChatView() -> Element {
)
}
#[component]
pub fn ControlView() -> Element {
let net: Coroutine<Command> = use_coroutine_handle();
let status = &STATE.status;
let server = STATE.server.read();
let Some(&UserState {
deaf,
self_deaf,
mute,
self_mute,
ref name,
channel,
..
}) = server.this_user()
else {
return rsx!();
};
let current_channel_name = server.channels[&channel].name.clone();
let Some(proxy_url) = &CONFIG.proxy_url else {
return rsx!();
};
let button_row = css!(
r#"
display: flex;
gap: 10px;
"#
);
let spacer = css!(
r#"
flex-grow: 1;
"#
);
let toggle_button = css!(
r#"
padding: 8px;
height: 100%;
aspect-ratio: 1 / 1;
background-color: unset;
border: solid rgb(255 255 255 / 0.1) 3px;
border-radius: 10px;
color: rgb(255 255 255 / 50%);
transition: all 0.5s ease-in-out;
"#
);
let toggle_button_on = css!(
r#"
padding: 8px;
height: 100%;
aspect-ratio: 1 / 1;
background-color: oklch(0.5 0.1381 21.71 / 20.12%);
border: solid rgb(255 255 255 / 0) 3px;
border-radius: 10px;
color: oklch(0.53 0.1505 21.71 / 89.38%);
transition: all 0.25s ease-in-out;
"#
);
let button_style = r#"
font-variation-settings: 'FILL' 1, 'wght' 700, 'GRAD' 0, 'opsz' 48;
vertical-align: middle;
font-size: 35px;
"#;
let connecting_status = css!(
r#"
color: yellow;
"#
);
let connected_status = css!(
r#"
color: oklch(0.55 0.1184 141.35);
"#
);
let disconnected_status = css!(
r#"
color: gray;
"#
);
let failed_status = css!(
r#"
color: red;
"#
);
let connection_info = css!(
r#"
color: gray;
"#
);
let user_edit_button = css!(
r#"
background-color: oklch(0.53 0.1431 264.18);
border-radius: 50%;
aspect-ratio: 1 / 1;
"#
);
let connection_status = match &*status.read() {
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"
}
}
},
Connected => rsx! {
div {
div {
class: "{connected_status}",
span {
class: "material-symbols-outlined",
style: "vertical-align: middle; font-size: 30px;",
"signal_cellular_alt"
}
span {
style: "width: 5px; display: inline-block;"
}
span {
style: "vertical-align: middle; font-size: 25px;",
"Connected"
}
}
div {
class: "{connection_info}",
span { style: "width: 3px; display: inline-block;"}
span { "{current_channel_name}" }
span { "" }
span { "{proxy_url}" }
}
}
},
Disconnected => rsx! {
div {
class: "{disconnected_status}",
span {
class: "material-symbols-outlined",
style: "vertical-align: middle;",
"signal_disconnected"
}
span {
style: "width: 5px; display: inline-block;"
}
span {
style: "vertical-align: middle;",
"Disconnected"
}
}
},
Failed(_) => rsx! {
div {
class: "{failed_status}",
span {
class: "material-symbols-outlined",
style: "vertical-align: middle;",
"error"
}
span {
style: "width: 5px; display: inline-block;"
}
span {
style: "vertical-align: middle;",
"Failed"
}
}
},
};
rsx!(
// Server control
div {
class: "{button_row}",
div {
{connection_status}
}
span { class: "{spacer}" }
button {
class: "{toggle_button}",
onclick: move |_| net.send(Disconnect),
span {
class: "material-symbols-outlined",
style: "{button_style}",
"signal_disconnected"
}
}
}
hr { style: "width: 100%;" }
// User control
div {
class: "{button_row}",
button {
class: "{user_edit_button}",
span {
class: "material-symbols-outlined",
style: "color: oklch(0.65 0.2245 28.06); font-size: 45px; font-variation-settings: 'FILL' 1, 'wght' 700, 'GRAD' 0, 'opsz' 48;",
"person_edit"
}
}
div {
div {
span { style: "font-size: 25px;", "{name}" }
}
div {
span { style: "font-size: 20px; color: gray;", "some data" }
}
}
span { class: "{spacer}" }
button {
class: match mute || self_mute {
true => toggle_button_on,
false => toggle_button,
},
role: "switch",
aria_checked: mute || self_mute,
disabled: mute,
onclick: move |_| net.send(SetMute { mute: !self_mute }),
match mute || self_mute {
true => rsx!(span { class: "material-symbols-outlined", style: "{button_style}", "mic_off"}),
false => rsx!(span { class: "material-symbols-outlined", style: "{button_style}", "mic"}),
}
}
button {
class: match deaf || self_deaf {
true => toggle_button_on,
false => toggle_button,
},
role: "switch",
aria_checked: deaf || self_deaf,
disabled: deaf,
onclick: move |_| net.send(SetDeaf { deaf: !self_deaf }),
match deaf || self_deaf {
true => rsx!(span { class: "material-symbols-outlined", style: "{button_style}", "volume_off"}),
false => rsx!(span { class: "material-symbols-outlined", style: "{button_style}", "volume_up"}),
}
}
}
)
}
#[component]
pub fn ServerView() -> Element {
let net: Coroutine<Command> = use_coroutine_handle();
@@ -381,21 +644,21 @@ pub fn ServerView() -> Element {
let grid = css!(
r#"
display: grid;
height: 100%;
height: 100%;
background-color: var(--bg-color);
grid-template-rows: auto 1fr;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr auto;
grid-template-columns: 1fr 2fr;
grid-template-areas:
"bar bar"
"tree chat";
"tree chat"
"control chat";
@media screen and (max-width: 720px) {
grid-template-rows: auto 1fr 1fr;
grid-template-columns: 1fr;
grid-template-areas:
"bar"
"tree"
"control"
"chat";
}
"#
@@ -423,60 +686,24 @@ pub fn ServerView() -> Element {
"
);
let top_bar = css!(
let control_box = css!(
"
padding: 16px;
grid-area: bar;
background-color: var(--login-bg-color);
margin: 16px;
background-color: var(--light-bg-color);
border-radius: 10px;
overflow: hidden;
grid-area: control;
display: flex;
flex-direction: row;
gap: 16px;
align-items: center;
button {
padding: 8px;
img {
height: 1em;
vertical-align: text-bottom;
}
}
gap: 10px;
flex-direction: column;
"
);
rsx!(
div {
class: "{grid}",
div {
class: "{top_bar}",
button {
onclick: move |_| net.send(Disconnect),
"Disconnect"
}
button {
role: "switch",
aria_checked: mute || self_mute,
disabled: mute,
onclick: move |_| net.send(SetMute { mute: !self_mute }),
match mute || self_mute {
true => rsx!(img { src: asset!("assets/mic-off-svgrepo-com.svg") }),
false => rsx!(img { src: asset!("assets/mic-svgrepo-com.svg") }),
}
"\u{00A0}Mute"
}
button {
role: "switch",
aria_checked: deaf || self_deaf,
disabled: deaf,
onclick: move |_| net.send(SetDeaf { deaf: !self_deaf }),
match deaf || self_deaf {
true => rsx!(img { src: asset!("assets/speaker-muted-svgrepo-com.svg") }),
false => rsx!(img { src: asset!("assets/speaker-medium-svgrepo-com.svg") }),
}
"\u{00A0}Deafen"
}
}
div {
class: "{channel_box}",
for (id, state) in server.channels.iter() {
@@ -489,6 +716,10 @@ pub fn ServerView() -> Element {
class: "{chat_box}",
ChatView {}
}
div {
class: "{control_box}",
ControlView {}
}
}
)
}
@@ -613,8 +844,9 @@ pub fn app() -> Element {
global_css!(
"
:root {
--txt-color: white;
--bg-color: #372f3a;
--txt-color: oklch(0.9 0 99);
--bg-color: oklch(0.15 0.01 338.64);
--light-bg-color: oklch(0.25 0.01 338.64);
--login-bg-color: #5d7680;
--primary-btn-color: #7bad9f;
--accent-normal: #7bad9f;
@@ -637,8 +869,10 @@ pub fn app() -> Element {
overflow: auto;
color: var(--txt-color);
font-family: sans-serif;
font-size: large;
font-family: Nunito;
font-size: 15pt;
font-weight: 600;
}
button {
@@ -675,6 +909,9 @@ pub fn app() -> Element {
);
rsx!(
document::Link{ rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap" }
document::Link{ rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" }
sir::AppStyle { }
match *STATE.status.read() {
Connected => rsx!(ServerView {}),