ui: Update `ThreadItem` component design (#43421)

Danilo Leal created

Release Notes:

- N/A

Change summary

crates/ui/src/components/label/spinner_label.rs |  4 +-
crates/ui/src/components/thread_item.rs         | 38 ++++++++++++++-----
2 files changed, 30 insertions(+), 12 deletions(-)

Detailed changes

crates/ui/src/components/label/spinner_label.rs 🔗

@@ -77,7 +77,7 @@ impl SpinnerLabel {
         let duration = variant.duration();
 
         SpinnerLabel {
-            base: Label::new(frames[0]),
+            base: Label::new(frames[0]).color(Color::Muted),
             variant,
             frames,
             duration,
@@ -164,7 +164,7 @@ impl RenderOnce for SpinnerLabel {
         let frames = self.frames.clone();
         let duration = self.duration;
 
-        self.base.color(Color::Muted).with_animation(
+        self.base.with_animation(
             self.variant.animation_id(),
             Animation::new(duration).repeat(),
             move |mut label, delta| {

crates/ui/src/components/thread_item.rs 🔗

@@ -1,4 +1,6 @@
-use crate::{Chip, DiffStat, Indicator, SpinnerLabel, prelude::*};
+use crate::{
+    Chip, DecoratedIcon, DiffStat, IconDecoration, IconDecorationKind, SpinnerLabel, prelude::*,
+};
 use gpui::{ClickEvent, SharedString};
 
 #[derive(IntoElement, RegisterComponent)]
@@ -85,16 +87,29 @@ impl ThreadItem {
 impl RenderOnce for ThreadItem {
     fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
         let icon_container = || h_flex().size_4().justify_center();
+        let agent_icon = Icon::new(self.icon)
+            .color(Color::Muted)
+            .size(IconSize::Small);
+
         let icon = if self.generation_done {
-            icon_container().child(Indicator::dot().color(Color::Accent))
-        } else if self.running {
-            icon_container().child(SpinnerLabel::new().color(Color::Accent))
-        } else {
-            icon_container().child(
-                Icon::new(self.icon)
-                    .color(Color::Muted)
-                    .size(IconSize::Small),
+            DecoratedIcon::new(
+                agent_icon,
+                Some(
+                    IconDecoration::new(
+                        IconDecorationKind::Dot,
+                        cx.theme().colors().surface_background,
+                        cx,
+                    )
+                    .color(cx.theme().colors().text_accent)
+                    .position(gpui::Point {
+                        x: px(-2.),
+                        y: px(-2.),
+                    }),
+                ),
             )
+            .into_any_element()
+        } else {
+            agent_icon.into_any_element()
         };
 
         let has_no_changes = self.added.is_none() && self.removed.is_none();
@@ -112,7 +127,10 @@ impl RenderOnce for ThreadItem {
                     .w_full()
                     .gap_1p5()
                     .child(icon)
-                    .child(Label::new(self.title).truncate()),
+                    .child(Label::new(self.title).truncate())
+                    .when(self.running, |this| {
+                        this.child(icon_container().child(SpinnerLabel::new().color(Color::Accent)))
+                    }),
             )
             .child(
                 h_flex()