1use 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#[derive(IntoElement)]
12pub struct Avatar {
13 initials: SharedString,
14 color: ColorName,
15 variant: Variant,
16 size: Size,
17 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
53pub(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, };
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}