chore: refine some ui components (#38)
Reviewed-on: https://git.reya.su/reya/coop/pulls/38
This commit was merged in pull request #38.
This commit is contained in:
@@ -15,4 +15,3 @@ anyhow.workspace = true
|
||||
smallvec.workspace = true
|
||||
flume.workspace = true
|
||||
log.workspace = true
|
||||
urlencoding = "2.1.3"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::RwLock;
|
||||
use instant::Duration;
|
||||
|
||||
use anyhow::{Error, anyhow};
|
||||
use common::EventExt;
|
||||
use gpui::{App, AppContext, Context, Entity, Global, Task, Window};
|
||||
use instant::Duration;
|
||||
use nostr_sdk::prelude::*;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use state::{Announcement, BOOTSTRAP_RELAYS, NostrRegistry, TIMEOUT};
|
||||
|
||||
@@ -5,8 +5,6 @@ use gpui::SharedString;
|
||||
use nostr_sdk::prelude::*;
|
||||
use state::Announcement;
|
||||
|
||||
const IMAGE_RESIZER: &str = "https://wsrv.nl";
|
||||
|
||||
/// Person
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Person {
|
||||
@@ -111,13 +109,7 @@ impl Person {
|
||||
.picture
|
||||
.as_ref()
|
||||
.filter(|picture| !picture.is_empty())
|
||||
.map(|picture| {
|
||||
let encoded_picture = urlencoding::encode(picture);
|
||||
let url = format!(
|
||||
"{IMAGE_RESIZER}/?url={encoded_picture}&w=100&h=100&fit=cover&mask=circle&n=-1"
|
||||
);
|
||||
url.into()
|
||||
})
|
||||
.map(|picture| picture.into())
|
||||
.unwrap_or_else(|| "brand/avatar.png".into())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
AbsoluteLength, App, Div, Hsla, ImageSource, Img, InteractiveElement, Interactivity,
|
||||
IntoElement, ParentElement, RenderOnce, StyleRefinement, Styled, StyledImage, Window, div, img,
|
||||
px,
|
||||
IntoElement, ObjectFit, ParentElement, RenderOnce, StyleRefinement, Styled, StyledImage,
|
||||
Window, div, img, px,
|
||||
};
|
||||
use theme::ActiveTheme;
|
||||
|
||||
@@ -26,9 +26,7 @@ pub(super) fn avatar_size(size: Size) -> AbsoluteLength {
|
||||
/// ```
|
||||
/// use ui::{Avatar};
|
||||
///
|
||||
/// Avatar::new("path/to/image.png")
|
||||
/// .grayscale(true)
|
||||
/// .border_color(gpui::red());
|
||||
/// Avatar::new("path/to/image.png").grayscale(true).border_color(gpui::red());
|
||||
/// ```
|
||||
#[derive(IntoElement)]
|
||||
pub struct Avatar {
|
||||
@@ -130,7 +128,7 @@ impl RenderOnce for Avatar {
|
||||
self.image
|
||||
.size(image_size)
|
||||
.rounded_full()
|
||||
.object_fit(gpui::ObjectFit::Fill)
|
||||
.object_fit(ObjectFit::Cover)
|
||||
.bg(cx.theme().ghost_element_background)
|
||||
.with_fallback(move || {
|
||||
img("brand/avatar.png")
|
||||
|
||||
@@ -51,7 +51,7 @@ impl Render for DragPanel {
|
||||
.overflow_hidden()
|
||||
.whitespace_nowrap()
|
||||
.rounded(cx.theme().radius)
|
||||
.text_xs()
|
||||
.text_sm()
|
||||
.text_color(cx.theme().text)
|
||||
.text_ellipsis()
|
||||
.when(cx.theme().shadow, |this| this.shadow_xs())
|
||||
@@ -312,6 +312,7 @@ impl TabPanel {
|
||||
|
||||
cx.emit(PanelEvent::ZoomOut);
|
||||
cx.emit(PanelEvent::LayoutChanged);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn detach_panel(
|
||||
@@ -321,10 +322,22 @@ impl TabPanel {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let panel_view = panel.view();
|
||||
let removed_ix = self.panels.iter().position(|p| p.view() == panel_view);
|
||||
self.panels.retain(|p| p.view() != panel_view);
|
||||
|
||||
if self.active_ix >= self.panels.len() {
|
||||
self.set_active_ix(self.panels.len().saturating_sub(1), window, cx)
|
||||
} else if let Some(removed_ix) = removed_ix {
|
||||
if removed_ix < self.active_ix {
|
||||
self.active_ix = self.active_ix.saturating_sub(1);
|
||||
} else if removed_ix == self.active_ix {
|
||||
// The active panel was removed and another panel shifted into
|
||||
// its position. Activate the new panel at the same index.
|
||||
if let Some(new_active) = self.panels.get(self.active_ix) {
|
||||
new_active.set_active(true, cx);
|
||||
}
|
||||
self.focus_active_panel(window, cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -613,7 +626,7 @@ impl TabPanel {
|
||||
div()
|
||||
.w_full()
|
||||
.text_ellipsis()
|
||||
.text_xs()
|
||||
.text_sm()
|
||||
.child(panel.title(cx)),
|
||||
)
|
||||
.when(state.draggable, |this| {
|
||||
@@ -687,8 +700,8 @@ impl TabPanel {
|
||||
.on_click(cx.listener({
|
||||
let panel = panel.clone();
|
||||
move |view, _ev, window, cx| {
|
||||
cx.stop_propagation();
|
||||
view.remove_panel(&panel, window, cx);
|
||||
view.set_active_ix(ix, window, cx);
|
||||
}
|
||||
})),
|
||||
)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use std::rc::Rc;
|
||||
use instant::Duration;
|
||||
|
||||
use gpui::prelude::FluentBuilder;
|
||||
use gpui::{
|
||||
@@ -7,6 +6,7 @@ use gpui::{
|
||||
InteractiveElement, IntoElement, KeyBinding, MouseButton, ParentElement, Pixels, Point,
|
||||
RenderOnce, SharedString, StyleRefinement, Styled, Window, anchored, div, hsla, point, px,
|
||||
};
|
||||
use instant::Duration;
|
||||
use theme::ActiveTheme;
|
||||
|
||||
use crate::actions::{Cancel, Confirm};
|
||||
@@ -359,8 +359,8 @@ impl RenderOnce for Modal {
|
||||
let y = self.margin_top.unwrap_or(view_size.height / 10.) + offset_top;
|
||||
let x = bounds.center().x - self.width / 2.;
|
||||
|
||||
let mut padding_right = px(8.);
|
||||
let mut padding_left = px(8.);
|
||||
let mut padding_right = px(16.);
|
||||
let mut padding_left = px(16.);
|
||||
|
||||
if let Some(pl) = self.style.padding.left {
|
||||
padding_left = pl.to_pixels(self.width.into(), window.rem_size());
|
||||
@@ -452,8 +452,8 @@ impl RenderOnce for Modal {
|
||||
.when_some(self.max_width, |this, w| this.max_w(w))
|
||||
.child(
|
||||
div()
|
||||
.px_2()
|
||||
.h_4()
|
||||
.px_4()
|
||||
.h_8()
|
||||
.w_full()
|
||||
.flex()
|
||||
.items_center()
|
||||
|
||||
@@ -183,12 +183,10 @@ impl RenderOnce for Tab {
|
||||
.items_center()
|
||||
.flex_shrink_0()
|
||||
.h(TABBAR_HEIGHT)
|
||||
.relative()
|
||||
.overflow_hidden()
|
||||
.text_color(fg)
|
||||
.text_sm()
|
||||
.when(!self.selected && !self.disabled, |this| {
|
||||
this.hover(|this| this.text_color(cx.theme().secondary_foreground))
|
||||
})
|
||||
.when_some(self.prefix, |this, prefix| this.child(prefix))
|
||||
.child(
|
||||
h_flex()
|
||||
@@ -222,5 +220,21 @@ impl RenderOnce for Tab {
|
||||
this.on_click(move |event, window, cx| on_click(event, window, cx))
|
||||
})
|
||||
})
|
||||
.child(
|
||||
div()
|
||||
.absolute()
|
||||
.bottom_0()
|
||||
.left_0()
|
||||
.right_0()
|
||||
.h_0p5()
|
||||
.when(self.selected && !self.disabled, |this| {
|
||||
this.bg(cx.theme().element_active)
|
||||
})
|
||||
.when(!self.selected && !self.disabled, |this| {
|
||||
this.invisible().group_hover("", |this| {
|
||||
this.visible().bg(cx.theme().secondary_background)
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ use theme::ActiveTheme;
|
||||
use ui::avatar::Avatar;
|
||||
use ui::button::{Button, ButtonVariants};
|
||||
use ui::indicator::Indicator;
|
||||
use ui::{Icon, IconName, Sizable, StyledExt, WindowExtension, h_flex, v_flex};
|
||||
use ui::{Disableable, Icon, IconName, Sizable, StyledExt, WindowExtension, h_flex, v_flex};
|
||||
|
||||
pub fn init(public_key: PublicKey, window: &mut Window, cx: &mut App) -> Entity<Screening> {
|
||||
cx.new(|cx| Screening::new(public_key, window, cx))
|
||||
@@ -263,7 +263,7 @@ impl Screening {
|
||||
let contacts = contacts.clone();
|
||||
let total = contacts.len();
|
||||
|
||||
this.title(SharedString::from("Mutual contacts")).child(
|
||||
this.title("Mutual contacts").child(
|
||||
v_flex().gap_1().pb_2().child(
|
||||
uniform_list("contacts", total, move |range, _window, cx| {
|
||||
let persons = PersonRegistry::global(cx);
|
||||
@@ -342,7 +342,7 @@ impl Render for Screening {
|
||||
.h_7()
|
||||
.justify_center()
|
||||
.rounded_full()
|
||||
.bg(cx.theme().surface_background)
|
||||
.bg(cx.theme().elevated_surface_background)
|
||||
.text_sm()
|
||||
.truncate()
|
||||
.text_ellipsis()
|
||||
@@ -355,7 +355,8 @@ impl Render for Screening {
|
||||
.gap_1()
|
||||
.child(
|
||||
Button::new("njump")
|
||||
.label("View on njump.me")
|
||||
.icon(IconName::Link)
|
||||
.label("njump.me")
|
||||
.secondary()
|
||||
.small()
|
||||
.rounded()
|
||||
@@ -386,21 +387,18 @@ impl Render for Screening {
|
||||
.text_sm()
|
||||
.child(status_badge(Some(self.followed), cx))
|
||||
.child(
|
||||
v_flex()
|
||||
.text_sm()
|
||||
.child(SharedString::from("Contact"))
|
||||
.child(
|
||||
div()
|
||||
.line_clamp(1)
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child({
|
||||
if self.followed {
|
||||
SharedString::from(CONTACT)
|
||||
} else {
|
||||
SharedString::from(NOT_CONTACT)
|
||||
}
|
||||
}),
|
||||
),
|
||||
v_flex().text_sm().child("Contact").child(
|
||||
div()
|
||||
.line_clamp(1)
|
||||
.text_color(cx.theme().text_muted)
|
||||
.child({
|
||||
if self.followed {
|
||||
SharedString::from(CONTACT)
|
||||
} else {
|
||||
SharedString::from(NOT_CONTACT)
|
||||
}
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
@@ -415,7 +413,7 @@ impl Render for Screening {
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_0p5()
|
||||
.child(SharedString::from("Activity on Public Relays"))
|
||||
.child("Activity on Public Relays")
|
||||
.child(
|
||||
Button::new("active")
|
||||
.icon(IconName::Info)
|
||||
@@ -484,25 +482,8 @@ impl Render for Screening {
|
||||
.gap_2()
|
||||
.child(status_badge(Some(mutuals > 0), cx))
|
||||
.child(
|
||||
v_flex()
|
||||
h_flex()
|
||||
.text_sm()
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_0p5()
|
||||
.child(SharedString::from("Mutual contacts"))
|
||||
.child(
|
||||
Button::new("mutuals")
|
||||
.icon(IconName::Info)
|
||||
.xsmall()
|
||||
.ghost()
|
||||
.rounded()
|
||||
.on_click(cx.listener(
|
||||
move |this, _, window, cx| {
|
||||
this.mutual_contacts(window, cx);
|
||||
},
|
||||
)),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.line_clamp(1)
|
||||
@@ -514,6 +495,17 @@ impl Render for Screening {
|
||||
SharedString::from(NO_MUTUAL)
|
||||
}
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
Button::new("mutuals")
|
||||
.icon(IconName::Info)
|
||||
.xsmall()
|
||||
.ghost()
|
||||
.rounded()
|
||||
.disabled(mutuals == 0)
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.mutual_contacts(window, cx);
|
||||
})),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -164,9 +164,7 @@ impl RenderOnce for RoomEntry {
|
||||
)
|
||||
.on_cancel(move |_event, window, cx| {
|
||||
window.dispatch_action(Box::new(ClosePanel), cx);
|
||||
// Prevent closing the modal on click
|
||||
// modal will be automatically closed after closing panel
|
||||
false
|
||||
true
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
@@ -354,6 +354,14 @@ impl Sidebar {
|
||||
cx.notify();
|
||||
});
|
||||
self.new_requests = false;
|
||||
|
||||
// Reset search state when switching to inbox/requests
|
||||
self.reset(window, cx);
|
||||
|
||||
// Clear the find input value
|
||||
self.find_input.update(cx, |this, cx| {
|
||||
this.set_value("", window, cx);
|
||||
});
|
||||
}
|
||||
|
||||
fn render_list_items(
|
||||
|
||||
Reference in New Issue
Block a user