2 Commits

Author SHA1 Message Date
4aabab3e4e wip: refactor tabs 2026-03-11 16:30:21 +07:00
affb339237 remove connect verification in chat ui 2026-03-11 08:46:36 +07:00
29 changed files with 131 additions and 222 deletions

View File

@@ -60,7 +60,6 @@
"tab_inactive_foreground": "#b5bfe2", "tab_inactive_foreground": "#b5bfe2",
"tab_active_background": "#303446", "tab_active_background": "#303446",
"tab_active_foreground": "#c6d0f5", "tab_active_foreground": "#c6d0f5",
"tab_hover_foreground": "#babbf1",
"scrollbar_thumb_background": "#c6d0f533", "scrollbar_thumb_background": "#c6d0f533",
"scrollbar_thumb_hover_background": "#c6d0f580", "scrollbar_thumb_hover_background": "#c6d0f580",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",
@@ -127,7 +126,6 @@
"tab_inactive_foreground": "#b5bfe2", "tab_inactive_foreground": "#b5bfe2",
"tab_active_background": "#303446", "tab_active_background": "#303446",
"tab_active_foreground": "#c6d0f5", "tab_active_foreground": "#c6d0f5",
"tab_hover_foreground": "#babbf1",
"scrollbar_thumb_background": "#c6d0f533", "scrollbar_thumb_background": "#c6d0f533",
"scrollbar_thumb_hover_background": "#c6d0f580", "scrollbar_thumb_hover_background": "#c6d0f580",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",

View File

@@ -60,7 +60,6 @@
"tab_inactive_foreground": "#5c5f77", "tab_inactive_foreground": "#5c5f77",
"tab_active_background": "#eff1f5", "tab_active_background": "#eff1f5",
"tab_active_foreground": "#4c4f69", "tab_active_foreground": "#4c4f69",
"tab_hover_foreground": "#8839ef",
"scrollbar_thumb_background": "#4c4f6933", "scrollbar_thumb_background": "#4c4f6933",
"scrollbar_thumb_hover_background": "#4c4f6980", "scrollbar_thumb_hover_background": "#4c4f6980",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",
@@ -127,7 +126,6 @@
"tab_inactive_foreground": "#5c5f77", "tab_inactive_foreground": "#5c5f77",
"tab_active_background": "#eff1f5", "tab_active_background": "#eff1f5",
"tab_active_foreground": "#4c4f69", "tab_active_foreground": "#4c4f69",
"tab_hover_foreground": "#8839ef",
"scrollbar_thumb_background": "#4c4f6933", "scrollbar_thumb_background": "#4c4f6933",
"scrollbar_thumb_hover_background": "#4c4f6980", "scrollbar_thumb_hover_background": "#4c4f6980",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",

View File

@@ -60,7 +60,6 @@
"tab_inactive_foreground": "#b8c0e0", "tab_inactive_foreground": "#b8c0e0",
"tab_active_background": "#24273a", "tab_active_background": "#24273a",
"tab_active_foreground": "#cad3f5", "tab_active_foreground": "#cad3f5",
"tab_hover_foreground": "#b7bdf8",
"scrollbar_thumb_background": "#cad3f533", "scrollbar_thumb_background": "#cad3f533",
"scrollbar_thumb_hover_background": "#cad3f580", "scrollbar_thumb_hover_background": "#cad3f580",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",
@@ -127,7 +126,6 @@
"tab_inactive_foreground": "#b8c0e0", "tab_inactive_foreground": "#b8c0e0",
"tab_active_background": "#24273a", "tab_active_background": "#24273a",
"tab_active_foreground": "#cad3f5", "tab_active_foreground": "#cad3f5",
"tab_hover_foreground": "#b7bdf8",
"scrollbar_thumb_background": "#cad3f533", "scrollbar_thumb_background": "#cad3f533",
"scrollbar_thumb_hover_background": "#cad3f580", "scrollbar_thumb_hover_background": "#cad3f580",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",

View File

@@ -60,7 +60,6 @@
"tab_inactive_foreground": "#bac2de", "tab_inactive_foreground": "#bac2de",
"tab_active_background": "#1e1e2e", "tab_active_background": "#1e1e2e",
"tab_active_foreground": "#cdd6f4", "tab_active_foreground": "#cdd6f4",
"tab_hover_foreground": "#b4befe",
"scrollbar_thumb_background": "#cdd6f433", "scrollbar_thumb_background": "#cdd6f433",
"scrollbar_thumb_hover_background": "#cdd6f580", "scrollbar_thumb_hover_background": "#cdd6f580",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",
@@ -127,7 +126,6 @@
"tab_inactive_foreground": "#bac2de", "tab_inactive_foreground": "#bac2de",
"tab_active_background": "#1e1e2e", "tab_active_background": "#1e1e2e",
"tab_active_foreground": "#cdd6f4", "tab_active_foreground": "#cdd6f4",
"tab_hover_foreground": "#b4befe",
"scrollbar_thumb_background": "#cdd6f433", "scrollbar_thumb_background": "#cdd6f433",
"scrollbar_thumb_hover_background": "#cdd6f580", "scrollbar_thumb_hover_background": "#cdd6f580",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",

View File

@@ -60,7 +60,6 @@
"tab_inactive_foreground": "#6F6E69", "tab_inactive_foreground": "#6F6E69",
"tab_active_background": "#FFFCF0", "tab_active_background": "#FFFCF0",
"tab_active_foreground": "#100F0F", "tab_active_foreground": "#100F0F",
"tab_hover_foreground": "#205EA6",
"scrollbar_thumb_background": "#100F0F33", "scrollbar_thumb_background": "#100F0F33",
"scrollbar_thumb_hover_background": "#100F0F4d", "scrollbar_thumb_hover_background": "#100F0F4d",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",
@@ -127,7 +126,6 @@
"tab_inactive_foreground": "#878580", "tab_inactive_foreground": "#878580",
"tab_active_background": "#100F0F", "tab_active_background": "#100F0F",
"tab_active_foreground": "#FFFCF0", "tab_active_foreground": "#FFFCF0",
"tab_hover_foreground": "#4385BE",
"scrollbar_thumb_background": "#FFFCF033", "scrollbar_thumb_background": "#FFFCF033",
"scrollbar_thumb_hover_background": "#FFFCF04d", "scrollbar_thumb_hover_background": "#FFFCF04d",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",

View File

@@ -60,7 +60,6 @@
"tab_inactive_foreground": "#797593", "tab_inactive_foreground": "#797593",
"tab_active_background": "#faf4ed", "tab_active_background": "#faf4ed",
"tab_active_foreground": "#575279", "tab_active_foreground": "#575279",
"tab_hover_foreground": "#907aa9",
"scrollbar_thumb_background": "#57527933", "scrollbar_thumb_background": "#57527933",
"scrollbar_thumb_hover_background": "#5752794d", "scrollbar_thumb_hover_background": "#5752794d",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",
@@ -127,7 +126,6 @@
"tab_inactive_foreground": "#797593", "tab_inactive_foreground": "#797593",
"tab_active_background": "#faf4ed", "tab_active_background": "#faf4ed",
"tab_active_foreground": "#575279", "tab_active_foreground": "#575279",
"tab_hover_foreground": "#907aa9",
"scrollbar_thumb_background": "#57527933", "scrollbar_thumb_background": "#57527933",
"scrollbar_thumb_hover_background": "#5752794d", "scrollbar_thumb_hover_background": "#5752794d",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",

View File

@@ -60,7 +60,6 @@
"tab_inactive_foreground": "#908caa", "tab_inactive_foreground": "#908caa",
"tab_active_background": "#232136", "tab_active_background": "#232136",
"tab_active_foreground": "#e0def4", "tab_active_foreground": "#e0def4",
"tab_hover_foreground": "#c4a7e7",
"scrollbar_thumb_background": "#e0def433", "scrollbar_thumb_background": "#e0def433",
"scrollbar_thumb_hover_background": "#e0def44d", "scrollbar_thumb_hover_background": "#e0def44d",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",
@@ -127,7 +126,6 @@
"tab_inactive_foreground": "#908caa", "tab_inactive_foreground": "#908caa",
"tab_active_background": "#232136", "tab_active_background": "#232136",
"tab_active_foreground": "#e0def4", "tab_active_foreground": "#e0def4",
"tab_hover_foreground": "#c4a7e7",
"scrollbar_thumb_background": "#e0def433", "scrollbar_thumb_background": "#e0def433",
"scrollbar_thumb_hover_background": "#e0def44d", "scrollbar_thumb_hover_background": "#e0def44d",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",

View File

@@ -60,7 +60,6 @@
"tab_inactive_foreground": "#908caa", "tab_inactive_foreground": "#908caa",
"tab_active_background": "#191724", "tab_active_background": "#191724",
"tab_active_foreground": "#e0def4", "tab_active_foreground": "#e0def4",
"tab_hover_foreground": "#c4a7e7",
"scrollbar_thumb_background": "#e0def433", "scrollbar_thumb_background": "#e0def433",
"scrollbar_thumb_hover_background": "#e0def44d", "scrollbar_thumb_hover_background": "#e0def44d",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",
@@ -127,7 +126,6 @@
"tab_inactive_foreground": "#908caa", "tab_inactive_foreground": "#908caa",
"tab_active_background": "#191724", "tab_active_background": "#191724",
"tab_active_foreground": "#e0def4", "tab_active_foreground": "#e0def4",
"tab_hover_foreground": "#c4a7e7",
"scrollbar_thumb_background": "#e0def433", "scrollbar_thumb_background": "#e0def433",
"scrollbar_thumb_hover_background": "#e0def44d", "scrollbar_thumb_hover_background": "#e0def44d",
"scrollbar_thumb_border": "#00000000", "scrollbar_thumb_border": "#00000000",

View File

@@ -1,6 +1,5 @@
use std::collections::{BTreeMap, BTreeSet, HashSet}; use std::collections::{BTreeMap, BTreeSet, HashSet};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration;
pub use actions::*; pub use actions::*;
use anyhow::{Context as AnyhowContext, Error}; use anyhow::{Context as AnyhowContext, Error};
@@ -24,7 +23,7 @@ use state::{NostrRegistry, upload};
use theme::ActiveTheme; use theme::ActiveTheme;
use ui::avatar::Avatar; use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants}; use ui::button::{Button, ButtonVariants};
use ui::dock_area::panel::{Panel, PanelEvent}; use ui::dock::{Panel, PanelEvent};
use ui::indicator::Indicator; use ui::indicator::Indicator;
use ui::input::{InputEvent, InputState, TextInput}; use ui::input::{InputEvent, InputState, TextInput};
use ui::menu::DropdownMenu; use ui::menu::DropdownMenu;
@@ -42,11 +41,6 @@ mod text;
const ANNOUNCEMENT: &str = const ANNOUNCEMENT: &str =
"This conversation is private. Only members can see each other's messages."; "This conversation is private. Only members can see each other's messages.";
const NO_INBOX: &str = "has not set up messaging relays. \
They will not receive messages you send.";
const NO_ANNOUNCEMENT: &str = "has not set up an encryption key. \
You cannot send messages encrypted with an encryption key to them yet. \
Coop automatically uses your identity to encrypt messages.";
pub fn init(room: WeakEntity<Room>, window: &mut Window, cx: &mut App) -> Entity<ChatPanel> { pub fn init(room: WeakEntity<Room>, window: &mut Window, cx: &mut App) -> Entity<ChatPanel> {
cx.new(|cx| ChatPanel::new(room, window, cx)) cx.new(|cx| ChatPanel::new(room, window, cx))
@@ -131,7 +125,7 @@ impl ChatPanel {
}); });
// Define subject input state // Define subject input state
let subject_input = cx.new(|cx| InputState::new(window, cx).placeholder("Nostr Meetup")); let subject_input = cx.new(|cx| InputState::new(window, cx).placeholder("New subject..."));
let subject_bar = cx.new(|_cx| false); let subject_bar = cx.new(|_cx| false);
// Define subscriptions // Define subscriptions
@@ -161,7 +155,6 @@ impl ChatPanel {
// Define all functions that will run after the current cycle // Define all functions that will run after the current cycle
cx.defer_in(window, |this, window, cx| { cx.defer_in(window, |this, window, cx| {
this.connect(window, cx);
this.handle_notifications(cx); this.handle_notifications(cx);
this.subscribe_room_events(window, cx); this.subscribe_room_events(window, cx);
this.get_messages(window, cx); this.get_messages(window, cx);
@@ -187,49 +180,6 @@ impl ChatPanel {
} }
} }
/// Get all necessary data for each member
fn connect(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let Ok((members, connect)) = self
.room
.read_with(cx, |this, cx| (this.members(), this.connect(cx)))
else {
return;
};
// Run the connect task in background
self.tasks.push(connect);
// Spawn another task to verify after 3 seconds
self.tasks.push(cx.spawn_in(window, async move |this, cx| {
cx.background_executor().timer(Duration::from_secs(3)).await;
// Verify the connection
this.update_in(cx, |this, _window, cx| {
let persons = PersonRegistry::global(cx);
for member in members.into_iter() {
let profile = persons.read(cx).get(&member, cx);
if profile.announcement().is_none() {
let content = format!("{} {}", profile.name(), NO_ANNOUNCEMENT);
let message = Message::warning(content);
this.insert_message(message, true, cx);
}
if profile.messaging_relays().is_empty() {
let content = format!("{} {}", profile.name(), NO_INBOX);
let message = Message::warning(content);
this.insert_message(message, true, cx);
}
}
})?;
Ok(())
}));
}
/// Handle nostr notifications /// Handle nostr notifications
fn handle_notifications(&mut self, cx: &mut Context<Self>) { fn handle_notifications(&mut self, cx: &mut Context<Self>) {
let nostr = NostrRegistry::global(cx); let nostr = NostrRegistry::global(cx);

View File

@@ -2,16 +2,16 @@ use std::time::Duration;
use anyhow::Error; use anyhow::Error;
use gpui::{ use gpui::{
div, AnyElement, App, AppContext, ClipboardItem, Context, Entity, EventEmitter, FocusHandle, AnyElement, App, AppContext, ClipboardItem, Context, Entity, EventEmitter, FocusHandle,
Focusable, IntoElement, ParentElement, Render, SharedString, Styled, Task, Window, Focusable, IntoElement, ParentElement, Render, SharedString, Styled, Task, Window, div,
}; };
use nostr_sdk::prelude::*; use nostr_sdk::prelude::*;
use state::KEYRING; use state::KEYRING;
use theme::ActiveTheme; use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants}; use ui::button::{Button, ButtonVariants};
use ui::dock_area::panel::{Panel, PanelEvent}; use ui::dock::{Panel, PanelEvent};
use ui::input::{InputState, TextInput}; use ui::input::{InputState, TextInput};
use ui::{divider, v_flex, IconName, Sizable, StyledExt}; use ui::{IconName, Sizable, StyledExt, divider, v_flex};
const MSG: &str = "Store your account keys in a safe location. \ const MSG: &str = "Store your account keys in a safe location. \
You can restore your account or move to another client anytime you want."; You can restore your account or move to another client anytime you want.";

View File

@@ -15,7 +15,7 @@ use state::NostrRegistry;
use theme::ActiveTheme; use theme::ActiveTheme;
use ui::avatar::Avatar; use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants}; use ui::button::{Button, ButtonVariants};
use ui::dock_area::panel::{Panel, PanelEvent}; use ui::dock::{Panel, PanelEvent};
use ui::input::{InputEvent, InputState, TextInput}; use ui::input::{InputEvent, InputState, TextInput};
use ui::{Disableable, IconName, Sizable, StyledExt, WindowExtension, h_flex, v_flex}; use ui::{Disableable, IconName, Sizable, StyledExt, WindowExtension, h_flex, v_flex};

View File

@@ -5,8 +5,7 @@ use gpui::{
use state::NostrRegistry; use state::NostrRegistry;
use theme::ActiveTheme; use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants}; use ui::button::{Button, ButtonVariants};
use ui::dock_area::dock::DockPlacement; use ui::dock::{DockPlacement, Panel, PanelEvent};
use ui::dock_area::panel::{Panel, PanelEvent};
use ui::{Icon, IconName, Sizable, StyledExt, h_flex, v_flex}; use ui::{Icon, IconName, Sizable, StyledExt, h_flex, v_flex};
use crate::panels::profile; use crate::panels::profile;

View File

@@ -13,7 +13,7 @@ use smallvec::{SmallVec, smallvec};
use state::NostrRegistry; use state::NostrRegistry;
use theme::ActiveTheme; use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants}; use ui::button::{Button, ButtonVariants};
use ui::dock_area::panel::{Panel, PanelEvent}; use ui::dock::{Panel, PanelEvent};
use ui::input::{InputEvent, InputState, TextInput}; use ui::input::{InputEvent, InputState, TextInput};
use ui::{Disableable, IconName, Sizable, StyledExt, WindowExtension, divider, h_flex, v_flex}; use ui::{Disableable, IconName, Sizable, StyledExt, WindowExtension, divider, h_flex, v_flex};

View File

@@ -14,7 +14,7 @@ use state::{NostrRegistry, upload};
use theme::ActiveTheme; use theme::ActiveTheme;
use ui::avatar::Avatar; use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants}; use ui::button::{Button, ButtonVariants};
use ui::dock_area::panel::{Panel, PanelEvent}; use ui::dock::{Panel, PanelEvent};
use ui::input::{InputState, TextInput}; use ui::input::{InputState, TextInput};
use ui::notification::Notification; use ui::notification::Notification;
use ui::{Disableable, IconName, Sizable, StyledExt, WindowExtension, h_flex, v_flex}; use ui::{Disableable, IconName, Sizable, StyledExt, WindowExtension, h_flex, v_flex};

View File

@@ -1,23 +1,23 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::time::Duration; use std::time::Duration;
use anyhow::{anyhow, Context as AnyhowContext, Error}; use anyhow::{Context as AnyhowContext, Error, anyhow};
use gpui::prelude::FluentBuilder; use gpui::prelude::FluentBuilder;
use gpui::{ use gpui::{
div, px, rems, Action, AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Action, AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable,
Focusable, InteractiveElement, IntoElement, ParentElement, Render, SharedString, Styled, InteractiveElement, IntoElement, ParentElement, Render, SharedString, Styled, Subscription,
Subscription, Task, TextAlign, Window, Task, TextAlign, Window, div, px, rems,
}; };
use nostr_sdk::prelude::*; use nostr_sdk::prelude::*;
use serde::Deserialize; use serde::Deserialize;
use smallvec::{smallvec, SmallVec}; use smallvec::{SmallVec, smallvec};
use state::NostrRegistry; use state::NostrRegistry;
use theme::ActiveTheme; use theme::ActiveTheme;
use ui::button::{Button, ButtonVariants}; use ui::button::{Button, ButtonVariants};
use ui::dock_area::panel::{Panel, PanelEvent}; use ui::dock::{Panel, PanelEvent};
use ui::input::{InputEvent, InputState, TextInput}; use ui::input::{InputEvent, InputState, TextInput};
use ui::menu::DropdownMenu; use ui::menu::DropdownMenu;
use ui::{divider, h_flex, v_flex, Disableable, IconName, Sizable, StyledExt, WindowExtension}; 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 \ const MSG: &str = "Relay List (or Gossip Relays) are a set of relays \
where you will publish all your events. Others also publish events \ where you will publish all your events. Others also publish events \

View File

@@ -3,16 +3,16 @@ use std::rc::Rc;
use chat::RoomKind; use chat::RoomKind;
use gpui::prelude::FluentBuilder; use gpui::prelude::FluentBuilder;
use gpui::{ use gpui::{
div, App, ClickEvent, InteractiveElement, IntoElement, ParentElement as _, RenderOnce, App, ClickEvent, InteractiveElement, IntoElement, ParentElement as _, RenderOnce, SharedString,
SharedString, StatefulInteractiveElement, Styled, Window, StatefulInteractiveElement, Styled, Window, div,
}; };
use nostr_sdk::prelude::*; use nostr_sdk::prelude::*;
use settings::AppSettings; use settings::AppSettings;
use theme::ActiveTheme; use theme::ActiveTheme;
use ui::avatar::Avatar; use ui::avatar::Avatar;
use ui::dock_area::ClosePanel; use ui::dock::ClosePanel;
use ui::modal::ModalButtonProps; use ui::modal::ModalButtonProps;
use ui::{h_flex, Icon, IconName, Selectable, Sizable, StyledExt, WindowExtension}; use ui::{Icon, IconName, Selectable, Sizable, StyledExt, WindowExtension, h_flex};
use crate::dialogs::screening; use crate::dialogs::screening;

View File

@@ -18,7 +18,7 @@ use smallvec::{SmallVec, smallvec};
use state::{FIND_DELAY, NostrRegistry}; use state::{FIND_DELAY, NostrRegistry};
use theme::{ActiveTheme, SIDEBAR_WIDTH, TABBAR_HEIGHT}; use theme::{ActiveTheme, SIDEBAR_WIDTH, TABBAR_HEIGHT};
use ui::button::{Button, ButtonVariants}; use ui::button::{Button, ButtonVariants};
use ui::dock_area::panel::{Panel, PanelEvent}; use ui::dock::{Panel, PanelEvent};
use ui::indicator::Indicator; use ui::indicator::Indicator;
use ui::input::{InputEvent, InputState, TextInput}; use ui::input::{InputEvent, InputState, TextInput};
use ui::notification::Notification; use ui::notification::Notification;

View File

@@ -18,9 +18,7 @@ use theme::{ActiveTheme, SIDEBAR_WIDTH, Theme, ThemeRegistry};
use title_bar::TitleBar; use title_bar::TitleBar;
use ui::avatar::Avatar; use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants}; use ui::button::{Button, ButtonVariants};
use ui::dock_area::dock::DockPlacement; use ui::dock::{ClosePanel, DockArea, DockItem, DockPlacement, PanelView};
use ui::dock_area::panel::PanelView;
use ui::dock_area::{ClosePanel, DockArea, DockItem};
use ui::menu::{DropdownMenu, PopupMenuItem}; use ui::menu::{DropdownMenu, PopupMenuItem};
use ui::notification::{Notification, NotificationKind}; use ui::notification::{Notification, NotificationKind};
use ui::{Disableable, IconName, Root, Sizable, WindowExtension, h_flex, v_flex}; use ui::{Disableable, IconName, Root, Sizable, WindowExtension, h_flex, v_flex};
@@ -277,8 +275,8 @@ impl Workspace {
/// Set the center dock layout /// Set the center dock layout
fn set_center_layout(&mut self, window: &mut Window, cx: &mut Context<Self>) { fn set_center_layout(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let dock = self.dock.downgrade(); let dock = self.dock.downgrade();
let greeeter = Arc::new(greeter::init(window, cx)); let greeter = Arc::new(greeter::init(window, cx));
let tabs = DockItem::tabs(vec![greeeter], None, &dock, window, cx); let tabs = DockItem::tabs(vec![greeter], None, &dock, window, cx);
let center = DockItem::split(Axis::Vertical, vec![tabs], &dock, window, cx); let center = DockItem::split(Axis::Vertical, vec![tabs], &dock, window, cx);
// Update the layout with center dock // Update the layout with center dock

View File

@@ -1,4 +1,4 @@
use gpui::{hsla, Hsla, Rgba}; use gpui::{Hsla, Rgba, hsla};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -77,11 +77,10 @@ pub struct ThemeColors {
pub ghost_element_disabled: Hsla, pub ghost_element_disabled: Hsla,
// Tab colors // Tab colors
pub tab_inactive_background: Hsla, pub tab_background: Hsla,
pub tab_inactive_foreground: Hsla, pub tab_foreground: Hsla,
pub tab_active_background: Hsla, pub tab_active_background: Hsla,
pub tab_active_foreground: Hsla, pub tab_active_foreground: Hsla,
pub tab_hover_foreground: Hsla,
// Scrollbar colors // Scrollbar colors
pub scrollbar_thumb_background: Hsla, pub scrollbar_thumb_background: Hsla,
@@ -166,11 +165,10 @@ impl ThemeColors {
ghost_element_selected: neutral().light().step_5(), ghost_element_selected: neutral().light().step_5(),
ghost_element_disabled: neutral().light_alpha().step_2(), ghost_element_disabled: neutral().light_alpha().step_2(),
tab_inactive_background: neutral().light().step_2(), tab_background: neutral().light().step_3(),
tab_inactive_foreground: neutral().light().step_11(), tab_foreground: neutral().light().step_11(),
tab_active_background: neutral().light().step_1(), tab_active_background: neutral().light().step_1(),
tab_active_foreground: neutral().light().step_12(), tab_active_foreground: neutral().light().step_12(),
tab_hover_foreground: brand().light().step_9(),
scrollbar_thumb_background: neutral().light_alpha().step_3(), scrollbar_thumb_background: neutral().light_alpha().step_3(),
scrollbar_thumb_hover_background: neutral().light_alpha().step_4(), scrollbar_thumb_hover_background: neutral().light_alpha().step_4(),
@@ -250,11 +248,10 @@ impl ThemeColors {
ghost_element_selected: neutral().dark().step_5(), ghost_element_selected: neutral().dark().step_5(),
ghost_element_disabled: neutral().dark_alpha().step_2(), ghost_element_disabled: neutral().dark_alpha().step_2(),
tab_inactive_background: neutral().dark().step_2(), tab_background: neutral().dark().step_3(),
tab_inactive_foreground: neutral().dark().step_11(), tab_foreground: neutral().dark().step_11(),
tab_active_background: neutral().dark().step_3(), tab_active_background: neutral().dark().step_1(),
tab_active_foreground: neutral().dark().step_12(), tab_active_foreground: neutral().dark().step_12(),
tab_hover_foreground: brand().dark().step_9(),
scrollbar_thumb_background: neutral().dark_alpha().step_3(), scrollbar_thumb_background: neutral().dark_alpha().step_3(),
scrollbar_thumb_hover_background: neutral().dark_alpha().step_4(), scrollbar_thumb_hover_background: neutral().dark_alpha().step_4(),

View File

@@ -34,7 +34,7 @@ pub const CLIENT_SIDE_DECORATION_BORDER: Pixels = px(1.0);
pub const TITLEBAR_HEIGHT: Pixels = px(36.0); pub const TITLEBAR_HEIGHT: Pixels = px(36.0);
/// Defines workspace tabbar height /// Defines workspace tabbar height
pub const TABBAR_HEIGHT: Pixels = px(28.0); pub const TABBAR_HEIGHT: Pixels = px(32.0);
/// Defines default sidebar width /// Defines default sidebar width
pub const SIDEBAR_WIDTH: Pixels = px(240.); pub const SIDEBAR_WIDTH: Pixels = px(240.);

View File

@@ -3,20 +3,26 @@ use std::sync::Arc;
use gpui::prelude::FluentBuilder as _; use gpui::prelude::FluentBuilder as _;
use gpui::{ use gpui::{
div, px, App, AppContext, Axis, Context, Element, Entity, IntoElement, MouseMoveEvent, App, AppContext, Axis, Context, Element, Empty, Entity, IntoElement, MouseMoveEvent,
MouseUpEvent, ParentElement as _, Pixels, Point, Render, Style, Styled as _, WeakEntity, MouseUpEvent, ParentElement as _, Pixels, Point, Render, Style, Styled as _, WeakEntity,
Window, Window, div, px,
}; };
use super::{DockArea, DockItem}; use super::{DockArea, DockItem};
use crate::dock_area::panel::PanelView;
use crate::dock_area::tab_panel::TabPanel;
use crate::resizable::{resize_handle, PANEL_MIN_SIZE};
use crate::StyledExt; use crate::StyledExt;
use crate::dock::panel::PanelView;
use crate::dock::tab_panel::TabPanel;
use crate::resizable::{PANEL_MIN_SIZE, resize_handle};
#[derive(Clone, Render)] #[derive(Clone)]
struct ResizePanel; struct ResizePanel;
impl Render for ResizePanel {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
Empty
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DockPlacement { pub enum DockPlacement {
Center, Center,

View File

@@ -2,22 +2,24 @@ use std::sync::Arc;
use gpui::prelude::FluentBuilder; use gpui::prelude::FluentBuilder;
use gpui::{ use gpui::{
actions, div, px, AnyElement, AnyView, App, AppContext, Axis, Bounds, Context, Decorations, AnyElement, AnyView, App, AppContext, Axis, Bounds, Context, Decorations, Edges, Entity,
Edges, Entity, EntityId, EventEmitter, Focusable, InteractiveElement as _, IntoElement, EntityId, EventEmitter, Focusable, InteractiveElement as _, IntoElement, ParentElement as _,
ParentElement as _, Pixels, Render, SharedString, Styled, Subscription, WeakEntity, Window, Pixels, Render, SharedString, Styled, Subscription, WeakEntity, Window, actions, div, px,
}; };
use theme::CLIENT_SIDE_DECORATION_ROUNDING; use theme::CLIENT_SIDE_DECORATION_ROUNDING;
use crate::dock_area::dock::{Dock, DockPlacement};
use crate::dock_area::panel::{Panel, PanelEvent, PanelStyle, PanelView};
use crate::dock_area::stack_panel::StackPanel;
use crate::dock_area::tab_panel::TabPanel;
use crate::ElementExt; use crate::ElementExt;
pub mod dock; #[allow(clippy::module_inception)]
pub mod panel; mod dock;
pub mod stack_panel; mod panel;
pub mod tab_panel; mod stack_panel;
mod tab_panel;
pub use dock::*;
pub use panel::*;
pub use stack_panel::*;
pub use tab_panel::*;
actions!(dock, [ToggleZoom, ClosePanel]); actions!(dock, [ToggleZoom, ClosePanel]);

View File

@@ -1,5 +1,5 @@
use gpui::{ use gpui::{
AnyElement, AnyView, App, Element, Entity, EventEmitter, FocusHandle, Focusable, Hsla, Render, AnyElement, AnyView, App, Element, Entity, EventEmitter, FocusHandle, Focusable, Render,
SharedString, Window, SharedString, Window,
}; };
@@ -21,12 +21,6 @@ pub enum PanelStyle {
TabBar, TabBar,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TitleStyle {
pub background: Hsla,
pub foreground: Hsla,
}
pub trait Panel: EventEmitter<PanelEvent> + Render + Focusable { pub trait Panel: EventEmitter<PanelEvent> + Render + Focusable {
/// The name of the panel used to serialize, deserialize and identify the panel. /// The name of the panel used to serialize, deserialize and identify the panel.
/// ///

View File

@@ -10,8 +10,8 @@ use smallvec::SmallVec;
use theme::{ActiveTheme, AxisExt as _, CLIENT_SIDE_DECORATION_ROUNDING, Placement}; use theme::{ActiveTheme, AxisExt as _, CLIENT_SIDE_DECORATION_ROUNDING, Placement};
use super::{DockArea, PanelEvent}; use super::{DockArea, PanelEvent};
use crate::dock_area::panel::{Panel, PanelView}; use crate::dock::panel::{Panel, PanelView};
use crate::dock_area::tab_panel::TabPanel; use crate::dock::tab_panel::TabPanel;
use crate::h_flex; use crate::h_flex;
use crate::resizable::{ use crate::resizable::{
PANEL_MIN_SIZE, ResizablePanelEvent, ResizablePanelGroup, ResizablePanelState, ResizableState, PANEL_MIN_SIZE, ResizablePanelEvent, ResizablePanelGroup, ResizablePanelState, ResizableState,

View File

@@ -5,15 +5,15 @@ use gpui::{
App, AppContext, Context, Corner, DefiniteLength, DismissEvent, DragMoveEvent, Empty, Entity, App, AppContext, Context, Corner, DefiniteLength, DismissEvent, DragMoveEvent, Empty, Entity,
EventEmitter, FocusHandle, Focusable, InteractiveElement as _, IntoElement, MouseButton, EventEmitter, FocusHandle, Focusable, InteractiveElement as _, IntoElement, MouseButton,
ParentElement, Pixels, Render, ScrollHandle, SharedString, StatefulInteractiveElement, Styled, ParentElement, Pixels, Render, ScrollHandle, SharedString, StatefulInteractiveElement, Styled,
WeakEntity, Window, div, px, rems, WeakEntity, Window, div, rems,
}; };
use theme::{ActiveTheme, AxisExt, CLIENT_SIDE_DECORATION_ROUNDING, Placement, TABBAR_HEIGHT}; use theme::{ActiveTheme, AxisExt, CLIENT_SIDE_DECORATION_ROUNDING, Placement, TABBAR_HEIGHT};
use crate::button::{Button, ButtonVariants as _}; use crate::button::{Button, ButtonVariants as _};
use crate::dock_area::dock::DockPlacement; use crate::dock::dock::DockPlacement;
use crate::dock_area::panel::{Panel, PanelView}; use crate::dock::panel::{Panel, PanelView};
use crate::dock_area::stack_panel::StackPanel; use crate::dock::stack_panel::StackPanel;
use crate::dock_area::{ClosePanel, DockArea, PanelEvent, PanelStyle, ToggleZoom}; use crate::dock::{ClosePanel, DockArea, PanelEvent, PanelStyle, ToggleZoom};
use crate::menu::{DropdownMenu, PopupMenu}; use crate::menu::{DropdownMenu, PopupMenu};
use crate::tab::Tab; use crate::tab::Tab;
use crate::tab::tab_bar::TabBar; use crate::tab::tab_bar::TabBar;
@@ -425,14 +425,13 @@ impl TabPanel {
let view = cx.entity().clone(); let view = cx.entity().clone();
let build_popup_menu = move |this, cx: &App| view.read(cx).popup_menu(this, cx); let build_popup_menu = move |this, cx: &App| view.read(cx).popup_menu(this, cx);
let toolbar = self.toolbar_buttons(window, cx); let toolbar = self.toolbar_buttons(window, cx);
let has_toolbar = !toolbar.is_empty();
h_flex() h_flex()
.p_0p5() .p_0p5()
.gap_1() .gap_1p5()
.occlude() .occlude()
.rounded_full() .rounded_full()
.children(toolbar.into_iter().map(|btn| btn.small().ghost().rounded())) .children(toolbar.into_iter().map(|btn| btn.small().ghost()))
.when(self.zoomed, |this| { .when(self.zoomed, |this| {
this.child( this.child(
Button::new("zoom") Button::new("zoom")
@@ -445,15 +444,11 @@ impl TabPanel {
})), })),
) )
}) })
.when(has_toolbar, |this| {
this.child(div().flex_shrink_0().h_4().w_px().bg(cx.theme().border))
})
.child( .child(
Button::new("menu") Button::new("menu")
.icon(IconName::Ellipsis) .icon(IconName::Ellipsis)
.small() .small()
.ghost() .ghost()
.rounded()
.dropdown_menu({ .dropdown_menu({
let zoomable = state.zoomable; let zoomable = state.zoomable;
let closable = state.closable; let closable = state.closable;
@@ -654,12 +649,8 @@ impl TabPanel {
h_flex() h_flex()
.items_center() .items_center()
.top_0() .top_0()
.right(-px(1.))
.border_r_1()
.border_b_1()
.h_full() .h_full()
.border_color(cx.theme().border) .bg(cx.theme().tab_background)
.bg(cx.theme().surface_background)
.px_2() .px_2()
.children(left_dock_button) .children(left_dock_button)
.children(bottom_dock_button), .children(bottom_dock_button),
@@ -691,7 +682,7 @@ impl TabPanel {
MouseButton::Middle, MouseButton::Middle,
cx.listener({ cx.listener({
let panel = panel.clone(); let panel = panel.clone();
move |view, _, window, cx| { move |view, _ev, window, cx| {
view.remove_panel(&panel, window, cx); view.remove_panel(&panel, window, cx);
} }
}), }),
@@ -722,6 +713,19 @@ impl TabPanel {
}, },
)) ))
}) })
.suffix(
Button::new("close-{ix}")
.icon(IconName::Close)
.tooltip("Close panel")
.ghost()
.xsmall()
.on_click(cx.listener({
let panel = panel.clone();
move |view, _ev, window, cx| {
view.remove_panel(&panel, window, cx);
}
})),
)
}), }),
) )
})) }))
@@ -762,9 +766,6 @@ impl TabPanel {
.top_0() .top_0()
.right_0() .right_0()
.h_full() .h_full()
.border_color(cx.theme().border)
.border_l_1()
.border_b_1()
.child(self.render_toolbar(state, window, cx)) .child(self.render_toolbar(state, window, cx))
.when_some(right_dock_button, |this, btn| this.child(btn)), .when_some(right_dock_button, |this, btn| this.child(btn)),
) )
@@ -1099,6 +1100,7 @@ impl Focusable for TabPanel {
} }
impl EventEmitter<DismissEvent> for TabPanel {} impl EventEmitter<DismissEvent> for TabPanel {}
impl EventEmitter<PanelEvent> for TabPanel {} impl EventEmitter<PanelEvent> for TabPanel {}
impl Render for TabPanel { impl Render for TabPanel {

View File

@@ -17,7 +17,7 @@ pub mod avatar;
pub mod button; pub mod button;
pub mod checkbox; pub mod checkbox;
pub mod divider; pub mod divider;
pub mod dock_area; pub mod dock;
pub mod group_box; pub mod group_box;
pub mod history; pub mod history;
pub mod indicator; pub mod indicator;

View File

@@ -9,7 +9,7 @@ use gpui::{
}; };
use theme::{ActiveTheme, AxisExt}; use theme::{ActiveTheme, AxisExt};
use crate::dock_area::dock::DockPlacement; use crate::dock::DockPlacement;
pub(crate) const HANDLE_PADDING: Pixels = px(4.); pub(crate) const HANDLE_PADDING: Pixels = px(4.);
pub(crate) const HANDLE_SIZE: Pixels = px(1.); pub(crate) const HANDLE_SIZE: Pixels = px(1.);

View File

@@ -1,11 +1,11 @@
use gpui::prelude::FluentBuilder; use gpui::prelude::FluentBuilder;
use gpui::{ use gpui::{
div, px, AnyElement, App, Div, InteractiveElement, IntoElement, MouseButton, ParentElement, AnyElement, App, Div, InteractiveElement, IntoElement, MouseButton, ParentElement, RenderOnce,
RenderOnce, StatefulInteractiveElement, Styled, Window, StatefulInteractiveElement, Styled, Window, div, px,
}; };
use theme::{ActiveTheme, TABBAR_HEIGHT}; use theme::{ActiveTheme, TABBAR_HEIGHT};
use crate::{Selectable, Sizable, Size}; use crate::{Selectable, Sizable, Size, h_flex};
pub mod tab_bar; pub mod tab_bar;
@@ -106,59 +106,44 @@ impl Sizable for Tab {
impl RenderOnce for Tab { impl RenderOnce for Tab {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement { fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let (text_color, hover_text_color, bg_color, border_color) = let (text_color, bg_color) = match (self.selected, self.disabled) {
match (self.selected, self.disabled) { (true, false) => (
(true, false) => ( cx.theme().tab_active_foreground,
cx.theme().tab_active_foreground, cx.theme().tab_active_background,
cx.theme().tab_hover_foreground, ),
cx.theme().tab_active_background, (false, false) => (cx.theme().tab_foreground, cx.theme().tab_background),
cx.theme().border, (true, true) => (cx.theme().text_muted, cx.theme().tab_background),
), (false, true) => (cx.theme().text_placeholder, cx.theme().tab_background),
(false, false) => ( };
cx.theme().tab_inactive_foreground,
cx.theme().tab_hover_foreground,
cx.theme().ghost_element_background,
cx.theme().border_transparent,
),
(true, true) => (
cx.theme().tab_inactive_foreground,
cx.theme().tab_hover_foreground,
cx.theme().ghost_element_background,
cx.theme().border_disabled,
),
(false, true) => (
cx.theme().tab_inactive_foreground,
cx.theme().tab_hover_foreground,
cx.theme().ghost_element_background,
cx.theme().border_disabled,
),
};
self.base self.base
.id(self.ix) .id(self.ix)
.h(TABBAR_HEIGHT) .group("")
.px_4()
.relative() .relative()
.flex()
.items_center()
.flex_shrink_0() .flex_shrink_0()
.cursor_pointer()
.overflow_hidden() .overflow_hidden()
.text_xs() .child(
.text_ellipsis() h_flex()
.text_color(text_color) .h(TABBAR_HEIGHT - px(8.))
.bg(bg_color) .px_1()
.border_l(px(1.)) .text_xs()
.border_r(px(1.)) .text_ellipsis()
.border_color(border_color) .text_color(text_color)
.when(!self.selected && !self.disabled, |this| { .bg(bg_color)
this.hover(|this| this.text_color(hover_text_color)) .rounded(cx.theme().radius)
}) .when(cx.theme().shadow && self.selected, |this| this.shadow_xs())
.when_some(self.prefix, |this, prefix| { .when_some(self.prefix, |this, prefix| this.child(prefix))
this.child(prefix).text_color(text_color) .when_some(self.label, |this, label| this.child(label))
}) .when_some(self.suffix, |this, suffix| {
.when_some(self.label, |this, label| this.child(label)) this.child(
.when_some(self.suffix, |this, suffix| this.child(suffix)) div()
.pl_4()
.invisible()
.group_hover("", |this| this.visible())
.child(suffix),
)
}),
)
.on_mouse_down(MouseButton::Left, |_ev, _window, cx| { .on_mouse_down(MouseButton::Left, |_ev, _window, cx| {
cx.stop_propagation(); cx.stop_propagation();
}) })

View File

@@ -1,14 +1,14 @@
use gpui::prelude::FluentBuilder as _;
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
use gpui::Pixels; use gpui::Pixels;
use gpui::prelude::FluentBuilder as _;
use gpui::{ use gpui::{
div, px, AnyElement, App, Div, InteractiveElement, IntoElement, ParentElement, RenderOnce, AnyElement, App, Div, InteractiveElement, IntoElement, ParentElement, RenderOnce, ScrollHandle,
ScrollHandle, StatefulInteractiveElement as _, StyleRefinement, Styled, Window, StatefulInteractiveElement as _, StyleRefinement, Styled, Window, div, px,
}; };
use smallvec::SmallVec; use smallvec::SmallVec;
use theme::ActiveTheme; use theme::ActiveTheme;
use crate::{h_flex, Sizable, Size, StyledExt}; use crate::{Sizable, Size, StyledExt, h_flex};
#[derive(IntoElement)] #[derive(IntoElement)]
pub struct TabBar { pub struct TabBar {
@@ -96,24 +96,16 @@ impl RenderOnce for TabBar {
self.base self.base
.group("tab-bar") .group("tab-bar")
.relative() .relative()
.refine_style(&self.style) .flex()
.bg(cx.theme().surface_background) .items_center()
.child( .bg(cx.theme().tab_background)
div()
.id("border-bottom")
.absolute()
.left_0()
.bottom_0()
.size_full()
.border_b_1()
.border_color(cx.theme().border),
)
.text_color(cx.theme().text) .text_color(cx.theme().text)
.refine_style(&self.style)
.when_some(self.prefix, |this, prefix| this.child(prefix)) .when_some(self.prefix, |this, prefix| this.child(prefix))
.child( .child(
h_flex() h_flex()
.id("tabs") .id("tabs")
.flex_grow() .flex_1()
.overflow_x_scroll() .overflow_x_scroll()
.when_some(self.scroll_handle, |this, scroll_handle| { .when_some(self.scroll_handle, |this, scroll_handle| {
this.track_scroll(&scroll_handle) this.track_scroll(&scroll_handle)