Files
signed/crates/signed_app/src/inbox/helpers.rs
T
reya bc6e251b6d
Rust / build (macos-latest, stable) (push) Canceled after 0s
Rust / build (ubuntu-latest, stable) (push) Canceled after 0s
Rust / build (windows-latest, stable) (push) Canceled after 0s
Rust / build (macos-latest, stable) (pull_request) Canceled after 0s
Rust / build (ubuntu-latest, stable) (pull_request) Canceled after 0s
Rust / build (windows-latest, stable) (pull_request) Canceled after 0s
update gpui-native-kit and adopt text roles
2026-11-13 03:53:42 +07:00

194 lines
5.8 KiB
Rust

use assets::CustomIconName;
use gpui::prelude::FluentBuilder as _;
use gpui::{
AnyElement, App, Div, Entity, InteractiveElement as _, IntoElement, ParentElement as _,
SharedString, Stateful, Styled as _, div, px,
};
use gpui_native_kit::avatar::Avatar;
use gpui_native_kit::badge::Badge;
use gpui_native_kit::common::{Sizable as _, h_flex, v_flex};
use gpui_native_kit::icons::Icon;
use gpui_native_kit::theme::{ActiveTheme as _, TextRole, Typeset as _};
use metadata::ProfileDirectory;
use nostr::prelude::{Event, Kind, PublicKey};
use utils::relative_time;
pub fn repo_header(id: SharedString, name: SharedString, unread: usize, cx: &App) -> AnyElement {
h_flex()
.h_12()
.w_full()
.gap_2()
.child(
div()
.min_w_0()
.typeset(TextRole::Body, cx)
.whitespace_nowrap()
.text_ellipsis()
.child(name),
)
.when(unread > 0, |this| {
this.child(Badge::new(id.clone(), unread.to_string()))
})
.into_any_element()
}
pub fn empty_section_row(cx: &App) -> AnyElement {
h_flex()
.h_12()
.w_full()
.px_3()
.typeset(TextRole::Caption, cx)
.text_color(cx.theme().colors.muted_foreground)
.bg(cx.theme().colors.secondary)
.rounded(cx.theme().radius.control)
.child(SharedString::from("No activity yet."))
.into_any_element()
}
#[allow(clippy::too_many_arguments)]
pub fn thread(
prefix: &'static str,
ix: usize,
title: SharedString,
unread: bool,
first: bool,
last: bool,
events: Vec<Event>,
me: Option<PublicKey>,
directory: &Entity<ProfileDirectory>,
cx: &App,
) -> Stateful<Div> {
let mut timeline = v_flex().gap_2().w_full();
for event in events {
timeline = timeline.child(sub_activity(&event, me, directory, cx));
}
v_flex()
.id((prefix, ix))
.w_full()
.px_3()
.py_2()
.gap_2()
.bg(cx.theme().colors.secondary)
.when(first, |this| this.rounded_t(cx.theme().radius.control))
.when(last, |this| this.rounded_b(cx.theme().radius.control))
.when(!last, |this| {
this.border_b_1().border_color(cx.theme().colors.background)
})
.hover(|this| this.bg(cx.theme().colors.muted_hover))
.child(
h_flex()
.gap_2()
.typeset(TextRole::Body, cx)
.child(
h_flex()
.size_6()
.flex_shrink_0()
.items_center()
.justify_center()
.child(
Icon::named(CustomIconName::Inbox)
.small()
.color(cx.theme().colors.muted_foreground),
),
)
.child(
div()
.min_w_0()
.whitespace_nowrap()
.text_ellipsis()
.child(title),
)
.child(div().flex_1())
.when(unread, |this| {
this.child(
div()
.flex_shrink_0()
.size_2()
.rounded_full()
.bg(cx.theme().colors.primary),
)
}),
)
.child(timeline)
}
fn sub_activity(
event: &Event,
me: Option<PublicKey>,
directory: &Entity<ProfileDirectory>,
cx: &App,
) -> AnyElement {
let profile = directory.read(cx).profile(&event.pubkey, cx);
let name = if Some(event.pubkey) == me {
SharedString::from("You")
} else {
profile.name()
};
h_flex()
.w_full()
.gap_2()
.child(div().w_6().flex_shrink_0())
.child(
h_flex()
.flex_1()
.min_w_0()
.gap_1()
.typeset(TextRole::Caption, cx)
.child(
Avatar::new(event.pubkey)
.name(name.clone())
.picture(profile.picture())
.small(),
)
.child(name)
.child(SharedString::from(activity_phrase(event.kind)))
.child(div().flex_1())
.child(
div()
.text_color(cx.theme().colors.muted_foreground)
.child(SharedString::from(relative_time(event.created_at))),
),
)
.into_any_element()
}
fn activity_phrase(kind: Kind) -> &'static str {
match kind {
Kind::GitIssue => "opened an issue",
Kind::GitPullRequest => "opened a PR",
Kind::GitPullRequestUpdate => "updated a PR",
Kind::GitPatch => "created a patch",
Kind::Comment => "commented",
Kind::GitStatusOpen => "opened a status",
Kind::GitStatusApplied => "applied a status",
Kind::GitStatusClosed => "closed a status",
Kind::GitStatusDraft => "drafted a status",
_ => "did something",
}
}
pub fn empty_state(message: &'static str, cx: &App) -> AnyElement {
v_flex()
.w_full()
.flex_1()
.min_h_0()
.items_center()
.justify_center()
.gap_2()
.py_8()
.child(
Icon::named(CustomIconName::Inbox)
.size(px(24.))
.color(cx.theme().colors.muted_foreground),
)
.child(
div()
.typeset(TextRole::Body, cx)
.text_color(cx.theme().colors.muted_foreground)
.child(SharedString::from(message)),
)
.into_any_element()
}