Messaging · Channels: the chat list, its rows, a channel's head and its pins
ChannelList sets chats down in sections, each a list: a press, an arrow or Enter opens one, and the open chat is lit. A title names one section, and a section holds a chat. ChannelItem shows a hash or a lock, its unread count, a pin when pinned, and goes quiet when muted. DirectMessageItem shows a person's initials with their presence. Unread names stand out through ListItem's new strong; muted channels and offline people go quiet through its quiet. ChannelHeader holds the name and topic beside members, pins and a call, wrapping by the header rule. PinnedMessages lists pins newest first; a press, an arrow or Enter opens one, and Unpin lets one go. With none it shows a line and takes no Tab stop.
This commit is contained in:
1 parent
85df47fd5c
commit
cd14b32dfe
11 files changed
+1188
-17
No files matched your search
@@ -0,0 +1,214 @@
|
||||
use ely_gpui_component::{
|
||||
data_display::Presence,
|
||||
messaging::{
|
||||
ChannelHeader, ChannelItem, ChannelList, DirectMessageItem, PinnedMessage, PinnedMessages,
|
||||
},
|
||||
};
|
||||
use gpui::{AnyElement, App, IntoElement, ParentElement, SharedString, Styled, Window, div, px};
|
||||
use jiff::{SignedDuration, Timestamp};
|
||||
|
||||
use super::Page;
|
||||
use crate::{
|
||||
probe::probe,
|
||||
script::Step,
|
||||
ui::{change, keep, section},
|
||||
};
|
||||
|
||||
pub const PAGE: Page = Page {
|
||||
number: 28,
|
||||
slug: "messaging",
|
||||
title: "Messaging",
|
||||
summary: "Channels and people: the lists and heads of chats, the messages in them, the people behind them, and calls.",
|
||||
render,
|
||||
script: SCRIPT,
|
||||
};
|
||||
|
||||
const SCRIPT: &[Step] = &[
|
||||
Step::DownAt("messaging-channels", 120.0, 150.0),
|
||||
Step::UpAt("messaging-channels", 120.0, 150.0),
|
||||
Step::Key("down"),
|
||||
Step::Wait(200),
|
||||
Step::Shot("channel-opened"),
|
||||
];
|
||||
|
||||
/// The demo's chats: which is open and what waits unread in each.
|
||||
#[derive(Clone)]
|
||||
struct Chats {
|
||||
open: SharedString,
|
||||
unread: Vec<(SharedString, u32)>,
|
||||
}
|
||||
|
||||
impl Chats {
|
||||
fn unread(&self, key: &str) -> u32 {
|
||||
self.unread
|
||||
.iter()
|
||||
.find(|(each, _)| each.as_ref() == key)
|
||||
.map_or(0, |(_, count)| *count)
|
||||
}
|
||||
}
|
||||
|
||||
fn channels(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
||||
let chats = keep(
|
||||
"messaging-chats",
|
||||
|| Chats {
|
||||
open: "design".into(),
|
||||
unread: vec![
|
||||
("atrium".into(), 4),
|
||||
("general".into(), 12),
|
||||
("random".into(), 31),
|
||||
("ben".into(), 2),
|
||||
],
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
let now = chats.read(cx).clone();
|
||||
let channel = |key: &'static str| ChannelItem::new(key, key).unread(now.unread(key));
|
||||
let open = chats.clone();
|
||||
section(
|
||||
"ChannelList / ChatList",
|
||||
"Channels and people in sections, each a list: a press, an arrow or Enter opens a chat and clears what waited. Unread names stand out; a muted channel keeps quiet.",
|
||||
cx,
|
||||
)
|
||||
.child(probe(
|
||||
"messaging-channels",
|
||||
div().w(px(260.)).child(
|
||||
ChannelList::new("messaging-channels")
|
||||
.section("Starred", [("atrium", channel("atrium").pinned(true))])
|
||||
.section(
|
||||
"Channels",
|
||||
[
|
||||
("design", channel("design")),
|
||||
("general", channel("general")),
|
||||
("launch", channel("launch").private()),
|
||||
("random", channel("random").muted(true)),
|
||||
],
|
||||
)
|
||||
.section(
|
||||
"Direct messages",
|
||||
[
|
||||
("ana", DirectMessageItem::new("ana", "Ana Lima", Presence::Online)),
|
||||
("ben", DirectMessageItem::new("ben", "Ben Ito", Presence::Away).unread(now.unread("ben"))),
|
||||
("chloe", DirectMessageItem::new("chloe", "Chloé Martin", Presence::Busy)),
|
||||
("dev", DirectMessageItem::new("dev", "Dev Rao", Presence::Offline)),
|
||||
],
|
||||
)
|
||||
.open(now.open)
|
||||
.on_open(move |key, _, cx| {
|
||||
change(&open, cx, |chats| {
|
||||
chats.open = key.clone();
|
||||
chats.unread.retain(|(each, _)| each != key);
|
||||
})
|
||||
}),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
fn items(cx: &mut App) -> impl IntoElement + use<> {
|
||||
section(
|
||||
"ChannelItem / DirectMessageItem",
|
||||
"A channel by its mark, a hash or a lock, with its unread count, quiet when muted, pinned with a pin; a person with their presence on their initials.",
|
||||
cx,
|
||||
)
|
||||
.child(probe(
|
||||
"messaging-items",
|
||||
div()
|
||||
.w(px(520.))
|
||||
.flex()
|
||||
.gap_6()
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
.min_w_0()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.child(ChannelItem::new("item-unread", "design").unread(3))
|
||||
.child(ChannelItem::new("item-private", "launch").private())
|
||||
.child(ChannelItem::new("item-muted", "random").unread(31).muted(true))
|
||||
.child(ChannelItem::new("item-pinned", "atrium").pinned(true)),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
.min_w_0()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.child(DirectMessageItem::new("dm-on", "Ana Lima", Presence::Online).unread(1))
|
||||
.child(DirectMessageItem::new("dm-away", "Ben Ito", Presence::Away))
|
||||
.child(DirectMessageItem::new("dm-busy", "Chloé Martin", Presence::Busy))
|
||||
.child(DirectMessageItem::new("dm-off", "Dev Rao", Presence::Offline)),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
fn header(cx: &mut App) -> impl IntoElement + use<> {
|
||||
section(
|
||||
"ChannelHeader",
|
||||
"A channel's name and topic, and beside them its members, its pins and a call; the actions drop below on a narrow window.",
|
||||
cx,
|
||||
)
|
||||
.child(probe(
|
||||
"messaging-header",
|
||||
div().w(px(640.)).child(
|
||||
ChannelHeader::new("messaging-header", "design")
|
||||
.topic("Where the atrium takes its shape: drawings, samples and the week's reviews")
|
||||
.members(12, |_, _| log::info!("gallery: members"))
|
||||
.pins(3, |_, _| log::info!("gallery: pins"))
|
||||
.on_call(|_, _| log::info!("gallery: call")),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
fn pins(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
|
||||
let now = Timestamp::now();
|
||||
let pin = |key: &str, author: &str, hours: i64, text: &str| PinnedMessage {
|
||||
key: SharedString::from(key.to_string()),
|
||||
author: SharedString::from(author.to_string()),
|
||||
at: now - SignedDuration::from_hours(hours),
|
||||
text: SharedString::from(text.to_string()),
|
||||
};
|
||||
let all = vec![
|
||||
pin(
|
||||
"review",
|
||||
"Ana Lima",
|
||||
3,
|
||||
"Friday's review moves to 10:00, in the model room.",
|
||||
),
|
||||
pin(
|
||||
"samples",
|
||||
"Ben Ito",
|
||||
30,
|
||||
"Plaster samples are in the stair hall. Please leave notes on the backs.",
|
||||
),
|
||||
pin(
|
||||
"brief",
|
||||
"Chloé Martin",
|
||||
200,
|
||||
"The brief, final: light from above, one stair, olive trees by the windows.",
|
||||
),
|
||||
];
|
||||
let kept = keep("messaging-pins", move || all, window, cx);
|
||||
let shown = kept.read(cx).clone();
|
||||
section(
|
||||
"PinnedMessages",
|
||||
"Messages pinned in a chat, newest first: a press, an arrow or Enter opens one where it stands; Unpin lets one go.",
|
||||
cx,
|
||||
)
|
||||
.child(probe(
|
||||
"messaging-pins",
|
||||
div().w(px(420.)).child(
|
||||
PinnedMessages::new("messaging-pins", shown)
|
||||
.on_open(|key, _, _| log::info!("gallery: open {key}"))
|
||||
.on_unpin(move |key, _, cx| change(&kept, cx, |all| all.retain(|pin| pin.key != *key))),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
fn render(window: &mut Window, cx: &mut App) -> AnyElement {
|
||||
div()
|
||||
.child(channels(window, cx))
|
||||
.child(items(cx))
|
||||
.child(header(cx))
|
||||
.child(pins(window, cx))
|
||||
.into_any_element()
|
||||
}
|
||||
@@ -17,6 +17,7 @@ mod layout;
|
||||
mod lists;
|
||||
mod media;
|
||||
mod menus;
|
||||
mod messaging;
|
||||
mod motion;
|
||||
mod navigation;
|
||||
mod overlays;
|
||||
@@ -69,6 +70,7 @@ pub const ALL: &[Page] = &[
|
||||
generative::PAGE,
|
||||
media::PAGE,
|
||||
files::PAGE,
|
||||
messaging::PAGE,
|
||||
theme::PAGE,
|
||||
];
|
||||
|
||||
|
||||
Reference in new issue
Block a user