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 {
 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}