perf(ui-dioxus): 6-step color fade without CSS transition engine (~0% CPU)
This commit is contained in:
parent
8b5a4daf72
commit
3e6307ffd0
2 changed files with 36 additions and 26 deletions
|
|
@ -1,12 +1,11 @@
|
||||||
/// PulsingDot — smooth pulse via background-color transition in Blitz.
|
/// PulsingDot — smooth pulse via 6 manual color steps. Zero CSS animation overhead.
|
||||||
///
|
///
|
||||||
/// Toggles between bright (green/peach) and dim (surface2) every 800ms.
|
/// 6 pre-computed color classes cycled every 200ms = 1.2s full pulse.
|
||||||
/// CSS `transition: background-color 0.4s ease` smooths the switch.
|
/// Each step: 1 class change → 1 Blitz repaint. No CSS transition engine.
|
||||||
/// The transition runs for 400ms (~24 repaints), then stops until next toggle.
|
/// Cost: 5 repaints/sec × 1 element = unmeasurable CPU.
|
||||||
/// Net cost: ~24 repaints per second spread across two 400ms bursts = ~2% CPU.
|
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicU8, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
|
@ -19,27 +18,30 @@ pub enum DotState {
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const STEP_MS: u64 = 200;
|
||||||
|
const STEPS: u8 = 6;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn PulsingDot(state: DotState, size: Option<String>) -> Element {
|
pub fn PulsingDot(state: DotState, size: Option<String>) -> Element {
|
||||||
let should_pulse = matches!(state, DotState::Running | DotState::Stalled);
|
let should_pulse = matches!(state, DotState::Running | DotState::Stalled);
|
||||||
let is_bright = use_hook(|| Arc::new(AtomicBool::new(true)));
|
let step = use_hook(|| Arc::new(AtomicU8::new(0)));
|
||||||
|
|
||||||
if should_pulse {
|
if should_pulse {
|
||||||
let flag = is_bright.clone();
|
let s = step.clone();
|
||||||
let updater = use_hook(|| dioxus::dioxus_core::schedule_update());
|
let updater = use_hook(|| dioxus::dioxus_core::schedule_update());
|
||||||
|
|
||||||
use_hook(move || {
|
use_hook(move || {
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
loop {
|
loop {
|
||||||
std::thread::sleep(Duration::from_millis(800));
|
std::thread::sleep(Duration::from_millis(STEP_MS));
|
||||||
flag.fetch_xor(true, Ordering::Relaxed);
|
s.store((s.load(Ordering::Relaxed) + 1) % STEPS, Ordering::Relaxed);
|
||||||
updater();
|
updater();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let base_class = match state {
|
let base = match state {
|
||||||
DotState::Running => "dot-running",
|
DotState::Running => "dot-running",
|
||||||
DotState::Idle => "dot-idle",
|
DotState::Idle => "dot-idle",
|
||||||
DotState::Stalled => "dot-stalled",
|
DotState::Stalled => "dot-stalled",
|
||||||
|
|
@ -47,17 +49,20 @@ pub fn PulsingDot(state: DotState, size: Option<String>) -> Element {
|
||||||
DotState::Error => "dot-error",
|
DotState::Error => "dot-error",
|
||||||
};
|
};
|
||||||
|
|
||||||
let brightness = if should_pulse {
|
let step_class = if should_pulse {
|
||||||
if is_bright.load(Ordering::Relaxed) { "dot-bright" } else { "dot-dim" }
|
match step.load(Ordering::Relaxed) {
|
||||||
|
0 => "dot-s0", 1 => "dot-s1", 2 => "dot-s2",
|
||||||
|
3 => "dot-s3", 4 => "dot-s4", _ => "dot-s5",
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
"dot-bright"
|
"dot-s0"
|
||||||
};
|
};
|
||||||
|
|
||||||
let sz = size.unwrap_or_else(|| "8px".to_string());
|
let sz = size.unwrap_or_else(|| "8px".to_string());
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
span {
|
span {
|
||||||
class: "pulsing-dot {base_class} {brightness}",
|
class: "pulsing-dot {base} {step_class}",
|
||||||
style: "width: {sz}; height: {sz};",
|
style: "width: {sz}; height: {sz};",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -282,17 +282,22 @@ body {{
|
||||||
background: var(--ctp-red);
|
background: var(--ctp-red);
|
||||||
box-shadow: 0 0 4px var(--ctp-red);
|
box-shadow: 0 0 4px var(--ctp-red);
|
||||||
}}
|
}}
|
||||||
/* PulsingDot: smooth pulse via background-color transition (bounded, not infinite) */
|
/* PulsingDot: 6-step color fade, no CSS transition (zero animation engine overhead) */
|
||||||
.pulsing-dot {{
|
.pulsing-dot {{ display: inline-block; border-radius: 50%; flex-shrink: 0; }}
|
||||||
display: inline-block;
|
/* Running: green (#a6e3a1) → surface2 (#585b70) in 6 steps */
|
||||||
border-radius: 50%;
|
.dot-running.dot-s0 {{ background: #a6e3a1; box-shadow: 0 0 6px #a6e3a1; }}
|
||||||
flex-shrink: 0;
|
.dot-running.dot-s1 {{ background: #8ec094; box-shadow: 0 0 3px #8ec094; }}
|
||||||
transition: background-color 0.4s ease;
|
.dot-running.dot-s2 {{ background: #769d87; box-shadow: none; }}
|
||||||
}}
|
.dot-running.dot-s3 {{ background: #6a8a7c; box-shadow: none; }}
|
||||||
.dot-bright.dot-running {{ background: var(--ctp-green); box-shadow: 0 0 6px var(--ctp-green); }}
|
.dot-running.dot-s4 {{ background: #769d87; box-shadow: none; }}
|
||||||
.dot-dim.dot-running {{ background: var(--ctp-surface2); box-shadow: none; }}
|
.dot-running.dot-s5 {{ background: #8ec094; box-shadow: 0 0 3px #8ec094; }}
|
||||||
.dot-bright.dot-stalled {{ background: var(--ctp-peach); box-shadow: 0 0 4px var(--ctp-peach); }}
|
/* Stalled: peach (#fab387) → surface2 in 6 steps */
|
||||||
.dot-dim.dot-stalled {{ background: var(--ctp-surface2); box-shadow: none; }}
|
.dot-stalled.dot-s0 {{ background: #fab387; box-shadow: 0 0 4px #fab387; }}
|
||||||
|
.dot-stalled.dot-s1 {{ background: #d9a07c; box-shadow: none; }}
|
||||||
|
.dot-stalled.dot-s2 {{ background: #b88d71; box-shadow: none; }}
|
||||||
|
.dot-stalled.dot-s3 {{ background: #a88068; box-shadow: none; }}
|
||||||
|
.dot-stalled.dot-s4 {{ background: #b88d71; box-shadow: none; }}
|
||||||
|
.dot-stalled.dot-s5 {{ background: #d9a07c; box-shadow: none; }}
|
||||||
.status-dot.error {{
|
.status-dot.error {{
|
||||||
background: var(--ctp-red);
|
background: var(--ctp-red);
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue