Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T04:48:39.257Z 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

status_toast.rs

253 lines · 8.3 KB · rust
1use std::rc::Rc;
2
3use gpui::{DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, IntoElement};
4use ui::{Tooltip, prelude::*};
5use workspace::{ToastAction, ToastView};
6use zed_actions::toast;
7
8#[derive(RegisterComponent)]
9pub struct StatusToast {
10    icon: Option<Icon>,
11    text: SharedString,
12    action: Option<ToastAction>,
13    show_dismiss: bool,
14    auto_dismiss: bool,
15    this_handle: Entity<Self>,
16    focus_handle: FocusHandle,
17}
18
19impl StatusToast {
20    pub fn new(
21        text: impl Into<SharedString>,
22        cx: &mut App,
23        f: impl FnOnce(Self, &mut Context<Self>) -> Self,
24    ) -> Entity<Self> {
25        cx.new(|cx| {
26            let focus_handle = cx.focus_handle();
27
28            f(
29                Self {
30                    text: text.into(),
31                    icon: None,
32                    action: None,
33                    show_dismiss: false,
34                    auto_dismiss: true,
35                    this_handle: cx.entity(),
36                    focus_handle,
37                },
38                cx,
39            )
40        })
41    }
42
43    pub fn icon(mut self, icon: Icon) -> Self {
44        self.icon = Some(icon);
45        self
46    }
47
48    pub fn auto_dismiss(mut self, auto_dismiss: bool) -> Self {
49        self.auto_dismiss = auto_dismiss;
50        self
51    }
52
53    pub fn action(
54        mut self,
55        label: impl Into<SharedString>,
56        f: impl Fn(&mut Window, &mut App) + 'static,
57    ) -> Self {
58        let this_handle = self.this_handle.clone();
59        self.action = Some(ToastAction::new(
60            label.into(),
61            Some(Rc::new(move |window, cx| {
62                this_handle.update(cx, |_, cx| {
63                    cx.emit(DismissEvent);
64                });
65                f(window, cx);
66            })),
67        ));
68        self
69    }
70
71    pub fn dismiss_button(mut self, show: bool) -> Self {
72        self.show_dismiss = show;
73        self
74    }
75}
76
77impl Render for StatusToast {
78    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
79        let has_action_or_dismiss = self.action.is_some() || self.show_dismiss;
80
81        h_flex()
82            .id("status-toast")
83            .elevation_3(cx)
84            .gap_2()
85            .py_1p5()
86            .pl_2p5()
87            .map(|this| {
88                if has_action_or_dismiss {
89                    this.pr_1p5()
90                } else {
91                    this.pr_2p5()
92                }
93            })
94            .flex_none()
95            .bg(cx.theme().colors().surface_background)
96            .shadow_lg()
97            .when_some(self.icon.clone(), |this, icon| this.child(icon))
98            .child(Label::new(self.text.clone()).color(Color::Default))
99            .when_some(self.action.as_ref(), |this, action| {
100                this.child(
101                    Button::new(action.id.clone(), action.label.clone())
102                        .tooltip(Tooltip::for_action_title(
103                            action.label.clone(),
104                            &toast::RunAction,
105                        ))
106                        .color(Color::Muted)
107                        .when_some(action.on_click.clone(), |el, handler| {
108                            el.on_click(move |_click_event, window, cx| handler(window, cx))
109                        }),
110                )
111            })
112            .when(self.show_dismiss, |this| {
113                let handle = self.this_handle.clone();
114                this.child(
115                    IconButton::new("dismiss", IconName::Close)
116                        .shape(ui::IconButtonShape::Square)
117                        .icon_size(IconSize::Small)
118                        .icon_color(Color::Muted)
119                        .tooltip(Tooltip::text("Dismiss"))
120                        .on_click(move |_click_event, _window, cx| {
121                            handle.update(cx, |_, cx| {
122                                cx.emit(DismissEvent);
123                            });
124                        }),
125                )
126            })
127    }
128}
129
130impl ToastView for StatusToast {
131    fn action(&self) -> Option<ToastAction> {
132        self.action.clone()
133    }
134
135    fn auto_dismiss(&self) -> bool {
136        self.auto_dismiss
137    }
138}
139
140impl Focusable for StatusToast {
141    fn focus_handle(&self, _cx: &App) -> gpui::FocusHandle {
142        self.focus_handle.clone()
143    }
144}
145
146impl EventEmitter<DismissEvent> for StatusToast {}
147
148impl Component for StatusToast {
149    fn scope() -> ComponentScope {
150        ComponentScope::Notification
151    }
152
153    fn description() -> &'static str {
154        "A compact, transient toast used to surface status updates \
155        such as completed operations or pending updates, with optional icon, \
156        action, and dismiss affordances."
157    }
158
159    fn preview(_window: &mut Window, cx: &mut App) -> AnyElement {
160        let text_example = StatusToast::new("Operation completed", cx, |this, _| this);
161
162        let action_example = StatusToast::new("Update ready to install", cx, |this, _cx| {
163            this.action("Restart", |_, _| {})
164        });
165
166        let dismiss_button_example =
167            StatusToast::new("Dismiss Button", cx, |this, _| this.dismiss_button(true));
168
169        let icon_example = StatusToast::new(
170            "Nathan Sobo accepted your contact request",
171            cx,
172            |this, _| {
173                this.icon(
174                    Icon::new(IconName::Check)
175                        .size(IconSize::Small)
176                        .color(Color::Muted),
177                )
178            },
179        );
180
181        let success_example = StatusToast::new("Pushed 4 changes to `omega/main`", cx, |this, _| {
182            this.icon(
183                Icon::new(IconName::Check)
184                    .size(IconSize::Small)
185                    .color(Color::Success),
186            )
187        });
188
189        let error_example = StatusToast::new(
190            "git push: Couldn't find remote origin `iamnbutler/omega`",
191            cx,
192            |this, _cx| {
193                this.icon(
194                    Icon::new(IconName::XCircle)
195                        .size(IconSize::Small)
196                        .color(Color::Error),
197                )
198                .action("More Info", |_, _| {})
199            },
200        );
201
202        let warning_example = StatusToast::new("You have outdated settings", cx, |this, _cx| {
203            this.icon(
204                Icon::new(IconName::Warning)
205                    .size(IconSize::Small)
206                    .color(Color::Warning),
207            )
208            .action("More Info", |_, _| {})
209        });
210
211        let pr_example =
212            StatusToast::new("`omega/new-notification-system` created!", cx, |this, _cx| {
213                this.icon(
214                    Icon::new(IconName::GitBranch)
215                        .size(IconSize::Small)
216                        .color(Color::Muted),
217                )
218                .action("Open Pull Request", |_, cx| {
219                    cx.open_url("https://github.com/")
220                })
221            });
222
223        v_flex()
224            .gap_6()
225            .p_4()
226            .children(vec![
227                example_group_with_title(
228                    "Basic Toast",
229                    vec![
230                        single_example("Text", div().child(text_example).into_any_element()),
231                        single_example("Action", div().child(action_example).into_any_element()),
232                        single_example("Icon", div().child(icon_example).into_any_element()),
233                        single_example(
234                            "Dismiss Button",
235                            div().child(dismiss_button_example).into_any_element(),
236                        ),
237                    ],
238                ),
239                example_group_with_title(
240                    "Examples",
241                    vec![
242                        single_example("Success", div().child(success_example).into_any_element()),
243                        single_example("Error", div().child(error_example).into_any_element()),
244                        single_example("Warning", div().child(warning_example).into_any_element()),
245                        single_example("Create PR", div().child(pr_example).into_any_element()),
246                    ],
247                )
248                .vertical(),
249            ])
250            .into_any_element()
251    }
252}
253
Served at tenant.openagents/omega Member data and write actions are omitted.