Add stories for collab notifications (#3967)

This PR adds some basic stories for collab notifications to make them
easier to work on:

<img width="1076" alt="Screenshot 2024-01-08 at 9 43 39 PM"
src="https://github.com/zed-industries/zed/assets/1486634/4a0adcfa-1134-49c2-b589-74ac1d52af4c">

I factored out a `CollabNotification` component that defines the general
structure for one of these notifications, and this is the component that
we use in the stories, with representative values passed to it to
simulate the different instances of the notification.

We can't use the actual notification components in the stories due to
their data dependencies.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-01-08 21:54:59 -05:00 committed by GitHub
parent c40a7f3445
commit 4afa5fb23e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 169 additions and 83 deletions

2
Cargo.lock generated
View File

@ -1559,6 +1559,7 @@ dependencies = [
"serde_json",
"settings",
"smallvec",
"story",
"theme",
"theme_selector",
"time",
@ -7447,6 +7448,7 @@ dependencies = [
"backtrace-on-stack-overflow",
"chrono",
"clap 4.4.4",
"collab_ui",
"dialoguer",
"editor",
"fuzzy",

View File

@ -9,6 +9,8 @@ path = "src/collab_ui.rs"
doctest = false
[features]
default = []
stories = ["dep:story"]
test-support = [
"call/test-support",
"client/test-support",
@ -44,6 +46,7 @@ project = { path = "../project" }
recent_projects = { path = "../recent_projects" }
rpc = { path = "../rpc" }
settings = { path = "../settings" }
story = { path = "../story", optional = true }
feature_flags = { path = "../feature_flags"}
theme = { path = "../theme" }
theme_selector = { path = "../theme_selector" }

View File

@ -1,9 +1,16 @@
mod collab_notification;
pub mod incoming_call_notification;
pub mod project_shared_notification;
#[cfg(feature = "stories")]
mod stories;
use gpui::AppContext;
use std::sync::Arc;
use workspace::AppState;
pub mod incoming_call_notification;
pub mod project_shared_notification;
#[cfg(feature = "stories")]
pub use stories::*;
pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
incoming_call_notification::init(app_state, cx);

View File

@ -0,0 +1,52 @@
use gpui::{img, prelude::*, AnyElement};
use smallvec::SmallVec;
use ui::prelude::*;
#[derive(IntoElement)]
pub struct CollabNotification {
avatar_uri: SharedString,
accept_button: Button,
dismiss_button: Button,
children: SmallVec<[AnyElement; 2]>,
}
impl CollabNotification {
pub fn new(
avatar_uri: impl Into<SharedString>,
accept_button: Button,
dismiss_button: Button,
) -> Self {
Self {
avatar_uri: avatar_uri.into(),
accept_button,
dismiss_button,
children: SmallVec::new(),
}
}
}
impl ParentElement for CollabNotification {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
&mut self.children
}
}
impl RenderOnce for CollabNotification {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
h_stack()
.text_ui()
.justify_between()
.size_full()
.overflow_hidden()
.elevation_3(cx)
.p_2()
.gap_2()
.child(img(self.avatar_uri).w_12().h_12().rounded_full())
.child(v_stack().overflow_hidden().children(self.children))
.child(
v_stack()
.child(self.accept_button)
.child(self.dismiss_button),
)
}
}

View File

@ -1,15 +1,12 @@
use crate::notification_window_options;
use crate::notifications::collab_notification::CollabNotification;
use call::{ActiveCall, IncomingCall};
use futures::StreamExt;
use gpui::{
img, px, AppContext, ParentElement, Render, RenderOnce, Styled, ViewContext,
VisualContext as _, WindowHandle,
};
use gpui::{prelude::*, AppContext, WindowHandle};
use settings::Settings;
use std::sync::{Arc, Weak};
use theme::ThemeSettings;
use ui::prelude::*;
use ui::{h_stack, v_stack, Button, Label};
use ui::{prelude::*, Button, Label};
use util::ResultExt;
use workspace::AppState;
@ -31,8 +28,8 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
if let Some(incoming_call) = incoming_call {
let unique_screens = cx.update(|cx| cx.displays()).unwrap();
let window_size = gpui::Size {
width: px(380.),
height: px(64.),
width: px(400.),
height: px(72.),
};
for screen in unique_screens {
@ -129,35 +126,22 @@ impl Render for IncomingCallNotification {
cx.set_rem_size(ui_font_size);
h_stack()
.font(ui_font)
.text_ui()
.justify_between()
.size_full()
.overflow_hidden()
.elevation_3(cx)
.p_2()
.gap_2()
.child(
img(self.state.call.calling_user.avatar_uri.clone())
.w_12()
.h_12()
.rounded_full(),
div().size_full().font(ui_font).child(
CollabNotification::new(
self.state.call.calling_user.avatar_uri.clone(),
Button::new("accept", "Accept").on_click({
let state = self.state.clone();
move |_, cx| state.respond(true, cx)
}),
Button::new("decline", "Decline").on_click({
let state = self.state.clone();
move |_, cx| state.respond(false, cx)
}),
)
.child(v_stack().overflow_hidden().child(Label::new(format!(
"{} is sharing a project in Zed",
self.state.call.calling_user.github_login
))))
.child(
v_stack()
.child(Button::new("accept", "Accept").render(cx).on_click({
let state = self.state.clone();
move |_, cx| state.respond(true, cx)
}))
.child(Button::new("decline", "Decline").render(cx).on_click({
let state = self.state.clone();
move |_, cx| state.respond(false, cx)
})),
)))),
)
}
}

View File

@ -1,12 +1,13 @@
use crate::notification_window_options;
use crate::notifications::collab_notification::CollabNotification;
use call::{room, ActiveCall};
use client::User;
use collections::HashMap;
use gpui::{img, px, AppContext, ParentElement, Render, Size, Styled, ViewContext, VisualContext};
use gpui::{AppContext, Size};
use settings::Settings;
use std::sync::{Arc, Weak};
use theme::ThemeSettings;
use ui::{h_stack, prelude::*, v_stack, Button, Label};
use ui::{prelude::*, Button, Label};
use workspace::AppState;
pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
@ -130,24 +131,16 @@ impl Render for ProjectSharedNotification {
cx.set_rem_size(ui_font_size);
h_stack()
.font(ui_font)
.text_ui()
.justify_between()
.size_full()
.overflow_hidden()
.elevation_3(cx)
.p_2()
.gap_2()
.child(
img(self.owner.avatar_uri.clone())
.w_12()
.h_12()
.rounded_full(),
div().size_full().font(ui_font).child(
CollabNotification::new(
self.owner.avatar_uri.clone(),
Button::new("open", "Open").on_click(cx.listener(move |this, _event, cx| {
this.join(cx);
})),
Button::new("dismiss", "Dismiss").on_click(cx.listener(move |this, _event, cx| {
this.dismiss(cx);
})),
)
.child(
v_stack()
.overflow_hidden()
.child(Label::new(self.owner.github_login.clone()))
.child(Label::new(format!(
"is sharing a project in Zed{}",
@ -163,18 +156,5 @@ impl Render for ProjectSharedNotification {
Some(Label::new(self.worktree_root_names.join(", ")))
}),
)
.child(
v_stack()
.child(Button::new("open", "Open").on_click(cx.listener(
move |this, _event, cx| {
this.join(cx);
},
)))
.child(Button::new("dismiss", "Dismiss").on_click(cx.listener(
move |this, _event, cx| {
this.dismiss(cx);
},
))),
)
}
}

View File

@ -0,0 +1,3 @@
mod collab_notification;
pub use collab_notification::*;

View File

@ -0,0 +1,50 @@
use gpui::prelude::*;
use story::{StoryContainer, StoryItem, StorySection};
use ui::prelude::*;
use crate::notifications::collab_notification::CollabNotification;
pub struct CollabNotificationStory;
impl Render for CollabNotificationStory {
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
let window_container = |width, height| div().w(px(width)).h(px(height));
StoryContainer::new(
"CollabNotification Story",
"crates/collab_ui/src/notifications/stories/collab_notification.rs",
)
.child(
StorySection::new().child(StoryItem::new(
"Incoming Call Notification",
window_container(400., 72.).child(
CollabNotification::new(
"https://avatars.githubusercontent.com/u/1486634?v=4",
Button::new("accept", "Accept"),
Button::new("decline", "Decline"),
)
.child(
v_stack()
.overflow_hidden()
.child(Label::new("maxdeviant is sharing a project in Zed")),
),
),
)),
)
.child(
StorySection::new().child(StoryItem::new(
"Project Shared Notification",
window_container(400., 72.).child(
CollabNotification::new(
"https://avatars.githubusercontent.com/u/1714999?v=4",
Button::new("open", "Open"),
Button::new("dismiss", "Dismiss"),
)
.child(Label::new("iamnbutler"))
.child(Label::new("is sharing a project in Zed:"))
.child(Label::new("zed")),
),
)),
)
}
}

View File

@ -14,6 +14,7 @@ anyhow.workspace = true
backtrace-on-stack-overflow = "0.3.0"
chrono = "0.4"
clap = { version = "4.4", features = ["derive", "string"] }
collab_ui = { path = "../collab_ui", features = ["stories"] }
strum = { version = "0.25.0", features = ["derive"] }
dialoguer = { version = "0.11.0", features = ["fuzzy-select"] }
editor = { path = "../editor" }

View File

@ -16,6 +16,7 @@ pub enum ComponentStory {
Avatar,
Button,
Checkbox,
CollabNotification,
ContextMenu,
Cursor,
Disclosure,
@ -45,6 +46,9 @@ impl ComponentStory {
Self::Avatar => cx.new_view(|_| ui::AvatarStory).into(),
Self::Button => cx.new_view(|_| ui::ButtonStory).into(),
Self::Checkbox => cx.new_view(|_| ui::CheckboxStory).into(),
Self::CollabNotification => cx
.new_view(|_| collab_ui::notifications::CollabNotificationStory)
.into(),
Self::ContextMenu => cx.new_view(|_| ui::ContextMenuStory).into(),
Self::Cursor => cx.new_view(|_| crate::stories::CursorStory).into(),
Self::Disclosure => cx.new_view(|_| ui::DisclosureStory).into(),