Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T05:42:29.888Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

announcement_toast.rs

197 lines · 7.1 KB · rust
1use crate::{ListBulletItem, prelude::*};
2use component::{Component, ComponentScope, example_group, single_example};
3use gpui::{AnyElement, ClickEvent, IntoElement, ParentElement, SharedString};
4use smallvec::SmallVec;
5
6#[derive(IntoElement, RegisterComponent)]
7pub struct AnnouncementToast {
8    illustration: Option<AnyElement>,
9    heading: Option<SharedString>,
10    description: Option<SharedString>,
11    bullet_items: SmallVec<[AnyElement; 6]>,
12    primary_action_label: SharedString,
13    primary_on_click: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
14    secondary_action_label: SharedString,
15    secondary_on_click: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
16    dismiss_on_click: Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>,
17}
18
19impl AnnouncementToast {
20    pub fn new() -> Self {
21        Self {
22            illustration: None,
23            heading: None,
24            description: None,
25            bullet_items: SmallVec::new(),
26            primary_action_label: "Try Now".into(),
27            primary_on_click: Box::new(|_, _, _| {}),
28            secondary_action_label: "Learn More".into(),
29            secondary_on_click: Box::new(|_, _, _| {}),
30            dismiss_on_click: Box::new(|_, _, _| {}),
31        }
32    }
33
34    pub fn illustration(mut self, illustration: impl IntoElement) -> Self {
35        self.illustration = Some(illustration.into_any_element());
36        self
37    }
38
39    pub fn heading(mut self, heading: impl Into<SharedString>) -> Self {
40        self.heading = Some(heading.into());
41        self
42    }
43
44    pub fn description(mut self, description: impl Into<SharedString>) -> Self {
45        self.description = Some(description.into());
46        self
47    }
48
49    pub fn bullet_item(mut self, item: impl IntoElement) -> Self {
50        self.bullet_items.push(item.into_any_element());
51        self
52    }
53
54    pub fn bullet_items(mut self, items: impl IntoIterator<Item = impl IntoElement>) -> Self {
55        self.bullet_items
56            .extend(items.into_iter().map(IntoElement::into_any_element));
57        self
58    }
59
60    pub fn primary_action_label(mut self, primary_action_label: impl Into<SharedString>) -> Self {
61        self.primary_action_label = primary_action_label.into();
62        self
63    }
64
65    pub fn primary_on_click(
66        mut self,
67        handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
68    ) -> Self {
69        self.primary_on_click = Box::new(handler);
70        self
71    }
72
73    pub fn secondary_action_label(
74        mut self,
75        secondary_action_label: impl Into<SharedString>,
76    ) -> Self {
77        self.secondary_action_label = secondary_action_label.into();
78        self
79    }
80
81    pub fn secondary_on_click(
82        mut self,
83        handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
84    ) -> Self {
85        self.secondary_on_click = Box::new(handler);
86        self
87    }
88
89    pub fn dismiss_on_click(
90        mut self,
91        handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
92    ) -> Self {
93        self.dismiss_on_click = Box::new(handler);
94        self
95    }
96}
97
98impl RenderOnce for AnnouncementToast {
99    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
100        let has_illustration = self.illustration.is_some();
101        let illustration = self.illustration;
102
103        v_flex()
104            .id("announcement-toast")
105            .occlude()
106            .relative()
107            .w_full()
108            .elevation_3(cx)
109            .when_some(illustration, |this, i| this.child(i))
110            .child(
111                v_flex()
112                    .p_4()
113                    .gap_4()
114                    .when(has_illustration, |s| {
115                        s.border_t_1()
116                            .border_color(cx.theme().colors().border_variant)
117                    })
118                    .child(
119                        v_flex()
120                            .min_w_0()
121                            .when_some(self.heading, |this, heading| {
122                                this.child(Headline::new(heading).size(HeadlineSize::Small))
123                            })
124                            .when_some(self.description, |this, description| {
125                                this.child(Label::new(description).color(Color::Muted))
126                            }),
127                    )
128                    .when(!self.bullet_items.is_empty(), |this| {
129                        this.child(v_flex().min_w_0().gap_1().children(self.bullet_items))
130                    })
131                    .child(
132                        v_flex()
133                            .gap_1()
134                            .child(
135                                Button::new("try-now", self.primary_action_label)
136                                    .style(ButtonStyle::Tinted(crate::TintColor::Accent))
137                                    .full_width()
138                                    .on_click(self.primary_on_click),
139                            )
140                            .child(
141                                Button::new("release-notes", self.secondary_action_label)
142                                    .style(ButtonStyle::OutlinedGhost)
143                                    .full_width()
144                                    .on_click(self.secondary_on_click),
145                            ),
146                    ),
147            )
148            .child(
149                div().absolute().top_1().right_1().child(
150                    IconButton::new("dismiss", IconName::Close)
151                        .icon_size(IconSize::Small)
152                        .on_click(self.dismiss_on_click),
153                ),
154            )
155    }
156}
157
158impl Component for AnnouncementToast {
159    fn scope() -> ComponentScope {
160        ComponentScope::Notification
161    }
162
163    fn description() -> &'static str {
164        "A special toast for announcing new and exciting features."
165    }
166
167    fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
168        let examples = vec![single_example(
169            "Basic",
170            div()
171                .w_80()
172                .child(
173                    AnnouncementToast::new()
174                        .heading("Introducing Parallel Agents")
175                        .description("Run multiple agent threads simultaneously across projects.")
176                        .bullet_item(ListBulletItem::new(
177                            "Mix and match Omega Agent with any ACP-compatible agent",
178                        ))
179                        .bullet_item(ListBulletItem::new(
180                            "Optional worktree isolation keeps agents from conflicting",
181                        ))
182                        .bullet_item(ListBulletItem::new(
183                            "Updated workspace layout designed for agentic workflows",
184                        ))
185                        .primary_action_label("Try Now")
186                        .secondary_action_label("Learn More"),
187                )
188                .into_any_element(),
189        )];
190
191        v_flex()
192            .gap_6()
193            .child(example_group(examples).vertical())
194            .into_any_element()
195    }
196}
197
Served at tenant.openagents/omega Member data and write actions are omitted.