photon_ui/components/
loader.rs1use crate::{
2 Component,
3 RenderError,
4 Rendered,
5};
6
7const SPINNER_FRAMES: &[&str] = &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
9
10#[derive(Clone)]
15pub struct Loader {
16 message: String,
17 frame: usize,
18 spinner_color: Option<String>,
19 message_color: Option<String>,
20}
21
22impl Loader {
23 pub fn new(
25 message: impl Into<String>,
26 spinner_color: Option<String>,
27 message_color: Option<String>,
28 ) -> Self {
29 Self {
30 message: message.into(),
31 frame: 0,
32 spinner_color,
33 message_color,
34 }
35 }
36
37 pub fn tick(&mut self) {
39 self.frame = (self.frame + 1) % SPINNER_FRAMES.len();
40 }
41}
42
43impl Component for Loader {
44 fn render(&self, _width: u16) -> Result<Rendered, RenderError> {
45 let spinner = SPINNER_FRAMES[self.frame];
46 let spinner_styled = self
49 .spinner_color
50 .as_ref()
51 .map(|c| format!("{}{}\x1b[22m\x1b[0m", c, spinner))
52 .unwrap_or_else(|| spinner.to_string());
53 let message_styled = self
54 .message_color
55 .as_ref()
56 .map(|c| format!("{}{}\x1b[22m\x1b[0m", c, self.message))
57 .unwrap_or_else(|| self.message.clone());
58 let line = format!("{} {}", spinner_styled, message_styled);
59 Ok(Rendered {
60 lines: vec![line],
61 cursor: None,
62 images: Vec::new(),
63 })
64 }
65}