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
47 .spinner_color
48 .as_ref()
49 .map(|c| format!("{}{}\x1b[0m", c, spinner))
50 .unwrap_or_else(|| spinner.to_string());
51 let message_styled = self
52 .message_color
53 .as_ref()
54 .map(|c| format!("{}{}\x1b[0m", c, self.message))
55 .unwrap_or_else(|| self.message.clone());
56 let line = format!("{} {}", spinner_styled, message_styled);
57 Ok(Rendered {
58 lines: vec![line],
59 cursor: None,
60 images: Vec::new(),
61 })
62 }
63}