1use std::marker::PhantomData;
2
3use gpui2::img;
4
5use crate::prelude::*;
6
7#[derive(Element)]
8pub struct Avatar<S: 'static + Send + Sync> {
9 state_type: PhantomData<S>,
10 src: SharedString,
11 shape: Shape,
12}
13
14impl<S: 'static + Send + Sync> Avatar<S> {
15 pub fn new(src: impl Into<SharedString>) -> Self {
16 Self {
17 state_type: PhantomData,
18 src: src.into(),
19 shape: Shape::Circle,
20 }
21 }
22
23 pub fn shape(mut self, shape: Shape) -> Self {
24 self.shape = shape;
25 self
26 }
27
28 fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
29 let theme = theme(cx);
30
31 let mut img = img();
32
33 if self.shape == Shape::Circle {
34 img = img.rounded_full();
35 } else {
36 img = img.rounded_md();
37 }
38
39 img.uri(self.src.clone())
40 .size_4()
41 .bg(theme.image_fallback_background)
42 }
43}
44
45#[cfg(feature = "stories")]
46pub use stories::*;
47
48#[cfg(feature = "stories")]
49mod stories {
50 use crate::Story;
51
52 use super::*;
53
54 #[derive(Element)]
55 pub struct AvatarStory<S: 'static + Send + Sync> {
56 state_type: PhantomData<S>,
57 }
58
59 impl<S: 'static + Send + Sync> AvatarStory<S> {
60 pub fn new() -> Self {
61 Self {
62 state_type: PhantomData,
63 }
64 }
65
66 fn render(
67 &mut self,
68 _view: &mut S,
69 cx: &mut ViewContext<S>,
70 ) -> impl Element<ViewState = S> {
71 Story::container(cx)
72 .child(Story::title_for::<_, Avatar<S>>(cx))
73 .child(Story::label(cx, "Default"))
74 .child(Avatar::new(
75 "https://avatars.githubusercontent.com/u/1714999?v=4",
76 ))
77 .child(Story::label(cx, "Rounded rectangle"))
78 .child(
79 Avatar::new("https://avatars.githubusercontent.com/u/1714999?v=4")
80 .shape(Shape::RoundedRectangle),
81 )
82 }
83 }
84}