wip: refactor

This commit is contained in:
2024-12-31 09:34:33 +07:00
parent 5b78e6ad12
commit b2f2491889
14 changed files with 205 additions and 120 deletions

BIN
assets/brand/coop-dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
assets/brand/coop-light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

3
assets/icons/group.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M17.75 19.25h2.596c1.163 0 2.106-1.001 1.788-2.12-.733-2.573-2.465-4.38-5.134-4.38-.446 0-.866.05-1.26.147M11.25 7a3.25 3.25 0 1 1-6.5 0 3.25 3.25 0 0 1 6.5 0Zm8.5.5a2.75 2.75 0 1 1-5.5 0 2.75 2.75 0 0 1 5.5 0ZM2.08 18.126c.78-3.14 2.78-5.376 5.92-5.376s5.14 2.237 5.918 5.376c.28 1.128-.658 2.124-1.82 2.124H3.901c-1.162 0-2.1-.996-1.82-2.124Z"/>
</svg>

After

Width:  |  Height:  |  Size: 550 B

View File

@@ -1,5 +1,6 @@
use coop_ui::{ use coop_ui::{
button::{Button, ButtonVariants}, button::{Button, ButtonVariants},
popup_menu::PopupMenuExt,
Icon, IconName, Sizable, Icon, IconName, Sizable,
}; };
use gpui::*; use gpui::*;
@@ -12,6 +13,8 @@ use crate::{
states::{metadata::MetadataRegistry, signal::SignalRegistry}, states::{metadata::MetadataRegistry, signal::SignalRegistry},
}; };
actions!(account, [ToDo]);
pub struct Account { pub struct Account {
public_key: PublicKey, public_key: PublicKey,
metadata: Model<Option<Metadata>>, metadata: Model<Option<Metadata>>,
@@ -83,5 +86,12 @@ impl Render for Account {
} }
}) })
}) })
.popup_menu(move |this, _cx| {
this.menu("Profile", Box::new(ToDo))
.menu("Contacts", Box::new(ToDo))
.menu("Settings", Box::new(ToDo))
.separator()
.menu("Change account", Box::new(ToDo))
})
} }
} }

View File

@@ -1,8 +1,7 @@
use coop_ui::{ use coop_ui::{
button::{Button, ButtonCustomVariant, ButtonRounded, ButtonVariants},
dock::{DockArea, DockItem, DockPlacement}, dock::{DockArea, DockItem, DockPlacement},
theme::{ActiveTheme, Theme, ThemeMode}, theme::Theme,
ContextModal, IconName, Root, Sizable, TitleBar, Root, TitleBar,
}; };
use gpui::*; use gpui::*;
use prelude::FluentBuilder; use prelude::FluentBuilder;
@@ -11,14 +10,20 @@ use std::sync::Arc;
use super::{ use super::{
account::Account, account::Account,
dock::{chat::ChatPanel, left_dock::LeftDock, welcome::WelcomePanel}, dock::{chat::ChatPanel, contact::ContactPanel, left_dock::LeftDock, welcome::WelcomePanel},
onboarding::Onboarding, onboarding::Onboarding,
}; };
use crate::states::{account::AccountRegistry, chat::Room}; use crate::states::{account::AccountRegistry, chat::Room};
#[derive(Clone, PartialEq, Eq, Deserialize)]
pub enum PanelKind {
Room(Arc<Room>),
Contact,
}
#[derive(Clone, PartialEq, Eq, Deserialize)] #[derive(Clone, PartialEq, Eq, Deserialize)]
pub struct AddPanel { pub struct AddPanel {
pub room: Arc<Room>, pub panel: PanelKind,
pub position: DockPlacement, pub position: DockPlacement,
} }
@@ -80,19 +85,6 @@ impl AppView {
} }
} }
fn change_theme_mode(&mut self, _: &ClickEvent, cx: &mut ViewContext<Self>) {
let mode = match cx.theme().mode.is_dark() {
true => ThemeMode::Light,
false => ThemeMode::Dark,
};
// Change theme
Theme::change(mode, cx);
// Rerender
cx.refresh();
}
fn init_layout(dock_area: WeakView<DockArea>, cx: &mut WindowContext) { fn init_layout(dock_area: WeakView<DockArea>, cx: &mut WindowContext) {
let left = DockItem::panel(Arc::new(LeftDock::new(cx))); let left = DockItem::panel(Arc::new(LeftDock::new(cx)));
let center = Self::init_dock_items(&dock_area, cx); let center = Self::init_dock_items(&dock_area, cx);
@@ -129,11 +121,22 @@ impl AppView {
} }
fn on_action_add_panel(&mut self, action: &AddPanel, cx: &mut ViewContext<Self>) { fn on_action_add_panel(&mut self, action: &AddPanel, cx: &mut ViewContext<Self>) {
let chat_panel = Arc::new(ChatPanel::new(&action.room, cx)); match &action.panel {
PanelKind::Room(room) => {
let panel = Arc::new(ChatPanel::new(room, cx));
self.dock.update(cx, |dock_area, cx| { self.dock.update(cx, |dock_area, cx| {
dock_area.add_panel(chat_panel, action.position, cx); dock_area.add_panel(panel, action.position, cx);
}); });
}
PanelKind::Contact => {
let panel = Arc::new(ContactPanel::new(cx));
self.dock.update(cx, |dock_area, cx| {
dock_area.add_panel(panel, action.position, cx);
});
}
};
} }
} }
@@ -149,59 +152,18 @@ impl Render for AppView {
.child( .child(
TitleBar::new() TitleBar::new()
// Left side // Left side
.child( .child(div())
div()
.flex()
.items_center()
.gap_2()
.child(
div().when_some(
self.account.read(cx).as_ref(),
|this, account| this.child(account.clone()),
),
)
.child(
Button::new("new")
.custom(
ButtonCustomVariant::new(cx)
.shadow(false)
.color(cx.theme().primary)
.border(cx.theme().primary)
.foreground(cx.theme().primary_foreground)
.active(cx.theme().primary_active)
.hover(cx.theme().primary_hover),
)
.xsmall()
.rounded(ButtonRounded::Size(px(24.)))
.label("Compose")
.on_click(move |_, cx| {
cx.open_modal(move |modal, _| {
modal.title("Compose").child("TODO").min_h(px(300.))
});
}),
),
)
// Right side // Right side
.child( .child(
div() div()
.flex() .flex()
.items_center() .items_center()
.justify_end() .justify_end()
.gap_1()
.px_2() .px_2()
.gap_2() .when_some(self.account.read(cx).as_ref(), |this, account| {
.child( this.child(account.clone())
Button::new("theme-mode") }),
.map(|this| {
if cx.theme().mode.is_dark() {
this.icon(IconName::Sun)
} else {
this.icon(IconName::Moon)
}
})
.small()
.ghost()
.on_click(cx.listener(Self::change_theme_mode)),
),
), ),
) )
.child(self.dock.clone()) .child(self.dock.clone())
@@ -213,8 +175,6 @@ impl Render for AppView {
} }
div() div()
.bg(cx.theme().background)
.text_color(cx.theme().foreground)
.size_full() .size_full()
.child(content) .child(content)
.child(div().absolute().top_8().children(notification_layer)) .child(div().absolute().top_8().children(notification_layer))

View File

@@ -0,0 +1,72 @@
use coop_ui::{
button::Button,
dock::{Panel, PanelEvent, PanelState},
popup_menu::PopupMenu,
};
use gpui::*;
pub struct ContactPanel {
name: SharedString,
closeable: bool,
zoomable: bool,
focus_handle: FocusHandle,
}
impl ContactPanel {
pub fn new(cx: &mut WindowContext) -> View<Self> {
cx.new_view(Self::view)
}
fn view(cx: &mut ViewContext<Self>) -> Self {
Self {
name: "Contacts".into(),
closeable: true,
zoomable: true,
focus_handle: cx.focus_handle(),
}
}
}
impl Panel for ContactPanel {
fn panel_id(&self) -> SharedString {
"Contact".into()
}
fn title(&self, _cx: &WindowContext) -> AnyElement {
self.name.clone().into_any_element()
}
fn closeable(&self, _cx: &WindowContext) -> bool {
self.closeable
}
fn zoomable(&self, _cx: &WindowContext) -> bool {
self.zoomable
}
fn popup_menu(&self, menu: PopupMenu, _cx: &WindowContext) -> PopupMenu {
menu.track_focus(&self.focus_handle)
}
fn toolbar_buttons(&self, _cx: &WindowContext) -> Vec<Button> {
vec![]
}
fn dump(&self, _cx: &AppContext) -> PanelState {
PanelState::new(self)
}
}
impl EventEmitter<PanelEvent> for ContactPanel {}
impl FocusableView for ContactPanel {
fn focus_handle(&self, _: &AppContext) -> gpui::FocusHandle {
self.focus_handle.clone()
}
}
impl Render for ContactPanel {
fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> impl IntoElement {
div().size_full().child("TODO")
}
}

View File

@@ -9,7 +9,7 @@ use crate::{
get_client, get_client,
states::{chat::Room, metadata::MetadataRegistry, signal::SignalRegistry}, states::{chat::Room, metadata::MetadataRegistry, signal::SignalRegistry},
utils::{ago, get_room_id, show_npub}, utils::{ago, get_room_id, show_npub},
views::app::AddPanel, views::app::{AddPanel, PanelKind},
}; };
pub struct InboxItem { pub struct InboxItem {
@@ -73,7 +73,7 @@ impl InboxItem {
let room = Arc::new(Room::new(&self.event, cx)); let room = Arc::new(Room::new(&self.event, cx));
cx.dispatch_action(Box::new(AddPanel { cx.dispatch_action(Box::new(AddPanel {
room, panel: PanelKind::Room(room),
position: coop_ui::dock::DockPlacement::Center, position: coop_ui::dock::DockPlacement::Center,
})) }))
} }

View File

@@ -189,9 +189,8 @@ impl Render for Inbox {
} }
v_flex() v_flex()
.gap_1()
.pt_2()
.px_2() .px_2()
.gap_1()
.child( .child(
div() div()
.id("inbox") .id("inbox")

View File

@@ -1,12 +1,14 @@
use coop_ui::{ use coop_ui::{
button::Button, button::{Button, ButtonVariants},
dock::{Panel, PanelEvent, PanelState}, dock::{Panel, PanelEvent, PanelState},
popup_menu::PopupMenu, popup_menu::PopupMenu,
scroll::ScrollbarAxis, scroll::ScrollbarAxis,
StyledExt, v_flex, ContextModal, Icon, IconName, Sizable, StyledExt,
}; };
use gpui::*; use gpui::*;
use crate::views::app::{AddPanel, PanelKind};
use super::inbox::Inbox; use super::inbox::Inbox;
pub struct LeftDock { pub struct LeftDock {
@@ -79,8 +81,54 @@ impl FocusableView for LeftDock {
impl Render for LeftDock { impl Render for LeftDock {
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement { fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
div() v_flex()
.child(self.inbox.clone())
.scrollable(self.view_id, ScrollbarAxis::Vertical) .scrollable(self.view_id, ScrollbarAxis::Vertical)
.pt_3()
.gap_3()
.child(
v_flex()
.px_2()
.gap_1()
.child(
Button::new("new")
.small()
.ghost()
.not_centered()
.bold()
.icon(Icon::new(IconName::Plus))
.label("Compose")
.on_click(|_, cx| {
cx.open_modal(move |modal, _| modal.title("Compose").child("TODO"));
}),
)
.child(
Button::new("contacts")
.small()
.ghost()
.not_centered()
.bold()
.icon(Icon::new(IconName::Group))
.label("Contacts")
.on_click(|_, cx| {
cx.dispatch_action(Box::new(AddPanel {
panel: PanelKind::Contact,
position: coop_ui::dock::DockPlacement::Center,
}))
}),
)
.child(
Button::new("find")
.small()
.ghost()
.not_centered()
.bold()
.icon(Icon::new(IconName::Search))
.label("Find")
.on_click(|_, cx| {
cx.open_modal(move |modal, _| modal.title("Find").child("TODO"));
}),
),
)
.child(self.inbox.clone())
} }
} }

View File

@@ -1,4 +1,5 @@
pub mod chat; pub mod chat;
pub mod contact;
pub mod inbox; pub mod inbox;
pub mod left_dock; pub mod left_dock;
pub mod welcome; pub mod welcome;

View File

@@ -8,7 +8,7 @@ use crate::{
indicator::Indicator, indicator::Indicator,
theme::{ActiveTheme, Colorize as _}, theme::{ActiveTheme, Colorize as _},
tooltip::Tooltip, tooltip::Tooltip,
Disableable, Icon, Selectable, Sizable, Size, Disableable, Icon, Selectable, Sizable, Size, StyledExt,
}; };
pub enum ButtonRounded { pub enum ButtonRounded {
@@ -169,6 +169,8 @@ pub struct Button {
size: Size, size: Size,
compact: bool, compact: bool,
reverse: bool, reverse: bool,
bold: bool,
centered: bool,
tooltip: Option<SharedString>, tooltip: Option<SharedString>,
on_click: OnClick, on_click: OnClick,
pub(crate) stop_propagation: bool, pub(crate) stop_propagation: bool,
@@ -202,6 +204,8 @@ impl Button {
loading: false, loading: false,
reverse: false, reverse: false,
compact: false, compact: false,
bold: false,
centered: true,
children: Vec::new(), children: Vec::new(),
loading_icon: None, loading_icon: None,
} }
@@ -261,6 +265,16 @@ impl Button {
self self
} }
pub fn not_centered(mut self) -> Self {
self.centered = false;
self
}
pub fn bold(mut self) -> Self {
self.bold = true;
self
}
pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self { pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self {
self.on_click = Some(Box::new(handler)); self.on_click = Some(Box::new(handler));
self self
@@ -340,7 +354,7 @@ impl RenderOnce for Button {
.id(self.id) .id(self.id)
.flex() .flex()
.items_center() .items_center()
.justify_center() .when(self.centered, |this| this.justify_center())
.cursor_pointer() .cursor_pointer()
.overflow_hidden() .overflow_hidden()
.when(cx.theme().shadow && normal_style.shadow, |this| { .when(cx.theme().shadow && normal_style.shadow, |this| {
@@ -359,8 +373,8 @@ impl RenderOnce for Button {
// Normal Button // Normal Button
match self.size { match self.size {
Size::Size(size) => this.px(size * 0.2), Size::Size(size) => this.px(size * 0.2),
Size::XSmall => this.h_5().px_2().when(self.compact, |this| this.px_0()), Size::XSmall => this.h_5().px_1().when(self.compact, |this| this.px_0()),
Size::Small => this.h_6().px_3().when(self.compact, |this| this.px_0p5()), Size::Small => this.h_6().px_2().when(self.compact, |this| this.px_0p5()),
_ => this.h_8().px_4().when(self.compact, |this| this.px_1()), _ => this.h_8().px_4().when(self.compact, |this| this.px_1()),
} }
} }
@@ -445,7 +459,7 @@ impl RenderOnce for Button {
.justify_center() .justify_center()
.map(|this| match self.size { .map(|this| match self.size {
Size::XSmall => this.gap_1().text_xs(), Size::XSmall => this.gap_1().text_xs(),
Size::Small => this.gap_1().text_xs(), Size::Small => this.gap_2().text_xs(),
_ => this.gap_2().text_base(), _ => this.gap_2().text_base(),
}) })
.when(!self.loading, |this| { .when(!self.loading, |this| {
@@ -461,7 +475,13 @@ impl RenderOnce for Button {
) )
}) })
.when_some(self.label, |this, label| { .when_some(self.label, |this, label| {
this.child(div().flex_none().line_height(relative(1.)).child(label)) this.child(
div()
.flex_none()
.line_height(relative(1.))
.child(label)
.when(self.bold, |this| this.font_semibold()),
)
}) })
.children(self.children) .children(self.children)
}) })

View File

@@ -40,6 +40,7 @@ pub enum IconName {
GalleryVerticalEnd, GalleryVerticalEnd,
GitHub, GitHub,
Globe, Globe,
Group,
Heart, Heart,
HeartOff, HeartOff,
Inbox, Inbox,
@@ -120,6 +121,7 @@ impl IconName {
Self::GalleryVerticalEnd => "icons/gallery-vertical-end.svg", Self::GalleryVerticalEnd => "icons/gallery-vertical-end.svg",
Self::GitHub => "icons/github.svg", Self::GitHub => "icons/github.svg",
Self::Globe => "icons/globe.svg", Self::Globe => "icons/globe.svg",
Self::Group => "icons/group.svg",
Self::Heart => "icons/heart.svg", Self::Heart => "icons/heart.svg",
Self::HeartOff => "icons/heart-off.svg", Self::HeartOff => "icons/heart-off.svg",
Self::Inbox => "icons/inbox.svg", Self::Inbox => "icons/inbox.svg",

View File

@@ -11,6 +11,8 @@ use crate::{
actions!(menu, [Confirm, Dismiss, SelectNext, SelectPrev]); actions!(menu, [Confirm, Dismiss, SelectNext, SelectPrev]);
const ITEM_HEIGHT: Pixels = px(26.);
pub fn init(cx: &mut AppContext) { pub fn init(cx: &mut AppContext) {
let context = Some("PopupMenu"); let context = Some("PopupMenu");
cx.bind_keys([ cx.bind_keys([
@@ -492,8 +494,6 @@ impl Render for PopupMenu {
let window_haft_height = cx.window_bounds().get_bounds().size.height * 0.5; let window_haft_height = cx.window_bounds().get_bounds().size.height * 0.5;
let max_height = window_haft_height.min(px(450.)); let max_height = window_haft_height.min(px(450.));
const ITEM_HEIGHT: Pixels = px(26.);
v_flex() v_flex()
.id("popup-menu") .id("popup-menu")
.key_context("PopupMenu") .key_context("PopupMenu")
@@ -540,11 +540,11 @@ impl Render for PopupMenu {
.map(|(ix, item)| { .map(|(ix, item)| {
let this = ListItem::new(("menu-item", ix)) let this = ListItem::new(("menu-item", ix))
.relative() .relative()
.text_sm() .items_center()
.py_0() .py_0()
.px_2() .px_2()
.rounded_md() .rounded_md()
.items_center() .text_xs()
.on_mouse_enter(cx.listener(move |this, _, cx| { .on_mouse_enter(cx.listener(move |this, _, cx| {
this.hovered_menu_ix = Some(ix); this.hovered_menu_ix = Some(ix);
cx.notify(); cx.notify();
@@ -667,7 +667,7 @@ impl Render for PopupMenu {
if hovered_ix == ix { if hovered_ix == ix {
this.child( this.child(
anchored() anchored()
.anchor(anchor) .anchor(anchor)
.child( .child(
div() div()
@@ -741,33 +741,3 @@ pub fn key_shortcut(key: Keystroke) -> String {
parts.push(&key); parts.push(&key);
parts.join("+") parts.join("+")
} }
#[cfg(test)]
mod tests {
#[test]
fn test_key_shortcut() {
use super::key_shortcut;
use gpui::Keystroke;
if cfg!(target_os = "windows") {
assert_eq!(key_shortcut(Keystroke::parse("a").unwrap()), "A");
assert_eq!(key_shortcut(Keystroke::parse("ctrl-a").unwrap()), "Ctrl+A");
assert_eq!(
key_shortcut(Keystroke::parse("ctrl-alt-a").unwrap()),
"Ctrl+Alt+A"
);
assert_eq!(
key_shortcut(Keystroke::parse("ctrl-alt-shift-a").unwrap()),
"Ctrl+Alt+Shift+A"
);
assert_eq!(
key_shortcut(Keystroke::parse("ctrl-alt-shift-win-a").unwrap()),
"Ctrl+Alt+Win+Shift+A"
);
assert_eq!(
key_shortcut(Keystroke::parse("ctrl-shift-backspace").unwrap()),
"Ctrl+Shift+Backspace"
);
}
}
}

View File

@@ -130,7 +130,7 @@ pub trait StyledExt: Styled + Sized {
.border_1() .border_1()
.border_color(cx.theme().border) .border_color(cx.theme().border)
.shadow_lg() .shadow_lg()
.rounded(px(cx.theme().radius)) .rounded_lg()
} }
} }