Files
coop/crates/community_ui/src/message.rs
T
2026-09-20 09:45:15 +07:00

109 lines
3.6 KiB
Rust

use std::collections::BTreeMap;
use common::TimestampExt;
use community::ChatMessage;
use gpui::prelude::FluentBuilder;
use gpui::{
AnyElement, App, InteractiveElement, IntoElement, ParentElement, SharedString, Styled, div,
};
use nostr_sdk::prelude::*;
use person::PersonRegistry;
use settings::AppSettings;
use theme::ActiveTheme;
use ui::avatar::Avatar;
use ui::{StyledExt, h_flex, v_flex};
pub(crate) fn render(ix: usize, message: &ChatMessage, cx: &App) -> AnyElement {
let persons = PersonRegistry::global(cx);
let author = persons.read(cx).get(&message.author, cx);
let hide_avatar = AppSettings::get_hide_avatar(cx);
div()
.id(ix)
.w_full()
.py_1()
.px_3()
.hover(|this| this.bg(cx.theme().surface_background))
.child(
h_flex()
.items_start()
.gap_3()
.when(!hide_avatar, |this| {
this.child(
Avatar::new(author.avatar())
.seed(author.avatar_seed())
.flex_shrink_0(),
)
})
.child(
v_flex()
.flex_1()
.min_w_0()
.gap_0p5()
.child(
h_flex()
.gap_2()
.text_sm()
.child(div().font_semibold().child(author.name()))
.child(
div()
.text_color(cx.theme().text_placeholder)
.child(Timestamp::from_secs(message.at_ms / 1000).to_ago()),
)
.when(message.edited_at.is_some(), |this| {
this.child(
div()
.text_color(cx.theme().text_placeholder)
.child("(edited)"),
)
}),
)
.child(content(message, cx))
.when(!message.reactions.is_empty(), |this| {
this.child(reactions(message, cx))
}),
),
)
.into_any_element()
}
fn content(message: &ChatMessage, cx: &App) -> AnyElement {
if message.deleted {
return div()
.text_sm()
.text_color(cx.theme().text_placeholder)
.child("Message deleted")
.into_any_element();
}
div()
.text_sm()
.child(SharedString::from(message.content.clone()))
.into_any_element()
}
fn reactions(message: &ChatMessage, cx: &App) -> AnyElement {
let mut grouped: BTreeMap<&str, usize> = BTreeMap::new();
for emoji in message.reactions.values() {
*grouped.entry(emoji.as_str()).or_default() += 1;
}
h_flex()
.mt_1()
.gap_1()
.children(grouped.into_iter().map(|(emoji, count)| {
h_flex()
.gap_1()
.py_0p5()
.px_1()
.rounded(cx.theme().radius)
.border_1()
.border_color(cx.theme().border)
.text_xs()
.child(SharedString::from(emoji))
.child(SharedString::from(count.to_string()))
}))
.into_any_element()
}