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 std::sync::Arc;
|
||||||
use ui::{
|
use ui::{
|
||||||
button::{Button, ButtonStyle},
|
button::Button,
|
||||||
drawer::Drawer,
|
drawer::Drawer,
|
||||||
|
h_flex,
|
||||||
modal::Modal,
|
modal::Modal,
|
||||||
popover::Popover,
|
popover::Popover,
|
||||||
popup_menu::PopupMenu,
|
popup_menu::PopupMenu,
|
||||||
theme::{ActiveTheme, Theme},
|
theme::{ActiveTheme, Theme},
|
||||||
ContextModal as _, IconName, Root, Sizable,
|
ContextModal, IconName, Root, Sizable,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::app_state::AppState;
|
use crate::app_state::AppState;
|
||||||
|
|
@ -273,10 +274,11 @@ pub fn open_new(
|
||||||
|
|
||||||
impl Render for StoryWorkspace {
|
impl Render for StoryWorkspace {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
let active_modal = cx.active_modal();
|
let active_modal = Root::read(cx).active_modal.clone();
|
||||||
let active_drawer = cx.active_drawer();
|
let active_drawer = Root::read(cx).active_drawer.clone();
|
||||||
let has_active_modal = active_modal.is_some();
|
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()
|
div()
|
||||||
.relative()
|
.relative()
|
||||||
|
|
@ -303,7 +305,6 @@ impl Render for StoryWorkspace {
|
||||||
.items_center()
|
.items_center()
|
||||||
.justify_end()
|
.justify_end()
|
||||||
.px_2()
|
.px_2()
|
||||||
.mr_3()
|
|
||||||
.gap_2()
|
.gap_2()
|
||||||
.child(self.locale_selector.clone())
|
.child(self.locale_selector.clone())
|
||||||
.child(
|
.child(
|
||||||
|
|
@ -330,10 +331,38 @@ impl Render for StoryWorkspace {
|
||||||
Button::new("github", cx)
|
Button::new("github", cx)
|
||||||
.icon(IconName::GitHub)
|
.icon(IconName::GitHub)
|
||||||
.small()
|
.small()
|
||||||
.style(ButtonStyle::Ghost)
|
.ghost()
|
||||||
.on_click(|_, cx| {
|
.on_click(|_, cx| {
|
||||||
cx.open_url("https://github.com/huacnlee/gpui-component")
|
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,
|
ArrowRight,
|
||||||
ArrowUp,
|
ArrowUp,
|
||||||
Asterisk,
|
Asterisk,
|
||||||
|
Bell,
|
||||||
Calendar,
|
Calendar,
|
||||||
Check,
|
Check,
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
|
|
@ -18,6 +19,7 @@ pub enum IconName {
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
ChevronUp,
|
ChevronUp,
|
||||||
ChevronsUpDown,
|
ChevronsUpDown,
|
||||||
|
CircleCheck,
|
||||||
CircleX,
|
CircleX,
|
||||||
Close,
|
Close,
|
||||||
Copy,
|
Copy,
|
||||||
|
|
@ -50,7 +52,6 @@ pub enum IconName {
|
||||||
ThumbsDown,
|
ThumbsDown,
|
||||||
ThumbsUp,
|
ThumbsUp,
|
||||||
TriangleAlert,
|
TriangleAlert,
|
||||||
CircleCheck,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IconName {
|
impl IconName {
|
||||||
|
|
@ -61,6 +62,7 @@ impl IconName {
|
||||||
IconName::ArrowRight => "icons/arrow-right.svg",
|
IconName::ArrowRight => "icons/arrow-right.svg",
|
||||||
IconName::ArrowUp => "icons/arrow-up.svg",
|
IconName::ArrowUp => "icons/arrow-up.svg",
|
||||||
IconName::Asterisk => "icons/asterisk.svg",
|
IconName::Asterisk => "icons/asterisk.svg",
|
||||||
|
IconName::Bell => "icons/bell.svg",
|
||||||
IconName::Calendar => "icons/calendar.svg",
|
IconName::Calendar => "icons/calendar.svg",
|
||||||
IconName::Check => "icons/check.svg",
|
IconName::Check => "icons/check.svg",
|
||||||
IconName::ChevronDown => "icons/chevron-down.svg",
|
IconName::ChevronDown => "icons/chevron-down.svg",
|
||||||
|
|
@ -68,6 +70,7 @@ impl IconName {
|
||||||
IconName::ChevronRight => "icons/chevron-right.svg",
|
IconName::ChevronRight => "icons/chevron-right.svg",
|
||||||
IconName::ChevronUp => "icons/chevron-up.svg",
|
IconName::ChevronUp => "icons/chevron-up.svg",
|
||||||
IconName::ChevronsUpDown => "icons/chevrons-up-down.svg",
|
IconName::ChevronsUpDown => "icons/chevrons-up-down.svg",
|
||||||
|
IconName::CircleCheck => "icons/circle-check.svg",
|
||||||
IconName::CircleX => "icons/circle-x.svg",
|
IconName::CircleX => "icons/circle-x.svg",
|
||||||
IconName::Close => "icons/close.svg",
|
IconName::Close => "icons/close.svg",
|
||||||
IconName::Copy => "icons/copy.svg",
|
IconName::Copy => "icons/copy.svg",
|
||||||
|
|
@ -100,7 +103,6 @@ impl IconName {
|
||||||
IconName::ThumbsDown => "icons/thumbs-down.svg",
|
IconName::ThumbsDown => "icons/thumbs-down.svg",
|
||||||
IconName::ThumbsUp => "icons/thumbs-up.svg",
|
IconName::ThumbsUp => "icons/thumbs-up.svg",
|
||||||
IconName::TriangleAlert => "icons/triangle-alert.svg",
|
IconName::TriangleAlert => "icons/triangle-alert.svg",
|
||||||
IconName::CircleCheck => "icons/circle-check.svg",
|
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,7 @@ impl Render for Notification {
|
||||||
|
|
||||||
/// A list of notifications.
|
/// A list of notifications.
|
||||||
pub struct NotificationList {
|
pub struct NotificationList {
|
||||||
notifications: Vec<View<Notification>>,
|
pub(crate) notifications: Vec<View<Notification>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NotificationList {
|
impl NotificationList {
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ pub trait ContextModal: Sized {
|
||||||
where
|
where
|
||||||
F: Fn(Drawer, &mut WindowContext) -> Drawer + 'static;
|
F: Fn(Drawer, &mut WindowContext) -> Drawer + 'static;
|
||||||
|
|
||||||
/// Return the active Drawer builder, you must add the Drawer to the view.
|
/// Return true, if there is an active Drawer.
|
||||||
fn active_drawer(&self) -> Option<Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>>;
|
fn has_active_drawer(&self) -> bool;
|
||||||
|
|
||||||
/// Closes the active Drawer.
|
/// Closes the active Drawer.
|
||||||
fn close_drawer(&mut self);
|
fn close_drawer(&mut self);
|
||||||
|
|
@ -32,8 +32,8 @@ pub trait ContextModal: Sized {
|
||||||
where
|
where
|
||||||
F: Fn(Modal, &mut WindowContext) -> Modal + 'static;
|
F: Fn(Modal, &mut WindowContext) -> Modal + 'static;
|
||||||
|
|
||||||
/// Return the active Modal builder, you must add the Modal to the view.
|
/// Return true, if there is an active Modal.
|
||||||
fn active_modal(&self) -> Option<Rc<dyn Fn(Modal, &mut WindowContext) -> Modal + 'static>>;
|
fn has_active_modal(&self) -> bool;
|
||||||
|
|
||||||
/// Closes the active Modal.
|
/// Closes the active Modal.
|
||||||
fn close_modal(&mut self);
|
fn close_modal(&mut self);
|
||||||
|
|
@ -41,8 +41,8 @@ pub trait ContextModal: Sized {
|
||||||
/// Pushes a notification to the notification list.
|
/// Pushes a notification to the notification list.
|
||||||
fn push_notification(&mut self, note: impl Into<Notification>);
|
fn push_notification(&mut self, note: impl Into<Notification>);
|
||||||
fn clear_notifications(&mut self);
|
fn clear_notifications(&mut self);
|
||||||
/// Returns the notification list view.
|
/// Returns number of notifications.
|
||||||
fn notification_view(&self) -> AnyView;
|
fn notifications(&self) -> Rc<Vec<View<Notification>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ContextModal for WindowContext<'a> {
|
impl<'a> ContextModal for WindowContext<'a> {
|
||||||
|
|
@ -50,19 +50,19 @@ impl<'a> ContextModal for WindowContext<'a> {
|
||||||
where
|
where
|
||||||
F: Fn(Drawer, &mut WindowContext) -> Drawer + 'static,
|
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.previous_focus_handle = cx.focused();
|
||||||
root.active_drawer = Some(Rc::new(build));
|
root.active_drawer = Some(Rc::new(build));
|
||||||
cx.notify();
|
cx.notify();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn active_drawer(&self) -> Option<Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>> {
|
fn has_active_drawer(&self) -> bool {
|
||||||
Root::read_root(&self).active_drawer.clone()
|
Root::read(&self).active_drawer.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_drawer(&mut self) {
|
fn close_drawer(&mut self) {
|
||||||
Root::update_root(self, |root, cx| {
|
Root::update(self, |root, cx| {
|
||||||
root.active_drawer = None;
|
root.active_drawer = None;
|
||||||
root.focus_back(cx);
|
root.focus_back(cx);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
|
@ -73,19 +73,19 @@ impl<'a> ContextModal for WindowContext<'a> {
|
||||||
where
|
where
|
||||||
F: Fn(Modal, &mut WindowContext) -> Modal + 'static,
|
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.previous_focus_handle = cx.focused();
|
||||||
root.active_modal = Some(Rc::new(build));
|
root.active_modal = Some(Rc::new(build));
|
||||||
cx.notify();
|
cx.notify();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn active_modal(&self) -> Option<Rc<dyn Fn(Modal, &mut WindowContext) -> Modal + 'static>> {
|
fn has_active_modal(&self) -> bool {
|
||||||
Root::read_root(&self).active_modal.clone()
|
Root::read(&self).active_modal.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_modal(&mut self) {
|
fn close_modal(&mut self) {
|
||||||
Root::update_root(self, |root, cx| {
|
Root::update(self, |root, cx| {
|
||||||
root.active_modal = None;
|
root.active_modal = None;
|
||||||
root.focus_back(cx);
|
root.focus_back(cx);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
|
@ -94,22 +94,27 @@ impl<'a> ContextModal for WindowContext<'a> {
|
||||||
|
|
||||||
fn push_notification(&mut self, note: impl Into<Notification>) {
|
fn push_notification(&mut self, note: impl Into<Notification>) {
|
||||||
let note = note.into();
|
let note = note.into();
|
||||||
Root::update_root(self, move |root, cx| {
|
Root::update(self, move |root, cx| {
|
||||||
root.notification_list
|
root.notification.update(cx, |view, cx| view.push(note, cx));
|
||||||
.update(cx, |view, cx| view.push(note, cx));
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_notifications(&mut self) {
|
fn clear_notifications(&mut self) {
|
||||||
Root::update_root(self, move |root, cx| {
|
Root::update(self, move |root, cx| {
|
||||||
root.notification_list.update(cx, |view, cx| view.clear(cx));
|
root.notification.update(cx, |view, cx| view.clear(cx));
|
||||||
cx.notify();
|
cx.notify();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notification_view(&self) -> AnyView {
|
fn notifications(&self) -> Rc<Vec<View<Notification>>> {
|
||||||
Root::read_root(&self).notification_list.clone().into()
|
Rc::new(
|
||||||
|
Root::read(&self)
|
||||||
|
.notification
|
||||||
|
.read(&self)
|
||||||
|
.notifications
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a, V> ContextModal for ViewContext<'a, V> {
|
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)
|
self.deref_mut().open_drawer(build)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn active_modal(&self) -> Option<Rc<dyn Fn(Modal, &mut WindowContext) -> Modal + 'static>> {
|
fn has_active_modal(&self) -> bool {
|
||||||
self.deref().active_modal()
|
self.deref().has_active_modal()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_drawer(&mut self) {
|
fn close_drawer(&mut self) {
|
||||||
|
|
@ -135,8 +140,8 @@ impl<'a, V> ContextModal for ViewContext<'a, V> {
|
||||||
self.deref_mut().open_modal(build)
|
self.deref_mut().open_modal(build)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn active_drawer(&self) -> Option<Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>> {
|
fn has_active_drawer(&self) -> bool {
|
||||||
self.deref().active_drawer()
|
self.deref().has_active_drawer()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_modal(&mut self) {
|
fn close_modal(&mut self) {
|
||||||
|
|
@ -151,8 +156,8 @@ impl<'a, V> ContextModal for ViewContext<'a, V> {
|
||||||
self.deref_mut().clear_notifications()
|
self.deref_mut().clear_notifications()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notification_view(&self) -> AnyView {
|
fn notifications(&self) -> Rc<Vec<View<Notification>>> {
|
||||||
self.deref().notification_view()
|
self.deref().notifications()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,9 +168,9 @@ pub struct Root {
|
||||||
/// Used to store the focus handle of the previus revious view.
|
/// Used to store the focus handle of the previus revious view.
|
||||||
/// When the Modal, Drawer closes, we will focus back to the previous view.
|
/// When the Modal, Drawer closes, we will focus back to the previous view.
|
||||||
previous_focus_handle: Option<FocusHandle>,
|
previous_focus_handle: Option<FocusHandle>,
|
||||||
active_drawer: Option<Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>>,
|
pub active_drawer: Option<Rc<dyn Fn(Drawer, &mut WindowContext) -> Drawer + 'static>>,
|
||||||
active_modal: Option<Rc<dyn Fn(Modal, &mut WindowContext) -> Modal + 'static>>,
|
pub active_modal: Option<Rc<dyn Fn(Modal, &mut WindowContext) -> Modal + 'static>>,
|
||||||
notification_list: View<NotificationList>,
|
pub notification: View<NotificationList>,
|
||||||
child: AnyView,
|
child: AnyView,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,12 +180,12 @@ impl Root {
|
||||||
previous_focus_handle: None,
|
previous_focus_handle: None,
|
||||||
active_drawer: None,
|
active_drawer: None,
|
||||||
active_modal: None,
|
active_modal: None,
|
||||||
notification_list: cx.new_view(NotificationList::new),
|
notification: cx.new_view(NotificationList::new),
|
||||||
child,
|
child,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_root<F>(cx: &mut WindowContext, f: F)
|
pub fn update<F>(cx: &mut WindowContext, f: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Self, &mut ViewContext<Self>) + 'static,
|
F: FnOnce(&mut Self, &mut ViewContext<Self>) + 'static,
|
||||||
{
|
{
|
||||||
|
|
@ -193,7 +198,7 @@ impl Root {
|
||||||
root.update(cx, |root, cx| f(root, cx))
|
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
|
let root = cx
|
||||||
.window_handle()
|
.window_handle()
|
||||||
.downcast::<Root>()
|
.downcast::<Root>()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue