Improve chat panel styling (#3758)
This PR improves the chat panel styling, especially with regards to the spacing. Release Notes: - N/A
This commit is contained in:
parent
7a9c4057a7
commit
824b68788f
2 changed files with 114 additions and 98 deletions
|
@ -21,7 +21,7 @@ use settings::{Settings, SettingsStore};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use theme::ActiveTheme as _;
|
use theme::ActiveTheme as _;
|
||||||
use time::{OffsetDateTime, UtcOffset};
|
use time::{OffsetDateTime, UtcOffset};
|
||||||
use ui::{prelude::*, Avatar, Button, Icon, IconButton, Label, Tooltip};
|
use ui::{prelude::*, Avatar, Button, Icon, IconButton, Label, TabBar, Tooltip};
|
||||||
use util::{ResultExt, TryFutureExt};
|
use util::{ResultExt, TryFutureExt};
|
||||||
use workspace::{
|
use workspace::{
|
||||||
dock::{DockPosition, Panel, PanelEvent},
|
dock::{DockPosition, Panel, PanelEvent},
|
||||||
|
@ -97,7 +97,9 @@ impl ChatPanel {
|
||||||
let message_list =
|
let message_list =
|
||||||
ListState::new(0, gpui::ListAlignment::Bottom, px(1000.), move |ix, cx| {
|
ListState::new(0, gpui::ListAlignment::Bottom, px(1000.), move |ix, cx| {
|
||||||
if let Some(view) = view.upgrade() {
|
if let Some(view) = view.upgrade() {
|
||||||
view.update(cx, |view, cx| view.render_message(ix, cx))
|
view.update(cx, |view, cx| {
|
||||||
|
view.render_message(ix, cx).into_any_element()
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
div().into_any()
|
div().into_any()
|
||||||
}
|
}
|
||||||
|
@ -262,38 +264,42 @@ impl ChatPanel {
|
||||||
v_stack()
|
v_stack()
|
||||||
.full()
|
.full()
|
||||||
.on_action(cx.listener(Self::send))
|
.on_action(cx.listener(Self::send))
|
||||||
|
.child(
|
||||||
|
h_stack().z_index(1).child(
|
||||||
|
TabBar::new("chat_header")
|
||||||
.child(
|
.child(
|
||||||
h_stack()
|
h_stack()
|
||||||
.w_full()
|
.w_full()
|
||||||
.h_7()
|
.h(rems(ui::Tab::HEIGHT_IN_REMS))
|
||||||
.justify_between()
|
.px_2()
|
||||||
.z_index(1)
|
|
||||||
.bg(cx.theme().colors().background)
|
|
||||||
.child(Label::new(
|
.child(Label::new(
|
||||||
self.active_chat
|
self.active_chat
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|c| Some(format!("#{}", c.0.read(cx).channel(cx)?.name)))
|
.and_then(|c| {
|
||||||
|
Some(format!("#{}", c.0.read(cx).channel(cx)?.name))
|
||||||
|
})
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
))
|
)),
|
||||||
.child(
|
)
|
||||||
h_stack()
|
.end_child(
|
||||||
.child(
|
|
||||||
IconButton::new("notes", Icon::File)
|
IconButton::new("notes", Icon::File)
|
||||||
.on_click(cx.listener(Self::open_notes))
|
.on_click(cx.listener(Self::open_notes))
|
||||||
.tooltip(|cx| Tooltip::text("Open notes", cx)),
|
.tooltip(|cx| Tooltip::text("Open notes", cx)),
|
||||||
)
|
)
|
||||||
.child(
|
.end_child(
|
||||||
IconButton::new("call", Icon::AudioOn)
|
IconButton::new("call", Icon::AudioOn)
|
||||||
.on_click(cx.listener(Self::join_call))
|
.on_click(cx.listener(Self::join_call))
|
||||||
.tooltip(|cx| Tooltip::text("Join call", cx)),
|
.tooltip(|cx| Tooltip::text("Join call", cx)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(div().flex_grow().px_2().py_1().map(|this| {
|
||||||
div()
|
if self.active_chat.is_some() {
|
||||||
.flex_grow()
|
this.child(list(self.message_list.clone()).full())
|
||||||
.child(self.render_active_channel_messages(cx)),
|
} else {
|
||||||
)
|
this
|
||||||
|
}
|
||||||
|
}))
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.z_index(1)
|
.z_index(1)
|
||||||
|
@ -304,17 +310,10 @@ impl ChatPanel {
|
||||||
.into_any()
|
.into_any()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_active_channel_messages(&self, _cx: &mut ViewContext<Self>) -> AnyElement {
|
fn render_message(&mut self, ix: usize, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
if self.active_chat.is_some() {
|
|
||||||
list(self.message_list.clone()).full().into_any_element()
|
|
||||||
} else {
|
|
||||||
div().into_any_element()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_message(&mut self, ix: usize, cx: &mut ViewContext<Self>) -> AnyElement {
|
|
||||||
let active_chat = &self.active_chat.as_ref().unwrap().0;
|
let active_chat = &self.active_chat.as_ref().unwrap().0;
|
||||||
let (message, is_continuation, is_admin) = active_chat.update(cx, |active_chat, cx| {
|
let (message, is_continuation_from_previous, is_continuation_to_next, is_admin) =
|
||||||
|
active_chat.update(cx, |active_chat, cx| {
|
||||||
let is_admin = self
|
let is_admin = self
|
||||||
.channel_store
|
.channel_store
|
||||||
.read(cx)
|
.read(cx)
|
||||||
|
@ -322,8 +321,13 @@ impl ChatPanel {
|
||||||
|
|
||||||
let last_message = active_chat.message(ix.saturating_sub(1));
|
let last_message = active_chat.message(ix.saturating_sub(1));
|
||||||
let this_message = active_chat.message(ix).clone();
|
let this_message = active_chat.message(ix).clone();
|
||||||
let is_continuation = last_message.id != this_message.id
|
let next_message =
|
||||||
&& this_message.sender.id == last_message.sender.id;
|
active_chat.message(ix.saturating_add(1).min(active_chat.message_count() - 1));
|
||||||
|
|
||||||
|
let is_continuation_from_previous = last_message.id != this_message.id
|
||||||
|
&& last_message.sender.id == this_message.sender.id;
|
||||||
|
let is_continuation_to_next = this_message.id != next_message.id
|
||||||
|
&& this_message.sender.id == next_message.sender.id;
|
||||||
|
|
||||||
if let ChannelMessageId::Saved(id) = this_message.id {
|
if let ChannelMessageId::Saved(id) = this_message.id {
|
||||||
if this_message
|
if this_message
|
||||||
|
@ -335,7 +339,12 @@ impl ChatPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(this_message, is_continuation, is_admin)
|
(
|
||||||
|
this_message,
|
||||||
|
is_continuation_from_previous,
|
||||||
|
is_continuation_to_next,
|
||||||
|
is_admin,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let _is_pending = message.is_pending();
|
let _is_pending = message.is_pending();
|
||||||
|
@ -359,27 +368,31 @@ impl ChatPanel {
|
||||||
ChannelMessageId::Pending(id) => ("pending-message", id).into(),
|
ChannelMessageId::Pending(id) => ("pending-message", id).into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut result = v_stack()
|
v_stack()
|
||||||
.w_full()
|
.w_full()
|
||||||
.id(element_id)
|
.id(element_id)
|
||||||
.relative()
|
.relative()
|
||||||
|
.overflow_hidden()
|
||||||
.group("")
|
.group("")
|
||||||
.mb_1();
|
.when(!is_continuation_from_previous, |this| {
|
||||||
|
this.child(
|
||||||
if !is_continuation {
|
|
||||||
result = result.child(
|
|
||||||
h_stack()
|
h_stack()
|
||||||
|
.gap_2()
|
||||||
.child(Avatar::new(message.sender.avatar_uri.clone()))
|
.child(Avatar::new(message.sender.avatar_uri.clone()))
|
||||||
.child(Label::new(message.sender.github_login.clone()))
|
.child(Label::new(message.sender.github_login.clone()))
|
||||||
.child(Label::new(format_timestamp(
|
.child(
|
||||||
|
Label::new(format_timestamp(
|
||||||
message.timestamp,
|
message.timestamp,
|
||||||
now,
|
now,
|
||||||
self.local_timezone,
|
self.local_timezone,
|
||||||
))),
|
))
|
||||||
);
|
.color(Color::Muted),
|
||||||
}
|
),
|
||||||
|
)
|
||||||
result
|
})
|
||||||
|
.when(!is_continuation_to_next, |this|
|
||||||
|
// HACK: This should really be a margin, but margins seem to get collapsed.
|
||||||
|
this.pb_2())
|
||||||
.child(text.element("body".into(), cx))
|
.child(text.element("body".into(), cx))
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
|
@ -396,7 +409,6 @@ impl ChatPanel {
|
||||||
)
|
)
|
||||||
})),
|
})),
|
||||||
)
|
)
|
||||||
.into_any()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_markdown_with_mentions(
|
fn render_markdown_with_mentions(
|
||||||
|
|
|
@ -102,7 +102,8 @@ impl RenderOnce for TabBar {
|
||||||
.w_full()
|
.w_full()
|
||||||
.h(rems(HEIGHT_IN_REMS))
|
.h(rems(HEIGHT_IN_REMS))
|
||||||
.bg(cx.theme().colors().tab_bar_background)
|
.bg(cx.theme().colors().tab_bar_background)
|
||||||
.child(
|
.when(!self.start_children.is_empty(), |this| {
|
||||||
|
this.child(
|
||||||
h_stack()
|
h_stack()
|
||||||
.flex_none()
|
.flex_none()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
|
@ -112,6 +113,7 @@ impl RenderOnce for TabBar {
|
||||||
.border_color(cx.theme().colors().border)
|
.border_color(cx.theme().colors().border)
|
||||||
.children(self.start_children),
|
.children(self.start_children),
|
||||||
)
|
)
|
||||||
|
})
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.relative()
|
.relative()
|
||||||
|
@ -140,7 +142,8 @@ impl RenderOnce for TabBar {
|
||||||
.children(self.children),
|
.children(self.children),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.when(!self.end_children.is_empty(), |this| {
|
||||||
|
this.child(
|
||||||
h_stack()
|
h_stack()
|
||||||
.flex_none()
|
.flex_none()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
|
@ -150,5 +153,6 @@ impl RenderOnce for TabBar {
|
||||||
.border_color(cx.theme().colors().border)
|
.border_color(cx.theme().colors().border)
|
||||||
.children(self.end_children),
|
.children(self.end_children),
|
||||||
)
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue