1use gpui::prelude::*;
9use gpui::{div, px, App, IntoElement, SharedString, Window};
10
11use crate::devtools::Probed;
12use crate::feedback::{Loader, LoaderVariant};
13use crate::theme::{theme, ColorName, Size};
14
15#[derive(IntoElement)]
17pub struct AIThinking {
18 label: Option<SharedString>,
19 size: Size,
20 color: Option<ColorName>,
21}
22
23impl AIThinking {
24 pub fn new() -> Self {
25 AIThinking {
26 label: None,
27 size: Size::Sm,
28 color: None,
29 }
30 }
31
32 pub fn label(mut self, label: impl Into<SharedString>) -> Self {
35 self.label = Some(label.into());
36 self
37 }
38
39 pub fn size(mut self, size: Size) -> Self {
40 self.size = size;
41 self
42 }
43
44 pub fn color(mut self, color: ColorName) -> Self {
45 self.color = Some(color);
46 self
47 }
48}
49
50impl Default for AIThinking {
51 fn default() -> Self {
52 AIThinking::new()
53 }
54}
55
56impl RenderOnce for AIThinking {
57 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
58 let t = theme(cx);
59 let font = t.font_size(self.size);
60 let dot_color = self
61 .color
62 .map_or_else(|| t.dimmed(), |name| t.color(name, 6))
63 .hsla();
64 let dimmed = t.dimmed().hsla();
65 div()
66 .flex()
67 .items_center()
68 .gap(px(8.0))
69 .text_size(px(font))
70 .text_color(dimmed)
71 .child(
72 Loader::new()
73 .variant(LoaderVariant::Dots)
74 .size(self.size)
75 .color(dot_color),
76 )
77 .children(self.label)
78 .probe("AIThinking")
79 }
80}