Files
zed/crates/gpui/examples/system_notifications.rs
Lukas Wirth ab1c37a4ef gpui_web: Let applications provide fonts (#63493)
`gpui_web` currently embeds IBM Plex Sans and Lilex into every browser
application during platform construction. Applications such as Delta
already provide their own fonts, so those binaries contain overlapping
font bundles and register the same faces twice.

This change starts the web platform with an empty font database,
matching the ownership boundary used by native applications: the
application selects and registers its fonts before opening a window.
Delta already follows that sequence. GPUI's browser-capable examples now
load the former eight-face bundle explicitly through shared example
support, while the standalone `hello_web` example demonstrates
registering a minimal application font directly.

Testing performed:

- `cargo check -p gpui --examples --target wasm32-unknown-unknown`
- `cargo check -p gpui --examples`
- `cargo check -p gpui_web --target wasm32-unknown-unknown`
- `cargo check --manifest-path
crates/gpui_web/examples/hello_web/Cargo.toml --target
wasm32-unknown-unknown`
- `./script/clippy -p gpui_web --target wasm32-unknown-unknown`
- `cargo fmt -p gpui -p gpui_web --check`

Release Notes:

- N/A
2026-08-31 13:07:22 +00:00

156 lines
5.6 KiB
Rust

#![cfg_attr(target_family = "wasm", no_main)]
//! Demonstrates posting, replacing, dismissing, and responding to system notifications.
#[path = "example_support/fonts.rs"]
mod example_support;
use gpui::{
App, Bounds, Context, Div, SharedString, Stateful, SystemNotification,
SystemNotificationAction, SystemNotificationResponse, Window, WindowBounds, WindowOptions, div,
prelude::*, px, rgb, size,
};
use gpui_platform::application;
const NOTIFICATION_TAG: &str = "gpui-system-notification-example";
struct SystemNotificationExample {
revision: usize,
status: SharedString,
}
impl Render for SystemNotificationExample {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div()
.flex()
.flex_col()
.size_full()
.gap_4()
.p_8()
.bg(rgb(0x18181b))
.text_color(rgb(0xf4f4f5))
.child(div().text_2xl().child("GPUI system notifications"))
.child(div().text_sm().text_color(rgb(0xa1a1aa)).child(
"Post repeatedly to replace the notification with the same tag. Click the \
notification body or an action button to send a response back to GPUI.",
))
.child(
div()
.flex()
.gap_3()
.child(button("show", "Show or replace").on_click(cx.listener(
|this, _, _, cx| {
this.revision += 1;
let revision = this.revision;
cx.show_system_notification(SystemNotification {
tag: NOTIFICATION_TAG.into(),
title: format!("Example notification {revision}").into(),
body: "This notification was posted by the GPUI example.".into(),
actions: vec![
SystemNotificationAction {
id: "open".into(),
label: "Open".into(),
},
SystemNotificationAction {
id: "snooze".into(),
label: "Snooze".into(),
},
],
});
this.status = format!("Posted notification revision {revision}").into();
cx.notify();
},
)))
.child(
button("dismiss", "Dismiss").on_click(cx.listener(|this, _, _, cx| {
cx.dismiss_system_notification(NOTIFICATION_TAG);
this.status = "Dismissed the notification".into();
cx.notify();
})),
),
)
.child(
div()
.mt_2()
.p_4()
.rounded_md()
.bg(rgb(0x27272a))
.child(self.status.clone()),
)
.when(cfg!(target_os = "macos"), |this| {
this.child(div().mt_2().text_xs().text_color(rgb(0x71717a)).child(
"macOS only delivers notifications when this example runs from an app bundle.",
))
})
}
}
fn button(id: &'static str, label: &'static str) -> Stateful<Div> {
div()
.id(id)
.px_4()
.py_2()
.rounded_md()
.bg(rgb(0x3f3f46))
.hover(|style| style.bg(rgb(0x52525b)))
.active(|style| style.bg(rgb(0x71717a)))
.cursor_pointer()
.child(label)
}
fn run_example() {
application().run(|cx: &mut App| {
if !example_support::load_fonts(cx) {
return;
}
cx.set_app_identity("dev.zed.gpui.system-notifications", "GPUI Notifications");
let view = cx.new(|_| SystemNotificationExample {
revision: 0,
status: "No notification posted yet".into(),
});
cx.on_system_notification_response({
let view = view.clone();
move |response, cx| {
let SystemNotificationResponse { tag, action_id } = response;
view.update(cx, |this, cx| {
this.status = match action_id {
Some(action_id) => {
format!("Received action '{action_id}' for tag '{tag}'").into()
}
None => format!("Notification body clicked for tag '{tag}'").into(),
};
cx.notify();
});
}
});
let bounds = Bounds::centered(None, size(px(560.), px(360.)), cx);
cx.open_window(
WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
titlebar: Some(gpui::TitlebarOptions {
title: Some("System Notifications Example".into()),
..Default::default()
}),
..Default::default()
},
move |_, _| view,
)
.expect("failed to open system notifications example window");
cx.activate(true);
});
}
#[cfg(not(target_family = "wasm"))]
fn main() {
run_example();
}
#[cfg(target_family = "wasm")]
#[wasm_bindgen::prelude::wasm_bindgen(start)]
pub fn start() {
gpui_platform::web_init();
run_example();
}