Update Root API (#150)
This commit is contained in:
parent
c9763224c2
commit
981d1391e6
5 changed files with 80 additions and 43 deletions
1
assets/icons/bell.svg
Normal file
1
assets/icons/bell.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-bell"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>
|
||||
|
After Width: | Height: | Size: 310 B |
|
|
@ -10,13 +10,14 @@ use workspace::{TitleBar, Workspace};
|
|||
|
||||
use std::sync::Arc;
|
||||
use ui::{
|
||||
button::{Button, ButtonStyle},
|
||||
button::Button,
|
||||
drawer::Drawer,
|
||||
h_flex,
|
||||
modal::Modal,
|
||||
popover::Popover,
|
||||
popup_menu::PopupMenu,
|
||||
theme::{ActiveTheme, Theme},
|
||||
ContextModal as _, IconName, Root, Sizable,
|
||||
ContextModal, IconName, Root, Sizable,
|
||||
};
|
||||
|
||||
use crate::app_state::AppState;
|
||||
|
|
@ -273,10 +274,11 @@ pub fn open_new(
|
|||
|
||||
impl Render for StoryWorkspace {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
let active_modal = cx.active_modal();
|
||||
let active_drawer = cx.active_drawer();
|
||||
let active_modal = Root::read(cx).active_modal.clone();
|
||||
let active_drawer = Root::read(cx).active_drawer.clone();
|
||||
let has_active_modal = active_modal.is_some();
|
||||
let notification_view = cx.notification_view();
|
||||
let notification_view = Root::read(cx).notification.clone();
|
||||
let notifications_count = cx.notifications().len();
|
||||
|
||||
div()
|
||||
.relative()
|
||||
|
|
@ -303,7 +305,6 @@ impl Render for StoryWorkspace {
|
|||
.items_center()
|
||||
.justify_end()
|
||||
.px_2()
|
||||
.mr_3()
|
||||
.gap_2()
|
||||
.child(self.locale_selector.clone())
|
||||
.child(
|
||||
|
|
@ -330,10 +331,38 @@ impl Render for StoryWorkspace {
|
|||
Button::new("github", cx)
|
||||
.icon(IconName::GitHub)
|
||||
.small()
|
||||
.style(ButtonStyle::Ghost)
|
||||
.ghost()
|
||||
.on_click(|_, cx| {
|
||||
cx.open_url("https://github.com/huacnlee/gpui-component")
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.relative()
|
||||
.child(
|
||||
Button::new("bell", cx)
|
||||
.small()
|
||||
.ghost()
|
||||
.compact()
|
||||
.icon(IconName::Bell),
|
||||
)
|
||||
.when(notifications_count > 0, |this| {
|
||||
this.child(
|
||||
h_flex()
|
||||
.absolute()
|
||||
.rounded_full()
|
||||
.top(px(-2.))
|
||||
.right(px(-2.))
|
||||
.p(px(1.))
|
||||
.min_w(px(12.))
|
||||
.bg(ui::red_500())
|
||||
.text_color(ui::white())
|
||||
.justify_center()
|
||||
.text_size(px(10.))
|
||||
.line_height(relative(1.))
|
||||
.child(format!("{}", notifications_count.min(99))),
|
||||
)
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ pub enum IconName {
|
|||
ArrowRight,
|
||||
ArrowUp,
|
||||
Asterisk,
|
||||
Bell,
|
||||
Calendar,
|
||||
Check,
|
||||
ChevronDown,
|
||||
|
|
@ -18,6 +19,7 @@ pub enum IconName {
|
|||
ChevronRight,
|
||||
ChevronUp,
|
||||
ChevronsUpDown,
|
||||
CircleCheck,
|
||||
CircleX,
|
||||
Close,
|
||||
Copy,
|
||||
|
|
@ -50,7 +52,6 @@ pub enum IconName {
|
|||
ThumbsDown,
|
||||
ThumbsUp,
|
||||
TriangleAlert,
|
||||
CircleCheck,
|
||||
}
|
||||
|
||||
impl IconName {
|
||||
|
|
@ -61,6 +62,7 @@ impl IconName {
|
|||
IconName::ArrowRight => "icons/arrow-right.svg",
|
||||
IconName::ArrowUp => "icons/arrow-up.svg",
|
||||
IconName::Asterisk => "icons/asterisk.svg",
|
||||
IconName::Bell => "icons/bell.svg",
|
||||
IconName::Calendar => "icons/calendar.svg",
|
||||
IconName::Check => "icons/check.svg",
|
||||
IconName::ChevronDown => "icons/chevron-down.svg",
|
||||
|
|
@ -68,6 +70,7 @@ impl IconName {
|
|||
IconName::ChevronRight => "icons/chevron-right.svg",
|
||||
IconName::ChevronUp => "icons/chevron-up.svg",
|
||||
IconName::ChevronsUpDown => "icons/chevrons-up-down.svg",
|
||||
IconName::CircleCheck => "icons/circle-check.svg",
|
||||
IconName::CircleX => "icons/circle-x.svg",
|
||||
IconName::Close => "icons/close.svg",
|
||||
IconName::Copy => "icons/copy.svg",
|
||||
|
|
@ -100,7 +103,6 @@ impl IconName {
|
|||
IconName::ThumbsDown => "icons/thumbs-down.svg",
|
||||
IconName::ThumbsUp => "icons/thumbs-up.svg",
|
||||
IconName::TriangleAlert => "icons/triangle-alert.svg",
|
||||
IconName::CircleCheck => "icons/circle-check.svg",
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ impl Render for Notification {
|
|||
|
||||
/// A list of notifications.
|
||||
pub struct NotificationList {
|
||||
notifications: Vec<View<Notification>>,
|
||||
pub(crate) notifications: Vec<View<Notification>>,
|
||||
}
|
||||
|
||||
impl NotificationList {
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ pub trait ContextModal: Sized {
|
|||
where
|
||||
F: Fn(Drawer, &mut WindowContext) -> Drawer + 'static;
|
||||
|
||||
/// Return the active Drawer builder, you must add the Drawer to the view.
|
||||
fn active_drawer(&self) -> Option<Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>>;
|
||||
/// Return true, if there is an active Drawer.
|
||||
fn has_active_drawer(&self) -> bool;
|
||||
|
||||
/// Closes the active Drawer.
|
||||
fn close_drawer(&mut self);
|
||||
|
|
@ -32,8 +32,8 @@ pub trait ContextModal: Sized {
|
|||
where
|
||||
F: Fn(Modal, &mut WindowContext) -> Modal + 'static;
|
||||
|
||||
/// Return the active Modal builder, you must add the Modal to the view.
|
||||
fn active_modal(&self) -> Option<Rc<dyn Fn(Modal, &mut WindowContext) -> Modal + 'static>>;
|
||||
/// Return true, if there is an active Modal.
|
||||
fn has_active_modal(&self) -> bool;
|
||||
|
||||
/// Closes the active Modal.
|
||||
fn close_modal(&mut self);
|
||||
|
|
@ -41,8 +41,8 @@ pub trait ContextModal: Sized {
|
|||
/// Pushes a notification to the notification list.
|
||||
fn push_notification(&mut self, note: impl Into<Notification>);
|
||||
fn clear_notifications(&mut self);
|
||||
/// Returns the notification list view.
|
||||
fn notification_view(&self) -> AnyView;
|
||||
/// Returns number of notifications.
|
||||
fn notifications(&self) -> Rc<Vec<View<Notification>>>;
|
||||
}
|
||||
|
||||
impl<'a> ContextModal for WindowContext<'a> {
|
||||
|
|
@ -50,19 +50,19 @@ impl<'a> ContextModal for WindowContext<'a> {
|
|||
where
|
||||
F: Fn(Drawer, &mut WindowContext) -> Drawer + 'static,
|
||||
{
|
||||
Root::update_root(self, move |root, cx| {
|
||||
Root::update(self, move |root, cx| {
|
||||
root.previous_focus_handle = cx.focused();
|
||||
root.active_drawer = Some(Rc::new(build));
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
|
||||
fn active_drawer(&self) -> Option<Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>> {
|
||||
Root::read_root(&self).active_drawer.clone()
|
||||
fn has_active_drawer(&self) -> bool {
|
||||
Root::read(&self).active_drawer.is_some()
|
||||
}
|
||||
|
||||
fn close_drawer(&mut self) {
|
||||
Root::update_root(self, |root, cx| {
|
||||
Root::update(self, |root, cx| {
|
||||
root.active_drawer = None;
|
||||
root.focus_back(cx);
|
||||
cx.notify();
|
||||
|
|
@ -73,19 +73,19 @@ impl<'a> ContextModal for WindowContext<'a> {
|
|||
where
|
||||
F: Fn(Modal, &mut WindowContext) -> Modal + 'static,
|
||||
{
|
||||
Root::update_root(self, move |root, cx| {
|
||||
Root::update(self, move |root, cx| {
|
||||
root.previous_focus_handle = cx.focused();
|
||||
root.active_modal = Some(Rc::new(build));
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
|
||||
fn active_modal(&self) -> Option<Rc<dyn Fn(Modal, &mut WindowContext) -> Modal + 'static>> {
|
||||
Root::read_root(&self).active_modal.clone()
|
||||
fn has_active_modal(&self) -> bool {
|
||||
Root::read(&self).active_modal.is_some()
|
||||
}
|
||||
|
||||
fn close_modal(&mut self) {
|
||||
Root::update_root(self, |root, cx| {
|
||||
Root::update(self, |root, cx| {
|
||||
root.active_modal = None;
|
||||
root.focus_back(cx);
|
||||
cx.notify();
|
||||
|
|
@ -94,22 +94,27 @@ impl<'a> ContextModal for WindowContext<'a> {
|
|||
|
||||
fn push_notification(&mut self, note: impl Into<Notification>) {
|
||||
let note = note.into();
|
||||
Root::update_root(self, move |root, cx| {
|
||||
root.notification_list
|
||||
.update(cx, |view, cx| view.push(note, cx));
|
||||
Root::update(self, move |root, cx| {
|
||||
root.notification.update(cx, |view, cx| view.push(note, cx));
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
|
||||
fn clear_notifications(&mut self) {
|
||||
Root::update_root(self, move |root, cx| {
|
||||
root.notification_list.update(cx, |view, cx| view.clear(cx));
|
||||
Root::update(self, move |root, cx| {
|
||||
root.notification.update(cx, |view, cx| view.clear(cx));
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
|
||||
fn notification_view(&self) -> AnyView {
|
||||
Root::read_root(&self).notification_list.clone().into()
|
||||
fn notifications(&self) -> Rc<Vec<View<Notification>>> {
|
||||
Rc::new(
|
||||
Root::read(&self)
|
||||
.notification
|
||||
.read(&self)
|
||||
.notifications
|
||||
.clone(),
|
||||
)
|
||||
}
|
||||
}
|
||||
impl<'a, V> ContextModal for ViewContext<'a, V> {
|
||||
|
|
@ -120,8 +125,8 @@ impl<'a, V> ContextModal for ViewContext<'a, V> {
|
|||
self.deref_mut().open_drawer(build)
|
||||
}
|
||||
|
||||
fn active_modal(&self) -> Option<Rc<dyn Fn(Modal, &mut WindowContext) -> Modal + 'static>> {
|
||||
self.deref().active_modal()
|
||||
fn has_active_modal(&self) -> bool {
|
||||
self.deref().has_active_modal()
|
||||
}
|
||||
|
||||
fn close_drawer(&mut self) {
|
||||
|
|
@ -135,8 +140,8 @@ impl<'a, V> ContextModal for ViewContext<'a, V> {
|
|||
self.deref_mut().open_modal(build)
|
||||
}
|
||||
|
||||
fn active_drawer(&self) -> Option<Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>> {
|
||||
self.deref().active_drawer()
|
||||
fn has_active_drawer(&self) -> bool {
|
||||
self.deref().has_active_drawer()
|
||||
}
|
||||
|
||||
fn close_modal(&mut self) {
|
||||
|
|
@ -151,8 +156,8 @@ impl<'a, V> ContextModal for ViewContext<'a, V> {
|
|||
self.deref_mut().clear_notifications()
|
||||
}
|
||||
|
||||
fn notification_view(&self) -> AnyView {
|
||||
self.deref().notification_view()
|
||||
fn notifications(&self) -> Rc<Vec<View<Notification>>> {
|
||||
self.deref().notifications()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,9 +168,9 @@ pub struct Root {
|
|||
/// Used to store the focus handle of the previus revious view.
|
||||
/// When the Modal, Drawer closes, we will focus back to the previous view.
|
||||
previous_focus_handle: Option<FocusHandle>,
|
||||
active_drawer: Option<Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>>,
|
||||
active_modal: Option<Rc<dyn Fn(Modal, &mut WindowContext) -> Modal + 'static>>,
|
||||
notification_list: View<NotificationList>,
|
||||
pub active_drawer: Option<Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>>,
|
||||
pub active_modal: Option<Rc<dyn Fn(Modal, &mut WindowContext) -> Modal + 'static>>,
|
||||
pub notification: View<NotificationList>,
|
||||
child: AnyView,
|
||||
}
|
||||
|
||||
|
|
@ -175,12 +180,12 @@ impl Root {
|
|||
previous_focus_handle: None,
|
||||
active_drawer: None,
|
||||
active_modal: None,
|
||||
notification_list: cx.new_view(NotificationList::new),
|
||||
notification: cx.new_view(NotificationList::new),
|
||||
child,
|
||||
}
|
||||
}
|
||||
|
||||
fn update_root<F>(cx: &mut WindowContext, f: F)
|
||||
pub fn update<F>(cx: &mut WindowContext, f: F)
|
||||
where
|
||||
F: FnOnce(&mut Self, &mut ViewContext<Self>) + 'static,
|
||||
{
|
||||
|
|
@ -193,7 +198,7 @@ impl Root {
|
|||
root.update(cx, |root, cx| f(root, cx))
|
||||
}
|
||||
|
||||
fn read_root<'a>(cx: &'a WindowContext) -> &'a Self {
|
||||
pub fn read<'a>(cx: &'a WindowContext) -> &'a Self {
|
||||
let root = cx
|
||||
.window_handle()
|
||||
.downcast::<Root>()
|
||||
|
|
|
|||
Loading…
Reference in a new issue