1use gpui::{AnyElement, IntoElement, ParentElement, SharedString};
2use ui::{ListItem, prelude::*};
3
4/// A reusable list item component for adding LLM provider configuration instructions
5pub struct InstructionListItem {
6 label: SharedString,
7 button_label: Option<SharedString>,
8 button_link: Option<String>,
9}
10
11impl InstructionListItem {
12 pub fn new(
13 label: impl Into<SharedString>,
14 button_label: Option<impl Into<SharedString>>,
15 button_link: Option<impl Into<String>>,
16 ) -> Self {
17 Self {
18 label: label.into(),
19 button_label: button_label.map(|l| l.into()),
20 button_link: button_link.map(|l| l.into()),
21 }
22 }
23
24 pub fn text_only(label: impl Into<SharedString>) -> Self {
25 Self {
26 label: label.into(),
27 button_label: None,
28 button_link: None,
29 }
30 }
31}
32
33impl IntoElement for InstructionListItem {
34 type Element = AnyElement;
35
36 fn into_element(self) -> Self::Element {
37 let item_content = if let (Some(button_label), Some(button_link)) =
38 (self.button_label, self.button_link)
39 {
40 let link = button_link.clone();
41 h_flex().flex_wrap().child(Label::new(self.label)).child(
42 Button::new("link-button", button_label)
43 .style(ButtonStyle::Subtle)
44 .icon(IconName::ArrowUpRight)
45 .icon_size(IconSize::XSmall)
46 .icon_color(Color::Muted)
47 .on_click(move |_, _window, cx| cx.open_url(&link)),
48 )
49 } else {
50 div().child(Label::new(self.label))
51 };
52
53 div()
54 .child(
55 ListItem::new("list-item")
56 .selectable(false)
57 .start_slot(
58 Icon::new(IconName::Dash)
59 .size(IconSize::XSmall)
60 .color(Color::Hidden),
61 )
62 .child(item_content),
63 )
64 .into_any()
65 }
66}