Skip to main content

guise/data/
avatar.rs

1//! `Avatar` — a circular initials/placeholder badge.
2
3use gpui::prelude::*;
4use gpui::{div, px, App, FontWeight, IntoElement, SharedString, Window};
5
6use crate::devtools::Probed;
7use crate::style::{surface, Variant};
8use crate::theme::{theme, ColorName, Size};
9
10/// A user avatar showing initials.
11#[derive(IntoElement)]
12pub struct Avatar {
13  initials: SharedString,
14  color: ColorName,
15  variant: Variant,
16  size: Size,
17  /// `None` renders a full circle; `Some` sets a square corner radius.
18  radius: Option<Size>,
19}
20
21impl Avatar {
22  pub fn new(initials: impl Into<SharedString>) -> Self {
23    Avatar {
24      initials: initials.into(),
25      color: ColorName::Gray,
26      variant: Variant::Light,
27      size: Size::Md,
28      radius: None,
29    }
30  }
31
32  pub fn color(mut self, color: ColorName) -> Self {
33    self.color = color;
34    self
35  }
36
37  pub fn variant(mut self, variant: Variant) -> Self {
38    self.variant = variant;
39    self
40  }
41
42  pub fn size(mut self, size: Size) -> Self {
43    self.size = size;
44    self
45  }
46
47  pub fn radius(mut self, radius: Size) -> Self {
48    self.radius = Some(radius);
49    self
50  }
51}
52
53/// Avatar diameter (px) across the size scale. Shared with `AvatarGroup`.
54pub(crate) fn avatar_size(size: Size) -> f32 {
55  match size {
56    Size::Xs => 16.0,
57    Size::Sm => 26.0,
58    Size::Md => 38.0,
59    Size::Lg => 56.0,
60    Size::Xl => 84.0,
61  }
62}
63
64impl RenderOnce for Avatar {
65  fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
66    let t = theme(cx);
67    let s = surface(t, self.color, self.variant);
68    let dim = avatar_size(self.size);
69    let radius = match self.radius {
70      Some(r) => t.radius(r),
71      None => dim, // full circle
72    };
73
74    let mut el = div()
75      .w(px(dim))
76      .h(px(dim))
77      .flex()
78      .items_center()
79      .justify_center()
80      .rounded(px(radius))
81      .bg(s.bg)
82      .text_color(s.fg)
83      .text_size(px(dim * 0.4))
84      .font_weight(FontWeight::SEMIBOLD)
85      .child(self.initials);
86    if let Some(border) = s.border {
87      el = el.border_1().border_color(border);
88    }
89    el.probe("Avatar")
90      .attr("variant", self.variant.label())
91      .attr("size", self.size.label())
92  }
93}