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