Merge pull request #917 from zed-industries/titlebar-design

Implement titlebar design
This commit is contained in:
Nathan Sobo 2022-04-26 08:17:48 -06:00 committed by GitHub
commit 2ae2daefe1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 455 additions and 1208 deletions

View file

@ -1,6 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.87348 15.1266C4.04217 12.2953 4.04217 7.70484 6.87348 4.87354M17.1265 4.87354C19.9578 7.70484 19.9578 12.2953 17.1265 15.1266" stroke="#636B78" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8.9948 13.0052C7.33507 11.3454 7.33507 8.65448 8.9948 6.99475M15.0052 6.99475C16.6649 8.65448 16.6649 11.3454 15.0052 13.0052" stroke="#636B78" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.5 10C12.5 10.2761 12.2761 10.5 12 10.5C11.7239 10.5 11.5 10.2761 11.5 10C11.5 9.72386 11.7239 9.5 12 9.5C12.2761 9.5 12.5 9.72386 12.5 10Z" stroke="#636B78" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 13.75V19.25" stroke="#636B78" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 879 B

3
assets/icons/share.svg Normal file
View file

@ -0,0 +1,3 @@
<svg width="12" height="14" viewBox="0 0 12 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.0002 0.333344C2.77885 0.333344 0.16687 2.94532 0.16687 6.16668C0.16687 8.56824 1.61921 10.6302 3.69291 11.5234C3.60229 10.9831 3.53223 10.4404 3.51062 10.0091C2.25203 9.19011 1.41661 7.77605 1.41661 6.16668C1.41661 3.63933 3.4726 1.58334 5.99994 1.58334C8.52729 1.58334 10.5833 3.63933 10.5833 6.16668C10.5833 7.77579 9.74786 9.19011 8.48979 10.0104C8.46791 10.4401 8.39734 10.9836 8.30645 11.5253C10.38 10.6302 11.8331 8.56772 11.8331 6.16668C11.8331 2.94532 9.22117 0.333344 5.99981 0.333344H6.0002ZM6.0002 8.45834C5.14395 8.45834 4.33354 8.68295 4.33354 9.59767C4.33354 10.4604 4.66895 12.3138 4.87052 13.056C5.00541 13.5521 5.50802 13.6667 6.0002 13.6667C6.49239 13.6667 6.9963 13.5527 7.12989 13.0578C7.33093 12.3099 7.66687 10.4583 7.66687 9.59897C7.66687 8.6823 6.85697 8.45834 6.0002 8.45834ZM6.0002 7.62501C6.80619 7.62501 7.45854 6.97267 7.45854 6.16668C7.45854 5.36069 6.78406 4.70834 6.0002 4.70834C5.21635 4.70834 4.54187 5.35939 4.54187 6.16668C4.54187 6.97397 5.19291 7.62501 6.0002 7.62501ZM9.7502 6.16668C9.7502 4.09558 8.0713 2.41668 6.0002 2.41668C3.92911 2.41668 2.2502 4.09636 2.2502 6.16668C2.2502 7.33413 2.79499 8.36407 3.63145 9.05209C3.75776 8.72267 3.99942 8.37814 4.46609 8.13959C4.46635 8.13803 4.47416 8.13803 4.47937 8.13803C3.88822 7.6797 3.5002 6.97136 3.5002 6.16668C3.5002 4.78595 4.61947 3.66668 6.0002 3.66668C7.38093 3.66668 8.5002 4.78595 8.5002 6.16668C8.5002 6.97189 8.11296 7.68048 7.52182 8.13751C7.5252 8.13803 7.53484 8.13855 7.53406 8.13933C8.00098 8.37788 8.24213 8.72215 8.36869 9.05183C9.20567 8.36433 9.74994 7.33308 9.74994 6.16642L9.7502 6.16668Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -258,8 +258,9 @@
"avatar_width": 18,
"height": 32,
"background": "#26232a",
"share_icon_color": "#8b8792",
"share_icon_active_color": "#576ddb",
"padding": {
"left": 80
},
"title": {
"family": "Zed Sans",
"color": "#e2dfe7",
@ -324,10 +325,48 @@
"right": 4
}
},
"share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"color": "#8b8792"
},
"hovered_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#58526052",
"color": "#8b8792"
},
"hovered_active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#58526052",
"color": "#efecf4"
},
"active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#5852607a",
"color": "#efecf4"
},
"outdated_warning": {
"family": "Zed Sans",
"color": "#a06e3b",
"size": 13
"size": 13,
"margin": {
"right": 6
}
}
},
"toolbar": {

View file

@ -258,8 +258,9 @@
"avatar_width": 18,
"height": 32,
"background": "#e2dfe7",
"share_icon_color": "#585260",
"share_icon_active_color": "#576ddb",
"padding": {
"left": 80
},
"title": {
"family": "Zed Sans",
"color": "#26232a",
@ -324,10 +325,48 @@
"right": 4
}
},
"share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"color": "#585260"
},
"hovered_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#8b87921f",
"color": "#585260"
},
"hovered_active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#8b87921f",
"color": "#19171c"
},
"active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#8b87922e",
"color": "#19171c"
},
"outdated_warning": {
"family": "Zed Sans",
"color": "#a06e3b",
"size": 13
"size": 13,
"margin": {
"right": 6
}
}
},
"toolbar": {

View file

@ -258,8 +258,9 @@
"avatar_width": 18,
"height": 32,
"background": "#2b2b2b",
"share_icon_color": "#9c9c9c",
"share_icon_active_color": "#2472f2",
"padding": {
"left": 80
},
"title": {
"family": "Zed Sans",
"color": "#f1f1f1",
@ -324,10 +325,48 @@
"right": 4
}
},
"share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"color": "#9c9c9c"
},
"hovered_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#323232",
"color": "#9c9c9c"
},
"hovered_active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#323232",
"color": "#ffffff"
},
"active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#1c1c1c",
"color": "#ffffff"
},
"outdated_warning": {
"family": "Zed Sans",
"color": "#f7bb57",
"size": 13
"size": 13,
"margin": {
"right": 6
}
}
},
"toolbar": {

View file

@ -258,8 +258,9 @@
"avatar_width": 18,
"height": 32,
"background": "#eaeaea",
"share_icon_color": "#717171",
"share_icon_active_color": "#484bed",
"padding": {
"left": 80
},
"title": {
"family": "Zed Sans",
"color": "#2b2b2b",
@ -324,10 +325,48 @@
"right": 4
}
},
"share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"color": "#717171"
},
"hovered_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#e3e3e3",
"color": "#717171"
},
"hovered_active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#e3e3e3",
"color": "#000000"
},
"active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#d5d5d5",
"color": "#000000"
},
"outdated_warning": {
"family": "Zed Sans",
"color": "#d3a20b",
"size": 13
"size": 13,
"margin": {
"right": 6
}
}
},
"toolbar": {

View file

@ -258,8 +258,9 @@
"avatar_width": 18,
"height": 32,
"background": "#073642",
"share_icon_color": "#93a1a1",
"share_icon_active_color": "#268bd2",
"padding": {
"left": 80
},
"title": {
"family": "Zed Sans",
"color": "#eee8d5",
@ -324,10 +325,48 @@
"right": 4
}
},
"share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"color": "#93a1a1"
},
"hovered_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#586e7552",
"color": "#93a1a1"
},
"hovered_active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#586e7552",
"color": "#fdf6e3"
},
"active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#586e757a",
"color": "#fdf6e3"
},
"outdated_warning": {
"family": "Zed Sans",
"color": "#b58900",
"size": 13
"size": 13,
"margin": {
"right": 6
}
}
},
"toolbar": {

View file

@ -258,8 +258,9 @@
"avatar_width": 18,
"height": 32,
"background": "#eee8d5",
"share_icon_color": "#586e75",
"share_icon_active_color": "#268bd2",
"padding": {
"left": 80
},
"title": {
"family": "Zed Sans",
"color": "#073642",
@ -324,10 +325,48 @@
"right": 4
}
},
"share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"color": "#586e75"
},
"hovered_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#93a1a11f",
"color": "#586e75"
},
"hovered_active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#93a1a11f",
"color": "#002b36"
},
"active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#93a1a12e",
"color": "#002b36"
},
"outdated_warning": {
"family": "Zed Sans",
"color": "#b58900",
"size": 13
"size": 13,
"margin": {
"right": 6
}
}
},
"toolbar": {

View file

@ -258,8 +258,9 @@
"avatar_width": 18,
"height": 32,
"background": "#293256",
"share_icon_color": "#979db4",
"share_icon_active_color": "#3d8fd1",
"padding": {
"left": 80
},
"title": {
"family": "Zed Sans",
"color": "#dfe2f1",
@ -324,10 +325,48 @@
"right": 4
}
},
"share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"color": "#979db4"
},
"hovered_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#5e668752",
"color": "#979db4"
},
"hovered_active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#5e668752",
"color": "#f5f7ff"
},
"active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#5e66877a",
"color": "#f5f7ff"
},
"outdated_warning": {
"family": "Zed Sans",
"color": "#c08b30",
"size": 13
"size": 13,
"margin": {
"right": 6
}
}
},
"toolbar": {

View file

@ -258,8 +258,9 @@
"avatar_width": 18,
"height": 32,
"background": "#dfe2f1",
"share_icon_color": "#5e6687",
"share_icon_active_color": "#3d8fd1",
"padding": {
"left": 80
},
"title": {
"family": "Zed Sans",
"color": "#293256",
@ -324,10 +325,48 @@
"right": 4
}
},
"share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"color": "#5e6687"
},
"hovered_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#979db41f",
"color": "#5e6687"
},
"hovered_active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#979db41f",
"color": "#202746"
},
"active_share_icon": {
"margin": {
"top": 3,
"bottom": 2
},
"corner_radius": 6,
"background": "#979db42e",
"color": "#202746"
},
"outdated_warning": {
"family": "Zed Sans",
"color": "#c08b30",
"size": 13
"size": 13,
"margin": {
"right": 6
}
}
},
"toolbar": {

View file

@ -669,6 +669,10 @@ impl Project {
.map(|worktree| worktree.read(cx).id())
}
pub fn can_share(&self, cx: &AppContext) -> bool {
self.is_local() && self.visible_worktrees(cx).next().is_some()
}
pub fn share(&self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
let rpc = self.client.clone();
cx.spawn(|this, mut cx| async move {

View file

@ -55,8 +55,10 @@ pub struct Titlebar {
pub avatar_width: f32,
pub avatar_ribbon: AvatarRibbon,
pub offline_icon: OfflineIcon,
pub share_icon_color: Color,
pub share_icon_active_color: Color,
pub share_icon: ShareIcon,
pub hovered_share_icon: ShareIcon,
pub active_share_icon: ShareIcon,
pub hovered_active_share_icon: ShareIcon,
pub avatar: ImageStyle,
pub sign_in_prompt: ContainedText,
pub hovered_sign_in_prompt: ContainedText,
@ -79,6 +81,13 @@ pub struct OfflineIcon {
pub color: Color,
}
#[derive(Clone, Deserialize, Default)]
pub struct ShareIcon {
#[serde(flatten)]
pub container: ContainerStyle,
pub color: Color,
}
#[derive(Clone, Deserialize, Default)]
pub struct Tab {
pub height: f32,

View file

@ -1297,7 +1297,7 @@ impl Workspace {
if project.is_local() {
if project.is_shared() {
project.unshare(cx);
} else {
} else if project.can_share(cx) {
project.share(cx).detach();
}
}
@ -1475,28 +1475,38 @@ impl Workspace {
}
fn render_titlebar(&self, theme: &Theme, cx: &mut RenderContext<Self>) -> ElementBox {
let mut worktree_root_names = String::new();
{
let mut worktrees = self.project.read(cx).visible_worktrees(cx).peekable();
while let Some(worktree) = worktrees.next() {
worktree_root_names.push_str(worktree.read(cx).root_name());
if worktrees.peek().is_some() {
worktree_root_names.push_str(", ");
}
}
}
ConstrainedBox::new(
Container::new(
Stack::new()
.with_child(
Align::new(
Label::new("zed".into(), theme.workspace.titlebar.title.clone())
.boxed(),
)
.boxed(),
Label::new(worktree_root_names, theme.workspace.titlebar.title.clone())
.aligned()
.left()
.boxed(),
)
.with_child(
Align::new(
Flex::row()
.with_children(self.render_share_icon(theme, cx))
.with_children(self.render_collaborators(theme, cx))
.with_child(self.render_current_user(
.with_children(self.render_current_user(
self.user_store.read(cx).current_user().as_ref(),
self.project.read(cx).replica_id(),
theme,
cx,
))
.with_children(self.render_connection_status(cx))
.with_children(self.render_share_icon(theme, cx))
.boxed(),
)
.right()
@ -1540,25 +1550,30 @@ impl Workspace {
replica_id: ReplicaId,
theme: &Theme,
cx: &mut RenderContext<Self>,
) -> ElementBox {
) -> Option<ElementBox> {
let status = *self.client.status().borrow();
if let Some(avatar) = user.and_then(|user| user.avatar.clone()) {
self.render_avatar(avatar, replica_id, None, theme, cx)
Some(self.render_avatar(avatar, replica_id, None, theme, cx))
} else if matches!(status, client::Status::UpgradeRequired) {
None
} else {
MouseEventHandler::new::<Authenticate, _, _>(0, cx, |state, _| {
let style = if state.hovered {
&theme.workspace.titlebar.hovered_sign_in_prompt
} else {
&theme.workspace.titlebar.sign_in_prompt
};
Label::new("Sign in".to_string(), style.text.clone())
.contained()
.with_style(style.container)
.boxed()
})
.on_click(|cx| cx.dispatch_action(Authenticate))
.with_cursor_style(CursorStyle::PointingHand)
.aligned()
.boxed()
Some(
MouseEventHandler::new::<Authenticate, _, _>(0, cx, |state, _| {
let style = if state.hovered {
&theme.workspace.titlebar.hovered_sign_in_prompt
} else {
&theme.workspace.titlebar.sign_in_prompt
};
Label::new("Sign in".to_string(), style.text.clone())
.contained()
.with_style(style.container)
.boxed()
})
.on_click(|cx| cx.dispatch_action(Authenticate))
.with_cursor_style(CursorStyle::PointingHand)
.aligned()
.boxed(),
)
}
}
@ -1598,6 +1613,8 @@ impl Workspace {
)
.constrained()
.with_width(theme.workspace.right_sidebar.width)
.contained()
.with_margin_left(2.)
.boxed();
if let Some(peer_id) = peer_id {
@ -1611,22 +1628,39 @@ impl Workspace {
}
fn render_share_icon(&self, theme: &Theme, cx: &mut RenderContext<Self>) -> Option<ElementBox> {
if self.project().read(cx).is_local() && self.client.user_id().is_some() {
let color = if self.project().read(cx).is_shared() {
theme.workspace.titlebar.share_icon_active_color
} else {
theme.workspace.titlebar.share_icon_color
};
if self.project().read(cx).is_local()
&& self.client.user_id().is_some()
&& self.project().read(cx).can_share(cx)
{
Some(
MouseEventHandler::new::<ToggleShare, _, _>(0, cx, |_, _| {
Align::new(
Svg::new("icons/broadcast-24.svg")
.with_color(color)
.constrained()
.with_width(24.)
.boxed(),
)
.boxed()
MouseEventHandler::new::<ToggleShare, _, _>(0, cx, |state, cx| {
let style = if self.project().read(cx).is_shared() {
if state.hovered {
&theme.workspace.titlebar.hovered_active_share_icon
} else {
&theme.workspace.titlebar.active_share_icon
}
} else {
if state.hovered {
&theme.workspace.titlebar.hovered_share_icon
} else {
&theme.workspace.titlebar.share_icon
}
};
Svg::new("icons/share.svg")
.with_color(style.color)
.constrained()
.with_height(14.)
.aligned()
.contained()
.with_style(style.container)
.constrained()
.with_width(24.)
.aligned()
.constrained()
.with_width(theme.workspace.right_sidebar.width)
.aligned()
.boxed()
})
.with_cursor_style(CursorStyle::PointingHand)
.on_click(|cx| cx.dispatch_action(ToggleShare))

1134
styles/dist/tokens.json vendored

File diff suppressed because it is too large Load diff

View file

@ -68,6 +68,10 @@ export default function workspace(theme: Theme) {
},
},
};
const shareIcon = {
margin: { top: 3, bottom: 2 },
cornerRadius: 6,
};
return {
background: backgroundColor(theme, 300),
@ -112,8 +116,9 @@ export default function workspace(theme: Theme) {
avatarWidth: 18,
height: 32,
background: backgroundColor(theme, 100),
shareIconColor: iconColor(theme, "secondary"),
shareIconActiveColor: iconColor(theme, "feature"),
padding: {
left: 80,
},
title: text(theme, "sans", "primary"),
avatar: {
cornerRadius: 10,
@ -141,9 +146,29 @@ export default function workspace(theme: Theme) {
right: 4,
},
},
shareIcon: {
...shareIcon,
color: iconColor(theme, "secondary")
},
hoveredShareIcon: {
...shareIcon,
background: backgroundColor(theme, 100, "hovered"),
color: iconColor(theme, "secondary"),
},
hoveredActiveShareIcon: {
...shareIcon,
background: backgroundColor(theme, 100, "hovered"),
color: iconColor(theme, "active"),
},
activeShareIcon: {
...shareIcon,
background: backgroundColor(theme, 100, "active"),
color: iconColor(theme, "active"),
},
outdatedWarning: {
...text(theme, "sans", "warning"),
size: 13,
margin: { right: 6 }
},
},
toolbar: {