migrate to gpui-component

This commit is contained in:
2026-06-02 18:15:54 +07:00
parent 5d4c8634ef
commit bac04ab4da
116 changed files with 1165 additions and 24445 deletions

View File

@@ -28,9 +28,7 @@ icons = [
[dependencies]
assets = { path = "../crates/assets" }
ui = { path = "../crates/ui" }
title_bar = { path = "../crates/title_bar" }
theme = { path = "../crates/theme" }
common = { path = "../crates/common" }
state = { path = "../crates/state" }
device = { path = "../crates/device" }
@@ -47,6 +45,7 @@ gpui_linux.workspace = true
gpui_windows.workspace = true
gpui_macos.workspace = true
gpui_tokio.workspace = true
gpui-component.workspace = true
reqwest_client.workspace = true
nostr-connect.workspace = true

View File

@@ -1,17 +1,17 @@
use anyhow::Error;
use common::CoopIcon;
use gpui::prelude::FluentBuilder;
use gpui::{
App, AppContext, Context, Entity, InteractiveElement, IntoElement, ParentElement, Render,
SharedString, StatefulInteractiveElement, Styled, Subscription, Task, Window, div, px,
};
use gpui_component::avatar::Avatar;
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::spinner::Spinner;
use gpui_component::{ActiveTheme, Disableable, Icon, Sizable, WindowExt, h_flex, v_flex};
use nostr_sdk::prelude::*;
use person::PersonRegistry;
use state::{NostrRegistry, StateEvent};
use theme::ActiveTheme;
use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants};
use ui::indicator::Indicator;
use ui::{Disableable, Icon, IconName, Sizable, WindowExtension, h_flex, v_flex};
use crate::dialogs::connect::ConnectSigner;
use crate::dialogs::import::ImportKey;
@@ -45,7 +45,7 @@ impl AccountSelector {
let subscription = cx.subscribe_in(&nostr, window, |this, _state, event, window, cx| {
match event {
StateEvent::SignerSet => {
window.close_all_modals(cx);
window.close_all_dialogs(cx);
window.refresh();
}
StateEvent::Error(e) => {
@@ -124,10 +124,10 @@ impl AccountSelector {
fn open_import(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let import = cx.new(|cx| ImportKey::new(window, cx));
window.open_modal(cx, move |this, _window, _cx| {
window.open_dialog(cx, move |this, _window, _cx| {
this.width(px(460.))
.title("Import a Secret Key or Bunker Connection")
.show_close(true)
.close_button(true)
.pb_2()
.child(import.clone())
});
@@ -136,10 +136,10 @@ impl AccountSelector {
fn open_connect(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let connect = cx.new(|cx| ConnectSigner::new(window, cx));
window.open_modal(cx, move |this, _window, _cx| {
window.open_dialog(cx, move |this, _window, _cx| {
this.width(px(460.))
.title("Scan QR Code to Connect")
.show_close(true)
.close_button(true)
.pb_2()
.child(connect.clone())
});
@@ -162,7 +162,7 @@ impl Render for AccountSelector {
.italic()
.text_xs()
.text_center()
.text_color(cx.theme().text_danger)
.text_color(cx.theme().danger_active)
.child(error.clone()),
)
})
@@ -182,15 +182,15 @@ impl Render for AccountSelector {
.justify_between()
.w_full()
.rounded(cx.theme().radius)
.bg(cx.theme().ghost_element_background)
.hover(|this| this.bg(cx.theme().ghost_element_hover))
.bg(cx.theme().secondary)
.hover(|this| this.bg(cx.theme().secondary_hover))
.child(
h_flex()
.gap_2()
.child(Avatar::new(profile.avatar()).small())
.child(Avatar::new().src(profile.avatar()).small())
.child(div().text_sm().child(profile.name())),
)
.when(logging_in, |this| this.child(Indicator::new().small()))
.when(logging_in, |this| this.child(Spinner::new().small()))
.when(!logging_in, |this| {
this.child(
h_flex()
@@ -199,7 +199,7 @@ impl Render for AccountSelector {
.group_hover("", |this| this.visible())
.child(
Button::new(format!("del-{ix}"))
.icon(IconName::Close)
.icon(CoopIcon::Close)
.ghost()
.small()
.disabled(logging_in)
@@ -224,7 +224,7 @@ impl Render for AccountSelector {
items
})
.child(div().w_full().h_px().bg(cx.theme().border_variant))
.child(div().w_full().h_px().bg(cx.theme().border))
.child(
h_flex()
.gap_1()
@@ -232,7 +232,7 @@ impl Render for AccountSelector {
.w_full()
.child(
Button::new("input")
.icon(Icon::new(IconName::Usb))
.icon(Icon::new(CoopIcon::Usb))
.label("Import")
.ghost()
.small()
@@ -243,7 +243,7 @@ impl Render for AccountSelector {
)
.child(
Button::new("qr")
.icon(Icon::new(IconName::Scan))
.icon(Icon::new(CoopIcon::Scan))
.label("Scan QR to connect")
.ghost()
.small()

View File

@@ -7,13 +7,12 @@ use gpui::{
AppContext, Context, Entity, Image, IntoElement, ParentElement, Render, SharedString, Styled,
Subscription, Window, div, img, px,
};
use gpui_component::{ActiveTheme, v_flex};
use nostr_connect::prelude::*;
use state::{
CLIENT_NAME, CoopAuthUrlHandler, NOSTR_CONNECT_RELAY, NOSTR_CONNECT_TIMEOUT, NostrRegistry,
StateEvent,
};
use theme::ActiveTheme;
use ui::v_flex;
pub struct ConnectSigner {
/// QR Code
@@ -101,14 +100,14 @@ impl Render for ConnectSigner {
div()
.text_xs()
.text_center()
.text_color(cx.theme().text_danger)
.text_color(cx.theme().danger_active)
.child(error.clone()),
)
})
.child(
div()
.text_xs()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from(MSG)),
)
}

View File

@@ -6,13 +6,12 @@ use gpui::{
AppContext, Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled,
Subscription, Task, Window, div,
};
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::input::{Input, InputEvent, InputState};
use gpui_component::{ActiveTheme, Disableable, v_flex};
use nostr_connect::prelude::*;
use smallvec::{SmallVec, smallvec};
use state::{CoopAuthUrlHandler, NostrRegistry, StateEvent};
use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants};
use ui::input::{InputEvent, InputState, TextInput};
use ui::{Disableable, v_flex};
#[derive(Debug)]
pub struct ImportKey {
@@ -248,9 +247,9 @@ impl Render for ImportKey {
v_flex()
.gap_1()
.text_sm()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child("nsec or bunker://")
.child(TextInput::new(&self.key_input)),
.child(Input::new(&self.key_input)),
)
.when(
self.key_input.read(cx).value().starts_with("ncryptsec1"),
@@ -259,9 +258,9 @@ impl Render for ImportKey {
v_flex()
.gap_1()
.text_sm()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child("Password:")
.child(TextInput::new(&self.pass_input)),
.child(Input::new(&self.pass_input)),
)
},
)
@@ -280,7 +279,7 @@ impl Render for ImportKey {
div()
.text_xs()
.text_center()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from(format!(
"Approve connection request from your signer in {} seconds",
i
@@ -292,7 +291,7 @@ impl Render for ImportKey {
div()
.text_xs()
.text_center()
.text_color(cx.theme().text_danger)
.text_color(cx.theme().danger_active)
.child(error.clone()),
)
})

View File

@@ -7,11 +7,10 @@ use gpui::{
AppContext, Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled,
Subscription, Task, Window, div,
};
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::input::{Input, InputEvent, InputState};
use gpui_component::{ActiveTheme, WindowExt, v_flex};
use nostr_connect::prelude::*;
use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants};
use ui::input::{InputEvent, InputState, TextInput};
use ui::{WindowExtension, v_flex};
#[derive(Debug)]
pub struct RestoreEncryption {
@@ -66,7 +65,7 @@ impl RestoreEncryption {
});
// Close the current modal
window.close_modal(cx);
window.close_dialog(cx);
}
fn set_error<S>(&mut self, message: S, cx: &mut Context<Self>)
@@ -105,9 +104,9 @@ impl Render for RestoreEncryption {
v_flex()
.gap_1()
.text_sm()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child("Secret Key")
.child(TextInput::new(&self.key_input)),
.child(Input::new(&self.key_input)),
)
.child(
Button::new("restore")
@@ -122,7 +121,7 @@ impl Render for RestoreEncryption {
div()
.text_xs()
.text_center()
.text_color(cx.theme().text_danger)
.text_color(cx.theme().danger_active)
.child(error.clone()),
)
})

View File

@@ -2,21 +2,20 @@ use std::collections::HashMap;
use std::time::Duration;
use anyhow::{Context as AnyhowContext, Error};
use common::TimestampExt;
use common::{CoopIcon, TimestampExt};
use gpui::prelude::FluentBuilder;
use gpui::{
App, AppContext, Context, Div, Entity, InteractiveElement, IntoElement, ParentElement, Render,
SharedString, Styled, Subscription, Task, Window, div, px, relative, uniform_list,
};
use gpui_component::avatar::Avatar;
use gpui_component::button::{Button, ButtonRounded, ButtonVariants};
use gpui_component::spinner::Spinner;
use gpui_component::{ActiveTheme, Icon, Sizable, StyledExt, WindowExt, h_flex, v_flex};
use nostr_sdk::prelude::*;
use person::{Person, PersonRegistry, shorten_pubkey};
use smallvec::{SmallVec, smallvec};
use state::{BOOTSTRAP_RELAYS, NostrAddress, NostrRegistry, TIMEOUT};
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};
pub fn init(public_key: PublicKey, window: &mut Window, cx: &mut App) -> Entity<Screening> {
cx.new(|cx| Screening::new(public_key, window, cx))
@@ -52,7 +51,7 @@ impl Screening {
subscriptions.push(cx.on_release_in(window, move |this, window, cx| {
this.tasks.clear();
window.close_all_modals(cx);
window.close_all_dialogs(cx);
}));
cx.defer_in(window, move |this, _window, cx| {
@@ -238,7 +237,7 @@ impl Screening {
self.tasks.push(cx.spawn_in(window, async move |_, cx| {
if task.await.is_ok() {
cx.update(|window, cx| {
window.close_modal(cx);
window.close_dialog(cx);
window.push_notification("Report submitted successfully", cx);
})
.ok();
@@ -249,7 +248,7 @@ impl Screening {
fn mutual_contacts(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let contacts = self.mutual_contacts.clone();
window.open_modal(cx, move |this, _window, _cx| {
window.open_dialog(cx, move |this, _window, _cx| {
let contacts = contacts.clone();
let total = contacts.len();
@@ -273,8 +272,8 @@ impl Screening {
.gap_1p5()
.rounded(cx.theme().radius)
.text_sm()
.hover(|this| this.bg(cx.theme().elevated_surface_background))
.child(Avatar::new(profile.avatar()).small())
.hover(|this| this.bg(cx.theme().muted))
.child(Avatar::new().src(profile.avatar()).small())
.child(profile.name()),
);
}
@@ -314,7 +313,7 @@ impl Render for Screening {
.items_center()
.justify_center()
.text_center()
.child(Avatar::new(profile.avatar()).large())
.child(Avatar::new().src(profile.avatar()).large())
.child(
div()
.font_semibold()
@@ -332,7 +331,8 @@ impl Render for Screening {
.h_7()
.justify_center()
.rounded_full()
.bg(cx.theme().surface_background)
.bg(cx.theme().muted)
.text_color(cx.theme().muted_foreground)
.text_sm()
.truncate()
.text_ellipsis()
@@ -348,7 +348,7 @@ impl Render for Screening {
.label("View on njump.me")
.secondary()
.small()
.rounded()
.rounded(ButtonRounded::Large)
.on_click(cx.listener(move |this, _e, window, cx| {
this.open_njump(window, cx);
})),
@@ -356,10 +356,10 @@ impl Render for Screening {
.child(
Button::new("report")
.tooltip("Report as a scam or impostor")
.icon(IconName::Warning)
.icon(CoopIcon::Warning)
.small()
.warning()
.rounded()
.rounded(ButtonRounded::Large)
.on_click(cx.listener(move |this, _e, window, cx| {
this.report(window, cx);
})),
@@ -382,7 +382,7 @@ impl Render for Screening {
.child(
div()
.line_clamp(1)
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child({
if self.followed {
SharedString::from(CONTACT)
@@ -408,10 +408,10 @@ impl Render for Screening {
.child(SharedString::from("Activity on Public Relays"))
.child(
Button::new("active")
.icon(IconName::Info)
.icon(CoopIcon::Info)
.xsmall()
.ghost()
.rounded()
.rounded(ButtonRounded::Large)
.tooltip(RELAY_INFO),
),
)
@@ -419,7 +419,7 @@ impl Render for Screening {
div()
.w_full()
.line_clamp(1)
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.map(|this| {
if let Some(t) = self.last_active {
this.child(SharedString::from(format!(
@@ -453,7 +453,7 @@ impl Render for Screening {
.child(
div()
.line_clamp(1)
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child({
if self.address(cx).is_some() {
if self.verified {
@@ -482,10 +482,10 @@ impl Render for Screening {
.child(SharedString::from("Mutual contacts"))
.child(
Button::new("mutuals")
.icon(IconName::Info)
.icon(CoopIcon::Info)
.xsmall()
.ghost()
.rounded()
.rounded(ButtonRounded::Large)
.on_click(cx.listener(
move |this, _, window, cx| {
this.mutual_contacts(window, cx);
@@ -496,7 +496,7 @@ impl Render for Screening {
.child(
div()
.line_clamp(1)
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child({
if mutuals > 0 {
SharedString::from(mutuals_str)
@@ -518,15 +518,15 @@ fn status_badge(status: Option<bool>, cx: &App) -> Div {
.flex_shrink_0()
.map(|this| {
if let Some(status) = status {
this.child(Icon::new(IconName::CheckCircle).small().text_color({
this.child(Icon::new(CoopIcon::CheckCircle).small().text_color({
if status {
cx.theme().icon_accent
cx.theme().primary_active
} else {
cx.theme().icon_muted
cx.theme().muted_foreground
}
}))
} else {
this.child(Indicator::new().small())
this.child(Spinner::new().small())
}
})
}

View File

@@ -1,17 +1,17 @@
use common::CoopIcon;
use gpui::http_client::Url;
use gpui::{
App, AppContext, Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled,
Window, div, px,
};
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::group_box::{GroupBox, GroupBoxVariants};
use gpui_component::input::{Input, InputState};
use gpui_component::menu::{DropdownMenu, PopupMenuItem};
use gpui_component::notification::Notification;
use gpui_component::switch::Switch;
use gpui_component::{ActiveTheme, Sizable, WindowExt, h_flex, v_flex};
use settings::{AppSettings, AuthMode};
use theme::{ActiveTheme, Theme, ThemeMode};
use ui::button::{Button, ButtonVariants};
use ui::group_box::{GroupBox, GroupBoxVariants};
use ui::input::{InputState, TextInput};
use ui::menu::{DropdownMenu, PopupMenuItem};
use ui::notification::Notification;
use ui::switch::Switch;
use ui::{IconName, Sizable, WindowExtension, h_flex, v_flex};
pub fn init(window: &mut Window, cx: &mut App) -> Entity<Preferences> {
cx.new(|cx| Preferences::new(window, cx))
@@ -46,12 +46,6 @@ impl Preferences {
}
}
}
/// Set the theme mode (light or dark)
fn set_theme_mode(mode: ThemeMode, window: &mut Window, cx: &mut App) {
AppSettings::update_theme_mode(mode, cx);
Theme::change(mode, Some(window), cx);
}
}
impl Render for Preferences {
@@ -68,7 +62,6 @@ impl Render for Preferences {
let screening = AppSettings::get_screening(cx);
let hide_avatar = AppSettings::get_hide_avatar(cx);
let auth_mode = AppSettings::get_auth_mode(cx);
let theme_mode = AppSettings::get_theme_mode(cx);
v_flex()
.gap_4()
@@ -80,7 +73,7 @@ impl Render for Preferences {
.child(
Switch::new("screening")
.label("Screening")
.description(SCREENING)
.tooltip(SCREENING)
.checked(screening)
.on_click(move |_, _window, cx| {
AppSettings::update_screening(!screening, cx);
@@ -89,7 +82,7 @@ impl Render for Preferences {
.child(
Switch::new("avatar")
.label("Hide user avatar")
.description(AVATAR)
.tooltip(AVATAR)
.checked(hide_avatar)
.on_click(move |_, _window, cx| {
AppSettings::update_hide_avatar(!hide_avatar, cx);
@@ -109,14 +102,14 @@ impl Render for Preferences {
.child(
div()
.text_xs()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from(AUTH)),
),
)
.child(
Button::new("auth")
.label(auth_mode.to_string())
.ghost_alt()
.ghost()
.small()
.dropdown_menu(|this, _window, _cx| {
this.min_w(px(256.))
@@ -157,28 +150,11 @@ impl Render for Preferences {
.child(
div()
.text_xs()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from(MODE)),
),
)
.child(
Button::new("theme-mode")
.label(theme_mode.name())
.ghost_alt()
.small()
.dropdown_menu(|this, _window, _cx| {
this.item(PopupMenuItem::new("Light").on_click(
|_, window, cx| {
Self::set_theme_mode(ThemeMode::Light, window, cx);
},
))
.item(
PopupMenuItem::new("Dark").on_click(|_, window, cx| {
Self::set_theme_mode(ThemeMode::Dark, window, cx);
}),
)
}),
),
.child(Button::new("theme-mode").label("Auto").ghost().small()),
)
.child(
h_flex()
@@ -190,21 +166,11 @@ impl Render for Preferences {
.child(
div()
.text_xs()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from(RESET)),
),
)
.child(
Button::new("reset")
.label("Reset")
.ghost_alt()
.small()
.on_click(move |_ev, window, cx| {
AppSettings::global(cx).update(cx, |this, cx| {
this.reset_theme(window, cx);
})
}),
),
.child(Button::new("reset").label("Reset").ghost().small()),
),
)
.child(
@@ -218,10 +184,10 @@ impl Render for Preferences {
.child(
h_flex()
.gap_1()
.child(TextInput::new(&self.file_input).text_xs().small())
.child(Input::new(&self.file_input).text_xs().small())
.child(
Button::new("update-file-server")
.icon(IconName::Check)
.icon(CoopIcon::Check)
.ghost()
.size_8()
.on_click(cx.listener(move |this, _ev, window, cx| {
@@ -233,7 +199,7 @@ impl Render for Preferences {
div()
.text_size(px(10.))
.italic()
.text_color(cx.theme().text_placeholder)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from("Only support blossom service")),
),
),

View File

@@ -6,9 +6,9 @@ use gpui::{
WindowBackgroundAppearance, WindowBounds, WindowDecorations, WindowKind, WindowOptions,
actions, point, px, size,
};
use gpui_component::Root;
use gpui_platform::application;
use state::{APP_ID, CLIENT_NAME};
use ui::Root;
mod dialogs;
mod panels;
@@ -75,10 +75,7 @@ fn main() {
gpui_tokio::init(cx);
// Initialize components
ui::init(cx);
// Initialize theme registry
theme::init(cx);
gpui_component::init(cx);
// Initialize settings
settings::init(window, cx);
@@ -104,7 +101,7 @@ fn main() {
auto_update::init(window, cx);
// Root Entity
Root::new(workspace::init(window, cx).into(), window, cx)
Root::new(workspace::init(window, cx), window, cx)
})
})
.expect("Failed to open window. Please restart the application.");

View File

@@ -1,17 +1,17 @@
use std::time::Duration;
use anyhow::Error;
use common::CoopIcon;
use gpui::{
AnyElement, App, AppContext, ClipboardItem, Context, Entity, EventEmitter, FocusHandle,
Focusable, IntoElement, ParentElement, Render, SharedString, Styled, Task, Window, div,
App, AppContext, ClipboardItem, Context, Entity, EventEmitter, FocusHandle, Focusable,
IntoElement, ParentElement, Render, SharedString, Styled, Task, Window, div,
};
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::dock::{Panel, PanelEvent};
use gpui_component::input::{Input, InputState};
use gpui_component::{ActiveTheme, Sizable, StyledExt, v_flex};
use nostr_sdk::prelude::*;
use state::KEYRING;
use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants};
use ui::dock::{Panel, PanelEvent};
use ui::input::{InputState, TextInput};
use ui::{IconName, Sizable, StyledExt, divider, v_flex};
const MSG: &str = "Store your account keys in a safe location. \
You can restore your account or move to another client anytime you want.";
@@ -22,7 +22,6 @@ pub fn init(window: &mut Window, cx: &mut App) -> Entity<BackupPanel> {
#[derive(Debug)]
pub struct BackupPanel {
name: SharedString,
focus_handle: FocusHandle,
/// Public key input
@@ -40,8 +39,8 @@ pub struct BackupPanel {
impl BackupPanel {
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
let npub_input = cx.new(|cx| InputState::new(window, cx).disabled(true));
let nsec_input = cx.new(|cx| InputState::new(window, cx).disabled(true).masked(true));
let npub_input = cx.new(|cx| InputState::new(window, cx));
let nsec_input = cx.new(|cx| InputState::new(window, cx).masked(true));
// Run at the end of current cycle
cx.defer_in(window, |this, window, cx| {
@@ -49,7 +48,6 @@ impl BackupPanel {
});
Self {
name: "Backup".into(),
focus_handle: cx.focus_handle(),
npub_input,
nsec_input,
@@ -108,12 +106,8 @@ impl BackupPanel {
}
impl Panel for BackupPanel {
fn panel_id(&self) -> SharedString {
self.name.clone()
}
fn title(&self, _cx: &App) -> AnyElement {
self.name.clone().into_any_element()
fn panel_name(&self) -> &'static str {
"Backup"
}
}
@@ -134,10 +128,10 @@ impl Render for BackupPanel {
.child(
div()
.text_xs()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from(MSG)),
)
.child(divider(cx))
.child(div().h_1().w_full().bg(cx.theme().border))
.child(
v_flex()
.gap_2()
@@ -152,11 +146,11 @@ impl Render for BackupPanel {
div()
.text_xs()
.font_semibold()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from("Public Key:")),
)
.child(
TextInput::new(&self.npub_input)
Input::new(&self.npub_input)
.small()
.bordered(false)
.disabled(true),
@@ -170,11 +164,11 @@ impl Render for BackupPanel {
div()
.text_xs()
.font_semibold()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from("Secret Key:")),
)
.child(
TextInput::new(&self.nsec_input)
Input::new(&self.nsec_input)
.small()
.bordered(false)
.disabled(true),
@@ -182,7 +176,7 @@ impl Render for BackupPanel {
)
.child(
Button::new("copy")
.icon(IconName::Copy)
.icon(CoopIcon::Copy)
.label({
if self.copied {
"Copied"

View File

@@ -2,22 +2,22 @@ use std::collections::HashSet;
use std::time::Duration;
use anyhow::{Context as AnyhowContext, Error};
use common::CoopIcon;
use gpui::prelude::FluentBuilder;
use gpui::{
AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable,
InteractiveElement, IntoElement, ParentElement, Render, SharedString, Styled, Subscription,
Task, TextAlign, Window, div, rems,
App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
IntoElement, ParentElement, Render, SharedString, Styled, Subscription, Task, TextAlign,
Window, div, rems,
};
use gpui_component::avatar::Avatar;
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::dock::{Panel, PanelEvent};
use gpui_component::input::{Input, InputEvent, InputState};
use gpui_component::{ActiveTheme, Disableable, Sizable, StyledExt, WindowExt, h_flex, v_flex};
use nostr_sdk::prelude::*;
use person::PersonRegistry;
use smallvec::{SmallVec, smallvec};
use state::NostrRegistry;
use theme::ActiveTheme;
use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants};
use ui::dock::{Panel, PanelEvent};
use ui::input::{InputEvent, InputState, TextInput};
use ui::{Disableable, IconName, Sizable, StyledExt, WindowExtension, h_flex, v_flex};
pub fn init(window: &mut Window, cx: &mut App) -> Entity<ContactListPanel> {
cx.new(|cx| ContactListPanel::new(window, cx))
@@ -25,7 +25,6 @@ pub fn init(window: &mut Window, cx: &mut App) -> Entity<ContactListPanel> {
#[derive(Debug)]
pub struct ContactListPanel {
name: SharedString,
focus_handle: FocusHandle,
/// Npub input
@@ -67,7 +66,6 @@ impl ContactListPanel {
});
Self {
name: "Contact List".into(),
focus_handle: cx.focus_handle(),
input,
updating: false,
@@ -217,18 +215,18 @@ impl ContactListPanel {
.px_2()
.justify_between()
.rounded(cx.theme().radius)
.bg(cx.theme().secondary_background)
.bg(cx.theme().secondary)
.text_color(cx.theme().secondary_foreground)
.child(
h_flex()
.gap_2()
.text_sm()
.child(Avatar::new(profile.avatar()).small())
.child(Avatar::new().src(profile.avatar()).small())
.child(profile.name()),
)
.child(
Button::new("remove_{ix}")
.icon(IconName::Close)
.icon(CoopIcon::Close)
.xsmall()
.ghost()
.invisible()
@@ -261,12 +259,8 @@ impl ContactListPanel {
}
impl Panel for ContactListPanel {
fn panel_id(&self) -> SharedString {
self.name.clone()
}
fn title(&self, _cx: &App) -> AnyElement {
self.name.clone().into_any_element()
fn panel_name(&self) -> &'static str {
"Contact List"
}
}
@@ -290,7 +284,7 @@ impl Render for ContactListPanel {
div()
.text_xs()
.font_semibold()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from("New contact:")),
)
.child(
@@ -301,14 +295,14 @@ impl Render for ContactListPanel {
.gap_1()
.w_full()
.child(
TextInput::new(&self.input)
Input::new(&self.input)
.small()
.bordered(false)
.cleanable(),
.cleanable(true),
)
.child(
Button::new("add")
.icon(IconName::Plus)
.icon(CoopIcon::Plus)
.tooltip("Add contact")
.ghost()
.size(rems(2.))
@@ -322,7 +316,7 @@ impl Render for ContactListPanel {
div()
.italic()
.text_xs()
.text_color(cx.theme().text_danger)
.text_color(cx.theme().danger_active)
.child(error.clone()),
)
}),
@@ -342,7 +336,7 @@ impl Render for ContactListPanel {
})
.child(
Button::new("submit")
.icon(IconName::CheckCircle)
.icon(CoopIcon::CheckCircle)
.label("Update")
.primary()
.small()

View File

@@ -1,12 +1,12 @@
use common::CoopIcon;
use gpui::{
AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable,
IntoElement, ParentElement, Render, SharedString, Styled, Window, div, svg,
App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable, IntoElement,
ParentElement, Render, SharedString, Styled, Window, div, svg,
};
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::dock::{DockPlacement, Panel, PanelEvent};
use gpui_component::{ActiveTheme, Icon, Sizable, StyledExt, h_flex, v_flex};
use state::NostrRegistry;
use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants};
use ui::dock::{DockPlacement, Panel, PanelEvent};
use ui::{Icon, IconName, Sizable, StyledExt, h_flex, v_flex};
use crate::panels::profile;
use crate::workspace::Workspace;
@@ -16,14 +16,12 @@ pub fn init(window: &mut Window, cx: &mut App) -> Entity<GreeterPanel> {
}
pub struct GreeterPanel {
name: SharedString,
focus_handle: FocusHandle,
}
impl GreeterPanel {
fn new(_window: &mut Window, cx: &mut App) -> Self {
Self {
name: "Onboarding".into(),
focus_handle: cx.focus_handle(),
}
}
@@ -50,19 +48,17 @@ impl GreeterPanel {
}
impl Panel for GreeterPanel {
fn panel_id(&self) -> SharedString {
self.name.clone()
fn panel_name(&self) -> &'static str {
"Greeter"
}
fn title(&self, cx: &App) -> AnyElement {
div()
.child(
svg()
.path("brand/coop.svg")
.size_4()
.text_color(cx.theme().text_muted),
)
.into_any_element()
fn title(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div().child(
svg()
.path("brand/coop.svg")
.size_4()
.text_color(cx.theme().muted_foreground),
)
}
}
@@ -100,20 +96,15 @@ impl Render for GreeterPanel {
svg()
.path("brand/coop.svg")
.size_12()
.text_color(cx.theme().icon_muted),
.text_color(cx.theme().muted),
)
.child(
v_flex()
.child(
div()
.font_semibold()
.text_color(cx.theme().text)
.child(SharedString::from(TITLE)),
)
.child(div().font_semibold().child(SharedString::from(TITLE)))
.child(
div()
.text_xs()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from(DESCRIPTION)),
),
),
@@ -128,7 +119,7 @@ impl Render for GreeterPanel {
.w_full()
.text_xs()
.font_semibold()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from("Get Started"))
.child(div().flex_1().h_px().bg(cx.theme().border)),
)
@@ -138,7 +129,7 @@ impl Render for GreeterPanel {
.w_full()
.child(
Button::new("profile")
.icon(Icon::new(IconName::Profile))
.icon(Icon::new(CoopIcon::Profile))
.label("Update profile")
.ghost()
.small()
@@ -149,7 +140,7 @@ impl Render for GreeterPanel {
)
.child(
Button::new("invite")
.icon(Icon::new(IconName::Invite))
.icon(Icon::new(CoopIcon::Invite))
.label("Invite friends")
.ghost()
.small()

View File

@@ -2,20 +2,20 @@ use std::collections::HashSet;
use std::time::Duration;
use anyhow::{Context as AnyhowContext, Error, anyhow};
use common::CoopIcon;
use gpui::prelude::FluentBuilder;
use gpui::{
AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable,
InteractiveElement, IntoElement, ParentElement, Render, SharedString, Styled, Subscription,
Task, TextAlign, Window, div, rems,
App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
IntoElement, ParentElement, Render, SharedString, Styled, Subscription, Task, TextAlign,
Window, div, rems,
};
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::dock::{Panel, PanelEvent};
use gpui_component::input::{Input, InputEvent, InputState};
use gpui_component::{ActiveTheme, Disableable, Sizable, StyledExt, WindowExt, h_flex, v_flex};
use nostr_sdk::prelude::*;
use smallvec::{SmallVec, smallvec};
use state::NostrRegistry;
use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants};
use ui::dock::{Panel, PanelEvent};
use ui::input::{InputEvent, InputState, TextInput};
use ui::{Disableable, IconName, Sizable, StyledExt, WindowExtension, divider, h_flex, v_flex};
const MSG: &str = "Messaging Relays are relays that hosted all your messages. \
Other users will find your relays and send messages to it.";
@@ -26,7 +26,6 @@ pub fn init(window: &mut Window, cx: &mut App) -> Entity<MessagingRelayPanel> {
#[derive(Debug)]
pub struct MessagingRelayPanel {
name: SharedString,
focus_handle: FocusHandle,
/// Relay URL input
@@ -68,7 +67,6 @@ impl MessagingRelayPanel {
});
Self {
name: "Update Messaging Relays".into(),
focus_handle: cx.focus_handle(),
input,
updating: false,
@@ -228,12 +226,12 @@ impl MessagingRelayPanel {
.px_2()
.justify_between()
.rounded(cx.theme().radius)
.bg(cx.theme().secondary_background)
.bg(cx.theme().secondary)
.text_color(cx.theme().secondary_foreground)
.child(div().text_sm().child(SharedString::from(url.to_string())))
.child(
Button::new("remove_{ix}")
.icon(IconName::Close)
.icon(CoopIcon::Close)
.xsmall()
.ghost()
.invisible()
@@ -266,12 +264,8 @@ impl MessagingRelayPanel {
}
impl Panel for MessagingRelayPanel {
fn panel_id(&self) -> SharedString {
self.name.clone()
}
fn title(&self, _cx: &App) -> AnyElement {
self.name.clone().into_any_element()
fn panel_name(&self) -> &'static str {
"Update Messaging Relays"
}
}
@@ -292,10 +286,10 @@ impl Render for MessagingRelayPanel {
.child(
div()
.text_xs()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from(MSG)),
)
.child(divider(cx))
.child(div().h_1().w_full().bg(cx.theme().border))
.child(
v_flex()
.gap_2()
@@ -306,7 +300,7 @@ impl Render for MessagingRelayPanel {
div()
.text_xs()
.font_semibold()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from("Relays:")),
)
.child(
@@ -317,14 +311,14 @@ impl Render for MessagingRelayPanel {
.gap_1()
.w_full()
.child(
TextInput::new(&self.input)
Input::new(&self.input)
.small()
.bordered(false)
.cleanable(),
.bordered(true)
.cleanable(true),
)
.child(
Button::new("add")
.icon(IconName::Plus)
.icon(CoopIcon::Plus)
.tooltip("Add relay")
.ghost()
.size(rems(2.))
@@ -338,7 +332,7 @@ impl Render for MessagingRelayPanel {
div()
.italic()
.text_xs()
.text_color(cx.theme().text_danger)
.text_color(cx.theme().danger_active)
.child(error.clone()),
)
}),
@@ -358,7 +352,7 @@ impl Render for MessagingRelayPanel {
})
.child(
Button::new("submit")
.icon(IconName::CheckCircle)
.icon(CoopIcon::CheckCircle)
.label("Update")
.primary()
.small()

View File

@@ -2,22 +2,21 @@ use std::str::FromStr;
use std::time::Duration;
use anyhow::{Context as AnyhowContext, Error};
use common::CoopIcon;
use gpui::{
AnyElement, App, AppContext, ClipboardItem, Context, Entity, EventEmitter, FocusHandle,
Focusable, IntoElement, ParentElement, PathPromptOptions, Render, SharedString, Styled, Task,
Window, div,
App, AppContext, ClipboardItem, Context, Entity, EventEmitter, FocusHandle, Focusable,
IntoElement, ParentElement, PathPromptOptions, Render, SharedString, Styled, Task, Window, div,
};
use gpui_component::avatar::Avatar;
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::dock::{Panel, PanelEvent};
use gpui_component::input::{Input, InputState};
use gpui_component::notification::Notification;
use gpui_component::{ActiveTheme, Disableable, Sizable, StyledExt, WindowExt, h_flex, v_flex};
use nostr_sdk::prelude::*;
use person::{Person, PersonRegistry, shorten_pubkey};
use settings::AppSettings;
use state::{NostrRegistry, upload};
use theme::ActiveTheme;
use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants};
use ui::dock::{Panel, PanelEvent};
use ui::input::{InputState, TextInput};
use ui::notification::Notification;
use ui::{Disableable, IconName, Sizable, StyledExt, WindowExtension, h_flex, v_flex};
pub fn init(public_key: PublicKey, window: &mut Window, cx: &mut App) -> Entity<ProfilePanel> {
cx.new(|cx| ProfilePanel::new(public_key, window, cx))
@@ -25,7 +24,6 @@ pub fn init(public_key: PublicKey, window: &mut Window, cx: &mut App) -> Entity<
#[derive(Debug)]
pub struct ProfilePanel {
name: SharedString,
focus_handle: FocusHandle,
/// User's public key
@@ -65,7 +63,7 @@ impl ProfilePanel {
// Use multi-line input for bio
let bio_input = cx.new(|cx| {
InputState::new(window, cx)
.multi_line()
.multi_line(true)
.auto_grow(3, 8)
.placeholder("A short introduce about you.")
});
@@ -76,7 +74,6 @@ impl ProfilePanel {
});
Self {
name: "Update Profile".into(),
focus_handle: cx.focus_handle(),
public_key,
name_input,
@@ -286,12 +283,8 @@ impl ProfilePanel {
}
impl Panel for ProfilePanel {
fn panel_id(&self) -> SharedString {
self.name.clone()
}
fn title(&self, _cx: &App) -> AnyElement {
self.name.clone().into_any_element()
fn panel_name(&self) -> &'static str {
"Update Profile"
}
}
@@ -328,14 +321,13 @@ impl Render for ProfilePanel {
.items_center()
.justify_center()
.gap_4()
.child(Avatar::new(avatar).large())
.child(Avatar::new().src(avatar).large())
.child(
Button::new("upload")
.icon(IconName::PlusCircle)
.icon(CoopIcon::PlusCircle)
.label("Add an avatar")
.xsmall()
.ghost()
.rounded()
.disabled(self.uploading)
.loading(self.uploading)
.on_click(cx.listener(move |this, _, window, cx| {
@@ -349,10 +341,10 @@ impl Render for ProfilePanel {
.child(
div()
.text_sm()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from("What should people call you?")),
)
.child(TextInput::new(&self.name_input).bordered(false).small()),
.child(Input::new(&self.name_input).bordered(false).small()),
)
.child(
v_flex()
@@ -360,10 +352,10 @@ impl Render for ProfilePanel {
.child(
div()
.text_sm()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from("A short introduction about you:")),
)
.child(TextInput::new(&self.bio_input).bordered(false).small()),
.child(Input::new(&self.bio_input).bordered(false).small()),
)
.child(
v_flex()
@@ -371,10 +363,10 @@ impl Render for ProfilePanel {
.child(
div()
.text_sm()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from("Website:")),
)
.child(TextInput::new(&self.website_input).bordered(false).small()),
.child(Input::new(&self.website_input).bordered(false).small()),
)
.child(
v_flex()
@@ -382,7 +374,7 @@ impl Render for ProfilePanel {
.child(
div()
.text_sm()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from("Public Key:")),
)
.child(
@@ -392,7 +384,7 @@ impl Render for ProfilePanel {
.justify_center()
.gap_3()
.rounded(cx.theme().radius)
.bg(cx.theme().secondary_background)
.bg(cx.theme().secondary)
.text_sm()
.text_color(cx.theme().secondary_foreground)
.child(shorten_pkey)
@@ -400,9 +392,9 @@ impl Render for ProfilePanel {
Button::new("copy")
.icon({
if self.copied {
IconName::CheckCircle
CoopIcon::CheckCircle
} else {
IconName::Copy
CoopIcon::Copy
}
})
.xsmall()
@@ -415,7 +407,7 @@ impl Render for ProfilePanel {
)
.child(
Button::new("submit")
.icon(IconName::CheckCircle)
.icon(CoopIcon::CheckCircle)
.label("Update")
.primary()
.small()

View File

@@ -2,22 +2,22 @@ use std::collections::HashSet;
use std::time::Duration;
use anyhow::{Context as AnyhowContext, Error, anyhow};
use common::CoopIcon;
use gpui::prelude::FluentBuilder;
use gpui::{
Action, AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable,
Action, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable,
InteractiveElement, IntoElement, ParentElement, Render, SharedString, Styled, Subscription,
Task, TextAlign, Window, div, px, rems,
};
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::dock::{Panel, PanelEvent};
use gpui_component::input::{Input, InputEvent, InputState};
use gpui_component::menu::DropdownMenu;
use gpui_component::{ActiveTheme, Disableable, Sizable, StyledExt, WindowExt, h_flex, v_flex};
use nostr_sdk::prelude::*;
use serde::Deserialize;
use smallvec::{SmallVec, smallvec};
use state::NostrRegistry;
use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants};
use ui::dock::{Panel, PanelEvent};
use ui::input::{InputEvent, InputState, TextInput};
use ui::menu::DropdownMenu;
use ui::{Disableable, IconName, Sizable, StyledExt, WindowExtension, divider, h_flex, v_flex};
const MSG: &str = "Relay List (or Gossip Relays) are a set of relays \
where you will publish all your events. Others also publish events \
@@ -259,7 +259,7 @@ impl RelayListPanel {
.px_2()
.justify_between()
.rounded(cx.theme().radius)
.bg(cx.theme().secondary_background)
.bg(cx.theme().secondary)
.text_color(cx.theme().secondary_foreground)
.child(
h_flex()
@@ -284,7 +284,7 @@ impl RelayListPanel {
)
.child(
Button::new("remove_{ix}")
.icon(IconName::Close)
.icon(CoopIcon::Close)
.xsmall()
.ghost()
.invisible()
@@ -317,12 +317,12 @@ impl RelayListPanel {
}
impl Panel for RelayListPanel {
fn panel_id(&self) -> SharedString {
self.name.clone()
fn panel_name(&self) -> &'static str {
"Relay List"
}
fn title(&self, _cx: &App) -> AnyElement {
self.name.clone().into_any_element()
fn title(&mut self, window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
self.name.clone()
}
}
@@ -344,10 +344,10 @@ impl Render for RelayListPanel {
.child(
div()
.text_xs()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from(MSG)),
)
.child(divider(cx))
.child(div().h_1().w_full().bg(cx.theme().border))
.child(
v_flex()
.gap_2()
@@ -358,7 +358,7 @@ impl Render for RelayListPanel {
div()
.text_xs()
.font_semibold()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from("Relays:")),
)
.child(
@@ -369,10 +369,10 @@ impl Render for RelayListPanel {
.gap_1()
.w_full()
.child(
TextInput::new(&self.input)
Input::new(&self.input)
.small()
.bordered(false)
.cleanable(),
.cleanable(true),
)
.child(
Button::new("metadata")
@@ -394,7 +394,7 @@ impl Render for RelayListPanel {
)
.child(
Button::new("add")
.icon(IconName::Plus)
.icon(CoopIcon::Plus)
.tooltip("Add relay")
.ghost()
.size(rems(2.))
@@ -408,7 +408,7 @@ impl Render for RelayListPanel {
div()
.italic()
.text_xs()
.text_color(cx.theme().text_danger)
.text_color(cx.theme().danger_active)
.child(error.clone()),
)
}),
@@ -428,7 +428,7 @@ impl Render for RelayListPanel {
})
.child(
Button::new("submit")
.icon(IconName::CheckCircle)
.icon(CoopIcon::CheckCircle)
.label("Update")
.primary()
.small()

View File

@@ -1,23 +1,21 @@
use chat::ChatRegistry;
use common::CoopIcon;
use gpui::{
AnyElement, App, AppContext, ClipboardItem, Context, Entity, EventEmitter, FocusHandle,
Focusable, InteractiveElement, IntoElement, ListAlignment, ListState, ParentElement, Render,
SharedString, Styled, Window, div, list, px, relative,
Styled, Window, div, list, px, relative,
};
use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants};
use ui::dock::{Panel, PanelEvent};
use ui::scroll::Scrollbar;
use ui::{Icon, IconName, Sizable, h_flex, v_flex};
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::dock::{Panel, PanelEvent};
use gpui_component::scroll::Scrollbar;
use gpui_component::{ActiveTheme, Icon, Sizable, h_flex, v_flex};
pub fn init(window: &mut Window, cx: &mut App) -> Entity<TrashPanel> {
cx.new(|cx| TrashPanel::new(window, cx))
}
pub struct TrashPanel {
name: SharedString,
focus_handle: FocusHandle,
/// List state for messages
list_state: ListState,
}
@@ -29,7 +27,6 @@ impl TrashPanel {
let list_state = ListState::new(count, ListAlignment::Bottom, px(1024.));
Self {
name: "Trash".into(),
focus_handle: cx.focus_handle(),
list_state,
}
@@ -65,11 +62,11 @@ impl TrashPanel {
.w_full()
.gap_1()
.rounded(cx.theme().radius_lg)
.bg(cx.theme().surface_background)
.bg(cx.theme().muted)
.text_sm()
.child(
div()
.text_color(cx.theme().text_danger)
.text_color(cx.theme().muted_foreground)
.child(message.reason.clone()),
)
.child(
@@ -78,7 +75,7 @@ impl TrashPanel {
.w_full()
.px_2()
.justify_between()
.bg(cx.theme().elevated_surface_background)
.bg(cx.theme().muted)
.border_1()
.border_color(cx.theme().border)
.rounded(cx.theme().radius)
@@ -92,7 +89,7 @@ impl TrashPanel {
)
.child(
Button::new(format!("copy-{ix}"))
.icon(IconName::Copy)
.icon(CoopIcon::Copy)
.ghost()
.small()
.on_click(cx.listener(move |this, _ev, _window, cx| {
@@ -109,17 +106,16 @@ impl TrashPanel {
}
impl Panel for TrashPanel {
fn panel_id(&self) -> SharedString {
self.name.clone()
fn panel_name(&self) -> &'static str {
"Trash"
}
fn title(&self, _cx: &App) -> AnyElement {
fn title(&mut self, window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
h_flex()
.gap_1()
.text_sm()
.child(Icon::new(IconName::Warning).small())
.child(Icon::new(CoopIcon::Warning).small())
.child("Errors")
.into_any_element()
}
}

View File

@@ -1,18 +1,18 @@
use std::rc::Rc;
use chat::RoomKind;
use common::CoopIcon;
use gpui::prelude::FluentBuilder;
use gpui::{
App, ClickEvent, InteractiveElement, IntoElement, ParentElement as _, RenderOnce, SharedString,
StatefulInteractiveElement, Styled, Window, div,
};
use gpui_component::avatar::Avatar;
use gpui_component::dialog::DialogButtonProps;
use gpui_component::dock::ClosePanel;
use gpui_component::{ActiveTheme, Icon, Selectable, Sizable, StyledExt, WindowExt, h_flex};
use nostr_sdk::prelude::*;
use settings::AppSettings;
use theme::ActiveTheme;
use ui::avatar::Avatar;
use ui::dock::ClosePanel;
use ui::modal::ModalButtonProps;
use ui::{Icon, IconName, Selectable, Sizable, StyledExt, WindowExtension, h_flex};
use crate::dialogs::screening;
@@ -106,7 +106,7 @@ impl RenderOnce for RoomEntry {
.rounded(cx.theme().radius)
.when(!hide_avatar, |this| {
this.when_some(self.avatar, |this, avatar| {
this.child(Avatar::new(avatar).small().flex_shrink_0())
this.child(Avatar::new().src(avatar).small().flex_shrink_0())
})
})
.child(
@@ -127,9 +127,9 @@ impl RenderOnce for RoomEntry {
.child(name)
.when(is_selected, |this| {
this.child(
Icon::new(IconName::CheckCircle)
Icon::new(CoopIcon::CheckCircle)
.small()
.text_color(cx.theme().icon_accent),
.text_color(cx.theme().primary_active),
)
}),
)
@@ -139,11 +139,11 @@ impl RenderOnce for RoomEntry {
.gap_1p5()
.flex_shrink_0()
.text_xs()
.text_color(cx.theme().text_placeholder)
.text_color(cx.theme().muted_foreground)
.when_some(self.created_at, |this, created_at| this.child(created_at)),
),
)
.hover(|this| this.bg(cx.theme().elevated_surface_background))
.hover(|this| this.bg(cx.theme().muted))
.when_some(self.handler, |this, handler| {
this.on_click(move |event, window, cx| {
handler(event, window, cx);
@@ -154,11 +154,10 @@ impl RenderOnce for RoomEntry {
{
let screening = screening::init(public_key, window, cx);
window.open_modal(cx, move |this, _window, _cx| {
this.confirm()
.child(screening.clone())
window.open_dialog(cx, move |this, _window, _cx| {
this.child(screening.clone())
.button_props(
ModalButtonProps::default()
DialogButtonProps::default()
.cancel_text("Ignore")
.ok_text("Response"),
)

View File

@@ -4,26 +4,27 @@ use std::time::Duration;
use anyhow::{Context as AnyhowContext, Error};
use chat::{ChatEvent, ChatRegistry, Room, RoomKind};
use common::{DebouncedDelay, TimestampExt, coop_cache};
use common::{CoopIcon, DebouncedDelay, TimestampExt, coop_cache};
use entry::RoomEntry;
use gpui::prelude::FluentBuilder;
use gpui::{
App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable, IntoElement,
ParentElement, Render, SharedString, Styled, Subscription, Task, UniformListScrollHandle,
Window, div, uniform_list,
Window, div, px, uniform_list,
};
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::dock::{Panel, PanelEvent};
use gpui_component::input::{Input, InputEvent, InputState};
use gpui_component::notification::Notification;
use gpui_component::scroll::Scrollbar;
use gpui_component::spinner::Spinner;
use gpui_component::{
ActiveTheme, Icon, Selectable, Sizable, StyledExt, WindowExt, h_flex, v_flex,
};
use nostr_sdk::prelude::*;
use person::PersonRegistry;
use smallvec::{SmallVec, smallvec};
use state::{FIND_DELAY, IMAGE_CACHE_SIZE, NostrRegistry};
use theme::{ActiveTheme, SIDEBAR_WIDTH, TABBAR_HEIGHT};
use ui::button::{Button, ButtonVariants};
use ui::dock::{Panel, PanelEvent};
use ui::indicator::Indicator;
use ui::input::{InputEvent, InputState, TextInput};
use ui::notification::Notification;
use ui::scroll::Scrollbar;
use ui::{Icon, IconName, Selectable, Sizable, StyledExt, WindowExtension, h_flex, v_flex};
mod entry;
@@ -35,7 +36,6 @@ pub fn init(window: &mut Window, cx: &mut App) -> Entity<Sidebar> {
/// Sidebar.
pub struct Sidebar {
name: SharedString,
focus_handle: FocusHandle,
scroll_handle: UniformListScrollHandle,
@@ -135,7 +135,6 @@ impl Sidebar {
);
Self {
name: "Sidebar".into(),
focus_handle: cx.focus_handle(),
scroll_handle: UniformListScrollHandle::new(),
find_input,
@@ -249,11 +248,10 @@ impl Sidebar {
}
/// Set the finding status
fn set_finding(&mut self, status: bool, _window: &mut Window, cx: &mut Context<Self>) {
fn set_finding(&mut self, status: bool, window: &mut Window, cx: &mut Context<Self>) {
// Disable the input to prevent duplicate requests
self.find_input.update(cx, |this, cx| {
this.set_disabled(status, cx);
this.set_loading(status, cx);
this.set_loading(status, window, cx);
});
// Set the search status
self.finding = status;
@@ -473,8 +471,8 @@ impl Sidebar {
}
impl Panel for Sidebar {
fn panel_id(&self) -> SharedString {
self.name.clone()
fn panel_name(&self) -> &'static str {
"Sidebar"
}
}
@@ -508,25 +506,27 @@ impl Render for Sidebar {
.gap_2()
.child(
h_flex()
.h(TABBAR_HEIGHT)
.h(px(28.0))
.border_b_1()
.border_color(cx.theme().border)
.bg(cx.theme().tab_background)
.bg(cx.theme().tab_bar)
.child(
TextInput::new(&self.find_input)
Input::new(&self.find_input)
.appearance(false)
.bordered(false)
.small()
.text_xs()
.when(!self.find_input.read(cx).loading, |this| {
this.suffix(
Button::new("find-icon")
.icon(IconName::Search)
.tooltip("Press Enter to search")
.transparent()
.small(),
)
}),
.text_xs(),
/*
.when(!self.find_input.read(cx).loading, |this| {
this.suffix(
Button::new("find-icon")
.icon(CoopIcon::Search)
.tooltip("Press Enter to search")
.transparent()
.small(),
)
})
*/
),
)
.child(
@@ -537,11 +537,10 @@ impl Render for Sidebar {
.when(show_find_panel, |this| {
this.child(
Button::new("search-results")
.icon(IconName::Search)
.icon(CoopIcon::Search)
.tooltip("All search results")
.small()
.ghost_alt()
.font_semibold()
.ghost()
.flex_1()
.selected(true),
)
@@ -550,16 +549,15 @@ impl Render for Sidebar {
Button::new("all")
.map(|this| {
if self.current_filter(&RoomKind::Ongoing, cx) {
this.icon(IconName::InboxFill)
this.icon(CoopIcon::InboxFill)
} else {
this.icon(IconName::Inbox)
this.icon(CoopIcon::Inbox)
}
})
.when(!show_find_panel, |this| this.label("Inbox"))
.tooltip("All ongoing conversations")
.small()
.ghost_alt()
.font_semibold()
.ghost()
.flex_1()
.selected(
!show_find_panel && self.current_filter(&RoomKind::Ongoing, cx),
@@ -572,22 +570,21 @@ impl Render for Sidebar {
Button::new("requests")
.map(|this| {
if self.current_filter(&RoomKind::Request, cx) {
this.icon(IconName::FistbumpFill)
this.icon(CoopIcon::FistbumpFill)
} else {
this.icon(IconName::Fistbump)
this.icon(CoopIcon::Fistbump)
}
})
.when(!show_find_panel, |this| this.label("Requests"))
.tooltip("Incoming new conversations")
.small()
.ghost_alt()
.font_semibold()
.ghost()
.flex_1()
.selected(
!show_find_panel && !self.current_filter(&RoomKind::Ongoing, cx),
)
.when(self.new_requests, |this| {
this.child(div().size_1().rounded_full().bg(cx.theme().cursor))
this.child(div().size_1().rounded_full().bg(cx.theme().caret))
})
.on_click(cx.listener(|this, _ev, window, cx| {
this.set_filter(RoomKind::default(), window, cx);
@@ -596,14 +593,14 @@ impl Render for Sidebar {
)
.when(!show_find_panel && !loading && total_rooms == 0, |this| {
this.child(
div().w(SIDEBAR_WIDTH).px_2().child(
div().w(px(240.)).px_2().child(
v_flex()
.p_3()
.h_24()
.w_full()
.border_2()
.border_dashed()
.border_color(cx.theme().border_variant)
.border_color(cx.theme().border)
.rounded(cx.theme().radius_lg)
.items_center()
.justify_center()
@@ -614,11 +611,14 @@ impl Render for Sidebar {
.font_semibold()
.child(SharedString::from("No conversations")),
)
.child(div().text_xs().text_color(cx.theme().text_muted).child(
SharedString::from(
"Start a conversation with someone to get started.",
),
)),
.child(
div()
.text_xs()
.text_color(cx.theme().muted_foreground)
.child(SharedString::from(
"Start a conversation with someone to get started.",
)),
),
),
)
})
@@ -635,14 +635,14 @@ impl Render for Sidebar {
.gap_1()
.flex_1()
.border_b_1()
.border_color(cx.theme().border_variant)
.border_color(cx.theme().border)
.child(
h_flex()
.gap_0p5()
.text_xs()
.font_semibold()
.text_color(cx.theme().text_muted)
.child(Icon::new(IconName::ChevronDown))
.text_color(cx.theme().muted_foreground)
.child(Icon::new(CoopIcon::ChevronDown))
.child(SharedString::from("Results")),
)
.child(
@@ -668,8 +668,8 @@ impl Render for Sidebar {
.gap_0p5()
.text_xs()
.font_semibold()
.text_color(cx.theme().text_muted)
.child(Icon::new(IconName::ChevronDown).small())
.text_color(cx.theme().muted_foreground)
.child(Icon::new(CoopIcon::ChevronDown).small())
.child(SharedString::from("Suggestions")),
)
.child(
@@ -740,14 +740,14 @@ impl Render for Sidebar {
.h_9()
.justify_center()
.bg(cx.theme().background.opacity(0.85))
.border_color(cx.theme().border_disabled)
.border_color(cx.theme().border)
.border_1()
.when(cx.theme().shadow, |this| this.shadow_xs())
.rounded_full()
.text_xs()
.font_semibold()
.text_color(cx.theme().text_muted)
.child(Indicator::new().small().color(cx.theme().icon_accent))
.text_color(cx.theme().muted_foreground)
.child(Spinner::new().small().color(cx.theme().primary_active))
.child(SharedString::from("Getting messages...")),
),
)

View File

@@ -1,8 +1,7 @@
use std::sync::Arc;
use ::settings::AppSettings;
use chat::{ChatEvent, ChatRegistry};
use common::{CoopImageCache, download_dir};
use common::{CoopIcon, CoopImageCache, download_dir};
use device::{DeviceEvent, DeviceRegistry};
use gpui::prelude::FluentBuilder;
use gpui::{
@@ -10,19 +9,18 @@ use gpui::{
Render, SharedString, StatefulInteractiveElement, Styled, Subscription, Window, div,
image_cache, px, relative,
};
use gpui_component::avatar::Avatar;
use gpui_component::button::{Button, ButtonVariants};
use gpui_component::dock::{ClosePanel, DockArea, DockItem, DockPlacement, PanelView};
use gpui_component::menu::{DropdownMenu, PopupMenuItem};
use gpui_component::notification::{Notification, NotificationType};
use gpui_component::{ActiveTheme, Icon, Root, Sizable, Theme, WindowExt, h_flex, v_flex};
use nostr_sdk::prelude::*;
use person::{PersonRegistry, shorten_pubkey};
use serde::Deserialize;
use smallvec::{SmallVec, smallvec};
use state::{IMAGE_CACHE_SIZE, NostrRegistry, StateEvent};
use theme::{ActiveTheme, SIDEBAR_WIDTH, Theme, ThemeRegistry};
use title_bar::TitleBar;
use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants};
use ui::dock::{ClosePanel, DockArea, DockItem, DockPlacement, PanelView};
use ui::menu::{DropdownMenu, PopupMenuItem};
use ui::notification::{Notification, NotificationKind};
use ui::{Icon, IconName, Root, Sizable, WindowExtension, h_flex, v_flex};
use crate::dialogs::restore::RestoreEncryption;
use crate::dialogs::{accounts, settings};
@@ -84,7 +82,7 @@ impl Workspace {
let nostr = NostrRegistry::global(cx);
let titlebar = cx.new(|_| TitleBar::new());
let dock = cx.new(|cx| DockArea::new(window, cx));
let dock = cx.new(|cx| DockArea::new("dock", None, window, cx));
let image_cache = CoopImageCache::new(IMAGE_CACHE_SIZE, cx);
let mut subscriptions = smallvec![];
@@ -106,7 +104,7 @@ impl Workspace {
.title("Preparing a new identity")
.message(PREPARE_MSG)
.autohide(false)
.with_kind(NotificationKind::Info);
.with_type(NotificationType::Info);
window.push_notification(note, cx);
}
@@ -114,7 +112,7 @@ impl Workspace {
let note = Notification::new()
.id::<RelayNotifcation>()
.message("Connecting to the bootstrap relays...")
.with_kind(NotificationKind::Info);
.with_type(NotificationType::Info);
window.push_notification(note, cx);
}
@@ -122,14 +120,14 @@ impl Workspace {
let note = Notification::new()
.id::<RelayNotifcation>()
.message("Connected to the bootstrap relays")
.with_kind(NotificationKind::Success);
.with_type(NotificationType::Success);
window.push_notification(note, cx);
}
StateEvent::SignerSet => {
this.set_center_layout(window, cx);
// Clear the signer notification
window.clear_notification::<SignerNotifcation>(cx);
window.remove_notification::<SignerNotifcation>(cx);
}
StateEvent::Show => {
this.account_selector(window, cx);
@@ -152,7 +150,7 @@ impl Workspace {
.autohide(false)
.title("Wait for approval")
.message(MSG)
.with_kind(NotificationKind::Info);
.with_type(NotificationType::Info);
window.push_notification(note, cx);
}
@@ -161,7 +159,7 @@ impl Workspace {
.id::<DeviceNotifcation>()
.autohide(false)
.message("Creating encryption key")
.with_kind(NotificationKind::Info);
.with_type(NotificationType::Info);
window.push_notification(note, cx);
}
@@ -169,7 +167,7 @@ impl Workspace {
let note = Notification::new()
.id::<DeviceNotifcation>()
.message("Encryption Key has been set")
.with_kind(NotificationKind::Success);
.with_type(NotificationType::Success);
window.push_notification(note, cx);
}
@@ -190,6 +188,7 @@ impl Workspace {
this.add_panel(
Arc::new(chat_ui::init(room, window, cx)),
DockPlacement::Center,
None,
window,
cx,
);
@@ -197,14 +196,11 @@ impl Workspace {
}
}
ChatEvent::CloseRoom(..) => {
this.dock.update(cx, |this, cx| {
// Force focus to the tab panel
this.focus_tab_panel(window, cx);
this.dock.update(cx, |_this, cx| {
// Dispatch the close panel action
cx.defer_in(window, |_, window, cx| {
window.dispatch_action(Box::new(ClosePanel), cx);
window.close_all_modals(cx);
window.close_all_dialogs(cx);
});
});
}
@@ -219,11 +215,13 @@ impl Workspace {
subscriptions.push(
// Observe the chat registry
cx.observe(&chat, move |this, chat, cx| {
/*
let ids = this.panel_ids(cx);
chat.update(cx, |this, cx| {
this.refresh_rooms(&ids, cx);
});
*/
}),
);
@@ -250,30 +248,19 @@ impl Workspace {
{
workspace.update(cx, |this, cx| {
this.dock.update(cx, |this, cx| {
this.add_panel(Arc::new(panel), placement, window, cx);
this.add_panel(Arc::new(panel), placement, None, window, cx);
});
});
}
}
/// Get all panel ids
fn panel_ids(&self, cx: &App) -> Vec<u64> {
self.dock
.read(cx)
.items
.panel_ids(cx)
.into_iter()
.filter_map(|panel| panel.parse::<u64>().ok())
.collect()
}
/// Set the dock layout
fn set_layout(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let left = DockItem::panel(Arc::new(sidebar::init(window, cx)));
// Update the dock layout with sidebar on the left
self.dock.update(cx, |this, cx| {
this.set_left_dock(left, Some(SIDEBAR_WIDTH), true, window, cx);
this.set_left_dock(left, Some(px(240.)), true, window, cx);
});
}
@@ -281,7 +268,7 @@ impl Workspace {
fn set_center_layout(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let dock = self.dock.downgrade();
let greeter = Arc::new(greeter::init(window, cx));
let tabs = DockItem::tabs(vec![greeter], None, &dock, window, cx);
let tabs = DockItem::tabs(vec![greeter], &dock, window, cx);
let center = DockItem::split(Axis::Vertical, vec![tabs], &dock, window, cx);
// Update the layout with center dock
@@ -296,9 +283,9 @@ impl Workspace {
Command::ShowSettings => {
let view = settings::init(window, cx);
window.open_modal(cx, move |this, _window, _cx| {
window.open_dialog(cx, move |this, _window, _cx| {
this.width(px(520.))
.show_close(true)
.close_button(true)
.pb_2()
.title("Preferences")
.child(view.clone())
@@ -313,6 +300,7 @@ impl Workspace {
this.add_panel(
Arc::new(profile::init(public_key, window, cx)),
DockPlacement::Right,
None,
window,
cx,
);
@@ -324,6 +312,7 @@ impl Workspace {
this.add_panel(
Arc::new(contact_list::init(window, cx)),
DockPlacement::Right,
None,
window,
cx,
);
@@ -334,6 +323,7 @@ impl Workspace {
this.add_panel(
Arc::new(backup::init(window, cx)),
DockPlacement::Right,
None,
window,
cx,
);
@@ -344,6 +334,7 @@ impl Workspace {
this.add_panel(
Arc::new(messaging_relays::init(window, cx)),
DockPlacement::Right,
None,
window,
cx,
);
@@ -361,6 +352,7 @@ impl Workspace {
this.add_panel(
Arc::new(relay_list::init(window, cx)),
DockPlacement::Right,
None,
window,
cx,
);
@@ -426,11 +418,10 @@ impl Workspace {
let device = DeviceRegistry::global(cx);
let ent = device.downgrade();
window.open_modal(cx, move |this, _window, cx| {
window.open_dialog(cx, move |this, _window, cx| {
let ent = ent.clone();
this.confirm()
.show_close(true)
this.close_button(true)
.title("Reset Encryption Key")
.child(
v_flex()
@@ -440,7 +431,7 @@ impl Workspace {
.child(
div()
.italic()
.text_color(cx.theme().text_danger)
.text_color(cx.theme().danger_active)
.child(SharedString::from(ENC_WARN)),
),
)
@@ -458,7 +449,7 @@ impl Workspace {
fn import_encryption(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let restore = cx.new(|cx| RestoreEncryption::new(window, cx));
window.open_modal(cx, move |this, _window, _cx| {
window.open_dialog(cx, move |this, _window, _cx| {
this.width(px(520.))
.title("Restore Encryption")
.child(restore.clone())
@@ -468,10 +459,10 @@ impl Workspace {
fn account_selector(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let accounts = accounts::init(window, cx);
window.open_modal(cx, move |this, _window, _cx| {
window.open_dialog(cx, move |this, _window, _cx| {
this.width(px(520.))
.title("Continue with")
.show_close(false)
.close_button(false)
.keyboard(false)
.overlay_closable(false)
.child(accounts.clone())
@@ -479,7 +470,8 @@ impl Workspace {
}
fn theme_selector(&mut self, window: &mut Window, cx: &mut Context<Self>) {
window.open_modal(cx, move |this, _window, cx| {
/*
* window.open_modal(cx, move |this, _window, cx| {
let registry = ThemeRegistry::global(cx);
let themes = registry.read(cx).themes();
@@ -522,7 +514,7 @@ impl Workspace {
.group_hover("", |this| this.visible())
.child(
Button::new(format!("url-{ix}"))
.icon(IconName::Link)
.icon(CoopIcon::Link)
.ghost()
.small()
.on_click({
@@ -534,7 +526,7 @@ impl Workspace {
)
.child(
Button::new(format!("set-{ix}"))
.icon(IconName::Check)
.icon(CoopIcon::Check)
.primary()
.small()
.on_click({
@@ -556,6 +548,7 @@ impl Workspace {
items
}))
});
*/
}
fn titlebar_left(&mut self, cx: &mut Context<Self>) -> impl IntoElement {
@@ -570,7 +563,7 @@ impl Workspace {
this.child(
div()
.text_xs()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(SharedString::from("Choose an account to continue...")),
)
})
@@ -582,11 +575,11 @@ impl Workspace {
this.child(
Button::new("current-user")
.child(Avatar::new(avatar.clone()).xsmall())
.child(Avatar::new().src(avatar.clone()).xsmall())
.small()
.caret()
.compact()
.transparent()
.ghost()
.dropdown_caret(true)
.dropdown_menu(move |this, _window, _cx| {
let avatar = avatar.clone();
let name = name.clone();
@@ -596,40 +589,40 @@ impl Workspace {
h_flex()
.gap_1p5()
.text_xs()
.text_color(cx.theme().text_muted)
.child(Avatar::new(avatar.clone()).xsmall())
.text_color(cx.theme().muted_foreground)
.child(Avatar::new().src(avatar.clone()).xsmall())
.child(name.clone())
}))
.separator()
.menu_with_icon(
"Profile",
IconName::Profile,
CoopIcon::Profile,
Box::new(Command::ShowProfile),
)
.menu_with_icon(
"Contact List",
IconName::Book,
CoopIcon::Book,
Box::new(Command::ShowContactList),
)
.menu_with_icon(
"Backup",
IconName::UserKey,
CoopIcon::UserKey,
Box::new(Command::ShowBackup),
)
.menu_with_icon(
"Themes",
IconName::Sun,
CoopIcon::Sun,
Box::new(Command::ToggleTheme),
)
.separator()
.menu_with_icon(
"Accounts",
IconName::Group,
CoopIcon::Group,
Box::new(Command::ToggleAccount),
)
.menu_with_icon(
"Settings",
IconName::Settings,
CoopIcon::Settings,
Box::new(Command::ShowSettings),
)
}),
@@ -657,7 +650,6 @@ impl Workspace {
let announcement = profile.announcement();
h_flex()
.when(!cx.theme().platform.is_mac(), |this| this.pr_2())
.gap_2()
.when(trash_messages > 0, |this| {
this.child(
@@ -667,11 +659,11 @@ impl Workspace {
.px_1()
.gap_1()
.rounded(cx.theme().radius)
.hover(|this| this.bg(cx.theme().ghost_element_hover))
.hover(|this| this.bg(cx.theme().danger_hover))
.child(
Icon::new(IconName::Warning)
Icon::new(CoopIcon::Warning)
.small()
.text_color(cx.theme().text_danger),
.text_color(cx.theme().danger_foreground),
)
.child(
div()
@@ -693,7 +685,7 @@ impl Workspace {
})
.child(
Button::new("key")
.icon(IconName::UserKey)
.icon(CoopIcon::UserKey)
.tooltip("Decoupled encryption key")
.small()
.ghost()
@@ -715,9 +707,9 @@ impl Workspace {
.gap_1()
.text_sm()
.child(
Icon::new(IconName::Device)
Icon::new(CoopIcon::Device)
.small()
.text_color(cx.theme().icon_muted),
.text_color(cx.theme().muted_foreground),
)
.child(name.clone())
}))
@@ -726,9 +718,9 @@ impl Workspace {
.gap_1()
.text_sm()
.child(
Icon::new(IconName::UserKey)
Icon::new(CoopIcon::UserKey)
.small()
.text_color(cx.theme().icon_muted),
.text_color(cx.theme().muted_foreground),
)
.child(SharedString::from(pkey.clone()))
}))
@@ -736,30 +728,30 @@ impl Workspace {
.separator()
.menu_with_icon(
"Backup",
IconName::Shield,
CoopIcon::Shield,
Box::new(Command::BackupEncryption),
)
.menu_with_icon(
"Restore from secret key",
IconName::Usb,
CoopIcon::Usb,
Box::new(Command::ImportEncryption),
)
.separator()
.menu_with_icon(
"Reload",
IconName::Refresh,
CoopIcon::Refresh,
Box::new(Command::RefreshEncryption),
)
.menu_with_icon(
"Reset",
IconName::Warning,
CoopIcon::Warning,
Box::new(Command::ResetEncryption),
)
}),
)
.child(
Button::new("inbox")
.icon(IconName::Inbox)
.icon(CoopIcon::Inbox)
.small()
.ghost()
.loading(initializing)
@@ -798,14 +790,14 @@ impl Workspace {
div()
.size_1p5()
.rounded_full()
.bg(cx.theme().icon_accent),
.bg(cx.theme().primary_foreground),
)
.child(url.clone()),
)
.child(
div()
.text_xs()
.text_color(cx.theme().text_muted)
.text_color(cx.theme().muted_foreground)
.child(count.clone()),
)
}))
@@ -815,17 +807,17 @@ impl Workspace {
menu.separator()
.menu_with_icon(
"Reload",
IconName::Refresh,
CoopIcon::Refresh,
Box::new(Command::RefreshMessagingRelays),
)
.menu_with_icon(
"Manage gossip relays",
IconName::Relay,
CoopIcon::Relay,
Box::new(Command::ShowRelayList),
)
.menu_with_icon(
"Manage messaging relays",
IconName::Settings,
CoopIcon::Settings,
Box::new(Command::ShowMessaging),
)
}),
@@ -835,7 +827,7 @@ impl Workspace {
impl Render for Workspace {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let modal_layer = Root::render_modal_layer(window, cx);
let modal_layer = Root::render_dialog_layer(window, cx);
let notification_layer = Root::render_notification_layer(window, cx);
// Titlebar elements