1use std::time::Duration;
2
3use gpui::{Animation, AnimationExt, AnyView, IntoElement, Window, pulsating_between};
4use settings::Settings;
5use theme::ThemeSettings;
6use ui::{ButtonLike, TintColor, prelude::*};
7
8#[derive(IntoElement)]
9pub struct MentionCrease {
10 id: ElementId,
11 icon: SharedString,
12 label: SharedString,
13 is_toggled: bool,
14 is_loading: bool,
15 image_preview: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView + 'static>>,
16}
17
18impl MentionCrease {
19 pub fn new(
20 id: impl Into<ElementId>,
21 icon: impl Into<SharedString>,
22 label: impl Into<SharedString>,
23 ) -> Self {
24 Self {
25 id: id.into(),
26 icon: icon.into(),
27 label: label.into(),
28 is_toggled: false,
29 is_loading: false,
30 image_preview: None,
31 }
32 }
33
34 pub fn is_toggled(mut self, is_toggled: bool) -> Self {
35 self.is_toggled = is_toggled;
36 self
37 }
38
39 pub fn is_loading(mut self, is_loading: bool) -> Self {
40 self.is_loading = is_loading;
41 self
42 }
43
44 pub fn image_preview(
45 mut self,
46 builder: impl Fn(&mut Window, &mut App) -> AnyView + 'static,
47 ) -> Self {
48 self.image_preview = Some(Box::new(builder));
49 self
50 }
51}
52
53impl RenderOnce for MentionCrease {
54 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
55 let settings = ThemeSettings::get_global(cx);
56 let font_size = settings.agent_buffer_font_size(cx);
57 let buffer_font = settings.buffer_font.clone();
58
59 let button_height = DefiniteLength::Absolute(AbsoluteLength::Pixels(
60 px(window.line_height().into()) - px(1.),
61 ));
62
63 ButtonLike::new(self.id)
64 .style(ButtonStyle::Outlined)
65 .size(ButtonSize::Compact)
66 .height(button_height)
67 .selected_style(ButtonStyle::Tinted(TintColor::Accent))
68 .toggle_state(self.is_toggled)
69 .when_some(self.image_preview, |this, image_preview| {
70 this.hoverable_tooltip(image_preview)
71 })
72 .child(
73 h_flex()
74 .pb_px()
75 .gap_1()
76 .font(buffer_font)
77 .text_size(font_size)
78 .child(
79 Icon::from_path(self.icon.clone())
80 .size(IconSize::XSmall)
81 .color(Color::Muted),
82 )
83 .child(self.label.clone())
84 .map(|this| {
85 if self.is_loading {
86 this.with_animation(
87 "loading-context-crease",
88 Animation::new(Duration::from_secs(2))
89 .repeat()
90 .with_easing(pulsating_between(0.4, 0.8)),
91 |label, delta| label.opacity(delta),
92 )
93 .into_any()
94 } else {
95 this.into_any()
96 }
97 }),
98 )
99 }
100}