guise-ui 1.5.2

A component library for gpui, Zed's GPU-accelerated UI framework: a themed palette, sizing tokens, 130+ composable components, a reactive state layer, and an in-app Safari-style inspector.
Documentation
//! `Progress` — a horizontal completion bar.

use gpui::prelude::*;
use gpui::{div, px, relative, App, IntoElement, Window};

use crate::devtools::Probed;
use crate::style::ColorValue;
use crate::theme::{theme, ColorName, Size};

/// A determinate progress bar. `value` is a percentage
/// in `0.0..=100.0`.
#[derive(IntoElement)]
pub struct Progress {
  value: f32,
  color: ColorValue,
  size: Size,
  radius: Option<Size>,
}

impl Progress {
  pub fn new(value: f32) -> Self {
    Progress {
      value: value.clamp(0.0, 100.0),
      color: ColorValue::Named(ColorName::Blue),
      size: Size::Md,
      radius: None,
    }
  }

  pub fn color(mut self, color: impl Into<ColorValue>) -> Self {
    self.color = color.into();
    self
  }

  pub fn size(mut self, size: Size) -> Self {
    self.size = size;
    self
  }

  pub fn radius(mut self, radius: Size) -> Self {
    self.radius = Some(radius);
    self
  }

  fn height(&self) -> f32 {
    match self.size {
      Size::Xs => 4.0,
      Size::Sm => 6.0,
      Size::Md => 8.0,
      Size::Lg => 12.0,
      Size::Xl => 16.0,
    }
  }
}

impl RenderOnce for Progress {
  fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
    let t = theme(cx);
    let height = self.height();
    let radius = self.radius.map(|r| t.radius(r)).unwrap_or(height / 2.0);
    let track = t
      .color(ColorName::Gray, if t.scheme.is_dark() { 7 } else { 2 })
      .hsla();
    let fill = crate::style::solid(t, self.color);
    let fraction = (self.value / 100.0).clamp(0.0, 1.0);

    div()
      .w_full()
      .h(px(height))
      .rounded(px(radius))
      .bg(track)
      .child(
        div()
          .h_full()
          .w(relative(fraction))
          .rounded(px(radius))
          .bg(fill),
      )
      .probe("Progress")
      .attr_with("value", || format!("{:.0}%", self.value * 100.0))
      .attr("size", self.size.label())
  }
}