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 let unique_id = SharedString::from(format!("{}-button", self.label));
42
43 h_flex().flex_wrap().child(Label::new(self.label)).child(
44 Button::new(unique_id, button_label)
45 .style(ButtonStyle::Subtle)
46 .icon(IconName::ArrowUpRight)
47 .icon_size(IconSize::XSmall)
48 .icon_color(Color::Muted)
49 .on_click(move |_, _window, cx| cx.open_url(&link)),
50 )
51 } else {
52 div().child(Label::new(self.label))
53 };
54
55 div()
56 .child(
57 ListItem::new("list-item")
58 .selectable(false)
59 .start_slot(
60 Icon::new(IconName::Dash)
61 .size(IconSize::XSmall)
62 .color(Color::Hidden),
63 )
64 .child(item_content),
65 )
66 .into_any()
67 }
68}