Start work on styling of follower avatars in facepiles
* Make follower avatars smaller than top-level avatars * Make avatars in facepiles overlap * Render an opaque background behind avatars in facepiles.
This commit is contained in:
parent
0dc92bec5c
commit
b7cf426908
3 changed files with 50 additions and 23 deletions
|
@ -17,7 +17,7 @@ use gpui::{
|
||||||
};
|
};
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use std::{ops::Range, sync::Arc};
|
use std::{ops::Range, sync::Arc};
|
||||||
use theme::Theme;
|
use theme::{AvatarStyle, Theme};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
use workspace::{FollowNextCollaborator, JoinProject, ToggleFollow, Workspace};
|
use workspace::{FollowNextCollaborator, JoinProject, ToggleFollow, Workspace};
|
||||||
|
|
||||||
|
@ -614,21 +614,22 @@ impl CollabTitlebarItem {
|
||||||
if let Some(location) = location {
|
if let Some(location) = location {
|
||||||
if let ParticipantLocation::SharedProject { project_id } = location {
|
if let ParticipantLocation::SharedProject { project_id } = location {
|
||||||
if Some(project_id) == workspace.read(cx).project().read(cx).remote_id() {
|
if Some(project_id) == workspace.read(cx).project().read(cx).remote_id() {
|
||||||
avatar_style = theme.workspace.titlebar.avatar;
|
avatar_style = &theme.workspace.titlebar.avatar;
|
||||||
} else {
|
} else {
|
||||||
avatar_style = theme.workspace.titlebar.inactive_avatar;
|
avatar_style = &theme.workspace.titlebar.inactive_avatar;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
avatar_style = theme.workspace.titlebar.inactive_avatar;
|
avatar_style = &theme.workspace.titlebar.inactive_avatar;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
avatar_style = theme.workspace.titlebar.avatar;
|
avatar_style = &theme.workspace.titlebar.avatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
let content = Stack::new()
|
let content = Stack::new()
|
||||||
.with_children(user.avatar.as_ref().map(|avatar| {
|
.with_children(user.avatar.as_ref().map(|avatar| {
|
||||||
let flex = Flex::row()
|
let flex = Flex::row()
|
||||||
.with_child(Self::render_face(avatar.clone(), avatar_style, theme))
|
// .with_reversed_paint_order()
|
||||||
|
.with_child(Self::render_face(avatar.clone(), avatar_style.clone()))
|
||||||
.with_children(
|
.with_children(
|
||||||
(|| {
|
(|| {
|
||||||
let room = room?.read(cx);
|
let room = room?.read(cx);
|
||||||
|
@ -652,14 +653,22 @@ impl CollabTitlebarItem {
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Some(Self::render_face(avatar.clone(), avatar_style, theme))
|
Some(
|
||||||
|
Container::new(Self::render_face(
|
||||||
|
avatar.clone(),
|
||||||
|
theme.workspace.titlebar.follower_avatar.clone(),
|
||||||
|
))
|
||||||
|
.with_margin_left(
|
||||||
|
-1.0 * theme.workspace.titlebar.follower_avatar_overlap,
|
||||||
|
)
|
||||||
|
.boxed(),
|
||||||
|
)
|
||||||
}))
|
}))
|
||||||
})()
|
})()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten(),
|
.flatten(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let room = ActiveCall::global(cx).read(cx).room();
|
|
||||||
if let (Some(replica_id), Some(room)) = (replica_id, room) {
|
if let (Some(replica_id), Some(room)) = (replica_id, room) {
|
||||||
let followed_by_self = is_being_followed
|
let followed_by_self = is_being_followed
|
||||||
&& room
|
&& room
|
||||||
|
@ -669,7 +678,6 @@ impl CollabTitlebarItem {
|
||||||
.any(|&follower| {
|
.any(|&follower| {
|
||||||
Some(follower) == workspace.read(cx).client().peer_id()
|
Some(follower) == workspace.read(cx).client().peer_id()
|
||||||
});
|
});
|
||||||
|
|
||||||
if followed_by_self {
|
if followed_by_self {
|
||||||
let color = theme.editor.replica_selection_style(replica_id).selection;
|
let color = theme.editor.replica_selection_style(replica_id).selection;
|
||||||
return flex.contained().with_background_color(color).boxed();
|
return flex.contained().with_background_color(color).boxed();
|
||||||
|
@ -742,11 +750,14 @@ impl CollabTitlebarItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_face(avatar: Arc<ImageData>, avatar_style: ImageStyle, theme: &Theme) -> ElementBox {
|
fn render_face(avatar: Arc<ImageData>, avatar_style: AvatarStyle) -> ElementBox {
|
||||||
Image::new(avatar)
|
Image::new(avatar)
|
||||||
.with_style(avatar_style)
|
.with_style(avatar_style.image)
|
||||||
.constrained()
|
.constrained()
|
||||||
.with_width(theme.workspace.titlebar.avatar_width)
|
.with_width(avatar_style.width)
|
||||||
|
.contained()
|
||||||
|
.with_background_color(Color::white())
|
||||||
|
.with_corner_radius(avatar_style.image.corner_radius)
|
||||||
.aligned()
|
.aligned()
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,12 +74,13 @@ pub struct Titlebar {
|
||||||
pub container: ContainerStyle,
|
pub container: ContainerStyle,
|
||||||
pub height: f32,
|
pub height: f32,
|
||||||
pub title: TextStyle,
|
pub title: TextStyle,
|
||||||
pub avatar_width: f32,
|
|
||||||
pub avatar_margin: f32,
|
pub avatar_margin: f32,
|
||||||
pub avatar_ribbon: AvatarRibbon,
|
pub avatar_ribbon: AvatarRibbon,
|
||||||
|
pub follower_avatar_overlap: f32,
|
||||||
pub offline_icon: OfflineIcon,
|
pub offline_icon: OfflineIcon,
|
||||||
pub avatar: ImageStyle,
|
pub avatar: AvatarStyle,
|
||||||
pub inactive_avatar: ImageStyle,
|
pub inactive_avatar: AvatarStyle,
|
||||||
|
pub follower_avatar: AvatarStyle,
|
||||||
pub sign_in_prompt: Interactive<ContainedText>,
|
pub sign_in_prompt: Interactive<ContainedText>,
|
||||||
pub outdated_warning: ContainedText,
|
pub outdated_warning: ContainedText,
|
||||||
pub share_button: Interactive<ContainedText>,
|
pub share_button: Interactive<ContainedText>,
|
||||||
|
@ -88,6 +89,13 @@ pub struct Titlebar {
|
||||||
pub toggle_contacts_badge: ContainerStyle,
|
pub toggle_contacts_badge: ContainerStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize, Default)]
|
||||||
|
pub struct AvatarStyle {
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub image: ImageStyle,
|
||||||
|
pub width: f32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default)]
|
#[derive(Deserialize, Default)]
|
||||||
pub struct ContactsPopover {
|
pub struct ContactsPopover {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
|
|
@ -41,6 +41,7 @@ export default function workspace(colorScheme: ColorScheme) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const avatarWidth = 18;
|
const avatarWidth = 18;
|
||||||
|
const followerAvatarWidth = 14;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
background: background(layer),
|
background: background(layer),
|
||||||
|
@ -80,7 +81,6 @@ export default function workspace(colorScheme: ColorScheme) {
|
||||||
},
|
},
|
||||||
statusBar: statusBar(colorScheme),
|
statusBar: statusBar(colorScheme),
|
||||||
titlebar: {
|
titlebar: {
|
||||||
avatarWidth,
|
|
||||||
avatarMargin: 8,
|
avatarMargin: 8,
|
||||||
height: 33, // 32px + 1px for overlaid border
|
height: 33, // 32px + 1px for overlaid border
|
||||||
background: background(layer),
|
background: background(layer),
|
||||||
|
@ -95,6 +95,7 @@ export default function workspace(colorScheme: ColorScheme) {
|
||||||
|
|
||||||
// Collaborators
|
// Collaborators
|
||||||
avatar: {
|
avatar: {
|
||||||
|
width: avatarWidth,
|
||||||
cornerRadius: avatarWidth / 2,
|
cornerRadius: avatarWidth / 2,
|
||||||
border: {
|
border: {
|
||||||
color: "#00000088",
|
color: "#00000088",
|
||||||
|
@ -102,6 +103,7 @@ export default function workspace(colorScheme: ColorScheme) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
inactiveAvatar: {
|
inactiveAvatar: {
|
||||||
|
width: avatarWidth,
|
||||||
cornerRadius: avatarWidth / 2,
|
cornerRadius: avatarWidth / 2,
|
||||||
border: {
|
border: {
|
||||||
color: "#00000088",
|
color: "#00000088",
|
||||||
|
@ -109,6 +111,15 @@ export default function workspace(colorScheme: ColorScheme) {
|
||||||
},
|
},
|
||||||
grayscale: true,
|
grayscale: true,
|
||||||
},
|
},
|
||||||
|
followerAvatar: {
|
||||||
|
width: followerAvatarWidth,
|
||||||
|
cornerRadius: followerAvatarWidth / 2,
|
||||||
|
border: {
|
||||||
|
color: "#00000088",
|
||||||
|
width: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
followerAvatarOverlap: 4,
|
||||||
avatarRibbon: {
|
avatarRibbon: {
|
||||||
height: 3,
|
height: 3,
|
||||||
width: 12,
|
width: 12,
|
||||||
|
@ -118,7 +129,7 @@ export default function workspace(colorScheme: ColorScheme) {
|
||||||
// Sign in buttom
|
// Sign in buttom
|
||||||
// FlatButton, Variant
|
// FlatButton, Variant
|
||||||
signInPrompt: {
|
signInPrompt: {
|
||||||
...titlebarButton
|
...titlebarButton,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Offline Indicator
|
// Offline Indicator
|
||||||
|
@ -184,8 +195,8 @@ export default function workspace(colorScheme: ColorScheme) {
|
||||||
background: foreground(layer, "accent"),
|
background: foreground(layer, "accent"),
|
||||||
},
|
},
|
||||||
shareButton: {
|
shareButton: {
|
||||||
...titlebarButton
|
...titlebarButton,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
toolbar: {
|
toolbar: {
|
||||||
|
@ -241,9 +252,6 @@ export default function workspace(colorScheme: ColorScheme) {
|
||||||
shadow: colorScheme.modalShadow,
|
shadow: colorScheme.modalShadow,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
dropTargetOverlayColor: withOpacity(
|
dropTargetOverlayColor: withOpacity(foreground(layer, "variant"), 0.5),
|
||||||
foreground(layer, "variant"),
|
|
||||||
0.5
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue