From 5145795f33ed5a127cbff792f464156201786b9b Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 20 Dec 2023 11:27:28 -0500 Subject: [PATCH 1/7] Adjust styles for notification panel container --- crates/collab_ui2/src/notification_panel.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/collab_ui2/src/notification_panel.rs b/crates/collab_ui2/src/notification_panel.rs index 35288e810d..e2deced60f 100644 --- a/crates/collab_ui2/src/notification_panel.rs +++ b/crates/collab_ui2/src/notification_panel.rs @@ -19,7 +19,7 @@ use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsStore}; use std::{sync::Arc, time::Duration}; use time::{OffsetDateTime, UtcOffset}; -use ui::{h_stack, v_stack, Avatar, Button, Clickable, Icon, IconButton, IconElement, Label}; +use ui::{h_stack, prelude::*, v_stack, Avatar, Button, Icon, IconButton, IconElement, Label}; use util::{ResultExt, TryFutureExt}; use workspace::{ dock::{DockPosition, Panel, PanelEvent}, @@ -545,16 +545,22 @@ impl NotificationPanel { impl Render for NotificationPanel { type Element = AnyElement; - fn render(&mut self, _: &mut ViewContext) -> AnyElement { + fn render(&mut self, cx: &mut ViewContext) -> AnyElement { if self.client.user_id().is_none() { self.render_sign_in_prompt() } else if self.notification_list.item_count() == 0 { self.render_empty_state() } else { v_stack() - .bg(gpui::red()) .child( h_stack() + .justify_between() + .px_2() + .py_1() + // Match the height of the tab bar so they line up. + .h(rems(ui::Tab::HEIGHT_IN_REMS)) + .border_b_1() + .border_color(cx.theme().colors().border) .child(Label::new("Notifications")) .child(IconElement::new(Icon::Envelope)), ) From 3886b1993d22ae66a89f5c32d3139553fe159bca Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 20 Dec 2023 11:41:51 -0500 Subject: [PATCH 2/7] Fix formatting breakage --- crates/collab_ui2/src/collab_panel.rs | 67 ++++++++++++++------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/crates/collab_ui2/src/collab_panel.rs b/crates/collab_ui2/src/collab_panel.rs index 35e2f8d7ed..52149a481f 100644 --- a/crates/collab_ui2/src/collab_panel.rs +++ b/crates/collab_ui2/src/collab_panel.rs @@ -1624,40 +1624,43 @@ impl CollabPanel { } fn render_signed_out(&mut self, cx: &mut ViewContext) -> Div { - v_stack() - .items_center() - .child(v_stack().gap_6().p_4() - .child( - Label::new("Work with your team in realtime with collaborative editing, voice, shared notes and more.") - ) - .child(v_stack().gap_2() + let collab_blurb = "Work with your team in realtime with collaborative editing, voice, shared notes and more."; + v_stack().items_center().child( + v_stack() + .gap_6() + .p_4() + .child(Label::new(collab_blurb)) .child( - Button::new("sign_in", "Sign in") - .icon_color(Color::Muted) - .icon(Icon::Github) - .icon_position(IconPosition::Start) - .style(ButtonStyle::Filled) - .full_width() - .on_click(cx.listener( - |this, _, cx| { - let client = this.client.clone(); - cx.spawn(|_, mut cx| async move { - client - .authenticate_and_connect(true, &cx) - .await - .notify_async_err(&mut cx); - }) - .detach() - }, - ))) - .child( - div().flex().w_full().items_center().child( - Label::new("Sign in to enable collaboration.") - .color(Color::Muted) - .size(LabelSize::Small) - )), - )) + v_stack() + .gap_2() + .child( + Button::new("sign_in", "Sign in") + .icon_color(Color::Muted) + .icon(Icon::Github) + .icon_position(IconPosition::Start) + .style(ButtonStyle::Filled) + .full_width() + .on_click(cx.listener(|this, _, cx| { + let client = this.client.clone(); + cx.spawn(|_, mut cx| async move { + client + .authenticate_and_connect(true, &cx) + .await + .notify_async_err(&mut cx); + }) + .detach() + })), + ) + .child( + div().flex().w_full().items_center().child( + Label::new("Sign in to enable collaboration.") + .color(Color::Muted) + .size(LabelSize::Small), + ), + ), + ), + ) } fn render_list_entry(&mut self, ix: usize, cx: &mut ViewContext) -> AnyElement { From 636c12ec3f140745152b4dbd92a4fcc7160636fb Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 20 Dec 2023 11:45:18 -0500 Subject: [PATCH 3/7] Style signed-out and empty states for the notification panel --- crates/collab_ui2/src/notification_panel.rs | 111 ++++++++++++-------- 1 file changed, 65 insertions(+), 46 deletions(-) diff --git a/crates/collab_ui2/src/notification_panel.rs b/crates/collab_ui2/src/notification_panel.rs index e2deced60f..8a16261da4 100644 --- a/crates/collab_ui2/src/notification_panel.rs +++ b/crates/collab_ui2/src/notification_panel.rs @@ -439,28 +439,6 @@ impl NotificationPanel { false } - fn render_sign_in_prompt(&self) -> AnyElement { - Button::new( - "sign_in_prompt_button", - "Sign in to view your notifications", - ) - .on_click({ - let client = self.client.clone(); - move |_, cx| { - let client = client.clone(); - cx.spawn(move |cx| async move { - client.authenticate_and_connect(true, &cx).log_err().await; - }) - .detach() - } - }) - .into_any_element() - } - - fn render_empty_state(&self) -> AnyElement { - Label::new("You have no notifications").into_any_element() - } - fn on_notification_event( &mut self, _: Model, @@ -543,31 +521,72 @@ impl NotificationPanel { } impl Render for NotificationPanel { - type Element = AnyElement; + type Element = Div; - fn render(&mut self, cx: &mut ViewContext) -> AnyElement { - if self.client.user_id().is_none() { - self.render_sign_in_prompt() - } else if self.notification_list.item_count() == 0 { - self.render_empty_state() - } else { - v_stack() - .child( - h_stack() - .justify_between() - .px_2() - .py_1() - // Match the height of the tab bar so they line up. - .h(rems(ui::Tab::HEIGHT_IN_REMS)) - .border_b_1() - .border_color(cx.theme().colors().border) - .child(Label::new("Notifications")) - .child(IconElement::new(Icon::Envelope)), - ) - .child(list(self.notification_list.clone()).size_full()) - .size_full() - .into_any_element() - } + fn render(&mut self, cx: &mut ViewContext) -> Div { + v_stack() + .size_full() + .child( + h_stack() + .justify_between() + .px_2() + .py_1() + // Match the height of the tab bar so they line up. + .h(rems(ui::Tab::HEIGHT_IN_REMS)) + .border_b_1() + .border_color(cx.theme().colors().border) + .child(Label::new("Notifications")) + .child(IconElement::new(Icon::Envelope)), + ) + .map(|this| { + if self.client.user_id().is_none() { + this.child( + v_stack() + .gap_2() + .p_4() + .child( + Button::new("sign_in_prompt_button", "Sign in") + .icon_color(Color::Muted) + .icon(Icon::Github) + .icon_position(IconPosition::Start) + .style(ButtonStyle::Filled) + .full_width() + .on_click({ + let client = self.client.clone(); + move |_, cx| { + let client = client.clone(); + cx.spawn(move |cx| async move { + client + .authenticate_and_connect(true, &cx) + .log_err() + .await; + }) + .detach() + } + }), + ) + .child( + div().flex().w_full().items_center().child( + Label::new("Sign in to view notifications.") + .color(Color::Muted) + .size(LabelSize::Small), + ), + ), + ) + } else if self.notification_list.item_count() == 0 { + this.child( + v_stack().p_4().child( + div().flex().w_full().items_center().child( + Label::new("You have no notifications.") + .color(Color::Muted) + .size(LabelSize::Small), + ), + ), + ) + } else { + this.child(list(self.notification_list.clone()).size_full()) + } + }) } } From 9c4e8699bad5502325f2a4860b9ad65aab89e6eb Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 20 Dec 2023 12:45:18 -0500 Subject: [PATCH 4/7] Remove unneeded wrapping element --- crates/collab_ui2/src/collab_panel.rs | 66 +++++++++++++-------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/crates/collab_ui2/src/collab_panel.rs b/crates/collab_ui2/src/collab_panel.rs index 52149a481f..20edd9be56 100644 --- a/crates/collab_ui2/src/collab_panel.rs +++ b/crates/collab_ui2/src/collab_panel.rs @@ -1626,41 +1626,39 @@ impl CollabPanel { fn render_signed_out(&mut self, cx: &mut ViewContext) -> Div { let collab_blurb = "Work with your team in realtime with collaborative editing, voice, shared notes and more."; - v_stack().items_center().child( - v_stack() - .gap_6() - .p_4() - .child(Label::new(collab_blurb)) - .child( - v_stack() - .gap_2() - .child( - Button::new("sign_in", "Sign in") - .icon_color(Color::Muted) - .icon(Icon::Github) - .icon_position(IconPosition::Start) - .style(ButtonStyle::Filled) - .full_width() - .on_click(cx.listener(|this, _, cx| { - let client = this.client.clone(); - cx.spawn(|_, mut cx| async move { - client - .authenticate_and_connect(true, &cx) - .await - .notify_async_err(&mut cx); - }) - .detach() - })), - ) - .child( - div().flex().w_full().items_center().child( - Label::new("Sign in to enable collaboration.") - .color(Color::Muted) - .size(LabelSize::Small), - ), + v_stack() + .gap_6() + .p_4() + .child(Label::new(collab_blurb)) + .child( + v_stack() + .gap_2() + .child( + Button::new("sign_in", "Sign in") + .icon_color(Color::Muted) + .icon(Icon::Github) + .icon_position(IconPosition::Start) + .style(ButtonStyle::Filled) + .full_width() + .on_click(cx.listener(|this, _, cx| { + let client = this.client.clone(); + cx.spawn(|_, mut cx| async move { + client + .authenticate_and_connect(true, &cx) + .await + .notify_async_err(&mut cx); + }) + .detach() + })), + ) + .child( + div().flex().w_full().items_center().child( + Label::new("Sign in to enable collaboration.") + .color(Color::Muted) + .size(LabelSize::Small), ), - ), - ) + ), + ) } fn render_list_entry(&mut self, ix: usize, cx: &mut ViewContext) -> AnyElement { From 87f879bfa974c21742a96a89a89a2a7e488999b0 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 20 Dec 2023 12:48:30 -0500 Subject: [PATCH 5/7] Add text wrapping to notifications --- crates/collab_ui2/src/notification_panel.rs | 129 +++++++++++--------- 1 file changed, 68 insertions(+), 61 deletions(-) diff --git a/crates/collab_ui2/src/notification_panel.rs b/crates/collab_ui2/src/notification_panel.rs index 8a16261da4..e13d4bbe79 100644 --- a/crates/collab_ui2/src/notification_panel.rs +++ b/crates/collab_ui2/src/notification_panel.rs @@ -6,11 +6,11 @@ use collections::HashMap; use db::kvp::KEY_VALUE_STORE; use futures::StreamExt; use gpui::{ - actions, div, list, px, serde_json, AnyElement, AppContext, AsyncWindowContext, CursorStyle, - DismissEvent, Div, Element, EventEmitter, FocusHandle, FocusableView, InteractiveElement, - IntoElement, ListAlignment, ListScrollEvent, ListState, Model, ParentElement, Render, Stateful, - StatefulInteractiveElement, Styled, Task, View, ViewContext, VisualContext, WeakView, - WindowContext, + actions, div, img, list, px, serde_json, AnyElement, AppContext, AsyncWindowContext, + CursorStyle, DismissEvent, Div, Element, EventEmitter, FocusHandle, FocusableView, + InteractiveElement, IntoElement, ListAlignment, ListScrollEvent, ListState, Model, + ParentElement, Render, Stateful, StatefulInteractiveElement, Styled, Task, View, ViewContext, + VisualContext, WeakView, WindowContext, }; use notifications::{NotificationEntry, NotificationEvent, NotificationStore}; use project::Fs; @@ -227,63 +227,10 @@ impl NotificationPanel { } Some( - div() + h_stack() .id(ix) - .child( - h_stack() - .children(actor.map(|actor| Avatar::new(actor.avatar_uri.clone()))) - .child( - v_stack().child(Label::new(text)).child( - h_stack() - .child(Label::new(format_timestamp( - timestamp, - now, - self.local_timezone, - ))) - .children(if let Some(is_accepted) = response { - Some(div().child(Label::new(if is_accepted { - "You accepted" - } else { - "You declined" - }))) - } else if needs_response { - Some( - h_stack() - .child(Button::new("decline", "Decline").on_click( - { - let notification = notification.clone(); - let view = cx.view().clone(); - move |_, cx| { - view.update(cx, |this, cx| { - this.respond_to_notification( - notification.clone(), - false, - cx, - ) - }); - } - }, - )) - .child(Button::new("accept", "Accept").on_click({ - let notification = notification.clone(); - let view = cx.view().clone(); - move |_, cx| { - view.update(cx, |this, cx| { - this.respond_to_notification( - notification.clone(), - true, - cx, - ) - }); - } - })), - ) - } else { - None - }), - ), - ), - ) + .size_full() + .gap_2() .when(can_navigate, |el| { el.cursor(CursorStyle::PointingHand).on_click({ let notification = notification.clone(); @@ -292,6 +239,66 @@ impl NotificationPanel { }) }) }) + .children( + actor.map(|actor| img(actor.avatar_uri.clone()).w_8().h_8().rounded_full()), + ) + .child( + v_stack() + .gap_1() + .size_full() + .child(Label::new(text.clone())) + .child( + h_stack() + .justify_between() + .child( + Label::new(format_timestamp( + timestamp, + now, + self.local_timezone, + )) + .color(Color::Muted), + ) + .children(if let Some(is_accepted) = response { + Some(div().child(Label::new(if is_accepted { + "You accepted" + } else { + "You declined" + }))) + } else if needs_response { + Some( + h_stack() + .child(Button::new("decline", "Decline").on_click({ + let notification = notification.clone(); + let view = cx.view().clone(); + move |_, cx| { + view.update(cx, |this, cx| { + this.respond_to_notification( + notification.clone(), + false, + cx, + ) + }); + } + })) + .child(Button::new("accept", "Accept").on_click({ + let notification = notification.clone(); + let view = cx.view().clone(); + move |_, cx| { + view.update(cx, |this, cx| { + this.respond_to_notification( + notification.clone(), + true, + cx, + ) + }); + } + })), + ) + } else { + None + }), + ), + ) .into_any(), ) } From b0b4610a73f014333935bc72e954e2bd706d7521 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 20 Dec 2023 13:05:21 -0500 Subject: [PATCH 6/7] Fix positioning of right items --- crates/collab_ui2/src/notification_panel.rs | 31 ++++++++++++++------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/crates/collab_ui2/src/notification_panel.rs b/crates/collab_ui2/src/notification_panel.rs index e13d4bbe79..f3df2fc1d3 100644 --- a/crates/collab_ui2/src/notification_panel.rs +++ b/crates/collab_ui2/src/notification_panel.rs @@ -227,9 +227,13 @@ impl NotificationPanel { } Some( - h_stack() + div() .id(ix) + .flex() + .flex_row() .size_full() + .px_2() + .py_1() .gap_2() .when(can_navigate, |el| { el.cursor(CursorStyle::PointingHand).on_click({ @@ -239,9 +243,13 @@ impl NotificationPanel { }) }) }) - .children( - actor.map(|actor| img(actor.avatar_uri.clone()).w_8().h_8().rounded_full()), - ) + .children(actor.map(|actor| { + img(actor.avatar_uri.clone()) + .flex_none() + .w_8() + .h_8() + .rounded_full() + })) .child( v_stack() .gap_1() @@ -249,7 +257,6 @@ impl NotificationPanel { .child(Label::new(text.clone())) .child( h_stack() - .justify_between() .child( Label::new(format_timestamp( timestamp, @@ -259,14 +266,18 @@ impl NotificationPanel { .color(Color::Muted), ) .children(if let Some(is_accepted) = response { - Some(div().child(Label::new(if is_accepted { - "You accepted" - } else { - "You declined" - }))) + Some(div().flex().flex_grow().justify_end().child(Label::new( + if is_accepted { + "You accepted" + } else { + "You declined" + }, + ))) } else if needs_response { Some( h_stack() + .flex_grow() + .justify_end() .child(Button::new("decline", "Decline").on_click({ let notification = notification.clone(); let view = cx.view().clone(); From da34dd49bbb648d8e696098e80ed9f2d39b5c58f Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Wed, 20 Dec 2023 13:25:17 -0500 Subject: [PATCH 7/7] Fix text wrapping issues with `overflow_hidden` This seems to influence sizing calculations in ways I don't fully understand. --- crates/collab_ui2/src/notification_panel.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/collab_ui2/src/notification_panel.rs b/crates/collab_ui2/src/notification_panel.rs index f3df2fc1d3..20951b34db 100644 --- a/crates/collab_ui2/src/notification_panel.rs +++ b/crates/collab_ui2/src/notification_panel.rs @@ -254,6 +254,7 @@ impl NotificationPanel { v_stack() .gap_1() .size_full() + .overflow_hidden() .child(Label::new(text.clone())) .child( h_stack()