title bar: Adjust the onboarding banner component API (#27455)

This PR encapsulates the layout building of the Onboarding Banner
component inside of it, allowing to, at the call site, just pass an
icon, title, and subtitle. The `subtitle` parameter, by default, uses
the `Introducing:` label, which I think will be the one we'll use most
of the time for this specific component.

Release Notes:

- N/A
This commit is contained in:
Danilo Leal 2025-03-25 17:57:42 -03:00 committed by GitHub
parent 5953c6167b
commit 152432f1d9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 51 additions and 37 deletions

View file

@ -1,9 +1,9 @@
use gpui::{Action, Entity, Global, Render};
use gpui::{Action, Entity, Global, Render, SharedString};
use ui::{prelude::*, ButtonLike, Tooltip};
use util::ResultExt;
/// Prompts the user to try Zed's features
pub struct Banner {
/// Prompts the user to try newly released Zed's features
pub struct OnboardingBanner {
dismissed: bool,
source: String,
details: BannerDetails,
@ -11,23 +11,37 @@ pub struct Banner {
#[derive(Clone)]
struct BannerGlobal {
entity: Entity<Banner>,
entity: Entity<OnboardingBanner>,
}
impl Global for BannerGlobal {}
pub struct BannerDetails {
pub action: Box<dyn Action>,
pub banner_label: Box<dyn Fn(&Window, &mut Context<Banner>) -> AnyElement>,
pub icon_name: IconName,
pub label: SharedString,
pub subtitle: Option<SharedString>,
}
impl Banner {
pub fn new(source: &str, details: BannerDetails, cx: &mut Context<Self>) -> Self {
impl OnboardingBanner {
pub fn new(
source: &str,
icon_name: IconName,
label: impl Into<SharedString>,
subtitle: Option<SharedString>,
action: Box<dyn Action>,
cx: &mut Context<Self>,
) -> Self {
cx.set_global(BannerGlobal {
entity: cx.entity(),
});
Self {
source: source.to_string(),
details,
details: BannerDetails {
action,
icon_name,
label: label.into(),
subtitle: subtitle.or(Some(SharedString::from("Introducing:"))),
},
dismissed: get_dismissed(source),
}
}
@ -90,8 +104,8 @@ pub fn restore_banner(cx: &mut App) {
.detach_and_log_err(cx);
}
impl Render for Banner {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
impl Render for OnboardingBanner {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
if !self.should_show(cx) {
return div();
}
@ -103,7 +117,24 @@ impl Render for Banner {
.border_color(border_color)
.child(
ButtonLike::new("try-a-feature")
.child((self.details.banner_label)(window, cx))
.child(
h_flex()
.h_full()
.gap_1()
.child(Icon::new(self.details.icon_name).size(IconSize::Small))
.child(
h_flex()
.gap_0p5()
.when_some(self.details.subtitle.as_ref(), |this, subtitle| {
this.child(
Label::new(subtitle)
.size(LabelSize::Small)
.color(Color::Muted),
)
})
.child(Label::new(&self.details.label).size(LabelSize::Small)),
),
)
.on_click(cx.listener(|this, _, window, cx| {
telemetry::event!("Banner Clicked", source = this.source);
this.dismiss(cx);

View file

@ -1,6 +1,6 @@
mod application_menu;
mod banner;
mod collab;
mod onboarding_banner;
mod platforms;
mod window_controls;
@ -16,7 +16,6 @@ use crate::application_menu::{
use crate::platforms::{platform_linux, platform_mac, platform_windows};
use auto_update::AutoUpdateStatus;
use banner::{Banner, BannerDetails};
use call::ActiveCall;
use client::{Client, UserStore};
use feature_flags::{FeatureFlagAppExt, ZedPro};
@ -25,6 +24,7 @@ use gpui::{
InteractiveElement, Interactivity, IntoElement, MouseButton, ParentElement, Render, Stateful,
StatefulInteractiveElement, Styled, Subscription, WeakEntity, Window,
};
use onboarding_banner::OnboardingBanner;
use project::Project;
use rpc::proto;
use settings::Settings as _;
@ -39,7 +39,7 @@ use util::ResultExt;
use workspace::{notifications::NotifyResultExt, Workspace};
use zed_actions::{OpenBrowser, OpenRecent, OpenRemote};
pub use banner::restore_banner;
pub use onboarding_banner::restore_banner;
#[cfg(feature = "stories")]
pub use stories::*;
@ -128,7 +128,7 @@ pub struct TitleBar {
should_move: bool,
application_menu: Option<Entity<ApplicationMenu>>,
_subscriptions: Vec<Subscription>,
banner: Entity<Banner>,
banner: Entity<OnboardingBanner>,
}
impl Render for TitleBar {
@ -316,29 +316,12 @@ impl TitleBar {
subscriptions.push(cx.observe(&user_store, |_, _, cx| cx.notify()));
let banner = cx.new(|cx| {
Banner::new(
OnboardingBanner::new(
"Git Onboarding",
BannerDetails {
action: zed_actions::OpenGitIntegrationOnboarding.boxed_clone(),
banner_label: Box::new(|_, _| {
h_flex()
.h_full()
.items_center()
.gap_1()
.child(Icon::new(IconName::GitBranchSmall).size(IconSize::Small))
.child(
h_flex()
.gap_0p5()
.child(
Label::new("Introducing:")
.size(LabelSize::Small)
.color(Color::Muted),
)
.child(Label::new("Git Support").size(LabelSize::Small)),
)
.into_any_element()
}),
},
IconName::GitBranchSmall,
"Git Support",
None,
zed_actions::OpenGitIntegrationOnboarding.boxed_clone(),
cx,
)
});