1use crate::prelude::*;
2use gpui::{img, Div, Hsla, ImageSource, Img, IntoElement, Styled};
3
4#[derive(Debug, Default, PartialEq, Clone)]
5pub enum Shape {
6 #[default]
7 Circle,
8 RoundedRectangle,
9}
10
11#[derive(IntoElement)]
12pub struct Avatar {
13 image: Img,
14 border_color: Option<Hsla>,
15 is_available: Option<bool>,
16}
17
18impl RenderOnce for Avatar {
19 type Output = Div;
20
21 fn render(mut self, cx: &mut WindowContext) -> Self::Output {
22 if self.image.style().corner_radii.top_left.is_none() {
23 self = self.shape(Shape::Circle);
24 }
25
26 let size = cx.rem_size();
27
28 div()
29 .size(size + px(2.))
30 .map(|mut div| {
31 div.style().corner_radii = self.image.style().corner_radii.clone();
32 div
33 })
34 .when_some(self.border_color, |this, color| {
35 this.border().border_color(color)
36 })
37 .child(
38 self.image
39 .size(size)
40 .bg(cx.theme().colors().ghost_element_background),
41 )
42 .children(self.is_available.map(|is_free| {
43 // HACK: non-integer sizes result in oval indicators.
44 let indicator_size = (size * 0.4).round();
45
46 div()
47 .absolute()
48 .z_index(1)
49 .bg(if is_free {
50 cx.theme().status().created
51 } else {
52 cx.theme().status().deleted
53 })
54 .size(indicator_size)
55 .rounded(indicator_size)
56 .bottom_0()
57 .right_0()
58 }))
59 }
60}
61
62impl Avatar {
63 pub fn new(src: impl Into<ImageSource>) -> Self {
64 Avatar {
65 image: img(src),
66 is_available: None,
67 border_color: None,
68 }
69 }
70
71 pub fn shape(mut self, shape: Shape) -> Self {
72 self.image = match shape {
73 Shape::Circle => self.image.rounded_full(),
74 Shape::RoundedRectangle => self.image.rounded_md(),
75 };
76 self
77 }
78
79 pub fn grayscale(mut self, grayscale: bool) -> Self {
80 self.image = self.image.grayscale(grayscale);
81 self
82 }
83
84 pub fn border_color(mut self, color: impl Into<Hsla>) -> Self {
85 self.border_color = Some(color.into());
86 self
87 }
88
89 pub fn availability_indicator(mut self, is_available: impl Into<Option<bool>>) -> Self {
90 self.is_available = is_available.into();
91 self
92 }
93}