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<'app> {
6 app: &'app App,
7 label: SharedString,
8 button_label: Option<SharedString>,
9 button_link: Option<String>,
10}
11
12impl<'app> InstructionListItem<'app> {
13 pub fn new(
14 app: &'app App,
15 label: impl Into<SharedString>,
16 button_label: Option<impl Into<SharedString>>,
17 button_link: Option<impl Into<String>>,
18 ) -> Self {
19 Self {
20 app,
21 label: label.into(),
22 button_label: button_label.map(|l| l.into()),
23 button_link: button_link.map(|l| l.into()),
24 }
25 }
26
27 pub fn text_only(app: &'app App, label: impl Into<SharedString>) -> Self {
28 Self {
29 app,
30 label: label.into(),
31 button_label: None,
32 button_link: None,
33 }
34 }
35}
36
37impl IntoElement for InstructionListItem<'_> {
38 type Element = AnyElement;
39
40 fn into_element(self) -> Self::Element {
41 let item_content = if let (Some(button_label), Some(button_link)) =
42 (self.button_label, self.button_link)
43 {
44 let link = button_link.clone();
45 let unique_id = SharedString::from(format!("{}-button", self.label));
46
47 h_flex()
48 .flex_wrap()
49 .child(Label::new(self.label))
50 .child(
51 Button::new(unique_id, button_label, self.app)
52 .style(ButtonStyle::Subtle)
53 .icon(IconName::ArrowUpRight)
54 .icon_size(IconSize::Small)
55 .icon_color(Color::Muted)
56 .on_click(move |_, _window, cx| cx.open_url(&link)),
57 )
58 .into_any_element()
59 } else {
60 Label::new(self.label).into_any_element()
61 };
62
63 ListItem::new("list-item")
64 .selectable(false)
65 .start_slot(
66 Icon::new(IconName::Dash)
67 .size(IconSize::XSmall)
68 .color(Color::Hidden),
69 )
70 .child(div().w_full().child(item_content))
71 .into_any_element()
72 }
73}