From 4e30be3ebd79ecae52d84d6b69781cd639fe0610 Mon Sep 17 00:00:00 2001 From: Sam Sartor Date: Mon, 27 Oct 2025 18:54:34 -0600 Subject: [PATCH] switch to scss asset & remove sir --- Cargo.lock | 66 ------ gui/Cargo.toml | 3 - gui/assets/main.scss | 293 ++++++++++++++++++++++++++ gui/src/app.rs | 475 +++++-------------------------------------- 4 files changed, 339 insertions(+), 498 deletions(-) create mode 100644 gui/assets/main.scss diff --git a/Cargo.lock b/Cargo.lock index 9789115..f08c97d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,12 +107,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "arc-swap" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" - [[package]] name = "ashpd" version = "0.8.1" @@ -3256,15 +3250,6 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" -[[package]] -name = "litrs" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" -dependencies = [ - "proc-macro2", -] - [[package]] name = "lock_api" version = "0.4.12" @@ -3651,7 +3636,6 @@ dependencies = [ "serde", "serde-wasm-bindgen 0.6.5", "serde_json", - "sir", "tokio", "tokio-rustls", "tokio-util", @@ -3860,17 +3844,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -5022,23 +4995,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rsass" -version = "0.28.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212e14dfa9e48df42c0125c80a213a9a0269103130c8c154080fdbbb79ce7d52" -dependencies = [ - "arc-swap", - "fastrand", - "lazy_static", - "nom", - "num-bigint", - "num-integer", - "num-rational", - "num-traits", - "tracing", -] - [[package]] name = "rust-embed" version = "8.5.0" @@ -5782,28 +5738,6 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" -[[package]] -name = "sir" -version = "0.6.0-alpha.4" -source = "git+https://gitlab.com/samsartor/sir#99ac4db5c0a02debf15c145c998fe90d854269b2" -dependencies = [ - "dioxus", - "once_cell", - "sir-macro", -] - -[[package]] -name = "sir-macro" -version = "0.5.0" -source = "git+https://gitlab.com/samsartor/sir#99ac4db5c0a02debf15c145c998fe90d854269b2" -dependencies = [ - "litrs", - "proc-macro2", - "quote", - "rand 0.8.5", - "rsass", -] - [[package]] name = "slab" version = "0.4.9" diff --git a/gui/Cargo.toml b/gui/Cargo.toml index e51e62b..3649d77 100644 --- a/gui/Cargo.toml +++ b/gui/Cargo.toml @@ -82,9 +82,6 @@ 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 mumble-web2-common = { workspace = true } serde = { workspace = true } tracing-subscriber = { version = "0.3.18", features = ["ansi"] } diff --git a/gui/assets/main.scss b/gui/assets/main.scss new file mode 100644 index 0000000..6a42c04 --- /dev/null +++ b/gui/assets/main.scss @@ -0,0 +1,293 @@ +:root { + --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; + --accent-muted: #ff746c; + --accent-deafened: #464459; + --line-width: 2px; + --line-color: white; +} + +body { + margin: 0; +} + +#main { + height: 100vh; + display: flex; + flex-direction: column; + justify-content: space-around; + background-color: var(--bg-color); + overflow: auto; + color: var(--txt-color); + + font-family: Nunito; + font-size: 15pt; + font-weight: 600; + +} + +button { + font-weight: bold; + font-size: medium; + border: none; + border-radius: 4px; + color: var(--txt-color); + background-color: var(--primary-btn-color); + cursor: pointer; +} + +input { + border: none; + border-radius: 4px; + background-color: white; + color: black; +} + +input:focus, +input:focus-visible { + border: none; + outline: solid var(--line-width) var(--accent-normal); + outline-offset: -3px; +} + +a:link { + color: var(--accent-normal); +} + +a:visited { + color: var(--accent-muted); +} + +.userpil { + border-radius: 100px; + padding: 4px 8px; + width: fit-content; + + img { + height: 1em; + vertical-align: text-bottom; + } + + &.is_self { + font-weight: bolder; + } +} + +.channel { + &_details { + flex: 0 0 100%; + + summary { + cursor: pointer; + } + + summary:focus-visible { + outline: none; + } + } + + &_children { + border-left: solid var(--line-color) var(--line-width); + display: flex; + flex-direction: row; + flex-wrap: wrap; + gap: 8px; + margin-left: 5px; + padding-left: 11px; + padding-top: 4px; + } +} + +.chat { + &_panel { + display: flex; + flex-direction: column; + } + + &_history { + overflow-y: auto; + flex: 1 0 0; + } + + &_message { + display: flex; + flex-direction: row; + margin: 16px; + gap: 8px; + align-items: center; + } + + &_box_wrapper { + padding: 16px; + border-top: solid var(--line-color) var(--line-width); + } + + &_box { + display: flex; + flex-direction: row; + 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; + + border: none; + } + + input:focus { + outline: none; + } + } +} + +.user_edit_button { + background-color: oklch(0.53 0.1431 264.18); + border-radius: 50%; + aspect-ratio: 1 / 1; +} + +.button_row { + display: flex; + gap: 10px; + + .spacer { + flex-grow: 1; + } +} + +.toggle_button { + 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; + + &.is_on { + background-color: oklch(0.5 0.1381 21.71 / 20.12%); + color: oklch(0.53 0.1505 21.71 / 89.38%); + } + + .material-symbols-outlined { + font-variation-settings: 'FILL' 1, 'wght' 700, 'GRAD' 0, 'opsz' 48; + vertical-align: middle; + font-size: 35px; + } +} + +.server { + &_grid { + display: grid; + height: 100%; + background-color: var(--bg-color); + + grid-template-rows: 1fr auto; + grid-template-columns: 1fr 2fr; + grid-template-areas: + "tree chat" + "control chat"; + + @media screen and (max-width: 720px) { + grid-template-rows: auto 1fr 1fr; + grid-template-columns: 1fr; + grid-template-areas: + "tree" + "control" + "chat"; + } + } + + &_channel_box { + padding: 16px; + overflow: auto; + grid-area: tree; + } + + &_chat_box { + display: flex; + flex-direction: row; + grid-area: chat; + border-left: solid var(--line-color) var(--line-width); + + @media screen and (max-width: 720px) { + border-left: unset; + border-top: solid var(--line-color) var(--line-width); + } + } + + &_control_box { + padding: 16px; + margin: 16px; + background-color: var(--light-bg-color); + border-radius: 10px; + overflow: hidden; + grid-area: control; + + display: flex; + gap: 10px; + flex-direction: column; + } +} + +.login { + max-width: 50vw; + align-self: center; + padding: 32px; + border-radius: 16px; + background-color: var(--login-bg-color); + + display: flex; + flex-direction: column; + gap: 16px; + + input, + button { + padding: 8px; + } + + h1 { + margin: 0; + color: #b3c6b4; + } + + &_bttn { + font-weight: bold; + font-size: large; + } + + &_error { + + background-color: white; + border-radius: 4px; + overflow: auto; + padding: 4px; + color: red; + + pre { + color: black; + } + } +} \ No newline at end of file diff --git a/gui/src/app.rs b/gui/src/app.rs index f9edf97..dabdf3b 100644 --- a/gui/src/app.rs +++ b/gui/src/app.rs @@ -4,7 +4,6 @@ use dioxus::prelude::*; use mime_guess::Mime; use mumble_web2_common::{ClientConfig, ServerStatus}; use ordermap::OrderSet; -use sir::{css, global_css}; use std::collections::HashMap; use crate::imp; @@ -138,25 +137,6 @@ impl UserIcon { #[component] pub fn UserPill(name: String, icon: UserIcon, isself: bool) -> Element { - let pill = css!( - " - border-radius: 100px; - padding: 4px 8px; - width: fit-content; - - img { - height: 1em; - vertical-align: text-bottom; - } - " - ); - - let pill_self = css!( - " - font-weight: bolder; - " - ); - let color = match icon { UserIcon::Normal => "var(--accent-normal)", UserIcon::Muted => "var(--accent-muted)", @@ -166,7 +146,7 @@ pub fn UserPill(name: String, icon: UserIcon, isself: bool) -> Element { rsx!( div { - class: match isself { true => format!("{pill} {pill_self}"), false => format!("{pill}") }, + class: match isself { true => "userpil is_self", false => "userpil" }, style: "background-color: {color}", { icon.url().map(|url| rsx!(img { src: url })) } "\u{00A0}{name}\u{00A0}" @@ -200,34 +180,9 @@ pub fn Channel(id: ChannelId) -> Element { return rsx!("missing channel {id}"); }; - let channel_details = css!( - " - flex: 0 0 100%; - - summary { - cursor: pointer; - } - - summary:focus-visible { - outline: none; - } - " - ); - let channel_children = css!( - " - border-left: solid var(--line-color) var(--line-width); - display: flex; - flex-direction: row; - flex-wrap: wrap; - gap: 8px; - margin-left: 5px; - padding-left: 11px; - padding-top: 4px; " - ); - rsx!( details { - class: "{channel_details}", + class: "channel_details", open: true, summary { span { @@ -242,7 +197,7 @@ pub fn Channel(id: ChannelId) -> Element { } if state.users.len() + state.children.len() > 0 { div { - class: "{channel_children}", + class: "channel_children", for id in state.users.iter() { User { id: *id } } @@ -283,71 +238,6 @@ 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; - flex: 1 0 0; - " - ); - - let chat_message = css!( - " - display: flex; - flex-direction: row; - margin: 16px; - gap: 8px; - align-items: center; - " - ); - - 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; - 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; - - border: none; - } - - input:focus { - outline: none; - } - - " - ); - let mut do_send = move || { if let Some(user) = STATE.server.read().this_user() { net.send(SendChat { @@ -359,12 +249,12 @@ pub fn ChatView() -> Element { rsx!( div { - class: "{chat_panel}", + class: "chat_panel", div { - class: "{chat_history}", + class: "chat_history", for chat in server.chat.iter() { div { - class: "{chat_message}", + class: "chat_message", if let Some(sender) = chat.sender.and_then(|u| server.users.get(&u)) { UserPill { name: sender.name.clone(), @@ -379,9 +269,9 @@ pub fn ChatView() -> Element { } } div { - class: "{chat_box_wrapper}", + class: "chat_box_wrapper", div { - class: "{chat_box}", + class: "chat_box", input { placeholder: "say something", value: "{draft.read()}", @@ -418,25 +308,6 @@ pub fn ChatView() -> Element { ) } -// 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(config: Resource) -> Element { let net: Coroutine = use_coroutine_handle(); @@ -462,99 +333,15 @@ pub fn ControlView(config: Resource) -> Element { .as_ref() .and_then(|gui_config| gui_config.proxy_url.clone()); - 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 connecting_color = "yellow"; + let connected_color = "oklch(0.55 0.1184 141.35)"; + let disconnected_color = "gray"; + let failed_color = "red"; let connection_status = match &*status.read() { Connecting => rsx! { div { - class: "{connecting_status}", + style: "color: \"{connecting_color}\";", span { class: "material-symbols-outlined", style: "vertical-align: middle; font-size: 30px;", @@ -572,7 +359,7 @@ pub fn ControlView(config: Resource) -> Element { Connected => rsx! { div { div { - class: "{connected_status}", + style: "color: \"{connected_color}\";", span { class: "material-symbols-outlined", style: "vertical-align: middle; font-size: 30px;", @@ -587,7 +374,6 @@ pub fn ControlView(config: Resource) -> Element { } } div { - class: "{connection_info}", span { style: "width: 3px; display: inline-block;"} span { "{current_channel_name}" } if let Some(proxy_url) = proxy_url { @@ -599,7 +385,7 @@ pub fn ControlView(config: Resource) -> Element { }, Disconnected => rsx! { div { - class: "{disconnected_status}", + style: "color: \"{disconnected_color}\";", span { class: "material-symbols-outlined", style: "vertical-align: middle;", @@ -616,7 +402,7 @@ pub fn ControlView(config: Resource) -> Element { }, Failed(_) => rsx! { div { - class: "{failed_status}", + style: "color: \"{failed_color}\";", span { class: "material-symbols-outlined", style: "vertical-align: middle;", @@ -637,17 +423,16 @@ pub fn ControlView(config: Resource) -> Element { rsx!( // Server control div { - class: "{button_row}", + class: "button_row", div { {connection_status} } - span { class: "{spacer}" } + span { class: "spacer" } button { - class: "{toggle_button}", + class: "toggle_button", onclick: move |_| net.send(Disconnect), span { class: "material-symbols-outlined", - style: "{button_style}", "signal_disconnected" } } @@ -655,9 +440,9 @@ pub fn ControlView(config: Resource) -> Element { hr { style: "width: 100%;" } // User control div { - class: "{button_row}", + class: "button_row", button { - class: "{user_edit_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;", @@ -672,11 +457,11 @@ pub fn ControlView(config: Resource) -> Element { span { style: "font-size: 20px; color: gray;", "some data" } } } - span { class: "{spacer}" } + span { class: "spacer" } button { class: match denoise() { - true => toggle_button_on, - false => toggle_button, + true => "toggle_button is_on", + false => "toggle_button", }, role: "switch", aria_checked: denoise(), @@ -686,36 +471,36 @@ pub fn ControlView(config: Resource) -> Element { net.send(UpdateMicEffects { denoise: new_denoise }) }, match denoise() { - true => rsx!(span { class: "material-symbols-outlined", style: "{button_style}", "cadence"}), - false => rsx!(span { class: "material-symbols-outlined", style: "{button_style}", "graphic_eq"}), + true => rsx!(span { class: "material-symbols-outlined", "cadence"}), + false => rsx!(span { class: "material-symbols-outlined", "graphic_eq"}), } } button { class: match mute || self_mute { - true => toggle_button_on, - false => toggle_button, + true => "toggle_button is_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"}), + true => rsx!(span { class: "material-symbols-outlined", "mic_off"}), + false => rsx!(span { class: "material-symbols-outlined", "mic"}), } } button { class: match deaf || self_deaf { - true => toggle_button_on, - false => toggle_button, + true => "toggle_button in_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"}), + true => rsx!(span { class: "material-symbols-outlined", "volume_off"}), + false => rsx!(span { class: "material-symbols-outlined", "volume_up"}), } } } @@ -737,71 +522,11 @@ pub fn ServerView(config: Resource) -> Element { return rsx!(); }; - let grid = css!( - r#" - display: grid; - height: 100%; - background-color: var(--bg-color); - - grid-template-rows: 1fr auto; - grid-template-columns: 1fr 2fr; - grid-template-areas: - "tree chat" - "control chat"; - - @media screen and (max-width: 720px) { - grid-template-rows: auto 1fr 1fr; - grid-template-columns: 1fr; - grid-template-areas: - "tree" - "control" - "chat"; - } - "# - ); - - let channel_box = css!( - " - padding: 16px; - overflow: auto; - grid-area: tree; - " - ); - - let chat_box = css!( - " - display: flex; - flex-direction: row; - grid-area: chat; - border-left: solid var(--line-color) var(--line-width); - - @media screen and (max-width: 720px) { - border-left:unset; - border-top: solid var(--line-color) var(--line-width); - } - " - ); - - let control_box = css!( - " - padding: 16px; - margin: 16px; - background-color: var(--light-bg-color); - border-radius: 10px; - overflow: hidden; - grid-area: control; - - display: flex; - gap: 10px; - flex-direction: column; - " - ); - rsx!( div { - class: "{grid}", + class: "server_grid", div { - class: "{channel_box}", + class: "server_channel_box", for (id, state) in server.channels.iter() { if state.parent.is_none() { Channel { id: *id } @@ -809,11 +534,11 @@ pub fn ServerView(config: Resource) -> Element { } } div { - class: "{chat_box}", + class: "server_chat_box", ChatView {} } div { - class: "{control_box}", + class: "server_control_box", ControlView { config } } } @@ -865,49 +590,6 @@ pub fn LoginView(config: Resource) -> Element { let previous_username = imp::load_username(); let mut username = use_signal(|| previous_username.unwrap_or(String::new())); - let error = css!( - " - background-color: white; - border-radius: 4px; - overflow: auto; - padding: 4px; - color: red; - pre { - color: black; - } - " - ); - - let login_box = css!( - " - max-width: 50vw; - align-self: center; - padding: 32px; - border-radius: 16px; - background-color: var(--login-bg-color); - - display: flex; - flex-direction: column; - gap: 16px; - - input,button { - padding: 8px; - } - - h1 { - margin: 0; - color: #b3c6b4; - } - " - ); - - let bttn = css!( - " - font-weight: bold; - font-size: large; - " - ); - let do_connect = move |_| { //let _ = set_default_username(&username.read()); let _ = imp::set_default_username(&username.read()); @@ -921,25 +603,25 @@ pub fn LoginView(config: Resource) -> Element { let bottom = match &*status.read() { Disconnected => rsx! { button { - class: "{bttn}", + class: "login_bttn", onclick: do_connect.clone(), "Connect" } }, Connecting => rsx! { div { - class: "{bttn}", + class: "login_bttn", "Connecting..." } }, Failed(msg) => rsx!( button { - class: "{bttn}", + class: "login_bttn", onclick: do_connect.clone(), "Reconnect" } div { - class: "{error}", + class: "login_error", "Failed to connect:" pre { "{msg}" @@ -950,7 +632,7 @@ pub fn LoginView(config: Resource) -> Element { }; rsx!( div { - class: "{login_box}", + class: "login", h1 { "Mumble Web" } @@ -1025,6 +707,8 @@ pub fn LoginView(config: Resource) -> Element { } pub fn app() -> Element { + static STYLE: Asset = asset!("/assets/main.scss"); + use_coroutine(|rx: UnboundedReceiver| super::network_entrypoint(rx)); let config = use_resource(|| async move { match imp::load_config().await { @@ -1033,78 +717,11 @@ pub fn app() -> Element { } }); - global_css!( - " - :root { - --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; - --accent-muted: #ff746c; - --accent-deafened: #464459; - --line-width: 2px; - --line-color: white; - } - - body { - margin: 0; - } - - #main { - height: 100vh; - display: flex; - flex-direction: column; - justify-content: space-around; - background-color: var(--bg-color); - overflow: auto; - color: var(--txt-color); - - font-family: Nunito; - font-size: 15pt; - font-weight: 600; - - } - - button { - font-weight: bold; - font-size: medium; - border: none; - border-radius: 4px; - color: var(--txt-color); - background-color: var(--primary-btn-color); - cursor: pointer; - } - - input { - border: none; - border-radius: 4px; - background-color: white; - color: black; - } - - input:focus,input:focus-visible { - border: none; - outline: solid var(--line-width) var(--accent-normal); - outline-offset: -3px; - } - - a:link { - color: var(--accent-normal); - } - - a:visited { - color: var(--accent-muted); - } - " - ); - 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" } + document::Link{ rel: "stylesheet", href: STYLE } - sir::AppStyle { } match *STATE.status.read() { Connected => rsx!(ServerView { config }), _ => rsx!(LoginView { config }),