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] [workspace]
resolver = "2" resolver = "2"
members = [ "common","gui", "proxy"] members = ["common", "gui", "proxy"]
[workspace.dependencies] [workspace.dependencies]
serde = { version = "1.0.214", features = ["derive"] } serde = { version = "1.0.214", features = ["derive"] }
@@ -11,9 +11,7 @@ mumble-web2-common = { path = "common" }
version = "0.5.0" version = "0.5.0"
package = "mumble-protocol-2x" package = "mumble-protocol-2x"
default-features = false default-features = false
features = [ features = ["asynchronous-codec"]
"asynchronous-codec",
]
[profile] [profile]
+14 -4
View File
@@ -53,13 +53,13 @@ web-sys = { version = "0.3.72", features = [
"AudioDataCopyToOptions", "AudioDataCopyToOptions",
"AudioSampleFormat", "AudioSampleFormat",
"Storage", "Storage",
], optional = true} ], optional = true }
gloo-timers = { version = "0.3.0", features = ["futures"], optional = true } gloo-timers = { version = "0.3.0", features = ["futures"], optional = true }
tracing-web = { version = "0.1.3", optional = true } tracing-web = { version = "0.1.3", optional = true }
# Desktop Dependecies # 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 = { version = "1.41.1", features = ["net", "rt"], optional = true }
tokio-rustls = { version = "0.26.0", optional = true } tokio-rustls = { version = "0.26.0", optional = true }
opus = { version = "0.3.0", optional = true } opus = { version = "0.3.0", optional = true }
@@ -82,7 +82,9 @@ ordermap = "0.5.3"
html-purifier = "0.3.0" html-purifier = "0.3.0"
markdown = "0.3.0" markdown = "0.3.0"
futures-channel = "0.3.30" 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 } mumble-web2-common = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
tracing-subscriber = { version = "0.3.18", features = ["ansi"] } tracing-subscriber = { version = "0.3.18", features = ["ansi"] }
@@ -107,4 +109,12 @@ web = [
"gloo-timers", "gloo-timers",
"tracing-web", "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",
]
+290 -53
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] #[component]
pub fn ServerView() -> Element { pub fn ServerView() -> Element {
let net: Coroutine<Command> = use_coroutine_handle(); let net: Coroutine<Command> = use_coroutine_handle();
@@ -384,18 +647,18 @@ pub fn ServerView() -> Element {
height: 100%; height: 100%;
background-color: var(--bg-color); background-color: var(--bg-color);
grid-template-rows: auto 1fr; grid-template-rows: 1fr auto;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 2fr;
grid-template-areas: grid-template-areas:
"bar bar" "tree chat"
"tree chat"; "control chat";
@media screen and (max-width: 720px) { @media screen and (max-width: 720px) {
grid-template-rows: auto 1fr 1fr; grid-template-rows: auto 1fr 1fr;
grid-template-columns: 1fr; grid-template-columns: 1fr;
grid-template-areas: grid-template-areas:
"bar"
"tree" "tree"
"control"
"chat"; "chat";
} }
"# "#
@@ -423,60 +686,24 @@ pub fn ServerView() -> Element {
" "
); );
let top_bar = css!( let control_box = css!(
" "
padding: 16px; padding: 16px;
grid-area: bar; margin: 16px;
background-color: var(--login-bg-color); background-color: var(--light-bg-color);
border-radius: 10px;
overflow: hidden;
grid-area: control;
display: flex; display: flex;
flex-direction: row; gap: 10px;
gap: 16px; flex-direction: column;
align-items: center;
button {
padding: 8px;
img {
height: 1em;
vertical-align: text-bottom;
}
}
" "
); );
rsx!( rsx!(
div { div {
class: "{grid}", 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 { div {
class: "{channel_box}", class: "{channel_box}",
for (id, state) in server.channels.iter() { for (id, state) in server.channels.iter() {
@@ -489,6 +716,10 @@ pub fn ServerView() -> Element {
class: "{chat_box}", class: "{chat_box}",
ChatView {} ChatView {}
} }
div {
class: "{control_box}",
ControlView {}
}
} }
) )
} }
@@ -613,8 +844,9 @@ pub fn app() -> Element {
global_css!( global_css!(
" "
:root { :root {
--txt-color: white; --txt-color: oklch(0.9 0 99);
--bg-color: #372f3a; --bg-color: oklch(0.15 0.01 338.64);
--light-bg-color: oklch(0.25 0.01 338.64);
--login-bg-color: #5d7680; --login-bg-color: #5d7680;
--primary-btn-color: #7bad9f; --primary-btn-color: #7bad9f;
--accent-normal: #7bad9f; --accent-normal: #7bad9f;
@@ -637,8 +869,10 @@ pub fn app() -> Element {
overflow: auto; overflow: auto;
color: var(--txt-color); color: var(--txt-color);
font-family: sans-serif; font-family: Nunito;
font-size: large; font-size: 15pt;
font-weight: 600;
} }
button { button {
@@ -675,6 +909,9 @@ pub fn app() -> Element {
); );
rsx!( 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 { } sir::AppStyle { }
match *STATE.status.read() { match *STATE.status.read() {
Connected => rsx!(ServerView {}), Connected => rsx!(ServerView {}),