fix(ui-dioxus): class-toggle animation instead of inline opacity (Blitz compatible)
This commit is contained in:
parent
67ab77ebf4
commit
2f03cf0ef0
4 changed files with 66 additions and 153 deletions
123
ui-dioxus/Cargo.lock
generated
123
ui-dioxus/Cargo.lock
generated
|
|
@ -135,7 +135,6 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"agor-core",
|
||||
"dioxus",
|
||||
"dioxus-motion",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -543,12 +542,6 @@ version = "1.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "base16"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d27c3610c36aee21ce8ac510e6224498de4228ad772a171ed65643a24693a5a8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
|
|
@ -1355,7 +1348,6 @@ dependencies = [
|
|||
"dioxus-html",
|
||||
"dioxus-logger",
|
||||
"dioxus-native",
|
||||
"dioxus-router",
|
||||
"dioxus-signals",
|
||||
"dioxus-stores",
|
||||
"dioxus-web",
|
||||
|
|
@ -1586,25 +1578,6 @@ dependencies = [
|
|||
"tracing-wasm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dioxus-motion"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddf087cf8951428be38394cff816a327f1d15f2953af8a65986578179dff21a6"
|
||||
dependencies = [
|
||||
"dioxus",
|
||||
"easer",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"instant",
|
||||
"smallvec",
|
||||
"spin_sleep",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"wide 1.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dioxus-native"
|
||||
version = "0.7.3"
|
||||
|
|
@ -1651,41 +1624,6 @@ dependencies = [
|
|||
"rustc-hash 2.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dioxus-router"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d5b31f9e27231389bf5a117b7074d22d8c58358b484a2558e56fbab20e64ca4"
|
||||
dependencies = [
|
||||
"dioxus-cli-config",
|
||||
"dioxus-core",
|
||||
"dioxus-core-macro",
|
||||
"dioxus-history",
|
||||
"dioxus-hooks",
|
||||
"dioxus-html",
|
||||
"dioxus-router-macro",
|
||||
"dioxus-signals",
|
||||
"percent-encoding",
|
||||
"rustversion",
|
||||
"tracing",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dioxus-router-macro"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "838b9b441a95da62b39cae4defd240b5ebb0ec9f2daea1126099e00a838dc86f"
|
||||
dependencies = [
|
||||
"base16",
|
||||
"digest",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"sha2",
|
||||
"slab",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dioxus-rsx"
|
||||
version = "0.7.3"
|
||||
|
|
@ -1873,15 +1811,6 @@ version = "1.0.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
||||
|
||||
[[package]]
|
||||
name = "easer"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fba524f8b83c9c5bde02c2bb1627de9d1f81980489a6d54168cdfd08c258f917"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
|
|
@ -2979,15 +2908,6 @@ dependencies = [
|
|||
"cfb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ioctl-rs"
|
||||
version = "0.1.6"
|
||||
|
|
@ -4868,15 +4788,6 @@ dependencies = [
|
|||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "safe_arch"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f7caad094bd561859bcd467734a720c3c1f5d1f338995351fefe2190c45efed"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
|
|
@ -5119,17 +5030,6 @@ dependencies = [
|
|||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
|
|
@ -5319,15 +5219,6 @@ dependencies = [
|
|||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin_sleep"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c07347b7c0301b9adba4350bdcf09c039d0e7160922050db0439b3c6723c8ab"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spirv"
|
||||
version = "0.3.0+sdk-1.3.268.0"
|
||||
|
|
@ -6096,7 +5987,7 @@ version = "0.9.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a28554d13eb5daba527cc1b91b6c341372a0ae45ed277ffb2c6fbc04f319d7e"
|
||||
dependencies = [
|
||||
"wide 0.7.33",
|
||||
"wide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6944,17 +6835,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"safe_arch 0.7.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wide"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "198f6abc41fab83526d10880fa5c17e2b4ee44e763949b4bb34e2fd1e8ca48e4"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"safe_arch 1.0.0",
|
||||
"safe_arch",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -15,5 +15,4 @@ serde = { version = "1", features = ["derive"] }
|
|||
serde_json = "1"
|
||||
uuid = { version = "1", features = ["v4"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
dioxus-motion = { version = "0.3", default-features = false, features = ["desktop"] }
|
||||
log = "0.4"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
/// PulsingDot — Blitz-compatible animated status indicator using dioxus-motion.
|
||||
/// PulsingDot — Blitz-compatible animated status indicator.
|
||||
///
|
||||
/// Uses dioxus-motion's Tween with LoopMode::Alternate for infinite ping-pong.
|
||||
/// Avoids CSS @keyframes entirely — no Blitz full-scene repaint loop.
|
||||
/// Instead of animating opacity (Blitz doesn't reliably restyle inline style changes),
|
||||
/// we toggle between "bright" and "dim" CSS classes using a simple OS thread timer.
|
||||
/// This changes the `class` attribute which Blitz DOES process for restyling.
|
||||
///
|
||||
/// CPU cost: schedule_update fires every 1s (2 updates per cycle), not 30fps.
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_motion::prelude::*;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum DotState {
|
||||
|
|
@ -18,44 +23,43 @@ pub enum DotState {
|
|||
#[component]
|
||||
pub fn PulsingDot(state: DotState, size: Option<String>) -> Element {
|
||||
let should_pulse = matches!(state, DotState::Running | DotState::Stalled);
|
||||
let mut opacity = use_motion(1.0f32);
|
||||
let is_dim = use_hook(|| Arc::new(AtomicBool::new(false)));
|
||||
|
||||
// Infinite ping-pong tween: 1.0 → 0.4 → 1.0 → ...
|
||||
if should_pulse {
|
||||
use_effect(move || {
|
||||
opacity.animate_to(
|
||||
0.4,
|
||||
AnimationConfig::new(AnimationMode::Tween(
|
||||
Tween::new(Duration::from_millis(1000))
|
||||
))
|
||||
.with_loop(LoopMode::Alternate),
|
||||
);
|
||||
let dim = is_dim.clone();
|
||||
let updater = use_hook(|| dioxus::dioxus_core::schedule_update());
|
||||
|
||||
use_hook(move || {
|
||||
std::thread::spawn(move || {
|
||||
loop {
|
||||
std::thread::sleep(Duration::from_millis(1000));
|
||||
dim.fetch_xor(true, Ordering::Relaxed); // toggle
|
||||
updater(); // trigger re-render
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
let (color, shadow) = match state {
|
||||
DotState::Running => ("var(--ctp-green)", "0 0 6px var(--ctp-green)"),
|
||||
DotState::Idle => ("var(--ctp-overlay0)", "none"),
|
||||
DotState::Stalled => ("var(--ctp-peach)", "0 0 4px var(--ctp-peach)"),
|
||||
DotState::Done => ("var(--ctp-blue)", "none"),
|
||||
DotState::Error => ("var(--ctp-red)", "0 0 4px var(--ctp-red)"),
|
||||
let base_class = match state {
|
||||
DotState::Running => "dot-running",
|
||||
DotState::Idle => "dot-idle",
|
||||
DotState::Stalled => "dot-stalled",
|
||||
DotState::Done => "dot-done",
|
||||
DotState::Error => "dot-error",
|
||||
};
|
||||
|
||||
let dim_class = if should_pulse && is_dim.load(Ordering::Relaxed) {
|
||||
"dot-dim"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
let sz = size.unwrap_or_else(|| "8px".to_string());
|
||||
let op = if should_pulse { opacity.get_value() } else { 1.0 };
|
||||
|
||||
rsx! {
|
||||
span {
|
||||
style: "
|
||||
display: inline-block;
|
||||
width: {sz};
|
||||
height: {sz};
|
||||
border-radius: 50%;
|
||||
background: {color};
|
||||
box-shadow: {shadow};
|
||||
opacity: {op};
|
||||
flex-shrink: 0;
|
||||
",
|
||||
class: "pulsing-dot {base_class} {dim_class}",
|
||||
style: "width: {sz}; height: {sz};",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -257,6 +257,35 @@ body {{
|
|||
.status-dot.stalled {{
|
||||
background: var(--ctp-peach);
|
||||
}}
|
||||
|
||||
/* PulsingDot component classes */
|
||||
.pulsing-dot {{
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}}
|
||||
.dot-running {{
|
||||
background: var(--ctp-green);
|
||||
box-shadow: 0 0 6px var(--ctp-green);
|
||||
}}
|
||||
.dot-idle {{
|
||||
background: var(--ctp-overlay0);
|
||||
}}
|
||||
.dot-stalled {{
|
||||
background: var(--ctp-peach);
|
||||
box-shadow: 0 0 4px var(--ctp-peach);
|
||||
}}
|
||||
.dot-done {{
|
||||
background: var(--ctp-blue);
|
||||
}}
|
||||
.dot-error {{
|
||||
background: var(--ctp-red);
|
||||
box-shadow: 0 0 4px var(--ctp-red);
|
||||
}}
|
||||
.dot-dim {{
|
||||
background: var(--ctp-surface1);
|
||||
box-shadow: none;
|
||||
}}
|
||||
.status-dot.error {{
|
||||
background: var(--ctp-red);
|
||||
}}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue