Detailed changes
@@ -113,7 +113,6 @@ impl View for CollabTitlebarItem {
.with_child(
right_container.contained().with_background_color(
theme
- .workspace
.titlebar
.container
.background_color
@@ -200,11 +199,11 @@ impl CollabTitlebarItem {
.as_ref()
.and_then(RepositoryEntry::branch)
.map(|branch| format!("/{branch}"));
- let text_style = theme.workspace.titlebar.title.clone();
- let item_spacing = theme.workspace.titlebar.item_spacing;
+ let text_style = theme.titlebar.title.clone();
+ let item_spacing = theme.titlebar.item_spacing;
let mut highlight = text_style.clone();
- highlight.color = theme.workspace.titlebar.highlight_color;
+ highlight.color = theme.titlebar.highlight_color;
let style = LabelStyle {
text: text_style,
@@ -325,7 +324,7 @@ impl CollabTitlebarItem {
theme: &Theme,
cx: &mut ViewContext<Self>,
) -> AnyElement<Self> {
- let titlebar = &theme.workspace.titlebar;
+ let titlebar = &theme.titlebar;
let badge = if self
.user_store
@@ -410,7 +409,7 @@ impl CollabTitlebarItem {
}
let active = room.read(cx).is_screen_sharing();
- let titlebar = &theme.workspace.titlebar;
+ let titlebar = &theme.titlebar;
MouseEventHandler::<ToggleScreenSharing, Self>::new(0, cx, |state, _| {
let style = titlebar
.screen_share_button
@@ -459,7 +458,7 @@ impl CollabTitlebarItem {
tooltip = "Mute microphone\nRight click for options";
}
- let titlebar = &theme.workspace.titlebar;
+ let titlebar = &theme.titlebar;
MouseEventHandler::<ToggleMute, Self>::new(0, cx, |state, _| {
let style = titlebar
.toggle_microphone_button
@@ -512,7 +511,7 @@ impl CollabTitlebarItem {
tooltip = "Mute speakers\nRight click for options";
}
- let titlebar = &theme.workspace.titlebar;
+ let titlebar = &theme.titlebar;
MouseEventHandler::<ToggleDeafen, Self>::new(0, cx, |state, _| {
let style = titlebar
.toggle_speakers_button
@@ -547,7 +546,7 @@ impl CollabTitlebarItem {
let icon = "icons/radix/exit.svg";
let tooltip = "Leave call";
- let titlebar = &theme.workspace.titlebar;
+ let titlebar = &theme.titlebar;
MouseEventHandler::<LeaveCall, Self>::new(0, cx, |state, _| {
let style = titlebar.leave_call_button.style_for(state);
Svg::new(icon)
@@ -596,7 +595,7 @@ impl CollabTitlebarItem {
"Share project with call participants"
};
- let titlebar = &theme.workspace.titlebar;
+ let titlebar = &theme.titlebar;
enum ShareUnshare {}
Some(
@@ -627,7 +626,7 @@ impl CollabTitlebarItem {
)
.aligned()
.contained()
- .with_margin_left(theme.workspace.titlebar.item_spacing)
+ .with_margin_left(theme.titlebar.item_spacing)
.into_any(),
)
}
@@ -640,9 +639,9 @@ impl CollabTitlebarItem {
) -> AnyElement<Self> {
let tooltip = theme.tooltip.clone();
let user_menu_button_style = if avatar.is_some() {
- &theme.titlebar.user_menu_button_online
+ &theme.titlebar.user_menu.user_menu_button_online
} else {
- &theme.titlebar.user_menu_button_offline
+ &theme.titlebar.user_menu.user_menu_button_offline
};
let avatar_style = &user_menu_button_style.avatar;
@@ -703,7 +702,7 @@ impl CollabTitlebarItem {
}
fn render_sign_in_button(&self, theme: &Theme, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
- let titlebar = &theme.workspace.titlebar;
+ let titlebar = &theme.titlebar;
MouseEventHandler::<SignIn, Self>::new(0, cx, |state, _| {
let style = titlebar.sign_in_button.inactive_state().style_for(state);
Label::new("Sign In", style.text.clone())
@@ -771,7 +770,7 @@ impl CollabTitlebarItem {
theme,
cx,
))
- .with_margin_right(theme.workspace.titlebar.face_pile_spacing),
+ .with_margin_right(theme.titlebar.face_pile_spacing),
)
})
.collect()
@@ -795,7 +794,7 @@ impl CollabTitlebarItem {
theme,
cx,
))
- .with_margin_right(theme.workspace.titlebar.item_spacing)
+ .with_margin_right(theme.titlebar.item_spacing)
.into_any()
}
@@ -827,11 +826,10 @@ impl CollabTitlebarItem {
})
.unwrap_or(false);
- let leader_style = theme.workspace.titlebar.leader_avatar;
- let follower_style = theme.workspace.titlebar.follower_avatar;
+ let leader_style = theme.titlebar.leader_avatar;
+ let follower_style = theme.titlebar.follower_avatar;
let mut background_color = theme
- .workspace
.titlebar
.container
.background_color
@@ -846,7 +844,7 @@ impl CollabTitlebarItem {
let mut content = Stack::new()
.with_children(user.avatar.as_ref().map(|avatar| {
- let face_pile = FacePile::new(theme.workspace.titlebar.follower_avatar_overlap)
+ let face_pile = FacePile::new(theme.titlebar.follower_avatar_overlap)
.with_child(Self::render_face(
avatar.clone(),
Self::location_style(workspace, location, leader_style, cx),
@@ -891,7 +889,7 @@ impl CollabTitlebarItem {
let mut container = face_pile
.contained()
- .with_style(theme.workspace.titlebar.leader_selection);
+ .with_style(theme.titlebar.leader_selection);
if let Some(replica_id) = replica_id {
if followed_by_self {
@@ -908,8 +906,8 @@ impl CollabTitlebarItem {
Some(
AvatarRibbon::new(color)
.constrained()
- .with_width(theme.workspace.titlebar.avatar_ribbon.width)
- .with_height(theme.workspace.titlebar.avatar_ribbon.height)
+ .with_width(theme.titlebar.avatar_ribbon.width)
+ .with_height(theme.titlebar.avatar_ribbon.height)
.aligned()
.bottom(),
)
@@ -1029,22 +1027,22 @@ impl CollabTitlebarItem {
| client::Status::Reconnecting { .. }
| client::Status::ReconnectionError { .. } => Some(
Svg::new("icons/cloud_slash_12.svg")
- .with_color(theme.workspace.titlebar.offline_icon.color)
+ .with_color(theme.titlebar.offline_icon.color)
.constrained()
- .with_width(theme.workspace.titlebar.offline_icon.width)
+ .with_width(theme.titlebar.offline_icon.width)
.aligned()
.contained()
- .with_style(theme.workspace.titlebar.offline_icon.container)
+ .with_style(theme.titlebar.offline_icon.container)
.into_any(),
),
client::Status::UpgradeRequired => Some(
MouseEventHandler::<ConnectionStatusButton, Self>::new(0, cx, |_, _| {
Label::new(
"Please update Zed to collaborate",
- theme.workspace.titlebar.outdated_warning.text.clone(),
+ theme.titlebar.outdated_warning.text.clone(),
)
.contained()
- .with_style(theme.workspace.titlebar.outdated_warning.container)
+ .with_style(theme.titlebar.outdated_warning.container)
.aligned()
})
.with_cursor_style(CursorStyle::PointingHand)
@@ -66,7 +66,7 @@ pub struct Theme {
pub feedback: FeedbackStyle,
pub welcome: WelcomeStyle,
pub color_scheme: ColorScheme,
- pub titlebar: UserMenu,
+ pub titlebar: Titlebar,
}
#[derive(Deserialize, Default, Clone, JsonSchema)]
@@ -81,7 +81,6 @@ pub struct ThemeMeta {
pub struct Workspace {
pub background: Color,
pub blank_pane: BlankPaneStyle,
- pub titlebar: Titlebar,
pub tab_bar: TabBar,
pub pane_divider: Border,
pub leader_border_opacity: f32,
@@ -138,8 +137,8 @@ pub struct Titlebar {
pub toggle_microphone_button: Toggleable<Interactive<IconButton>>,
pub toggle_speakers_button: Toggleable<Interactive<IconButton>>,
pub leave_call_button: Interactive<IconButton>,
- pub user_menu_button: Toggleable<Interactive<IconButton>>,
pub toggle_contacts_badge: ContainerStyle,
+ pub user_menu: UserMenu,
}
#[derive(Clone, Deserialize, Default, JsonSchema)]
@@ -2296,11 +2296,11 @@ impl Workspace {
// (https://github.com/zed-industries/zed/issues/1290)
let is_fullscreen = cx.window_is_fullscreen();
let container_theme = if is_fullscreen {
- let mut container_theme = theme.workspace.titlebar.container;
+ let mut container_theme = theme.titlebar.container;
container_theme.padding.left = container_theme.padding.right;
container_theme
} else {
- theme.workspace.titlebar.container
+ theme.titlebar.container
};
enum TitleBar {}
@@ -2320,7 +2320,7 @@ impl Workspace {
}
})
.constrained()
- .with_height(theme.workspace.titlebar.height)
+ .with_height(theme.titlebar.height)
.into_any_named("titlebar")
}
@@ -1,6 +1,49 @@
import { ColorScheme } from "../common";
+import { icon_button, toggleable_icon_button } from "../component/icon_button"
+import { toggleable_text_button } from "../component/text_button"
import { interactive, toggleable } from "../element"
-import { background, foreground, text } from "./components";
+import { withOpacity } from "../theme/color";
+import { background, border, foreground, text } from "./components";
+
+const ITEM_SPACING = 8
+
+interface SpacingProps {
+ container_height: number;
+ spacing: number;
+}
+
+function build_spacing(
+ container_height: number,
+ element_height: number,
+ spacing: number
+) {
+ return {
+ group: spacing * 2,
+ item: spacing / 2,
+ marginY: (container_height - element_height) / 2,
+ marginX: (container_height - element_height) / 2,
+ }
+}
+
+function mac_os_controls(theme: ColorScheme, { container_height, spacing }: SpacingProps) {
+ return {}
+}
+
+function project_info(theme: ColorScheme, { container_height, spacing }: SpacingProps) {
+ return {}
+}
+
+function collaboration_stacks(theme: ColorScheme, { container_height, spacing }: SpacingProps) {
+ return {}
+}
+
+function sharing_controls(theme: ColorScheme, { container_height, spacing }: SpacingProps) {
+ return {}
+}
+
+function call_controls(theme: ColorScheme, { container_height, spacing }: SpacingProps) {
+ return {}
+}
const titlebarButton = (theme: ColorScheme) => toggleable({
base: interactive({
@@ -57,29 +100,210 @@ const titlebarButton = (theme: ColorScheme) => toggleable({
* When logged out only shows a chevron.
*/
function userMenuButton(theme: ColorScheme, online: boolean) {
+ const button = toggleable({
+ base: interactive({
+ base: {
+ cornerRadius: 6,
+ height: 19,
+ width: online ? 36 : 23,
+ padding: {
+ top: 2,
+ bottom: 2,
+ left: 6,
+ right: 6,
+ },
+ ...text(theme.lowest, "sans", { size: "xs" }),
+ background: background(theme.lowest),
+ },
+ state: {
+ hovered: {
+ ...text(theme.lowest, "sans", "hovered", {
+ size: "xs",
+ }),
+ background: background(theme.lowest, "hovered"),
+ },
+ clicked: {
+ ...text(theme.lowest, "sans", "pressed", {
+ size: "xs",
+ }),
+ background: background(theme.lowest, "pressed"),
+ },
+ },
+ }),
+ state: {
+ active: {
+ default: {
+ ...text(theme.lowest, "sans", "active", { size: "xs" }),
+ background: background(theme.middle),
+ },
+ hovered: {
+ ...text(theme.lowest, "sans", "active", { size: "xs" }),
+ background: background(theme.middle, "hovered"),
+ },
+ clicked: {
+ ...text(theme.lowest, "sans", "active", { size: "xs" }),
+ background: background(theme.middle, "pressed"),
+ },
+ },
+ }
+ });
+
return {
- user_menu: titlebarButton(theme),
+ user_menu: button,
avatar: {
icon_width: 16,
icon_height: 16,
cornerRadius: 4,
outer_corner_radius: 0,
outer_width: 0,
- outerWidth: 10,
- outerCornerRadius: 10
+ outerWidth: 16,
+ outerCornerRadius: 16
},
icon: {
+ margin: {
+ left: online ? 2 : 0,
+ },
width: 11,
height: 11,
- color: online ? foreground(theme.lowest) : background(theme.lowest)
+ color: foreground(theme.lowest)
}
}
}
export function titlebar(theme: ColorScheme) {
+ const avatarWidth = 18
+ const avatarOuterWidth = avatarWidth + 4
+ const followerAvatarWidth = 14
+ const followerAvatarOuterWidth = followerAvatarWidth + 4
+
return {
- userMenuButtonOnline: userMenuButton(theme, true),
- userMenuButtonOffline: userMenuButton(theme, false)
+ ITEM_SPACING,
+ facePileSpacing: 2,
+ height: 33, // 32px + 1px border. It's important the content area of the titlebar is evenly sized to vertically center avatar images.
+ background: background(theme.lowest),
+ border: border(theme.lowest, { bottom: true }),
+ padding: {
+ left: 80,
+ right: ITEM_SPACING,
+ },
+
+ // Project
+ title: text(theme.lowest, "sans", "variant"),
+ highlight_color: text(theme.lowest, "sans", "active").color,
+
+ // Collaborators
+ leaderAvatar: {
+ width: avatarWidth,
+ outerWidth: avatarOuterWidth,
+ cornerRadius: avatarWidth / 2,
+ outerCornerRadius: avatarOuterWidth / 2,
+ },
+ followerAvatar: {
+ width: followerAvatarWidth,
+ outerWidth: followerAvatarOuterWidth,
+ cornerRadius: followerAvatarWidth / 2,
+ outerCornerRadius: followerAvatarOuterWidth / 2,
+ },
+ inactiveAvatarGrayscale: true,
+ followerAvatarOverlap: 8,
+ leaderSelection: {
+ margin: {
+ top: 4,
+ bottom: 4,
+ },
+ padding: {
+ left: 2,
+ right: 2,
+ top: 2,
+ bottom: 2,
+ },
+ cornerRadius: 6,
+ },
+ avatarRibbon: {
+ height: 3,
+ width: 11,
+ // TODO: Chore: Make avatarRibbon colors driven by the theme rather than being hard coded.
+ },
+
+ // Sign in buttom
+ sign_in_button: toggleable_text_button(theme, {}),
+
+ // Offline Indicator
+ offlineIcon: {
+ color: foreground(theme.lowest, "variant"),
+ width: 16,
+ margin: {
+ left: ITEM_SPACING,
+ },
+ padding: {
+ right: 4,
+ },
+ },
+
+ // Notice that the collaboration server is out of date
+ outdatedWarning: {
+ ...text(theme.lowest, "sans", "warning", { size: "xs" }),
+ background: withOpacity(background(theme.lowest, "warning"), 0.3),
+ border: border(theme.lowest, "warning"),
+ margin: {
+ left: ITEM_SPACING,
+ },
+ padding: {
+ left: 8,
+ right: 8,
+ },
+ cornerRadius: 6,
+ },
+
+ leave_call_button: icon_button(theme, {
+ margin: {
+ left: ITEM_SPACING / 2,
+ right: ITEM_SPACING
+ },
+ }),
+
+ toggle_microphone_button: toggleable_icon_button(theme, {
+ margin: {
+ left: ITEM_SPACING,
+ right: ITEM_SPACING / 2
+ },
+ active_color: 'negative'
+ }),
+ toggle_speakers_button: toggleable_icon_button(theme, {
+ margin: {
+ left: ITEM_SPACING / 2,
+ right: ITEM_SPACING / 2
+ },
+ }),
+
+ screen_share_button: toggleable_icon_button(theme, {
+ margin: {
+ left: ITEM_SPACING / 2,
+ right: ITEM_SPACING
+ },
+ active_color: 'accent'
+ }),
+
+ toggle_contacts_button: toggleable_icon_button(theme, {
+ margin: {
+ left: ITEM_SPACING,
+ right: ITEM_SPACING / 2
+ },
+ }),
+
+ // Jewel that notifies you that there are new contact requests
+ toggleContactsBadge: {
+ cornerRadius: 3,
+ padding: 2,
+ margin: { top: 3, left: 3 },
+ border: border(theme.lowest),
+ background: foreground(theme.lowest, "accent"),
+ },
+ shareButton: toggleable_text_button(theme, {}),
+ user_menu: {
+ userMenuButtonOnline: userMenuButton(theme, true),
+ userMenuButtonOffline: userMenuButton(theme, false),
+ }
}
}
@@ -1,6 +1,5 @@
import { ColorScheme } from "../theme/colorScheme"
import { withOpacity } from "../theme/color"
-import { toggleable } from "../element"
import {
background,
border,
@@ -12,94 +11,11 @@ import {
import statusBar from "./statusBar"
import tabBar from "./tabBar"
import { interactive } from "../element"
-import merge from "ts-deepmerge"
-import { icon_button, toggleable_icon_button } from "../component/icon_button"
-import { text_button, toggleable_text_button } from "../component/text_button"
+
+import { titlebar } from "./titlebar"
export default function workspace(colorScheme: ColorScheme) {
const layer = colorScheme.lowest
const isLight = colorScheme.isLight
- const itemSpacing = 8
- const titlebarButton = toggleable({
- base: interactive({
- base: {
- cornerRadius: 6,
- padding: {
- top: 1,
- bottom: 1,
- left: 8,
- right: 8,
- },
- ...text(layer, "sans", "variant", { size: "xs" }),
- background: background(layer, "variant"),
- border: border(layer),
- },
- state: {
- hovered: {
- ...text(layer, "sans", "variant", "hovered", {
- size: "xs",
- }),
- background: background(layer, "variant", "hovered"),
- border: border(layer, "variant", "hovered"),
- },
- clicked: {
- ...text(layer, "sans", "variant", "pressed", {
- size: "xs",
- }),
- background: background(layer, "variant", "pressed"),
- border: border(layer, "variant", "pressed"),
- },
- },
- }),
- state: {
- active: {
- default: {
- ...text(layer, "sans", "variant", "active", { size: "xs" }),
- background: background(layer, "variant", "active"),
- border: border(layer, "variant", "active"),
- },
- },
- }
- });
- const signInButton = toggleable({
- base: interactive({
- base: {
- cornerRadius: 6,
- padding: {
- top: 1,
- bottom: 1,
- left: 8,
- right: 8,
- },
- ...text(layer, "sans", "variant", { size: "xs" }),
- background: background(layer, "variant"),
- },
- state: {
- hovered: {
- ...text(layer, "sans", "variant", "hovered", { size: "xs" }),
- background: background(layer, "variant", "hovered"),
- //border: border(layer, "variant", "hovered"),
- },
- clicked: {
- ...text(layer, "sans", "variant", "pressed", { size: "xs" }),
- background: background(layer, "variant", "pressed"),
- //border: border(layer, "variant", "pressed"),
- }
- }
- }),
- state: {
- active: {
- default: {
- ...text(layer, "sans", "variant", "active", { size: "xs" }),
- background: background(layer, "variant", "active"),
- //border: border(layer, "variant", "active"),
- }
- },
- }
- });
- const avatarWidth = 18
- const avatarOuterWidth = avatarWidth + 4
- const followerAvatarWidth = 14
- const followerAvatarOuterWidth = followerAvatarWidth + 4
return {
background: background(colorScheme.lowest),
@@ -209,163 +125,7 @@ export default function workspace(colorScheme: ColorScheme) {
width: 1,
},
statusBar: statusBar(colorScheme),
- titlebar: {
- itemSpacing,
- facePileSpacing: 2,
- height: 33, // 32px + 1px border. It's important the content area of the titlebar is evenly sized to vertically center avatar images.
- background: background(layer),
- border: border(layer, { bottom: true }),
- padding: {
- left: 80,
- right: itemSpacing,
- },
-
- // Project
- title: text(layer, "sans", "variant"),
- highlight_color: text(layer, "sans", "active").color,
-
- // Collaborators
- leaderAvatar: {
- width: avatarWidth,
- outerWidth: avatarOuterWidth,
- cornerRadius: avatarWidth / 2,
- outerCornerRadius: avatarOuterWidth / 2,
- },
- followerAvatar: {
- width: followerAvatarWidth,
- outerWidth: followerAvatarOuterWidth,
- cornerRadius: followerAvatarWidth / 2,
- outerCornerRadius: followerAvatarOuterWidth / 2,
- },
- inactiveAvatarGrayscale: true,
- followerAvatarOverlap: 8,
- leaderSelection: {
- margin: {
- top: 4,
- bottom: 4,
- },
- padding: {
- left: 2,
- right: 2,
- top: 2,
- bottom: 2,
- },
- cornerRadius: 6,
- },
- avatarRibbon: {
- height: 3,
- width: 11,
- // TODO: Chore: Make avatarRibbon colors driven by the theme rather than being hard coded.
- },
-
- // Sign in buttom
- // FlatButton, Variant
- sign_in_button: merge(titlebarButton, {
- inactive: {
- default: {
- margin: {
- left: itemSpacing,
- },
- },
- },
-
- signInButton,
-
- }),
-
- // Offline Indicator
- offlineIcon: {
- color: foreground(layer, "variant"),
- width: 16,
- margin: {
- left: itemSpacing,
- },
- padding: {
- right: 4,
- },
- },
-
- // Notice that the collaboration server is out of date
- outdatedWarning: {
- ...text(layer, "sans", "warning", { size: "xs" }),
- background: withOpacity(background(layer, "warning"), 0.3),
- border: border(layer, "warning"),
- margin: {
- left: itemSpacing,
- },
- padding: {
- left: 8,
- right: 8,
- },
- cornerRadius: 6,
- },
-
- leave_call_button: icon_button(colorScheme, {
- margin: {
- left: itemSpacing / 2,
- right: itemSpacing
- },
- }),
-
- toggle_microphone_button: toggleable_icon_button(colorScheme, {
- margin: {
- left: itemSpacing,
- right: itemSpacing / 2
- },
- active_color: 'negative'
- }),
-
- toggle_speakers_button: toggleable_icon_button(colorScheme, {
- margin: {
- left: itemSpacing / 2,
- right: itemSpacing / 2
- },
- }),
-
- screen_share_button: toggleable_icon_button(colorScheme, {
- margin: {
- left: itemSpacing / 2,
- right: itemSpacing
- },
- active_color: 'accent'
- }),
-
- toggle_contacts_button: toggleable_icon_button(colorScheme, {
- margin: {
- left: itemSpacing,
- right: itemSpacing / 2
- },
- }),
-
- user_menu_button:
- merge(titlebarButton, {
- inactive: {
- default: {
- buttonWidth: 20,
- iconWidth: 12,
- },
- },
- active: {
- default: {
- iconWidth: 12,
- button_width: 20,
- background: background(layer, "variant", "active"),
- color: foreground(layer, "variant", "active"),
- }
- },
- }),
-
- // Jewel that notifies you that there are new contact requests
- toggleContactsBadge: {
- cornerRadius: 3,
- padding: 2,
- margin: { top: 3, left: 3 },
- border: border(layer),
- background: foreground(layer, "accent"),
- },
- shareButton: toggleable_text_button(colorScheme, {}),
- },
-
+ titlebar: titlebar(colorScheme),
toolbar: {
height: 34,
background: background(colorScheme.highest),