@@ -12,8 +12,8 @@ use editor::{
};
use futures::{AsyncReadExt as _, FutureExt as _, future::Shared};
use gpui::{
- Animation, AnimationExt as _, AppContext, ClipboardEntry, Context, Empty, Entity, EntityId,
- Image, ImageFormat, Img, SharedString, Task, WeakEntity, pulsating_between,
+ AppContext, ClipboardEntry, Context, Empty, Entity, EntityId, Image, ImageFormat, Img,
+ SharedString, Task, WeakEntity,
};
use http_client::{AsyncBody, HttpClientWithUrl};
use itertools::Either;
@@ -32,13 +32,14 @@ use std::{
path::{Path, PathBuf},
rc::Rc,
sync::Arc,
- time::Duration,
};
use text::OffsetRangeExt;
-use ui::{ButtonLike, Disclosure, TintColor, Toggleable, prelude::*};
+use ui::{Disclosure, Toggleable, prelude::*};
use util::{ResultExt, debug_panic, rel_path::RelPath};
use workspace::{Workspace, notifications::NotifyResultExt as _};
+use crate::ui::MentionCrease;
+
pub type MentionTask = Shared<Task<Result<Mention, String>>>;
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -754,25 +755,8 @@ fn render_fold_icon_button(
.update(cx, |editor, cx| editor.is_range_selected(&fold_range, cx))
.unwrap_or_default();
- ButtonLike::new(fold_id)
- .style(ButtonStyle::Filled)
- .selected_style(ButtonStyle::Tinted(TintColor::Accent))
- .toggle_state(is_in_text_selection)
- .child(
- h_flex()
- .gap_1()
- .child(
- Icon::from_path(icon_path.clone())
- .size(IconSize::XSmall)
- .color(Color::Muted),
- )
- .child(
- Label::new(label.clone())
- .size(LabelSize::Small)
- .buffer_font(cx)
- .single_line(),
- ),
- )
+ MentionCrease::new(fold_id, icon_path.clone(), label.clone())
+ .is_toggled(is_in_text_selection)
.into_any_element()
}
})
@@ -947,12 +931,14 @@ impl Render for LoadingContext {
.editor
.update(cx, |editor, cx| editor.is_range_selected(&self.range, cx))
.unwrap_or_default();
- ButtonLike::new(("loading-context", self.id))
- .style(ButtonStyle::Filled)
- .selected_style(ButtonStyle::Tinted(TintColor::Accent))
- .toggle_state(is_in_text_selection)
- .when_some(self.image.clone(), |el, image_task| {
- el.hoverable_tooltip(move |_, cx| {
+
+ let id = ElementId::from(("loading_context", self.id));
+
+ MentionCrease::new(id, self.icon.clone(), self.label.clone())
+ .is_toggled(is_in_text_selection)
+ .is_loading(self.loading.is_some())
+ .when_some(self.image.clone(), |this, image_task| {
+ this.image_preview(move |_, cx| {
let image = image_task.peek().cloned().transpose().ok().flatten();
let image_task = image_task.clone();
cx.new::<ImageHover>(|cx| ImageHover {
@@ -971,35 +957,6 @@ impl Render for LoadingContext {
.into()
})
})
- .child(
- h_flex()
- .gap_1()
- .child(
- Icon::from_path(self.icon.clone())
- .size(IconSize::XSmall)
- .color(Color::Muted),
- )
- .child(
- Label::new(self.label.clone())
- .size(LabelSize::Small)
- .buffer_font(cx)
- .single_line(),
- )
- .map(|el| {
- if self.loading.is_some() {
- el.with_animation(
- "loading-context-crease",
- Animation::new(Duration::from_secs(2))
- .repeat()
- .with_easing(pulsating_between(0.4, 0.8)),
- |label, delta| label.opacity(delta),
- )
- .into_any()
- } else {
- el.into_any()
- }
- }),
- )
}
}
@@ -0,0 +1,100 @@
+use std::time::Duration;
+
+use gpui::{Animation, AnimationExt, AnyView, IntoElement, Window, pulsating_between};
+use settings::Settings;
+use theme::ThemeSettings;
+use ui::{ButtonLike, TintColor, prelude::*};
+
+#[derive(IntoElement)]
+pub struct MentionCrease {
+ id: ElementId,
+ icon: SharedString,
+ label: SharedString,
+ is_toggled: bool,
+ is_loading: bool,
+ image_preview: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyView + 'static>>,
+}
+
+impl MentionCrease {
+ pub fn new(
+ id: impl Into<ElementId>,
+ icon: impl Into<SharedString>,
+ label: impl Into<SharedString>,
+ ) -> Self {
+ Self {
+ id: id.into(),
+ icon: icon.into(),
+ label: label.into(),
+ is_toggled: false,
+ is_loading: false,
+ image_preview: None,
+ }
+ }
+
+ pub fn is_toggled(mut self, is_toggled: bool) -> Self {
+ self.is_toggled = is_toggled;
+ self
+ }
+
+ pub fn is_loading(mut self, is_loading: bool) -> Self {
+ self.is_loading = is_loading;
+ self
+ }
+
+ pub fn image_preview(
+ mut self,
+ builder: impl Fn(&mut Window, &mut App) -> AnyView + 'static,
+ ) -> Self {
+ self.image_preview = Some(Box::new(builder));
+ self
+ }
+}
+
+impl RenderOnce for MentionCrease {
+ fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
+ let settings = ThemeSettings::get_global(cx);
+ let font_size = settings.agent_buffer_font_size(cx);
+ let buffer_font = settings.buffer_font.clone();
+
+ let button_height = DefiniteLength::Absolute(AbsoluteLength::Pixels(
+ px(window.line_height().into()) - px(1.),
+ ));
+
+ ButtonLike::new(self.id)
+ .style(ButtonStyle::Outlined)
+ .size(ButtonSize::Compact)
+ .height(button_height)
+ .selected_style(ButtonStyle::Tinted(TintColor::Accent))
+ .toggle_state(self.is_toggled)
+ .when_some(self.image_preview, |this, image_preview| {
+ this.hoverable_tooltip(image_preview)
+ })
+ .child(
+ h_flex()
+ .pb_px()
+ .gap_1()
+ .font(buffer_font)
+ .text_size(font_size)
+ .child(
+ Icon::from_path(self.icon.clone())
+ .size(IconSize::XSmall)
+ .color(Color::Muted),
+ )
+ .child(self.label.clone())
+ .map(|this| {
+ if self.is_loading {
+ this.with_animation(
+ "loading-context-crease",
+ Animation::new(Duration::from_secs(2))
+ .repeat()
+ .with_easing(pulsating_between(0.4, 0.8)),
+ |label, delta| label.opacity(delta),
+ )
+ .into_any()
+ } else {
+ this.into_any()
+ }
+ }),
+ )
+ }
+}