instruction_list_item.rs

 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}