This commit is contained in:
2026-10-21 16:20:51 +07:00
parent d0ad1a6f57
commit d7160e196e
46 changed files with 2307 additions and 1534 deletions
+12 -15
View File
@@ -2,10 +2,9 @@ use gpui::{
AnyElement, App, IntoElement, ParentElement, SharedString, Styled, WeakEntity, Window, div, px,
relative,
};
use gpui_kit::component::avatar::Avatar;
use gpui_kit::component::{ActiveTheme, Sizable, WindowExt, h_flex, v_flex};
use nip29::{Group, GroupMetadata};
use ui::{TextStyle, Typeset as _, control_radius};
use ui::Avatar;
pub(crate) fn open(group: WeakEntity<Group>, window: &mut Window, cx: &mut App) {
window.open_dialog(cx, move |this, _window, cx| {
@@ -22,10 +21,7 @@ fn body(group: &WeakEntity<Group>, cx: &App) -> AnyElement {
};
let group = entity.read(cx);
let mut body = v_flex()
.gap_3()
.text_style(TextStyle::Callout)
.child(header(group, cx));
let mut body = v_flex().gap_3().text_xs().child(header(group, cx));
if let Some(metadata) = group.metadata() {
if let Some(about) = metadata.about.as_ref() {
@@ -130,23 +126,24 @@ fn header(group: &Group, cx: &App) -> AnyElement {
h_flex()
.gap_3()
.items_center()
.child(match group.display_image() {
Some(picture) => Avatar::new().src(picture).large().into_any_element(),
None => Avatar::new().large().into_any_element(),
})
.child(
Avatar::new(group.display_image())
.seed(key.cache_tag())
.large(),
)
.child(
v_flex()
.min_w_0()
.child(
div()
.text_style(TextStyle::Body)
.text_sm()
.font_weight(gpui::FontWeight::SEMIBOLD)
.truncate()
.child(group.display_name()),
)
.child(
div()
.text_style(TextStyle::Caption)
.text_xs()
.text_color(cx.theme().muted_foreground)
.truncate()
.child(SharedString::from(format!(
@@ -164,7 +161,7 @@ fn section(label: &'static str, content: AnyElement, cx: &App) -> AnyElement {
.gap_1()
.child(
div()
.text_style(TextStyle::Caption)
.text_xs()
.font_weight(gpui::FontWeight::MEDIUM)
.text_color(cx.theme().muted_foreground)
.child(label),
@@ -185,10 +182,10 @@ fn chip(label: impl Into<SharedString>, cx: &App) -> AnyElement {
div()
.px_2()
.py_1()
.rounded(px(control_radius()))
.rounded(cx.theme().radius)
.bg(cx.theme().secondary)
.text_color(cx.theme().foreground)
.text_style(TextStyle::Caption)
.text_xs()
.line_height(relative(1.))
.child(label.into())
.into_any_element()
+2 -3
View File
@@ -11,7 +11,6 @@ use gpui_kit::component::notification::Notification;
use gpui_kit::component::{ActiveTheme, Sizable, WindowExt, h_flex, v_flex};
use nip29::{Group, Invite};
use nostr_sdk::prelude::SecretKey;
use ui::{TextStyle, Typeset as _};
use crate::util::{field, report};
@@ -48,7 +47,7 @@ fn body(group: WeakEntity<Group>, input: Entity<InputState>, cx: &App) -> impl I
v_flex()
.gap_3()
.text_style(TextStyle::Callout)
.text_xs()
.child(
div()
.text_color(cx.theme().muted_foreground)
@@ -68,7 +67,7 @@ fn body(group: WeakEntity<Group>, input: Entity<InputState>, cx: &App) -> impl I
fn invite_row(group: WeakEntity<Group>, invite: &Invite, cx: &App) -> impl IntoElement {
let created = div()
.flex_shrink_0()
.text_style(TextStyle::Caption)
.text_xs()
.text_color(cx.theme().muted_foreground)
.child(invite.created_at.to_ago());
+32 -39
View File
@@ -11,7 +11,6 @@ use gpui::{
list, px,
};
use gpui_kit::assets::IconName;
use gpui_kit::component::avatar::Avatar;
use gpui_kit::component::button::{Button, ButtonVariant, ButtonVariants};
use gpui_kit::component::dialog::DialogButtonProps;
use gpui_kit::component::dock::{Panel, PanelEvent};
@@ -26,7 +25,7 @@ use serde::Deserialize;
use settings::AppSettings;
use smallvec::{SmallVec, smallvec};
use state::{NostrRegistry, upload};
use ui::{TextStyle, Typeset as _, control_radius};
use ui::Avatar;
use util::{attachment_name, display_name, opens_run, pin_label, report};
mod details;
@@ -209,7 +208,7 @@ pub fn confirm_leave(group: WeakEntity<Group>, window: &mut Window, cx: &mut App
)
.child(
div()
.text_style(TextStyle::Callout)
.text_xs()
.child("You will stop receiving messages from this group."),
)
.on_ok(move |_event, _window, cx| {
@@ -245,7 +244,7 @@ pub fn confirm_delete(group: WeakEntity<Group>, window: &mut Window, cx: &mut Ap
)
.child(
div()
.text_style(TextStyle::Callout)
.text_xs()
.child("The relay will remove this group for everyone."),
)
.on_ok(move |_event, window, cx| {
@@ -714,10 +713,10 @@ impl GroupPanel {
h_flex()
.flex_shrink_0()
.w_full()
.gap(px(ui::SPACE))
.gap_2()
.px_3()
.py_2()
.text_style(TextStyle::Callout)
.text_xs()
.border_b_1()
.border_color(cx.theme().border)
.child(
@@ -752,10 +751,10 @@ impl GroupPanel {
h_flex()
.flex_shrink_0()
.w_full()
.gap(px(ui::SPACE))
.gap_2()
.px_3()
.py_2()
.text_style(TextStyle::Callout)
.text_xs()
.bg(cx.theme().secondary)
.child(
Icon::new(IconName::Info)
@@ -819,9 +818,9 @@ impl GroupPanel {
div()
.px_1p5()
.py_0p5()
.rounded(px(control_radius()))
.rounded(cx.theme().radius)
.bg(cx.theme().primary)
.text_style(TextStyle::Caption)
.text_xs()
.text_color(cx.theme().muted_foreground)
.child(pin_label(group, pin))
}))
@@ -838,16 +837,12 @@ impl GroupPanel {
(
display_name(group),
match picture {
Some(picture) => Avatar::new().src(picture).large().into_any_element(),
None => Avatar::new().large().into_any_element(),
},
Avatar::new(picture.map(Into::into))
.seed(group.key().cache_tag())
.large(),
)
}
None => (
SharedString::from("this group"),
Avatar::new().large().into_any_element(),
),
None => (SharedString::from("this group"), Avatar::new(None).large()),
};
WelcomeMessage::new("welcome")
@@ -904,10 +899,10 @@ impl GroupPanel {
.w_full()
.justify_center()
.items_center()
.gap(px(ui::SPACE))
.gap_2()
.px_3()
.py_2()
.text_style(TextStyle::Callout)
.text_xs()
.text_color(cx.theme().muted_foreground);
match notice {
@@ -1117,9 +1112,9 @@ impl GroupPanel {
.gap_1()
.px_2()
.py_1()
.rounded(px(control_radius()))
.rounded(cx.theme().radius)
.bg(cx.theme().secondary)
.text_style(TextStyle::Caption)
.text_xs()
.child(
div()
.flex_shrink_0()
@@ -1170,8 +1165,8 @@ impl GroupPanel {
.px_2()
.border_1()
.border_color(cx.theme().border)
.rounded(px(control_radius()))
.text_style(TextStyle::Caption)
.rounded(cx.theme().radius)
.text_xs()
.text_color(cx.theme().muted_foreground)
.child(Icon::new(IconName::Link).xsmall())
.child(
@@ -1233,26 +1228,24 @@ impl Panel for GroupPanel {
.upgrade()
.map(|group| {
let group = group.read(cx);
let picture = group
.metadata()
.and_then(|metadata| metadata.picture.clone());
h_flex()
.gap_1()
.text_style(TextStyle::Caption)
.child(match picture {
Some(picture) => Avatar::new().src(picture).xsmall().into_any_element(),
None => Avatar::new().xsmall().into_any_element(),
})
.text_xs()
.child(
Avatar::new(
group
.metadata()
.and_then(|metadata| metadata.picture.clone())
.map(Into::into),
)
.seed(group.key().cache_tag())
.xsmall(),
)
.child(display_name(group))
.into_any_element()
})
.unwrap_or_else(|| {
div()
.text_style(TextStyle::Caption)
.child("Unknown")
.into_any_element()
})
.unwrap_or_else(|| div().text_xs().child("Unknown").into_any_element())
}
fn toolbar_buttons(
@@ -1296,7 +1289,7 @@ impl Render for GroupPanel {
None => h_flex()
.size_full()
.justify_center()
.text_style(TextStyle::Callout)
.text_xs()
.text_color(cx.theme().muted_foreground)
.child("No messages yet")
.into_any_element(),
+16 -21
View File
@@ -4,10 +4,9 @@ use common::TimestampExt;
use gpui::prelude::FluentBuilder;
use gpui::{
AnyElement, App, Entity, InteractiveElement, IntoElement, ParentElement, SharedString, Styled,
WeakEntity, div, px,
WeakEntity, div,
};
use gpui_kit::assets::IconName;
use gpui_kit::component::avatar::Avatar;
use gpui_kit::component::menu::{ContextMenuExt as _, PopupMenu, PopupMenuItem};
use gpui_kit::component::{ActiveTheme, Icon, Sizable, h_flex};
use nip29::{Activity, Group, Reaction};
@@ -15,7 +14,7 @@ use nostr_sdk::prelude::{EventId, Kind};
use person::Directory;
use settings::AppSettings;
use state::NostrRegistry;
use ui::{TextStyle, Typeset as _};
use ui::Avatar;
use crate::GroupPanel;
@@ -58,13 +57,11 @@ pub(crate) fn render(
let row = MessageRow::new(ix)
.show_author(show_author)
.hide_avatar(hide_avatar)
.avatar(match author.avatar() {
Some(picture) => Avatar::new()
.src(picture)
.flex_shrink_0()
.into_any_element(),
None => Avatar::new().flex_shrink_0().into_any_element(),
})
.avatar(
Avatar::new(author.avatar())
.seed(author.avatar_seed())
.flex_shrink_0(),
)
.author(author.name())
.timestamp(message.created_at.to_human_time())
.when(!message.replies_to.is_empty(), |this| {
@@ -217,26 +214,24 @@ pub(crate) fn render_activity(
h_flex()
.id(ix)
.w_full()
.gap(px(ui::SPACE))
.gap_2()
.py_1()
.px_3()
.hover(|this| this.bg(cx.theme().primary))
.child(badge(activity, cx))
.when(!hide_avatar, |this| {
this.child(match subject.avatar() {
Some(picture) => Avatar::new()
.src(picture)
this.child(
Avatar::new(subject.avatar())
.seed(subject.avatar_seed())
.small()
.flex_shrink_0()
.into_any_element(),
None => Avatar::new().small().flex_shrink_0().into_any_element(),
})
.flex_shrink_0(),
)
})
.child(
div()
.min_w_0()
.truncate()
.text_style(TextStyle::Callout)
.text_xs()
.font_weight(gpui::FontWeight::SEMIBOLD)
.child(subject.name()),
)
@@ -244,7 +239,7 @@ pub(crate) fn render_activity(
div()
.min_w_0()
.truncate()
.text_style(TextStyle::Callout)
.text_xs()
.text_color(cx.theme().muted_foreground)
.child(SharedString::from(action(activity))),
)
@@ -252,7 +247,7 @@ pub(crate) fn render_activity(
div()
.flex_shrink_0()
.ml_1()
.text_style(TextStyle::Caption)
.text_xs()
.text_color(cx.theme().muted_foreground)
.child(activity.created_at.to_ago()),
)
+3 -4
View File
@@ -4,7 +4,7 @@ use gpui::http_client::{AsyncBody, HttpClient};
use gpui::prelude::FluentBuilder;
use gpui::{
AnyElement, App, AppContext, Entity, IntoElement, ParentElement, SharedString, Styled,
WeakEntity, Window, div, px,
WeakEntity, Window, div,
};
use gpui_kit::component::button::{Button, ButtonVariants};
use gpui_kit::component::dialog::DialogButtonProps;
@@ -15,7 +15,6 @@ use gpui_kit::component::switch::Switch;
use gpui_kit::component::{ActiveTheme, Sizable, WindowExt, h_flex, v_flex};
use nip29::{Group, GroupId, GroupMetadata};
use nostr_sdk::prelude::RelayUrl;
use ui::{TextStyle, Typeset as _};
use crate::util::field;
@@ -126,7 +125,7 @@ pub(crate) fn open(group: WeakEntity<Group>, window: &mut Window, cx: &mut App)
.child(children_section(&children, cx))
.child(
v_flex()
.gap(px(ui::SPACE))
.gap_2()
.child(
form_field()
.label("Private")
@@ -287,7 +286,7 @@ fn children_section(children: &Entity<Vec<GroupId>>, cx: &App) -> AnyElement {
let mut section = v_flex()
.gap_1()
.text_style(TextStyle::Callout)
.text_xs()
.text_color(cx.theme().muted_foreground)
.child("Children");
+1 -2
View File
@@ -5,7 +5,6 @@ use gpui_kit::component::notification::Notification;
use gpui_kit::component::{ActiveTheme, WindowExt, v_flex};
use nip29::{Group, Pin, Row};
use nostr_sdk::prelude::Url;
use ui::{TextStyle, Typeset as _};
pub(crate) fn display_name(group: &Group) -> SharedString {
group
@@ -47,7 +46,7 @@ pub(crate) fn opens_run(rows: &[Row], index: usize) -> bool {
pub(crate) fn field(label: &'static str, input: &Entity<InputState>, cx: &App) -> Div {
v_flex()
.gap_1()
.text_style(TextStyle::Callout)
.text_xs()
.text_color(cx.theme().muted_foreground)
.child(label)
.child(Input::new(input))