feat: adopt the native OS theme (#66)

Reviewed-on: #66
This commit was merged in pull request #66.
This commit is contained in:
2026-10-23 04:07:11 +00:00
parent f44f0704f3
commit 30da985ac1
257 changed files with 5490 additions and 12236 deletions
+108 -75
View File
@@ -2,17 +2,22 @@ use auto_update::AutoUpdater;
use gpui::prelude::FluentBuilder;
use gpui::{
AnyElement, App, Context, Div, Entity, InteractiveElement, IntoElement, ParentElement,
Stateful, Styled, div, px,
Stateful, Styled, Window, div, px,
};
use gpui_kit::component::button::{Button, ButtonVariant, ButtonVariants};
use gpui_kit::component::dialog::DialogButtonProps;
use gpui_kit::component::menu::{DropdownMenu, PopupMenuItem};
use gpui_kit::component::{
ActiveTheme, Disableable, Icon, Selectable, Sizable, WindowExt, h_flex, v_flex,
};
use nostr_sdk::prelude::*;
use theme::TABBAR_HEIGHT;
use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants};
use ui::menu::DropdownMenu;
use ui::{Disableable, IconName, Selectable, Sizable, TRAFFIC_LIGHT_PADDING, h_flex};
use state::NostrRegistry;
use ui::{Avatar, IconName};
use super::Sidebar;
use crate::Command;
use crate::dock::TAB_BAR_HEIGHT;
use crate::nav::Nav;
impl Sidebar {
pub(super) fn render_user(
@@ -23,30 +28,22 @@ impl Sidebar {
let updater = AutoUpdater::try_global(cx);
let profile = self.directory.read(cx).person(current_user, cx);
let avatar = profile.avatar();
let avatar_seed = profile.avatar_seed();
h_flex()
.id("sidebar-user")
.w_full()
.h(TABBAR_HEIGHT)
.h(TAB_BAR_HEIGHT)
.flex_shrink_0()
.items_center()
.gap(px(theme::SPACE))
.justify_between()
.px_2()
.when(cfg!(target_os = "macos"), |this| {
this.pl(px(TRAFFIC_LIGHT_PADDING))
})
.when(cfg!(target_os = "macos"), |this| this.pl(px(80.)))
.child(
Button::new("current-user")
.child(
Avatar::new(avatar.clone())
.seed(avatar_seed.clone())
.small(),
)
.small()
.caret()
.compact()
.transparent()
.text()
.dropdown_caret(true)
.min_w_0()
.flex_shrink_1()
.child(Avatar::new(avatar).seed(profile.avatar_seed()).small())
.dropdown_menu(move |this, _window, _cx| {
this.menu_with_icon(
"Profile",
@@ -55,66 +52,80 @@ impl Sidebar {
)
.menu_with_icon("Relays", IconName::Relay, Box::new(Command::ShowRelayList))
.separator()
.menu_with_icon(
"Settings",
IconName::Settings,
Box::new(Command::ShowSettings),
.item(
PopupMenuItem::element(|_, cx| {
div().text_color(cx.theme().danger).child("Log out")
})
.on_click(|_, window, cx| {
open_logout_dialog(window, cx);
}),
)
}),
)
.child(div().flex_1())
.when_some(updater, |this, updater| {
this.child(self.render_updater(updater, cx))
})
.child(
Button::new("sidebar-search")
.icon(IconName::Search)
.tooltip("Search")
.selected(self.search_open)
.ghost()
.small()
.on_click(cx.listener(|this, _event, window, cx| {
this.toggle_search(window, cx);
})),
h_flex()
.gap_1()
.when_some(updater, |this, updater| {
this.child(self.render_updater(updater, cx))
})
.child(
Button::new("sidebar-search")
.icon(IconName::Search)
.tooltip("Search")
.selected(self.search_open)
.ghost()
.small()
.on_click(cx.listener(|this, _event, window, cx| {
this.toggle_search(window, cx);
})),
)
.child(
Button::new("sidebar-new")
.icon(IconName::PlusChat)
.tooltip("New")
.ghost()
.small()
.dropdown_menu(|menu, _window, _cx| {
menu.label("Public Group")
.menu("New Group", Box::new(Command::NewGroup))
.menu("Join Group", Box::new(Command::JoinGroup))
.separator()
.menu("New Chat", Box::new(Command::NewChat))
}),
)
.when(self.group_open, |this| {
this.child(
Button::new("sidebar-back")
.icon(IconName::ArrowLeft)
.tooltip("Back")
.ghost()
.small()
.on_click(cx.listener(|this, _event, _window, cx| {
this.hide_group(cx);
})),
)
}),
)
}
/// The bottom navigation, pinned below the list like signed's sidebar.
pub(super) fn render_footer(&self, _cx: &mut Context<Self>) -> Div {
v_flex()
.p_2()
.flex_shrink_0()
.gap_1()
.items_start()
.justify_start()
.child(
Button::new("sidebar-new")
.icon(IconName::PlusChat)
.tooltip("New")
.ghost()
.small()
.dropdown_menu(|menu, _window, _cx| {
menu.label("Public Group")
.menu_with_icon(
"New Group",
IconName::Group,
Box::new(Command::NewGroup),
)
.menu_with_icon(
"Join Group",
IconName::Door,
Box::new(Command::JoinGroup),
)
.separator()
.menu_with_icon(
"New Chat",
IconName::Message,
Box::new(Command::NewChat),
)
Nav::new("sidebar-settings")
.prefix(Icon::new(IconName::Settings).small())
.center_prefix(true)
.label("Settings")
.text_sm()
.on_click(|_, window, cx| {
window.dispatch_action(Box::new(Command::ShowSettings), cx)
}),
)
.when(self.group_open, |this| {
this.child(
Button::new("sidebar-back")
.icon(IconName::ArrowLeft)
.tooltip("Back")
.ghost()
.small()
.on_click(cx.listener(|this, _event, _window, cx| {
this.hide_group(cx);
})),
)
})
}
fn render_updater(&self, updater: Entity<AutoUpdater>, cx: &mut App) -> AnyElement {
@@ -123,7 +134,7 @@ impl Sidebar {
let staged = updater.read(cx).staged();
h_flex()
.gap(px(theme::SPACE))
.gap_2()
.when(!up_to_date, |this| {
this.child(
Button::new("update")
@@ -151,3 +162,25 @@ impl Sidebar {
.into_any_element()
}
}
/// Confirm signing out, then drop the stored credential like signed's exit dialog.
fn open_logout_dialog(window: &mut Window, cx: &mut App) {
const DESCRIPTION: &str = "Are you sure you want to log out? You will need to re-enter your credentials to sign back in.";
window.open_alert_dialog(cx, |alert, _, _| {
alert
.title("Log Out?")
.description(DESCRIPTION)
.button_props(
DialogButtonProps::default()
.ok_text("Log out")
.ok_variant(ButtonVariant::Danger)
.show_cancel(true),
)
.on_ok(|_, _, cx| {
let nostr = NostrRegistry::global(cx);
nostr.update(cx, |nostr, cx| nostr.sign_out(cx));
true
})
});
}