From 402786ec3ccf896678638d6507789487bbf7b401 Mon Sep 17 00:00:00 2001 From: reya Date: Mon, 6 Jan 2025 09:51:07 +0700 Subject: [PATCH] wip: refactor --- assets/icons/circle-check.svg | 3 + crates/app/src/main.rs | 13 +- crates/app/src/states/chat.rs | 42 ++- crates/app/src/views/inbox/item.rs | 2 +- crates/app/src/views/sidebar/contact_list.rs | 253 ++++++++++++++ .../src/views/{sidebar.rs => sidebar/mod.rs} | 71 +++- crates/ui/src/accordion.rs | 310 ------------------ crates/ui/src/button.rs | 6 +- crates/ui/src/lib.rs | 5 +- crates/ui/src/styled.rs | 65 +--- crates/ui/src/theme.rs | 49 --- crates/ui/src/window_border.rs | 3 - 12 files changed, 358 insertions(+), 464 deletions(-) create mode 100644 assets/icons/circle-check.svg create mode 100644 crates/app/src/views/sidebar/contact_list.rs rename crates/app/src/views/{sidebar.rs => sidebar/mod.rs} (57%) delete mode 100644 crates/ui/src/accordion.rs diff --git a/assets/icons/circle-check.svg b/assets/icons/circle-check.svg new file mode 100644 index 0000000..797bdc0 --- /dev/null +++ b/assets/icons/circle-check.svg @@ -0,0 +1,3 @@ + + + diff --git a/crates/app/src/main.rs b/crates/app/src/main.rs index 126e719..6a1c562 100644 --- a/crates/app/src/main.rs +++ b/crates/app/src/main.rs @@ -305,23 +305,30 @@ async fn main() { let bounds = Bounds::centered(None, size(px(900.0), px(680.0)), cx); let opts = WindowOptions { - window_bounds: Some(WindowBounds::Windowed(bounds)), - window_decorations: Some(WindowDecorations::Client), + #[cfg(not(target_os = "linux"))] titlebar: Some(TitlebarOptions { title: Some(SharedString::new_static(APP_NAME)), traffic_light_position: Some(point(px(9.0), px(9.0))), appears_transparent: true, }), + window_bounds: Some(WindowBounds::Windowed(bounds)), + window_decorations: Some(WindowDecorations::Client), + #[cfg(target_os = "linux")] + window_background: WindowBackgroundAppearance::Transparent, + #[cfg(target_os = "linux")] + window_decorations: Some(WindowDecorations::Client), + kind: WindowKind::Normal, ..Default::default() }; cx.open_window(opts, |cx| { let app_view = cx.new_view(AppView::new); + cx.set_window_title("Coop"); cx.activate(true); cx.new_view(|cx| Root::new(app_view.into(), cx)) }) - .unwrap(); + .expect("System error"); }); } diff --git a/crates/app/src/states/chat.rs b/crates/app/src/states/chat.rs index e64915d..7fc4c90 100644 --- a/crates/app/src/states/chat.rs +++ b/crates/app/src/states/chat.rs @@ -19,7 +19,31 @@ pub struct Room { } impl Room { - pub fn new(event: &Event, cx: &mut WindowContext<'_>) -> Self { + pub fn new( + owner: PublicKey, + members: Vec, + last_seen: Timestamp, + title: Option, + cx: &mut WindowContext<'_>, + ) -> Self { + // Get unique id based on members + let id = get_room_id(&owner, &members).into(); + + // Get metadata for all members if exists + let metadata = cx.global::().get(&owner); + + Self { + id, + title, + members, + last_seen, + owner, + metadata, + is_initialized: false, + } + } + + pub fn parse(event: &Event, cx: &mut WindowContext<'_>) -> Self { let owner = event.pubkey; let last_seen = event.created_at; @@ -36,21 +60,7 @@ impl Room { Some(name.into()) }; - // Get unique id based on members - let id = get_room_id(&owner, &members).into(); - - // Get metadata for all members if exists - let metadata = cx.global::().get(&owner); - - Self { - id, - title, - members, - last_seen, - owner, - metadata, - is_initialized: false, - } + Self::new(owner, members, last_seen, title, cx) } } diff --git a/crates/app/src/views/inbox/item.rs b/crates/app/src/views/inbox/item.rs index 971da10..2dbad55 100644 --- a/crates/app/src/views/inbox/item.rs +++ b/crates/app/src/views/inbox/item.rs @@ -69,7 +69,7 @@ impl InboxListItem { } pub fn action(&self, cx: &mut WindowContext<'_>) { - let room = Arc::new(Room::new(&self.event, cx)); + let room = Arc::new(Room::parse(&self.event, cx)); cx.dispatch_action(Box::new(AddPanel { panel: PanelKind::Room(room), diff --git a/crates/app/src/views/sidebar/contact_list.rs b/crates/app/src/views/sidebar/contact_list.rs new file mode 100644 index 0000000..5ae6442 --- /dev/null +++ b/crates/app/src/views/sidebar/contact_list.rs @@ -0,0 +1,253 @@ +use std::collections::{BTreeSet, HashSet}; + +use gpui::{ + div, img, impl_actions, list, px, Context, ElementId, FocusHandle, InteractiveElement, + IntoElement, ListAlignment, ListState, Model, ParentElement, Pixels, Render, RenderOnce, + SharedString, StatefulInteractiveElement, Styled, ViewContext, WindowContext, +}; +use nostr_sdk::prelude::*; +use serde::Deserialize; +use ui::{ + prelude::FluentBuilder, + theme::{ActiveTheme, Colorize}, + Icon, IconName, Selectable, StyledExt, +}; + +use crate::{ + constants::IMAGE_SERVICE, get_client, states::account::AccountRegistry, utils::show_npub, +}; + +#[derive(Clone, PartialEq, Eq, Deserialize)] +struct SelectContact(PublicKey); + +impl_actions!(contacts, [SelectContact]); + +#[derive(Clone, IntoElement)] +struct ContactListItem { + id: ElementId, + public_key: PublicKey, + metadata: Option, + selected: bool, +} + +impl ContactListItem { + pub fn new(public_key: PublicKey, metadata: Option) -> Self { + let id = SharedString::from(public_key.to_hex()).into(); + + Self { + id, + public_key, + metadata, + selected: false, + } + } +} + +impl Selectable for ContactListItem { + fn selected(mut self, selected: bool) -> Self { + self.selected = selected; + self + } + + fn element_id(&self) -> &gpui::ElementId { + &self.id + } +} + +impl RenderOnce for ContactListItem { + fn render(self, cx: &mut WindowContext) -> impl IntoElement { + let fallback = show_npub(self.public_key, 16); + let mut content = div().flex().items_center().gap_2().text_sm(); + + if let Some(metadata) = self.metadata { + content = content + .map(|this| { + if let Some(picture) = metadata.picture { + this.flex_shrink_0().child( + img(format!( + "{}/?url={}&w=72&h=72&fit=cover&mask=circle&n=-1", + IMAGE_SERVICE, picture + )) + .size_6(), + ) + } else { + this.flex_shrink_0() + .child(img("brand/avatar.png").size_6().rounded_full()) + } + }) + .map(|this| { + if let Some(display_name) = metadata.display_name { + this.flex_1().child(display_name) + } else { + this.flex_1().child(fallback) + } + }) + } else { + content = content + .child(img("brand/avatar.png").size_6().rounded_full()) + .child(fallback) + } + + div() + .id(self.id) + .w_full() + .h_8() + .px_1() + .rounded_md() + .flex() + .items_center() + .justify_between() + .child(content) + .when(self.selected, |this| { + this.child( + Icon::new(IconName::CircleCheck) + .size_4() + .text_color(cx.theme().primary), + ) + }) + .hover(|this| { + this.bg(cx.theme().muted.darken(0.1)) + .text_color(cx.theme().muted_foreground.darken(0.1)) + }) + .on_click(move |_, cx| { + cx.dispatch_action(Box::new(SelectContact(self.public_key))); + }) + } +} + +#[derive(Clone)] +struct Contacts { + #[allow(dead_code)] + count: usize, + items: Vec, +} + +pub struct ContactList { + list: ListState, + contacts: Model>, + selected: HashSet, + focus_handle: FocusHandle, +} + +impl ContactList { + pub fn new(cx: &mut ViewContext<'_, Self>) -> Self { + let list = ListState::new(0, ListAlignment::Top, Pixels(50.), move |_, _| { + div().into_any_element() + }); + + let contacts = cx.new_model(|_| BTreeSet::new()); + let async_contacts = contacts.clone(); + + let mut async_cx = cx.to_async(); + + cx.foreground_executor() + .spawn({ + let client = get_client(); + let current_user = cx.global::().get(); + + async move { + if let Some(public_key) = current_user { + if let Ok(profiles) = async_cx + .background_executor() + .spawn(async move { client.database().contacts(public_key).await }) + .await + { + _ = async_cx.update_model(&async_contacts, |model, cx| { + *model = profiles; + cx.notify(); + }); + } + } + } + }) + .detach(); + + cx.observe(&contacts, |this, model, cx| { + let profiles = model.read(cx).clone(); + let contacts = Contacts { + count: profiles.len(), + items: profiles + .into_iter() + .map(|contact| { + ContactListItem::new(contact.public_key(), Some(contact.metadata())) + }) + .collect(), + }; + + this.list = ListState::new( + contacts.items.len(), + ListAlignment::Top, + Pixels(50.), + move |idx, _cx| { + let item = contacts.items.get(idx).unwrap().clone(); + div().child(item).into_any_element() + }, + ); + + cx.notify(); + }) + .detach(); + + Self { + list, + contacts, + selected: HashSet::new(), + focus_handle: cx.focus_handle(), + } + } + + pub fn selected(&self) -> Vec { + self.selected.clone().into_iter().collect() + } + + fn on_action_select(&mut self, action: &SelectContact, cx: &mut ViewContext) { + self.selected.insert(action.0); + + let profiles = self.contacts.read(cx).clone(); + let contacts = Contacts { + count: profiles.len(), + items: profiles + .into_iter() + .map(|contact| { + let public_key = contact.public_key(); + let metadata = contact.metadata(); + + ContactListItem::new(public_key, Some(metadata)) + .selected(self.selected.contains(&public_key)) + }) + .collect(), + }; + + self.list = ListState::new( + contacts.items.len(), + ListAlignment::Top, + Pixels(50.), + move |idx, _cx| { + let item = contacts.items.get(idx).unwrap().clone(); + div().child(item).into_any_element() + }, + ); + + cx.notify(); + } +} + +impl Render for ContactList { + fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + div() + .track_focus(&self.focus_handle) + .on_action(cx.listener(Self::on_action_select)) + .flex() + .flex_col() + .gap_1() + .child(div().font_semibold().child("Contacts")) + .child( + div() + .p_1() + .bg(cx.theme().muted) + .text_color(cx.theme().muted_foreground) + .rounded_lg() + .child(list(self.list.clone()).h(px(300.))), + ) + } +} diff --git a/crates/app/src/views/sidebar.rs b/crates/app/src/views/sidebar/mod.rs similarity index 57% rename from crates/app/src/views/sidebar.rs rename to crates/app/src/views/sidebar/mod.rs index cb05e85..c6ee695 100644 --- a/crates/app/src/views/sidebar.rs +++ b/crates/app/src/views/sidebar/mod.rs @@ -1,14 +1,25 @@ +use std::sync::Arc; + +use contact_list::ContactList; use gpui::*; +use nostr_sdk::Timestamp; +use rnglib::{Language, RNG}; use ui::{ - button::{Button, ButtonVariants}, + button::{Button, ButtonRounded, ButtonVariants}, dock::{Panel, PanelEvent, PanelState}, popup_menu::PopupMenu, scroll::ScrollbarAxis, v_flex, ContextModal, Icon, IconName, Sizable, StyledExt, }; -use super::inbox::Inbox; -use crate::views::app::{AddPanel, PanelKind}; +use crate::states::{account::AccountRegistry, chat::Room}; + +use super::{ + app::{AddPanel, PanelKind}, + inbox::Inbox, +}; + +mod contact_list; pub struct Sidebar { // Panel @@ -38,6 +49,44 @@ impl Sidebar { inbox, } } + + fn show_compose(&mut self, cx: &mut ViewContext) { + let contact_list = cx.new_view(ContactList::new); + + cx.open_modal(move |modal, _cx| { + modal.child(contact_list.clone()).footer( + div().flex().gap_2().child( + Button::new("create") + .label("Create DM") + .primary() + .rounded(ButtonRounded::Large) + .w_full() + .on_click({ + let contact_list = contact_list.clone(); + move |_, cx| { + let members = contact_list.model.read(cx).selected(); + let owner = cx.global::().get().unwrap(); + let rng = RNG::from(&Language::Roman); + let name = rng.generate_names(2, true).join("-").to_lowercase(); + + let room = Arc::new(Room::new( + owner, + members, + Timestamp::now(), + Some(name.into()), + cx, + )); + + cx.dispatch_action(Box::new(AddPanel { + panel: PanelKind::Room(room), + position: ui::dock::DockPlacement::Center, + })) + } + }), + ), + ) + }) + } } impl Panel for Sidebar { @@ -79,7 +128,7 @@ impl FocusableView for Sidebar { } impl Render for Sidebar { - fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { + fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { v_flex() .scrollable(self.view_id, ScrollbarAxis::Vertical) .py_3() @@ -89,15 +138,13 @@ impl Render for Sidebar { .px_2() .gap_1() .child( - Button::new("new") + Button::new("compose") .small() .ghost() .not_centered() .icon(Icon::new(IconName::ComposeFill)) .label("New Message") - .on_click(|_, cx| { - cx.open_modal(move |modal, _| modal.child("TODO")); - }), + .on_click(cx.listener(|this, _, cx| this.show_compose(cx))), ) .child( Button::new("contacts") @@ -105,13 +152,7 @@ impl Render for Sidebar { .ghost() .not_centered() .icon(Icon::new(IconName::GroupFill)) - .label("Contacts") - .on_click(|_, cx| { - cx.dispatch_action(Box::new(AddPanel { - panel: PanelKind::Contact, - position: ui::dock::DockPlacement::Center, - })) - }), + .label("Contacts"), ), ) .child(self.inbox.clone()) diff --git a/crates/ui/src/accordion.rs b/crates/ui/src/accordion.rs deleted file mode 100644 index 0148011..0000000 --- a/crates/ui/src/accordion.rs +++ /dev/null @@ -1,310 +0,0 @@ -use std::{cell::Cell, rc::Rc, sync::Arc}; - -use gpui::{ - div, prelude::FluentBuilder as _, rems, AnyElement, Div, ElementId, InteractiveElement as _, - IntoElement, ParentElement, RenderOnce, SharedString, StatefulInteractiveElement as _, Styled, - WindowContext, -}; - -use crate::{h_flex, theme::ActiveTheme as _, v_flex, Icon, IconName, Sizable, Size}; - -type OnToggleClick = Option>; - -/// An AccordionGroup is a container for multiple Accordion elements. -#[derive(IntoElement)] -pub struct Accordion { - id: ElementId, - base: Div, - multiple: bool, - size: Size, - bordered: bool, - disabled: bool, - children: Vec, - on_toggle_click: OnToggleClick, -} - -impl Accordion { - pub fn new(id: impl Into) -> Self { - Self { - id: id.into(), - base: v_flex().gap_1(), - multiple: false, - size: Size::default(), - bordered: true, - children: Vec::new(), - disabled: false, - on_toggle_click: None, - } - } - - pub fn multiple(mut self, multiple: bool) -> Self { - self.multiple = multiple; - self - } - - pub fn bordered(mut self, bordered: bool) -> Self { - self.bordered = bordered; - self - } - - pub fn disabled(mut self, disabled: bool) -> Self { - self.disabled = disabled; - self - } - - pub fn item(mut self, child: F) -> Self - where - F: FnOnce(AccordionItem) -> AccordionItem, - { - let item = child(AccordionItem::new()); - self.children.push(item); - self - } - - /// Sets the on_toggle_click callback for the AccordionGroup. - /// - /// The first argument `Vec` is the indices of the open accordions. - pub fn on_toggle_click( - mut self, - on_toggle_click: impl Fn(&[usize], &mut WindowContext) + Send + Sync + 'static, - ) -> Self { - self.on_toggle_click = Some(Arc::new(on_toggle_click)); - self - } -} - -impl Sizable for Accordion { - fn with_size(mut self, size: impl Into) -> Self { - self.size = size.into(); - self - } -} - -impl RenderOnce for Accordion { - fn render(self, _: &mut WindowContext) -> impl IntoElement { - let mut open_ixs: Vec = Vec::new(); - let multiple = self.multiple; - let state = Rc::new(Cell::new(None)); - - self.children - .iter() - .enumerate() - .for_each(|(ix, accordion)| { - if accordion.open { - open_ixs.push(ix); - } - }); - - self.base - .id(self.id) - .children( - self.children - .into_iter() - .enumerate() - .map(|(ix, accordion)| { - let state = Rc::clone(&state); - accordion - .with_size(self.size) - .bordered(self.bordered) - .when(self.disabled, |this| this.disabled(true)) - .on_toggle_click(move |_, _| { - state.set(Some(ix)); - }) - }), - ) - .when_some( - self.on_toggle_click.filter(|_| !self.disabled), - move |this, on_toggle_click| { - this.on_click(move |_, cx| { - let mut open_ixs = open_ixs.clone(); - if let Some(ix) = state.get() { - if multiple { - if let Some(pos) = open_ixs.iter().position(|&i| i == ix) { - open_ixs.remove(pos); - } else { - open_ixs.push(ix); - } - } else { - let was_open = open_ixs.iter().any(|&i| i == ix); - open_ixs.clear(); - if !was_open { - open_ixs.push(ix); - } - } - } - - on_toggle_click(&open_ixs, cx); - }) - }, - ) - } -} - -type OnToggle = Option>; - -/// An Accordion is a vertically stacked list of items, each of which can be expanded to reveal the content associated with it. -#[derive(IntoElement)] -pub struct AccordionItem { - icon: Option, - title: AnyElement, - content: AnyElement, - open: bool, - size: Size, - bordered: bool, - disabled: bool, - on_toggle_click: OnToggle, -} - -impl AccordionItem { - pub fn new() -> Self { - Self { - icon: None, - title: SharedString::default().into_any_element(), - content: SharedString::default().into_any_element(), - open: false, - disabled: false, - on_toggle_click: None, - size: Size::default(), - bordered: true, - } - } - - pub fn icon(mut self, icon: impl Into) -> Self { - self.icon = Some(icon.into()); - self - } - - pub fn title(mut self, title: impl IntoElement) -> Self { - self.title = title.into_any_element(); - self - } - - pub fn content(mut self, content: impl IntoElement) -> Self { - self.content = content.into_any_element(); - self - } - - pub fn bordered(mut self, bordered: bool) -> Self { - self.bordered = bordered; - self - } - - pub fn open(mut self, open: bool) -> Self { - self.open = open; - self - } - - pub fn disabled(mut self, disabled: bool) -> Self { - self.disabled = disabled; - self - } - - fn on_toggle_click( - mut self, - on_toggle_click: impl Fn(&bool, &mut WindowContext) + 'static, - ) -> Self { - self.on_toggle_click = Some(Arc::new(on_toggle_click)); - self - } -} - -impl Default for AccordionItem { - fn default() -> Self { - Self::new() - } -} - -impl Sizable for AccordionItem { - fn with_size(mut self, size: impl Into) -> Self { - self.size = size.into(); - self - } -} - -impl RenderOnce for AccordionItem { - fn render(self, cx: &mut WindowContext) -> impl IntoElement { - let text_size = match self.size { - Size::XSmall => rems(0.875), - Size::Small => rems(0.875), - _ => rems(1.0), - }; - - v_flex() - .bg(cx.theme().accordion) - .overflow_hidden() - .when(self.bordered, |this| { - this.border_1().border_color(cx.theme().border).rounded_md() - }) - .text_size(text_size) - .child( - h_flex() - .id("accordion-title") - .justify_between() - .map(|this| match self.size { - Size::XSmall => this.py_0().px_1p5(), - Size::Small => this.py_0p5().px_2(), - Size::Large => this.py_1p5().px_4(), - _ => this.py_1().px_3(), - }) - .when(self.open, |this| { - this.when(self.bordered, |this| { - this.bg(cx.theme().accordion_active) - .text_color(cx.theme().foreground) - .border_b_1() - .border_color(cx.theme().border) - }) - }) - .child( - h_flex() - .items_center() - .map(|this| match self.size { - Size::XSmall => this.gap_1(), - Size::Small => this.gap_1(), - _ => this.gap_2(), - }) - .when_some(self.icon, |this, icon| { - this.child( - icon.with_size(self.size) - .text_color(cx.theme().muted_foreground), - ) - }) - .child(self.title), - ) - .when(!self.disabled, |this| { - this.cursor_pointer() - .hover(|this| this.bg(cx.theme().accordion_hover)) - .child( - Icon::new(if self.open { - IconName::ChevronUp - } else { - IconName::ChevronDown - }) - .xsmall() - .text_color(cx.theme().muted_foreground), - ) - }) - .when_some( - self.on_toggle_click.filter(|_| !self.disabled), - |this, on_toggle_click| { - this.on_click({ - move |_, cx| { - on_toggle_click(&!self.open, cx); - } - }) - }, - ), - ) - .when(self.open, |this| { - this.child( - div() - .map(|this| match self.size { - Size::XSmall => this.p_1p5(), - Size::Small => this.p_2(), - Size::Large => this.p_4(), - _ => this.p_3(), - }) - .child(self.content), - ) - }) - } -} diff --git a/crates/ui/src/button.rs b/crates/ui/src/button.rs index 88b6a75..32e353b 100644 --- a/crates/ui/src/button.rs +++ b/crates/ui/src/button.rs @@ -384,7 +384,7 @@ impl RenderOnce for Button { |this| match self.rounded { ButtonRounded::Small => this.rounded_l(px(cx.theme().radius * 0.5)), ButtonRounded::Medium => this.rounded_l(px(cx.theme().radius)), - ButtonRounded::Large => this.rounded_l(px(cx.theme().radius * 2.0)), + ButtonRounded::Large => this.rounded_l(px(cx.theme().radius * 1.6)), ButtonRounded::Size(px) => this.rounded_l(px), ButtonRounded::None => this.rounded_none(), }, @@ -394,7 +394,7 @@ impl RenderOnce for Button { |this| match self.rounded { ButtonRounded::Small => this.rounded_r(px(cx.theme().radius * 0.5)), ButtonRounded::Medium => this.rounded_r(px(cx.theme().radius)), - ButtonRounded::Large => this.rounded_r(px(cx.theme().radius * 2.0)), + ButtonRounded::Large => this.rounded_r(px(cx.theme().radius * 1.6)), ButtonRounded::Size(px) => this.rounded_r(px), ButtonRounded::None => this.rounded_none(), }, @@ -460,7 +460,7 @@ impl RenderOnce for Button { .map(|this| match self.size { Size::XSmall => this.gap_0p5().text_xs(), Size::Small => this.gap_1().text_xs(), - _ => this.gap_2().text_base(), + _ => this.gap_2().text_xs(), }) .when(!self.loading, |this| { this.when_some(self.icon, |this, icon| { diff --git a/crates/ui/src/lib.rs b/crates/ui/src/lib.rs index 27128a3..afaace2 100644 --- a/crates/ui/src/lib.rs +++ b/crates/ui/src/lib.rs @@ -1,4 +1,3 @@ -pub mod accordion; pub mod animation; pub mod badge; pub mod breadcrumb; @@ -35,8 +34,6 @@ pub mod tab; pub mod theme; pub mod tooltip; -pub use crate::Disableable; - pub use colors::*; pub use event::InteractiveElementExt; pub use focusable::FocusableCycle; @@ -46,6 +43,8 @@ pub use styled::*; pub use title_bar::*; pub use window_border::{window_border, WindowBorder}; +pub use crate::Disableable; + mod colors; mod event; mod focusable; diff --git a/crates/ui/src/styled.rs b/crates/ui/src/styled.rs index f9b2192..b7448cb 100644 --- a/crates/ui/src/styled.rs +++ b/crates/ui/src/styled.rs @@ -1,14 +1,13 @@ +use gpui::{ + div, px, Axis, Div, Element, ElementId, EntityId, FocusHandle, Pixels, Styled, WindowContext, +}; +use serde::{Deserialize, Serialize}; use std::fmt::{self, Display, Formatter}; use crate::{ scroll::{Scrollable, ScrollbarAxis}, theme::ActiveTheme, }; -use gpui::{ - div, px, Axis, Div, Edges, Element, ElementId, EntityId, FocusHandle, Pixels, Styled, - WindowContext, -}; -use serde::{Deserialize, Serialize}; /// Returns a `Div` as horizontal flex layout. pub fn h_flex() -> Div { @@ -147,47 +146,6 @@ pub enum Size { Large, } -impl Size { - /// Returns the height for table row. - pub fn table_row_height(&self) -> Pixels { - match self { - Size::XSmall => px(26.), - Size::Small => px(30.), - Size::Large => px(40.), - _ => px(32.), - } - } - /// Returns the padding for a table cell. - pub fn table_cell_padding(&self) -> Edges { - match self { - Size::XSmall => Edges { - top: px(2.), - bottom: px(2.), - left: px(4.), - right: px(4.), - }, - Size::Small => Edges { - top: px(3.), - bottom: px(3.), - left: px(6.), - right: px(6.), - }, - Size::Large => Edges { - top: px(8.), - bottom: px(8.), - left: px(12.), - right: px(12.), - }, - _ => Edges { - top: px(4.), - bottom: px(4.), - left: px(8.), - right: px(8.), - }, - } - } -} - impl From for Size { fn from(size: Pixels) -> Self { Size::Size(size) @@ -250,8 +208,6 @@ pub trait StyleSized { fn list_py(self, size: Size) -> Self; /// Apply size with the given `Size`. fn size_with(self, size: Size) -> Self; - /// Apply the table cell size (Font size, padding) with the given `Size`. - fn table_cell_size(self, size: Size) -> Self; } impl StyleSized for T { @@ -339,19 +295,6 @@ impl StyleSized for T { Size::Size(size) => self.size(size), } } - - fn table_cell_size(self, size: Size) -> Self { - let padding = size.table_cell_padding(); - match size { - Size::XSmall => self.text_sm(), - Size::Small => self.text_sm(), - _ => self, - } - .pl(padding.left) - .pr(padding.right) - .pt(padding.top) - .pb(padding.bottom) - } } pub trait AxisExt { diff --git a/crates/ui/src/theme.rs b/crates/ui/src/theme.rs index d493066..a21d8b4 100644 --- a/crates/ui/src/theme.rs +++ b/crates/ui/src/theme.rs @@ -149,9 +149,6 @@ impl Colorize for Hsla { pub struct ThemeColor { pub accent: Hsla, pub accent_foreground: Hsla, - pub accordion: Hsla, - pub accordion_active: Hsla, - pub accordion_hover: Hsla, pub background: Hsla, pub border: Hsla, pub window_border: Hsla, @@ -201,14 +198,6 @@ pub struct ThemeColor { pub tab_active_foreground: Hsla, pub tab_bar: Hsla, pub tab_foreground: Hsla, - pub table: Hsla, - pub table_active: Hsla, - pub table_active_border: Hsla, - pub table_even: Hsla, - pub table_head: Hsla, - pub table_head_foreground: Hsla, - pub table_hover: Hsla, - pub table_row_border: Hsla, pub title_bar: Hsla, pub title_bar_border: Hsla, pub sidebar: Hsla, @@ -225,9 +214,6 @@ impl ThemeColor { Self { accent: hsl(240.0, 5.0, 96.0), accent_foreground: hsl(240.0, 5.9, 10.0), - accordion: hsl(0.0, 0.0, 100.0), - accordion_active: hsl(240.0, 5.9, 90.0), - accordion_hover: hsl(240.0, 4.8, 95.9).opacity(0.7), background: hsl(0.0, 0.0, 100.), border: hsl(240.0, 5.9, 90.0), window_border: hsl(240.0, 5.9, 78.0), @@ -277,14 +263,6 @@ impl ThemeColor { tab_active_foreground: hsl(240.0, 10., 3.9), tab_bar: hsl(240.0, 4.8, 95.9), tab_foreground: hsl(240.0, 10., 3.9), - table: hsl(0.0, 0.0, 100.), - table_active: hsl(211.0, 97.0, 85.0).opacity(0.2), - table_active_border: hsl(211.0, 97.0, 85.0), - table_even: hsl(240.0, 5.0, 96.0), - table_head: hsl(0.0, 0.0, 100.), - table_head_foreground: hsl(240.0, 10., 3.9).opacity(0.7), - table_hover: hsl(240.0, 4.8, 95.0), - table_row_border: hsl(240.0, 7.7, 94.5), title_bar: hsl(0.0, 0.0, 98.0), title_bar_border: hsl(220.0, 13.0, 91.0), sidebar: hsl(0.0, 0.0, 98.0), @@ -301,9 +279,6 @@ impl ThemeColor { Self { accent: hsl(240.0, 3.7, 15.9), accent_foreground: hsl(0.0, 0.0, 78.0), - accordion: hsl(299.0, 2., 11.), - accordion_active: hsl(240.0, 3.7, 16.9), - accordion_hover: hsl(240.0, 3.7, 15.9).opacity(0.7), background: hsl(0.0, 0.0, 8.0), border: hsl(240.0, 3.7, 16.9), window_border: hsl(240.0, 3.7, 28.0), @@ -353,14 +328,6 @@ impl ThemeColor { tab_active_foreground: hsl(0., 0., 78.), tab_bar: hsl(299.0, 0., 5.5), tab_foreground: hsl(0., 0., 78.), - table: hsl(0.0, 0.0, 8.0), - table_active: hsl(240.0, 3.7, 15.0).opacity(0.2), - table_active_border: hsl(240.0, 5.9, 35.5), - table_even: hsl(240.0, 3.7, 10.0), - table_head: hsl(0.0, 0.0, 8.0), - table_head_foreground: hsl(0., 0., 78.).opacity(0.7), - table_hover: hsl(240.0, 3.7, 15.9).opacity(0.5), - table_row_border: hsl(240.0, 3.7, 16.9).opacity(0.5), title_bar: hsl(240.0, 0.0, 10.0), title_bar_border: hsl(240.0, 3.7, 15.9), sidebar: hsl(240.0, 0.0, 10.0), @@ -433,10 +400,6 @@ impl Theme { self.secondary_hover = self.secondary_hover.apply(mask_color); self.secondary_active = self.secondary_active.apply(mask_color); self.secondary_foreground = self.secondary_foreground.apply(mask_color); - // self.destructive = self.destructive.apply(mask_color); - // self.destructive_hover = self.destructive_hover.apply(mask_color); - // self.destructive_active = self.destructive_active.apply(mask_color); - // self.destructive_foreground = self.destructive_foreground.apply(mask_color); self.muted = self.muted.apply(mask_color); self.muted_foreground = self.muted_foreground.apply(mask_color); self.accent = self.accent.apply(mask_color); @@ -444,7 +407,6 @@ impl Theme { self.border = self.border.apply(mask_color); self.input = self.input.apply(mask_color); self.ring = self.ring.apply(mask_color); - // self.selection = self.selection.apply(mask_color); self.scrollbar = self.scrollbar.apply(mask_color); self.scrollbar_thumb = self.scrollbar_thumb.apply(mask_color); self.scrollbar_thumb_hover = self.scrollbar_thumb_hover.apply(mask_color); @@ -465,21 +427,10 @@ impl Theme { self.list_active = self.list_active.apply(mask_color); self.list_active_border = self.list_active_border.apply(mask_color); self.list_hover = self.list_hover.apply(mask_color); - self.table = self.table.apply(mask_color); - self.table_even = self.table_even.apply(mask_color); - self.table_active = self.table_active.apply(mask_color); - self.table_active_border = self.table_active_border.apply(mask_color); - self.table_hover = self.table_hover.apply(mask_color); - self.table_row_border = self.table_row_border.apply(mask_color); - self.table_head = self.table_head.apply(mask_color); - self.table_head_foreground = self.table_head_foreground.apply(mask_color); self.link = self.link.apply(mask_color); self.link_hover = self.link_hover.apply(mask_color); self.link_active = self.link_active.apply(mask_color); self.skeleton = self.skeleton.apply(mask_color); - self.accordion = self.accordion.apply(mask_color); - self.accordion_hover = self.accordion_hover.apply(mask_color); - self.accordion_active = self.accordion_active.apply(mask_color); self.title_bar = self.title_bar.apply(mask_color); self.title_bar_border = self.title_bar_border.apply(mask_color); self.sidebar = self.sidebar.apply(mask_color); diff --git a/crates/ui/src/window_border.rs b/crates/ui/src/window_border.rs index ff098e1..67a8728 100644 --- a/crates/ui/src/window_border.rs +++ b/crates/ui/src/window_border.rs @@ -1,6 +1,3 @@ -// From: -// https://github.com/zed-industries/zed/blob/a8afc63a91f6b75528540dcffe73dc8ce0c92ad8/crates/gpui/examples/window_shadow.rs - use gpui::{ canvas, div, point, prelude::FluentBuilder as _, px, AnyElement, Bounds, CursorStyle, Decorations, Edges, Hsla, InteractiveElement as _, IntoElement, MouseButton, ParentElement,