Start styling notification panel

This commit is contained in:
Max Brunsfeld 2023-10-22 16:03:33 +02:00
parent c20e781441
commit 23400a5a70
5 changed files with 81 additions and 39 deletions

View file

@ -443,7 +443,8 @@ impl ChatPanel {
Flex::row() Flex::row()
.with_child(render_avatar( .with_child(render_avatar(
message.sender.avatar.clone(), message.sender.avatar.clone(),
&theme, &theme.chat_panel.avatar,
theme.chat_panel.avatar_container,
)) ))
.with_child( .with_child(
Label::new( Label::new(

View file

@ -11,7 +11,7 @@ use call::{report_call_event_for_room, ActiveCall, Room};
use feature_flags::{ChannelsAlpha, FeatureFlagAppExt}; use feature_flags::{ChannelsAlpha, FeatureFlagAppExt};
use gpui::{ use gpui::{
actions, actions,
elements::{Empty, Image}, elements::{ContainerStyle, Empty, Image},
geometry::{ geometry::{
rect::RectF, rect::RectF,
vector::{vec2f, Vector2F}, vector::{vec2f, Vector2F},
@ -20,7 +20,7 @@ use gpui::{
AnyElement, AppContext, Element, ImageData, Task, AnyElement, AppContext, Element, ImageData, Task,
}; };
use std::{rc::Rc, sync::Arc}; use std::{rc::Rc, sync::Arc};
use theme::Theme; use theme::AvatarStyle;
use time::{OffsetDateTime, UtcOffset}; use time::{OffsetDateTime, UtcOffset};
use util::ResultExt; use util::ResultExt;
use workspace::AppState; use workspace::AppState;
@ -133,8 +133,11 @@ fn notification_window_options(
} }
} }
fn render_avatar<T: 'static>(avatar: Option<Arc<ImageData>>, theme: &Arc<Theme>) -> AnyElement<T> { fn render_avatar<T: 'static>(
let avatar_style = theme.chat_panel.avatar; avatar: Option<Arc<ImageData>>,
avatar_style: &AvatarStyle,
container: ContainerStyle,
) -> AnyElement<T> {
avatar avatar
.map(|avatar| { .map(|avatar| {
Image::from_data(avatar) Image::from_data(avatar)
@ -154,7 +157,7 @@ fn render_avatar<T: 'static>(avatar: Option<Arc<ImageData>>, theme: &Arc<Theme>)
.into_any() .into_any()
}) })
.contained() .contained()
.with_style(theme.chat_panel.avatar_container) .with_style(container)
.into_any() .into_any()
} }

View file

@ -21,7 +21,7 @@ use rpc::proto;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use settings::SettingsStore; use settings::SettingsStore;
use std::{sync::Arc, time::Duration}; use std::{sync::Arc, time::Duration};
use theme::{IconButton, Theme}; use theme::{ui, Theme};
use time::{OffsetDateTime, UtcOffset}; use time::{OffsetDateTime, UtcOffset};
use util::{ResultExt, TryFutureExt}; use util::{ResultExt, TryFutureExt};
use workspace::{ use workspace::{
@ -197,9 +197,9 @@ impl NotificationPanel {
let NotificationPresenter { let NotificationPresenter {
actor, actor,
text, text,
icon,
needs_response, needs_response,
can_navigate, can_navigate,
..
} = self.present_notification(entry, cx)?; } = self.present_notification(entry, cx)?;
let theme = theme::current(cx); let theme = theme::current(cx);
@ -227,17 +227,21 @@ impl NotificationPanel {
Flex::column() Flex::column()
.with_child( .with_child(
Flex::row() Flex::row()
.with_children( .with_children(actor.map(|actor| {
actor.map(|actor| render_avatar(actor.avatar.clone(), &theme)), render_avatar(
actor.avatar.clone(),
&style.avatar,
style.avatar_container,
) )
.with_child(render_icon_button(&theme.chat_panel.icon_button, icon)) }))
.with_child( .with_child(
Label::new( Label::new(
format_timestamp(timestamp, now, self.local_timezone), format_timestamp(timestamp, now, self.local_timezone),
style.timestamp.text.clone(), style.timestamp.text.clone(),
) )
.contained() .contained()
.with_style(style.timestamp.container), .with_style(style.timestamp.container)
.flex_float(),
) )
.align_children_center(), .align_children_center(),
) )
@ -245,8 +249,12 @@ impl NotificationPanel {
.with_children(if let Some(is_accepted) = response { .with_children(if let Some(is_accepted) = response {
Some( Some(
Label::new( Label::new(
if is_accepted { "Accepted" } else { "Declined" }, if is_accepted {
style.button.text.clone(), "You Accepted"
} else {
"You Declined"
},
style.read_text.text.clone(),
) )
.into_any(), .into_any(),
) )
@ -573,19 +581,34 @@ impl View for NotificationPanel {
fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> { fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
let theme = theme::current(cx); let theme = theme::current(cx);
let style = &theme.notification_panel;
let element = if self.client.user_id().is_none() { let element = if self.client.user_id().is_none() {
self.render_sign_in_prompt(&theme, cx) self.render_sign_in_prompt(&theme, cx)
} else if self.notification_list.item_count() == 0 { } else if self.notification_list.item_count() == 0 {
self.render_empty_state(&theme, cx) self.render_empty_state(&theme, cx)
} else { } else {
Flex::column()
.with_child(
Flex::row()
.with_child(Label::new("Notifications", style.title.text.clone()))
.with_child(ui::svg(&style.title_icon).flex_float())
.align_children_center()
.contained()
.with_style(style.title.container)
.constrained()
.with_height(style.title_height),
)
.with_child(
List::new(self.notification_list.clone()) List::new(self.notification_list.clone())
.contained() .contained()
.with_style(theme.chat_panel.list) .with_style(style.list)
.flex(1., true),
)
.into_any() .into_any()
}; };
element element
.contained() .contained()
.with_style(theme.chat_panel.container) .with_style(style.container)
.constrained() .constrained()
.with_min_width(150.) .with_min_width(150.)
.into_any() .into_any()
@ -675,19 +698,6 @@ impl Panel for NotificationPanel {
} }
} }
fn render_icon_button<V: View>(style: &IconButton, svg_path: &'static str) -> impl Element<V> {
Svg::new(svg_path)
.with_color(style.color)
.constrained()
.with_width(style.icon_width)
.aligned()
.constrained()
.with_width(style.button_width)
.with_height(style.button_width)
.contained()
.with_style(style.container)
}
pub struct NotificationToast { pub struct NotificationToast {
notification_id: u64, notification_id: u64,
actor: Option<Arc<User>>, actor: Option<Arc<User>>,

View file

@ -653,6 +653,9 @@ pub struct ChatPanel {
pub struct NotificationPanel { pub struct NotificationPanel {
#[serde(flatten)] #[serde(flatten)]
pub container: ContainerStyle, pub container: ContainerStyle,
pub title: ContainedText,
pub title_icon: SvgStyle,
pub title_height: f32,
pub list: ContainerStyle, pub list: ContainerStyle,
pub avatar: AvatarStyle, pub avatar: AvatarStyle,
pub avatar_container: ContainerStyle, pub avatar_container: ContainerStyle,

View file

@ -1,9 +1,9 @@
import { background, text } from "./components" import { background, border, text } from "./components"
import { icon_button } from "../component/icon_button" import { icon_button } from "../component/icon_button"
import { useTheme } from "../theme" import { useTheme } from "../theme"
import { interactive } from "../element" import { interactive } from "../element"
export default function chat_panel(): any { export default function (): any {
const theme = useTheme() const theme = useTheme()
const layer = theme.middle const layer = theme.middle
@ -12,12 +12,32 @@ export default function chat_panel(): any {
avatar: { avatar: {
icon_width: 24, icon_width: 24,
icon_height: 24, icon_height: 24,
corner_radius: 4, corner_radius: 12,
outer_width: 24, outer_width: 24,
outer_corner_radius: 16, outer_corner_radius: 24,
},
title: {
...text(layer, "sans", "default"),
padding: { left: 8, right: 8 },
border: border(layer, { bottom: true }),
},
title_height: 32,
title_icon: {
asset: "icons/feedback.svg",
color: text(theme.lowest, "sans", "default").color,
dimensions: {
width: 16,
height: 16,
},
},
read_text: {
padding: { top: 4, bottom: 4 },
...text(layer, "sans", "disabled"),
},
unread_text: {
padding: { top: 4, bottom: 4 },
...text(layer, "sans", "base"),
}, },
read_text: text(layer, "sans", "disabled"),
unread_text: text(layer, "sans", "base"),
button: interactive({ button: interactive({
base: { base: {
...text(theme.lowest, "sans", "on", { size: "xs" }), ...text(theme.lowest, "sans", "on", { size: "xs" }),
@ -42,7 +62,12 @@ export default function chat_panel(): any {
bottom: 2, bottom: 2,
}, },
}, },
list: {}, list: {
padding: {
left: 8,
right: 8,
},
},
icon_button: icon_button({ icon_button: icon_button({
variant: "ghost", variant: "ghost",
color: "variant", color: "variant",