Tune styles and disclosable elements
This commit is contained in:
parent
bfd3e53dcd
commit
2a182b6a7b
5 changed files with 93 additions and 30 deletions
|
@ -55,7 +55,7 @@ struct RemoveChannel {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
struct ToggleCollapsed {
|
struct ToggleCollapse {
|
||||||
channel_id: u64,
|
channel_id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,16 @@ struct RenameChannel {
|
||||||
channel_id: u64,
|
channel_id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
actions!(collab_panel, [ToggleFocus, Remove, Secondary]);
|
actions!(
|
||||||
|
collab_panel,
|
||||||
|
[
|
||||||
|
ToggleFocus,
|
||||||
|
Remove,
|
||||||
|
Secondary,
|
||||||
|
CollapseSelectedChannel,
|
||||||
|
ExpandSelectedChannel
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
impl_actions!(
|
impl_actions!(
|
||||||
collab_panel,
|
collab_panel,
|
||||||
|
@ -89,7 +98,7 @@ impl_actions!(
|
||||||
InviteMembers,
|
InviteMembers,
|
||||||
ManageMembers,
|
ManageMembers,
|
||||||
RenameChannel,
|
RenameChannel,
|
||||||
ToggleCollapsed
|
ToggleCollapse
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -113,6 +122,8 @@ pub fn init(_client: Arc<Client>, cx: &mut AppContext) {
|
||||||
cx.add_action(CollabPanel::rename_selected_channel);
|
cx.add_action(CollabPanel::rename_selected_channel);
|
||||||
cx.add_action(CollabPanel::rename_channel);
|
cx.add_action(CollabPanel::rename_channel);
|
||||||
cx.add_action(CollabPanel::toggle_channel_collapsed);
|
cx.add_action(CollabPanel::toggle_channel_collapsed);
|
||||||
|
cx.add_action(CollabPanel::collapse_selected_channel);
|
||||||
|
cx.add_action(CollabPanel::expand_selected_channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -1356,7 +1367,7 @@ impl CollabPanel {
|
||||||
.with_cursor_style(CursorStyle::PointingHand)
|
.with_cursor_style(CursorStyle::PointingHand)
|
||||||
.on_click(MouseButton::Left, move |_, this, cx| {
|
.on_click(MouseButton::Left, move |_, this, cx| {
|
||||||
if can_collapse {
|
if can_collapse {
|
||||||
this.toggle_expanded(section, cx);
|
this.toggle_section_expanded(section, cx);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1633,7 +1644,7 @@ impl CollabPanel {
|
||||||
})
|
})
|
||||||
.align_children_center()
|
.align_children_center()
|
||||||
.styleable_component()
|
.styleable_component()
|
||||||
.disclosable(disclosed, Box::new(ToggleCollapsed { channel_id }))
|
.disclosable(disclosed, Box::new(ToggleCollapse { channel_id }))
|
||||||
.with_id(channel_id as usize)
|
.with_id(channel_id as usize)
|
||||||
.with_style(theme.disclosure.clone())
|
.with_style(theme.disclosure.clone())
|
||||||
.element()
|
.element()
|
||||||
|
@ -1863,6 +1874,12 @@ impl CollabPanel {
|
||||||
OverlayPositionMode::Window
|
OverlayPositionMode::Window
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let expand_action_name = if self.is_channel_collapsed(channel_id) {
|
||||||
|
"Expand Subchannels"
|
||||||
|
} else {
|
||||||
|
"Collapse Subchannels"
|
||||||
|
};
|
||||||
|
|
||||||
context_menu.show(
|
context_menu.show(
|
||||||
position.unwrap_or_default(),
|
position.unwrap_or_default(),
|
||||||
if self.context_menu_on_selected {
|
if self.context_menu_on_selected {
|
||||||
|
@ -1871,6 +1888,7 @@ impl CollabPanel {
|
||||||
gpui::elements::AnchorCorner::BottomLeft
|
gpui::elements::AnchorCorner::BottomLeft
|
||||||
},
|
},
|
||||||
vec![
|
vec![
|
||||||
|
ContextMenuItem::action(expand_action_name, ToggleCollapse { channel_id }),
|
||||||
ContextMenuItem::action("New Subchannel", NewChannel { channel_id }),
|
ContextMenuItem::action("New Subchannel", NewChannel { channel_id }),
|
||||||
ContextMenuItem::Separator,
|
ContextMenuItem::Separator,
|
||||||
ContextMenuItem::action("Invite to Channel", InviteMembers { channel_id }),
|
ContextMenuItem::action("Invite to Channel", InviteMembers { channel_id }),
|
||||||
|
@ -1950,7 +1968,7 @@ impl CollabPanel {
|
||||||
| Section::Online
|
| Section::Online
|
||||||
| Section::Offline
|
| Section::Offline
|
||||||
| Section::ChannelInvites => {
|
| Section::ChannelInvites => {
|
||||||
self.toggle_expanded(*section, cx);
|
self.toggle_section_expanded(*section, cx);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ListEntry::Contact { contact, calling } => {
|
ListEntry::Contact { contact, calling } => {
|
||||||
|
@ -2038,7 +2056,7 @@ impl CollabPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_expanded(&mut self, section: Section, cx: &mut ViewContext<Self>) {
|
fn toggle_section_expanded(&mut self, section: Section, cx: &mut ViewContext<Self>) {
|
||||||
if let Some(ix) = self.collapsed_sections.iter().position(|s| *s == section) {
|
if let Some(ix) = self.collapsed_sections.iter().position(|s| *s == section) {
|
||||||
self.collapsed_sections.remove(ix);
|
self.collapsed_sections.remove(ix);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2047,8 +2065,37 @@ impl CollabPanel {
|
||||||
self.update_entries(false, cx);
|
self.update_entries(false, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_channel_collapsed(&mut self, action: &ToggleCollapsed, cx: &mut ViewContext<Self>) {
|
fn collapse_selected_channel(
|
||||||
|
&mut self,
|
||||||
|
_: &CollapseSelectedChannel,
|
||||||
|
cx: &mut ViewContext<Self>,
|
||||||
|
) {
|
||||||
|
let Some(channel_id) = self.selected_channel().map(|channel| channel.id) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.is_channel_collapsed(channel_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.toggle_channel_collapsed(&ToggleCollapse { channel_id }, cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expand_selected_channel(&mut self, _: &ExpandSelectedChannel, cx: &mut ViewContext<Self>) {
|
||||||
|
let Some(channel_id) = self.selected_channel().map(|channel| channel.id) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if !self.is_channel_collapsed(channel_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.toggle_channel_collapsed(&ToggleCollapse { channel_id }, cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle_channel_collapsed(&mut self, action: &ToggleCollapse, cx: &mut ViewContext<Self>) {
|
||||||
let channel_id = action.channel_id;
|
let channel_id = action.channel_id;
|
||||||
|
|
||||||
match self.collapsed_channels.binary_search(&channel_id) {
|
match self.collapsed_channels.binary_search(&channel_id) {
|
||||||
Ok(ix) => {
|
Ok(ix) => {
|
||||||
self.collapsed_channels.remove(ix);
|
self.collapsed_channels.remove(ix);
|
||||||
|
@ -2057,8 +2104,9 @@ impl CollabPanel {
|
||||||
self.collapsed_channels.insert(ix, channel_id);
|
self.collapsed_channels.insert(ix, channel_id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.update_entries(false, cx);
|
self.update_entries(true, cx);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
cx.focus_self();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_channel_collapsed(&self, channel: ChannelId) -> bool {
|
fn is_channel_collapsed(&self, channel: ChannelId) -> bool {
|
||||||
|
@ -2104,6 +2152,8 @@ impl CollabPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_subchannel(&mut self, action: &NewChannel, cx: &mut ViewContext<Self>) {
|
fn new_subchannel(&mut self, action: &NewChannel, cx: &mut ViewContext<Self>) {
|
||||||
|
self.collapsed_channels
|
||||||
|
.retain(|&channel| channel != action.channel_id);
|
||||||
self.channel_editing_state = Some(ChannelEditingState::Create {
|
self.channel_editing_state = Some(ChannelEditingState::Create {
|
||||||
parent_id: Some(action.channel_id),
|
parent_id: Some(action.channel_id),
|
||||||
pending_name: None,
|
pending_name: None,
|
||||||
|
|
|
@ -4,7 +4,8 @@ use crate::{Interactive, Toggleable};
|
||||||
|
|
||||||
use self::{action_button::ButtonStyle, disclosure::Disclosable, svg::SvgStyle, toggle::Toggle};
|
use self::{action_button::ButtonStyle, disclosure::Disclosable, svg::SvgStyle, toggle::Toggle};
|
||||||
|
|
||||||
pub type ToggleIconButtonStyle = Toggleable<Interactive<ButtonStyle<SvgStyle>>>;
|
pub type IconButtonStyle = Interactive<ButtonStyle<SvgStyle>>;
|
||||||
|
pub type ToggleIconButtonStyle = Toggleable<IconButtonStyle>;
|
||||||
|
|
||||||
pub trait ComponentExt<C: SafeStylable> {
|
pub trait ComponentExt<C: SafeStylable> {
|
||||||
fn toggleable(self, active: bool) -> Toggle<C, ()>;
|
fn toggleable(self, active: bool) -> Toggle<C, ()>;
|
||||||
|
@ -27,17 +28,19 @@ impl<C: SafeStylable> ComponentExt<C> for C {
|
||||||
pub mod disclosure {
|
pub mod disclosure {
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
elements::{Component, Empty, Flex, ParentElement, SafeStylable},
|
elements::{Component, ContainerStyle, Empty, Flex, ParentElement, SafeStylable},
|
||||||
Action, Element,
|
Action, Element,
|
||||||
};
|
};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
use super::{action_button::Button, svg::Svg, ComponentExt, ToggleIconButtonStyle};
|
use super::{action_button::Button, svg::Svg, ComponentExt, IconButtonStyle};
|
||||||
|
|
||||||
#[derive(Clone, Default, Deserialize, JsonSchema)]
|
#[derive(Clone, Default, Deserialize, JsonSchema)]
|
||||||
pub struct DisclosureStyle<S> {
|
pub struct DisclosureStyle<S> {
|
||||||
pub button: ToggleIconButtonStyle,
|
pub button: IconButtonStyle,
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub container: ContainerStyle,
|
||||||
pub spacing: f32,
|
pub spacing: f32,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
content: S,
|
content: S,
|
||||||
|
@ -99,6 +102,7 @@ pub mod disclosure {
|
||||||
impl<C: SafeStylable> Component for Disclosable<C, DisclosureStyle<C::Style>> {
|
impl<C: SafeStylable> Component for Disclosable<C, DisclosureStyle<C::Style>> {
|
||||||
fn render<V: gpui::View>(self, cx: &mut gpui::ViewContext<V>) -> gpui::AnyElement<V> {
|
fn render<V: gpui::View>(self, cx: &mut gpui::ViewContext<V>) -> gpui::AnyElement<V> {
|
||||||
Flex::row()
|
Flex::row()
|
||||||
|
.with_spacing(self.style.spacing)
|
||||||
.with_child(if let Some(disclosed) = self.disclosed {
|
.with_child(if let Some(disclosed) = self.disclosed {
|
||||||
Button::dynamic_action(self.action)
|
Button::dynamic_action(self.action)
|
||||||
.with_id(self.id)
|
.with_id(self.id)
|
||||||
|
@ -107,7 +111,6 @@ pub mod disclosure {
|
||||||
} else {
|
} else {
|
||||||
"icons/file_icons/chevron_right.svg"
|
"icons/file_icons/chevron_right.svg"
|
||||||
}))
|
}))
|
||||||
.toggleable(disclosed)
|
|
||||||
.with_style(self.style.button)
|
.with_style(self.style.button)
|
||||||
.element()
|
.element()
|
||||||
.into_any()
|
.into_any()
|
||||||
|
@ -119,7 +122,6 @@ pub mod disclosure {
|
||||||
.with_width(self.style.button.button_width.unwrap())
|
.with_width(self.style.button.button_width.unwrap())
|
||||||
.into_any()
|
.into_any()
|
||||||
})
|
})
|
||||||
.with_child(Empty::new().constrained().with_width(self.style.spacing))
|
|
||||||
.with_child(
|
.with_child(
|
||||||
self.content
|
self.content
|
||||||
.with_style(self.style.content)
|
.with_style(self.style.content)
|
||||||
|
@ -127,6 +129,8 @@ pub mod disclosure {
|
||||||
.flex(1., true),
|
.flex(1., true),
|
||||||
)
|
)
|
||||||
.align_children_center()
|
.align_children_center()
|
||||||
|
.contained()
|
||||||
|
.with_style(self.style.container)
|
||||||
.into_any()
|
.into_any()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,10 +44,10 @@ export function icon_button({ color, margin, layer, variant, size }: IconButtonO
|
||||||
}
|
}
|
||||||
|
|
||||||
const padding = {
|
const padding = {
|
||||||
top: size === Button.size.Small ? 0 : 2,
|
top: size === Button.size.Small ? 2 : 2,
|
||||||
bottom: size === Button.size.Small ? 0 : 2,
|
bottom: size === Button.size.Small ? 2 : 2,
|
||||||
left: size === Button.size.Small ? 0 : 4,
|
left: size === Button.size.Small ? 2 : 4,
|
||||||
right: size === Button.size.Small ? 0 : 4,
|
right: size === Button.size.Small ? 2 : 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
return interactive({
|
return interactive({
|
||||||
|
@ -55,10 +55,10 @@ export function icon_button({ color, margin, layer, variant, size }: IconButtonO
|
||||||
corner_radius: 6,
|
corner_radius: 6,
|
||||||
padding: padding,
|
padding: padding,
|
||||||
margin: m,
|
margin: m,
|
||||||
icon_width: 14,
|
icon_width: 12,
|
||||||
icon_height: 14,
|
icon_height: 14,
|
||||||
button_width: 20,
|
button_width: size === Button.size.Small ? 16 : 20,
|
||||||
button_height: 16,
|
button_height: 14,
|
||||||
},
|
},
|
||||||
state: {
|
state: {
|
||||||
default: {
|
default: {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { indicator } from "../component/indicator"
|
||||||
export default function contacts_panel(): any {
|
export default function contacts_panel(): any {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
|
||||||
|
const CHANNEL_SPACING = 4 as const
|
||||||
const NAME_MARGIN = 6 as const
|
const NAME_MARGIN = 6 as const
|
||||||
const SPACING = 12 as const
|
const SPACING = 12 as const
|
||||||
const INDENT_SIZE = 8 as const
|
const INDENT_SIZE = 8 as const
|
||||||
|
@ -153,8 +154,8 @@ export default function contacts_panel(): any {
|
||||||
return {
|
return {
|
||||||
...collab_modals(),
|
...collab_modals(),
|
||||||
disclosure: {
|
disclosure: {
|
||||||
button: toggleable_icon_button(theme, {}),
|
button: icon_button({ variant: "ghost", size: "sm" }),
|
||||||
spacing: 4,
|
spacing: CHANNEL_SPACING,
|
||||||
},
|
},
|
||||||
log_in_button: interactive({
|
log_in_button: interactive({
|
||||||
base: {
|
base: {
|
||||||
|
@ -198,7 +199,7 @@ export default function contacts_panel(): any {
|
||||||
add_channel_button: header_icon_button,
|
add_channel_button: header_icon_button,
|
||||||
leave_call_button: header_icon_button,
|
leave_call_button: header_icon_button,
|
||||||
row_height: ITEM_HEIGHT,
|
row_height: ITEM_HEIGHT,
|
||||||
channel_indent: INDENT_SIZE * 2,
|
channel_indent: INDENT_SIZE * 2 + 2,
|
||||||
section_icon_size: 14,
|
section_icon_size: 14,
|
||||||
header_row: {
|
header_row: {
|
||||||
...text(layer, "sans", { size: "sm", weight: "bold" }),
|
...text(layer, "sans", { size: "sm", weight: "bold" }),
|
||||||
|
@ -268,7 +269,7 @@ export default function contacts_panel(): any {
|
||||||
channel_name: {
|
channel_name: {
|
||||||
...text(layer, "sans", { size: "sm" }),
|
...text(layer, "sans", { size: "sm" }),
|
||||||
margin: {
|
margin: {
|
||||||
left: NAME_MARGIN,
|
left: CHANNEL_SPACING,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
list_empty_label_container: {
|
list_empty_label_container: {
|
||||||
|
|
|
@ -1,18 +1,26 @@
|
||||||
import { toggle_label_button_style } from "../component/label_button"
|
|
||||||
import { useTheme } from "../common"
|
import { useTheme } from "../common"
|
||||||
import { text_button } from "../component/text_button"
|
import { text_button } from "../component/text_button"
|
||||||
import { toggleable_icon_button } from "../component/icon_button"
|
import { icon_button } from "../component/icon_button"
|
||||||
import { text } from "./components"
|
import { text } from "./components"
|
||||||
|
import { toggleable } from "../element"
|
||||||
|
|
||||||
export default function contacts_panel(): any {
|
export default function contacts_panel(): any {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
button: text_button({}),
|
button: text_button({}),
|
||||||
toggle: toggle_label_button_style({ active_color: "accent" }),
|
toggle: toggleable({
|
||||||
|
base: text_button({}),
|
||||||
|
state: {
|
||||||
|
active: {
|
||||||
|
...text_button({ color: "accent" })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
disclosure: {
|
disclosure: {
|
||||||
...text(theme.lowest, "sans", "base"),
|
...text(theme.lowest, "sans", "base"),
|
||||||
button: toggleable_icon_button(theme, {}),
|
button: icon_button({ variant: "ghost" }),
|
||||||
spacing: 4,
|
spacing: 4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue