mention_crease.rs

  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}