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}