Cargo.lock 🔗
@@ -936,9 +936,11 @@ dependencies = [
"futures",
"fuzzy",
"gpui",
+ "language",
"log",
"picker",
"postage",
+ "project",
"serde",
"settings",
"theme",
Max Brunsfeld created
Cargo.lock | 2
assets/themes/cave-dark.json | 99 +--
assets/themes/cave-light.json | 99 +--
assets/themes/dark.json | 99 +--
assets/themes/light.json | 99 +--
assets/themes/solarized-dark.json | 99 +--
assets/themes/solarized-light.json | 99 +--
assets/themes/sulphurpool-dark.json | 99 +--
assets/themes/sulphurpool-light.json | 99 +--
crates/contacts_panel/Cargo.toml | 5
crates/contacts_panel/src/contacts_panel.rs | 680 ++++++++++++++++------
crates/theme/src/theme.rs | 10
styles/src/styleTree/contactsPanel.ts | 61 +
13 files changed, 791 insertions(+), 759 deletions(-)
@@ -936,9 +936,11 @@ dependencies = [
"futures",
"fuzzy",
"gpui",
+ "language",
"log",
"picker",
"postage",
+ "project",
"serde",
"settings",
"theme",
@@ -1249,20 +1249,29 @@
"button_width": 8,
"icon_width": 8
},
- "row": {
- "padding": {
- "left": 8
- }
- },
- "row_height": 28,
- "header": {
+ "header_row": {
"family": "Zed Mono",
"color": "#8b8792",
"size": 14,
"margin": {
"top": 8
+ },
+ "active": {
+ "family": "Zed Mono",
+ "color": "#e2dfe7",
+ "size": 14,
+ "background": "#5852605c"
}
},
+ "contact_row": {
+ "padding": {
+ "left": 8
+ },
+ "active": {
+ "background": "#5852605c"
+ }
+ },
+ "row_height": 28,
"tree_branch_color": "#655f6d",
"tree_branch_width": 1,
"contact_avatar": {
@@ -1294,26 +1303,7 @@
"button_width": 16,
"corner_radius": 8
},
- "project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#7e7887",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- }
- },
- "shared_project": {
+ "shared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1332,9 +1322,15 @@
"left": 8
},
"background": "#26232a",
- "corner_radius": 6
+ "corner_radius": 6,
+ "hover": {
+ "background": "#5852603d"
+ },
+ "active": {
+ "background": "#5852605c"
+ }
},
- "hovered_shared_project": {
+ "unshared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1352,47 +1348,14 @@
"padding": {
"left": 8
},
- "background": "#5852603d",
- "corner_radius": 6
- },
- "unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#7e7887",
- "size": 14,
- "margin": {
- "right": 6
- }
+ "background": "#26232a",
+ "corner_radius": 6,
+ "hover": {
+ "background": "#5852603d"
},
- "padding": {
- "left": 8
+ "active": {
+ "background": "#5852605c"
}
- },
- "hovered_unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#7e7887",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- },
- "corner_radius": 6
}
},
"contact_finder": {
@@ -1249,20 +1249,29 @@
"button_width": 8,
"icon_width": 8
},
- "row": {
- "padding": {
- "left": 8
- }
- },
- "row_height": 28,
- "header": {
+ "header_row": {
"family": "Zed Mono",
"color": "#585260",
"size": 14,
"margin": {
"top": 8
+ },
+ "active": {
+ "family": "Zed Mono",
+ "color": "#26232a",
+ "size": 14,
+ "background": "#8b87922e"
}
},
+ "contact_row": {
+ "padding": {
+ "left": 8
+ },
+ "active": {
+ "background": "#8b87922e"
+ }
+ },
+ "row_height": 28,
"tree_branch_color": "#7e7887",
"tree_branch_width": 1,
"contact_avatar": {
@@ -1294,26 +1303,7 @@
"button_width": 16,
"corner_radius": 8
},
- "project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#655f6d",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- }
- },
- "shared_project": {
+ "shared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1332,9 +1322,15 @@
"left": 8
},
"background": "#e2dfe7",
- "corner_radius": 6
+ "corner_radius": 6,
+ "hover": {
+ "background": "#8b87921f"
+ },
+ "active": {
+ "background": "#8b87922e"
+ }
},
- "hovered_shared_project": {
+ "unshared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1352,47 +1348,14 @@
"padding": {
"left": 8
},
- "background": "#8b87921f",
- "corner_radius": 6
- },
- "unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#655f6d",
- "size": 14,
- "margin": {
- "right": 6
- }
+ "background": "#e2dfe7",
+ "corner_radius": 6,
+ "hover": {
+ "background": "#8b87921f"
},
- "padding": {
- "left": 8
+ "active": {
+ "background": "#8b87922e"
}
- },
- "hovered_unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#655f6d",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- },
- "corner_radius": 6
}
},
"contact_finder": {
@@ -1249,20 +1249,29 @@
"button_width": 8,
"icon_width": 8
},
- "row": {
- "padding": {
- "left": 8
- }
- },
- "row_height": 28,
- "header": {
+ "header_row": {
"family": "Zed Mono",
"color": "#9c9c9c",
"size": 14,
"margin": {
"top": 8
+ },
+ "active": {
+ "family": "Zed Mono",
+ "color": "#f1f1f1",
+ "size": 14,
+ "background": "#1c1c1c"
}
},
+ "contact_row": {
+ "padding": {
+ "left": 8
+ },
+ "active": {
+ "background": "#1c1c1c"
+ }
+ },
+ "row_height": 28,
"tree_branch_color": "#404040",
"tree_branch_width": 1,
"contact_avatar": {
@@ -1294,26 +1303,7 @@
"button_width": 16,
"corner_radius": 8
},
- "project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#474747",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- }
- },
- "shared_project": {
+ "shared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1332,9 +1322,15 @@
"left": 8
},
"background": "#1c1c1c",
- "corner_radius": 6
+ "corner_radius": 6,
+ "hover": {
+ "background": "#232323"
+ },
+ "active": {
+ "background": "#2b2b2b"
+ }
},
- "hovered_shared_project": {
+ "unshared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1352,47 +1348,14 @@
"padding": {
"left": 8
},
- "background": "#232323",
- "corner_radius": 6
- },
- "unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#474747",
- "size": 14,
- "margin": {
- "right": 6
- }
+ "background": "#1c1c1c",
+ "corner_radius": 6,
+ "hover": {
+ "background": "#232323"
},
- "padding": {
- "left": 8
+ "active": {
+ "background": "#2b2b2b"
}
- },
- "hovered_unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#474747",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- },
- "corner_radius": 6
}
},
"contact_finder": {
@@ -1249,20 +1249,29 @@
"button_width": 8,
"icon_width": 8
},
- "row": {
- "padding": {
- "left": 8
- }
- },
- "row_height": 28,
- "header": {
+ "header_row": {
"family": "Zed Mono",
"color": "#474747",
"size": 14,
"margin": {
"top": 8
+ },
+ "active": {
+ "family": "Zed Mono",
+ "color": "#2b2b2b",
+ "size": 14,
+ "background": "#d5d5d5"
}
},
+ "contact_row": {
+ "padding": {
+ "left": 8
+ },
+ "active": {
+ "background": "#d5d5d5"
+ }
+ },
+ "row_height": 28,
"tree_branch_color": "#e3e3e3",
"tree_branch_width": 1,
"contact_avatar": {
@@ -1294,26 +1303,7 @@
"button_width": 16,
"corner_radius": 8
},
- "project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#808080",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- }
- },
- "shared_project": {
+ "shared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1332,9 +1322,15 @@
"left": 8
},
"background": "#f8f8f8",
- "corner_radius": 6
+ "corner_radius": 6,
+ "hover": {
+ "background": "#eaeaea"
+ },
+ "active": {
+ "background": "#e3e3e3"
+ }
},
- "hovered_shared_project": {
+ "unshared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1352,47 +1348,14 @@
"padding": {
"left": 8
},
- "background": "#eaeaea",
- "corner_radius": 6
- },
- "unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#808080",
- "size": 14,
- "margin": {
- "right": 6
- }
+ "background": "#f8f8f8",
+ "corner_radius": 6,
+ "hover": {
+ "background": "#eaeaea"
},
- "padding": {
- "left": 8
+ "active": {
+ "background": "#e3e3e3"
}
- },
- "hovered_unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#808080",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- },
- "corner_radius": 6
}
},
"contact_finder": {
@@ -1249,20 +1249,29 @@
"button_width": 8,
"icon_width": 8
},
- "row": {
- "padding": {
- "left": 8
- }
- },
- "row_height": 28,
- "header": {
+ "header_row": {
"family": "Zed Mono",
"color": "#93a1a1",
"size": 14,
"margin": {
"top": 8
+ },
+ "active": {
+ "family": "Zed Mono",
+ "color": "#eee8d5",
+ "size": 14,
+ "background": "#586e755c"
}
},
+ "contact_row": {
+ "padding": {
+ "left": 8
+ },
+ "active": {
+ "background": "#586e755c"
+ }
+ },
+ "row_height": 28,
"tree_branch_color": "#657b83",
"tree_branch_width": 1,
"contact_avatar": {
@@ -1294,26 +1303,7 @@
"button_width": 16,
"corner_radius": 8
},
- "project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#839496",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- }
- },
- "shared_project": {
+ "shared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1332,9 +1322,15 @@
"left": 8
},
"background": "#073642",
- "corner_radius": 6
+ "corner_radius": 6,
+ "hover": {
+ "background": "#586e753d"
+ },
+ "active": {
+ "background": "#586e755c"
+ }
},
- "hovered_shared_project": {
+ "unshared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1352,47 +1348,14 @@
"padding": {
"left": 8
},
- "background": "#586e753d",
- "corner_radius": 6
- },
- "unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#839496",
- "size": 14,
- "margin": {
- "right": 6
- }
+ "background": "#073642",
+ "corner_radius": 6,
+ "hover": {
+ "background": "#586e753d"
},
- "padding": {
- "left": 8
+ "active": {
+ "background": "#586e755c"
}
- },
- "hovered_unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#839496",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- },
- "corner_radius": 6
}
},
"contact_finder": {
@@ -1249,20 +1249,29 @@
"button_width": 8,
"icon_width": 8
},
- "row": {
- "padding": {
- "left": 8
- }
- },
- "row_height": 28,
- "header": {
+ "header_row": {
"family": "Zed Mono",
"color": "#586e75",
"size": 14,
"margin": {
"top": 8
+ },
+ "active": {
+ "family": "Zed Mono",
+ "color": "#073642",
+ "size": 14,
+ "background": "#93a1a12e"
}
},
+ "contact_row": {
+ "padding": {
+ "left": 8
+ },
+ "active": {
+ "background": "#93a1a12e"
+ }
+ },
+ "row_height": 28,
"tree_branch_color": "#839496",
"tree_branch_width": 1,
"contact_avatar": {
@@ -1294,26 +1303,7 @@
"button_width": 16,
"corner_radius": 8
},
- "project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#657b83",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- }
- },
- "shared_project": {
+ "shared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1332,9 +1322,15 @@
"left": 8
},
"background": "#eee8d5",
- "corner_radius": 6
+ "corner_radius": 6,
+ "hover": {
+ "background": "#93a1a11f"
+ },
+ "active": {
+ "background": "#93a1a12e"
+ }
},
- "hovered_shared_project": {
+ "unshared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1352,47 +1348,14 @@
"padding": {
"left": 8
},
- "background": "#93a1a11f",
- "corner_radius": 6
- },
- "unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#657b83",
- "size": 14,
- "margin": {
- "right": 6
- }
+ "background": "#eee8d5",
+ "corner_radius": 6,
+ "hover": {
+ "background": "#93a1a11f"
},
- "padding": {
- "left": 8
+ "active": {
+ "background": "#93a1a12e"
}
- },
- "hovered_unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#657b83",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- },
- "corner_radius": 6
}
},
"contact_finder": {
@@ -1249,20 +1249,29 @@
"button_width": 8,
"icon_width": 8
},
- "row": {
- "padding": {
- "left": 8
- }
- },
- "row_height": 28,
- "header": {
+ "header_row": {
"family": "Zed Mono",
"color": "#979db4",
"size": 14,
"margin": {
"top": 8
+ },
+ "active": {
+ "family": "Zed Mono",
+ "color": "#dfe2f1",
+ "size": 14,
+ "background": "#5e66875c"
}
},
+ "contact_row": {
+ "padding": {
+ "left": 8
+ },
+ "active": {
+ "background": "#5e66875c"
+ }
+ },
+ "row_height": 28,
"tree_branch_color": "#6b7394",
"tree_branch_width": 1,
"contact_avatar": {
@@ -1294,26 +1303,7 @@
"button_width": 16,
"corner_radius": 8
},
- "project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#898ea4",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- }
- },
- "shared_project": {
+ "shared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1332,9 +1322,15 @@
"left": 8
},
"background": "#293256",
- "corner_radius": 6
+ "corner_radius": 6,
+ "hover": {
+ "background": "#5e66873d"
+ },
+ "active": {
+ "background": "#5e66875c"
+ }
},
- "hovered_shared_project": {
+ "unshared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1352,47 +1348,14 @@
"padding": {
"left": 8
},
- "background": "#5e66873d",
- "corner_radius": 6
- },
- "unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#898ea4",
- "size": 14,
- "margin": {
- "right": 6
- }
+ "background": "#293256",
+ "corner_radius": 6,
+ "hover": {
+ "background": "#5e66873d"
},
- "padding": {
- "left": 8
+ "active": {
+ "background": "#5e66875c"
}
- },
- "hovered_unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#898ea4",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- },
- "corner_radius": 6
}
},
"contact_finder": {
@@ -1249,20 +1249,29 @@
"button_width": 8,
"icon_width": 8
},
- "row": {
- "padding": {
- "left": 8
- }
- },
- "row_height": 28,
- "header": {
+ "header_row": {
"family": "Zed Mono",
"color": "#5e6687",
"size": 14,
"margin": {
"top": 8
+ },
+ "active": {
+ "family": "Zed Mono",
+ "color": "#293256",
+ "size": 14,
+ "background": "#979db42e"
}
},
+ "contact_row": {
+ "padding": {
+ "left": 8
+ },
+ "active": {
+ "background": "#979db42e"
+ }
+ },
+ "row_height": 28,
"tree_branch_color": "#898ea4",
"tree_branch_width": 1,
"contact_avatar": {
@@ -1294,26 +1303,7 @@
"button_width": 16,
"corner_radius": 8
},
- "project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#6b7394",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- }
- },
- "shared_project": {
+ "shared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1332,9 +1322,15 @@
"left": 8
},
"background": "#dfe2f1",
- "corner_radius": 6
+ "corner_radius": 6,
+ "hover": {
+ "background": "#979db41f"
+ },
+ "active": {
+ "background": "#979db42e"
+ }
},
- "hovered_shared_project": {
+ "unshared_project_row": {
"guest_avatar_spacing": 4,
"height": 24,
"guest_avatar": {
@@ -1352,47 +1348,14 @@
"padding": {
"left": 8
},
- "background": "#979db41f",
- "corner_radius": 6
- },
- "unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#6b7394",
- "size": 14,
- "margin": {
- "right": 6
- }
+ "background": "#dfe2f1",
+ "corner_radius": 6,
+ "hover": {
+ "background": "#979db41f"
},
- "padding": {
- "left": 8
+ "active": {
+ "background": "#979db42e"
}
- },
- "hovered_unshared_project": {
- "guest_avatar_spacing": 4,
- "height": 24,
- "guest_avatar": {
- "corner_radius": 8,
- "width": 14
- },
- "name": {
- "family": "Zed Mono",
- "color": "#6b7394",
- "size": 14,
- "margin": {
- "right": 6
- }
- },
- "padding": {
- "left": 8
- },
- "corner_radius": 6
}
},
"contact_finder": {
@@ -21,3 +21,8 @@ futures = "0.3"
log = "0.4"
postage = { version = "0.4.1", features = ["futures-traits"] }
serde = { version = "1", features = ["derive"] }
+
+[dev-dependencies]
+language = { path = "../language", features = ["test-support"] }
+project = { path = "../project", features = ["test-support"] }
+workspace = { path = "../workspace", features = ["test-support"] }
@@ -15,6 +15,7 @@ use serde::Deserialize;
use settings::Settings;
use std::sync::Arc;
use theme::IconButton;
+use workspace::menu::{SelectNext, SelectPrev};
use workspace::{AppState, JoinProject};
impl_actions!(
@@ -22,12 +23,13 @@ impl_actions!(
[RequestContact, RemoveContact, RespondToContactRequest]
);
-#[derive(Debug)]
+#[derive(Clone, Debug)]
enum ContactEntry {
Header(&'static str),
IncomingRequest(Arc<User>),
OutgoingRequest(Arc<User>),
Contact(Arc<Contact>),
+ ContactProject(Arc<Contact>, usize),
}
pub struct ContactsPanel {
@@ -36,6 +38,7 @@ pub struct ContactsPanel {
list_state: ListState,
user_store: ModelHandle<UserStore>,
filter_editor: ViewHandle<Editor>,
+ selection: Option<usize>,
_maintain_contacts: Subscription,
}
@@ -57,6 +60,8 @@ pub fn init(cx: &mut MutableAppContext) {
cx.add_action(ContactsPanel::remove_contact);
cx.add_action(ContactsPanel::respond_to_contact_request);
cx.add_action(ContactsPanel::clear_filter);
+ cx.add_action(ContactsPanel::select_next);
+ cx.add_action(ContactsPanel::select_prev);
}
impl ContactsPanel {
@@ -72,6 +77,7 @@ impl ContactsPanel {
cx.subscribe(&user_query_editor, |this, _, event, cx| {
if let editor::Event::BufferEdited = event {
+ this.selection.take();
this.update_entries(cx)
}
})
@@ -88,17 +94,20 @@ impl ContactsPanel {
let theme = &theme.contacts_panel;
let current_user_id =
this.user_store.read(cx).current_user().map(|user| user.id);
+ let is_selected = this.selection == Some(ix);
match &this.entries[ix] {
ContactEntry::Header(text) => {
- Label::new(text.to_string(), theme.header.text.clone())
+ let header_style =
+ theme.header_row.style_for(&Default::default(), is_selected);
+ Label::new(text.to_string(), header_style.text.clone())
.contained()
.aligned()
.left()
.constrained()
.with_height(theme.row_height)
.contained()
- .with_style(theme.header.container)
+ .with_style(header_style.container)
.boxed()
}
ContactEntry::IncomingRequest(user) => Self::render_contact_request(
@@ -106,6 +115,7 @@ impl ContactsPanel {
this.user_store.clone(),
theme,
true,
+ is_selected,
cx,
),
ContactEntry::OutgoingRequest(user) => Self::render_contact_request(
@@ -113,18 +123,36 @@ impl ContactsPanel {
this.user_store.clone(),
theme,
false,
+ is_selected,
cx,
),
- ContactEntry::Contact(contact) => Self::render_contact(
- contact.clone(),
- current_user_id,
- app_state.clone(),
- theme,
- cx,
- ),
+ ContactEntry::Contact(contact) => {
+ Self::render_contact(contact.clone(), theme, is_selected)
+ }
+ ContactEntry::ContactProject(contact, project_ix) => {
+ let is_last_project_for_contact =
+ this.entries.get(ix + 1).map_or(true, |next| {
+ if let ContactEntry::ContactProject(next_contact, _) = next {
+ next_contact.user.id != contact.user.id
+ } else {
+ true
+ }
+ });
+ Self::render_contact_project(
+ contact.clone(),
+ current_user_id,
+ *project_ix,
+ app_state.clone(),
+ theme,
+ is_last_project_for_contact,
+ is_selected,
+ cx,
+ )
+ }
}
}
}),
+ selection: None,
entries: Default::default(),
match_candidates: Default::default(),
filter_editor: user_query_editor,
@@ -137,175 +165,173 @@ impl ContactsPanel {
}
fn render_contact(
+ contact: Arc<Contact>,
+ theme: &theme::ContactsPanel,
+ is_selected: bool,
+ ) -> ElementBox {
+ Flex::row()
+ .with_children(contact.user.avatar.clone().map(|avatar| {
+ Image::new(avatar)
+ .with_style(theme.contact_avatar)
+ .aligned()
+ .left()
+ .boxed()
+ }))
+ .with_child(
+ Label::new(
+ contact.user.github_login.clone(),
+ theme.contact_username.text.clone(),
+ )
+ .contained()
+ .with_style(theme.contact_username.container)
+ .aligned()
+ .left()
+ .boxed(),
+ )
+ .constrained()
+ .with_height(theme.row_height)
+ .contained()
+ .with_style(
+ *theme
+ .contact_row
+ .style_for(&Default::default(), is_selected),
+ )
+ .boxed()
+ }
+
+ fn render_contact_project(
contact: Arc<Contact>,
current_user_id: Option<u64>,
+ project_ix: usize,
app_state: Arc<AppState>,
theme: &theme::ContactsPanel,
+ is_last_project: bool,
+ is_selected: bool,
cx: &mut LayoutContext,
) -> ElementBox {
- let project_count = contact.non_empty_projects().count();
+ let project = &contact.projects[project_ix];
+ let project_id = project.id;
+
let font_cache = cx.font_cache();
- let line_height = theme.unshared_project.name.text.line_height(font_cache);
- let cap_height = theme.unshared_project.name.text.cap_height(font_cache);
- let baseline_offset = theme.unshared_project.name.text.baseline_offset(font_cache)
- + (theme.unshared_project.height - line_height) / 2.;
- let tree_branch_width = theme.tree_branch_width;
- let tree_branch_color = theme.tree_branch_color;
let host_avatar_height = theme
.contact_avatar
.width
.or(theme.contact_avatar.height)
.unwrap_or(0.);
+ let row = &theme.unshared_project_row.default;
+ let line_height = row.name.text.line_height(font_cache);
+ let cap_height = row.name.text.cap_height(font_cache);
+ let baseline_offset =
+ row.name.text.baseline_offset(font_cache) + (row.height - line_height) / 2.;
+ let tree_branch_width = theme.tree_branch_width;
+ let tree_branch_color = theme.tree_branch_color;
- Flex::column()
+ Flex::row()
.with_child(
- Flex::row()
- .with_children(contact.user.avatar.clone().map(|avatar| {
- Image::new(avatar)
- .with_style(theme.contact_avatar)
- .aligned()
- .left()
- .boxed()
- }))
- .with_child(
- Label::new(
- contact.user.github_login.clone(),
- theme.contact_username.text.clone(),
- )
- .contained()
- .with_style(theme.contact_username.container)
- .aligned()
- .left()
- .boxed(),
- )
- .constrained()
- .with_height(theme.row_height)
- .boxed(),
+ Canvas::new(move |bounds, _, cx| {
+ let start_x = bounds.min_x() + (bounds.width() / 2.) - (tree_branch_width / 2.);
+ let end_x = bounds.max_x();
+ let start_y = bounds.min_y();
+ let end_y = bounds.min_y() + baseline_offset - (cap_height / 2.);
+
+ cx.scene.push_quad(gpui::Quad {
+ bounds: RectF::from_points(
+ vec2f(start_x, start_y),
+ vec2f(
+ start_x + tree_branch_width,
+ if is_last_project {
+ end_y
+ } else {
+ bounds.max_y()
+ },
+ ),
+ ),
+ background: Some(tree_branch_color),
+ border: gpui::Border::default(),
+ corner_radius: 0.,
+ });
+ cx.scene.push_quad(gpui::Quad {
+ bounds: RectF::from_points(
+ vec2f(start_x, end_y),
+ vec2f(end_x, end_y + tree_branch_width),
+ ),
+ background: Some(tree_branch_color),
+ border: gpui::Border::default(),
+ corner_radius: 0.,
+ });
+ })
+ .constrained()
+ .with_width(host_avatar_height)
+ .boxed(),
)
- .with_children(
- contact
- .non_empty_projects()
- .enumerate()
- .map(|(ix, project)| {
- let project_id = project.id;
+ .with_child({
+ let is_host = Some(contact.user.id) == current_user_id;
+ let is_guest = !is_host
+ && project
+ .guests
+ .iter()
+ .any(|guest| Some(guest.id) == current_user_id);
+ let is_shared = project.is_shared;
+ let app_state = app_state.clone();
+
+ MouseEventHandler::new::<JoinProject, _, _>(
+ project_id as usize,
+ cx,
+ |mouse_state, _| {
+ let style = if project.is_shared {
+ &theme.shared_project_row
+ } else {
+ &theme.unshared_project_row
+ }
+ .style_for(mouse_state, is_selected);
Flex::row()
.with_child(
- Canvas::new(move |bounds, _, cx| {
- let start_x = bounds.min_x() + (bounds.width() / 2.)
- - (tree_branch_width / 2.);
- let end_x = bounds.max_x();
- let start_y = bounds.min_y();
- let end_y =
- bounds.min_y() + baseline_offset - (cap_height / 2.);
-
- cx.scene.push_quad(gpui::Quad {
- bounds: RectF::from_points(
- vec2f(start_x, start_y),
- vec2f(
- start_x + tree_branch_width,
- if ix + 1 == project_count {
- end_y
- } else {
- bounds.max_y()
- },
- ),
- ),
- background: Some(tree_branch_color),
- border: gpui::Border::default(),
- corner_radius: 0.,
- });
- cx.scene.push_quad(gpui::Quad {
- bounds: RectF::from_points(
- vec2f(start_x, end_y),
- vec2f(end_x, end_y + tree_branch_width),
- ),
- background: Some(tree_branch_color),
- border: gpui::Border::default(),
- corner_radius: 0.,
- });
- })
- .constrained()
- .with_width(host_avatar_height)
+ Label::new(
+ project.worktree_root_names.join(", "),
+ style.name.text.clone(),
+ )
+ .aligned()
+ .left()
+ .contained()
+ .with_style(style.name.container)
.boxed(),
)
- .with_child({
- let is_host = Some(contact.user.id) == current_user_id;
- let is_guest = !is_host
- && project
- .guests
- .iter()
- .any(|guest| Some(guest.id) == current_user_id);
- let is_shared = project.is_shared;
- let app_state = app_state.clone();
-
- MouseEventHandler::new::<ContactsPanel, _, _>(
- project_id as usize,
- cx,
- |mouse_state, _| {
- let style = match (project.is_shared, mouse_state.hovered) {
- (false, false) => &theme.unshared_project,
- (false, true) => &theme.hovered_unshared_project,
- (true, false) => &theme.shared_project,
- (true, true) => &theme.hovered_shared_project,
- };
-
- Flex::row()
- .with_child(
- Label::new(
- project.worktree_root_names.join(", "),
- style.name.text.clone(),
- )
- .aligned()
- .left()
- .contained()
- .with_style(style.name.container)
- .boxed(),
- )
- .with_children(project.guests.iter().filter_map(
- |participant| {
- participant.avatar.clone().map(|avatar| {
- Image::new(avatar)
- .with_style(style.guest_avatar)
- .aligned()
- .left()
- .contained()
- .with_margin_right(
- style.guest_avatar_spacing,
- )
- .boxed()
- })
- },
- ))
- .contained()
- .with_style(style.container)
- .constrained()
- .with_height(style.height)
- .boxed()
- },
- )
- .with_cursor_style(if !is_host && is_shared {
- CursorStyle::PointingHand
- } else {
- CursorStyle::Arrow
- })
- .on_click(move |_, cx| {
- if !is_host && !is_guest {
- cx.dispatch_global_action(JoinProject {
- project_id,
- app_state: app_state.clone(),
- });
- }
+ .with_children(project.guests.iter().filter_map(|participant| {
+ participant.avatar.clone().map(|avatar| {
+ Image::new(avatar)
+ .with_style(style.guest_avatar)
+ .aligned()
+ .left()
+ .contained()
+ .with_margin_right(style.guest_avatar_spacing)
+ .boxed()
})
- .flex(1., true)
- .boxed()
- })
+ }))
+ .contained()
+ .with_style(style.container)
.constrained()
- .with_height(theme.unshared_project.height)
+ .with_height(style.height)
.boxed()
- }),
- )
- .contained()
- .with_style(theme.row.clone())
+ },
+ )
+ .with_cursor_style(if !is_host && is_shared {
+ CursorStyle::PointingHand
+ } else {
+ CursorStyle::Arrow
+ })
+ .on_click(move |_, cx| {
+ if !is_host && !is_guest {
+ cx.dispatch_global_action(JoinProject {
+ project_id,
+ app_state: app_state.clone(),
+ });
+ }
+ })
+ .flex(1., true)
+ .boxed()
+ })
+ .constrained()
+ .with_height(row.height)
.boxed()
}
@@ -314,6 +340,7 @@ impl ContactsPanel {
user_store: ModelHandle<UserStore>,
theme: &theme::ContactsPanel,
is_incoming: bool,
+ is_selected: bool,
cx: &mut LayoutContext,
) -> ElementBox {
enum Reject {}
@@ -409,7 +436,11 @@ impl ContactsPanel {
row.constrained()
.with_height(theme.row_height)
.contained()
- .with_style(theme.row)
+ .with_style(
+ *theme
+ .contact_row
+ .style_for(&Default::default(), is_selected),
+ )
.boxed()
}
@@ -418,6 +449,7 @@ impl ContactsPanel {
let query = self.filter_editor.read(cx).text(cx);
let executor = cx.background().clone();
+ let prev_selected_entry = self.selection.and_then(|ix| self.entries.get(ix).cloned());
self.entries.clear();
let mut request_entries = Vec::new();
@@ -443,13 +475,11 @@ impl ContactsPanel {
&Default::default(),
executor.clone(),
));
- if !matches.is_empty() {
- request_entries.extend(
- matches.iter().map(|mat| {
- ContactEntry::IncomingRequest(incoming[mat.candidate_id].clone())
- }),
- );
- }
+ request_entries.extend(
+ matches
+ .iter()
+ .map(|mat| ContactEntry::IncomingRequest(incoming[mat.candidate_id].clone())),
+ );
}
let outgoing = user_store.outgoing_contact_requests();
@@ -474,13 +504,11 @@ impl ContactsPanel {
&Default::default(),
executor.clone(),
));
- if !matches.is_empty() {
- request_entries.extend(
- matches.iter().map(|mat| {
- ContactEntry::OutgoingRequest(outgoing[mat.candidate_id].clone())
- }),
- );
- }
+ request_entries.extend(
+ matches
+ .iter()
+ .map(|mat| ContactEntry::OutgoingRequest(outgoing[mat.candidate_id].clone())),
+ );
}
if !request_entries.is_empty() {
@@ -515,22 +543,33 @@ impl ContactsPanel {
.iter()
.partition::<Vec<_>, _>(|mat| contacts[mat.candidate_id].online);
- if !online_contacts.is_empty() {
- self.entries.push(ContactEntry::Header("Online"));
- self.entries.extend(
- online_contacts
- .into_iter()
- .map(|mat| ContactEntry::Contact(contacts[mat.candidate_id].clone())),
- );
+ for (matches, name) in [(online_contacts, "Online"), (offline_contacts, "Offline")] {
+ if !matches.is_empty() {
+ self.entries.push(ContactEntry::Header(name));
+ for mat in matches {
+ let contact = &contacts[mat.candidate_id];
+ self.entries.push(ContactEntry::Contact(contact.clone()));
+ self.entries
+ .extend(contact.projects.iter().enumerate().filter_map(
+ |(ix, project)| {
+ if project.worktree_root_names.is_empty() {
+ None
+ } else {
+ Some(ContactEntry::ContactProject(contact.clone(), ix))
+ }
+ },
+ ));
+ }
+ }
}
+ }
- if !offline_contacts.is_empty() {
- self.entries.push(ContactEntry::Header("Offline"));
- self.entries.extend(
- offline_contacts
- .into_iter()
- .map(|mat| ContactEntry::Contact(contacts[mat.candidate_id].clone())),
- );
+ if let Some(selection) = &mut self.selection {
+ for (ix, entry) in self.entries.iter().enumerate() {
+ if Some(entry) == prev_selected_entry.as_ref() {
+ *selection = ix;
+ break;
+ }
}
}
@@ -566,6 +605,30 @@ impl ContactsPanel {
self.filter_editor
.update(cx, |editor, cx| editor.set_text("", cx));
}
+
+ fn select_next(&mut self, _: &SelectNext, cx: &mut ViewContext<Self>) {
+ if let Some(ix) = self.selection {
+ if self.entries.len() > ix + 1 {
+ self.selection = Some(ix + 1);
+ }
+ } else if !self.entries.is_empty() {
+ self.selection = Some(0);
+ }
+ cx.notify();
+ self.list_state.reset(self.entries.len());
+ }
+
+ fn select_prev(&mut self, _: &SelectPrev, cx: &mut ViewContext<Self>) {
+ if let Some(ix) = self.selection {
+ if ix > 0 {
+ self.selection = Some(ix - 1);
+ } else {
+ self.selection = None;
+ }
+ }
+ cx.notify();
+ self.list_state.reset(self.entries.len());
+ }
}
fn render_icon_button(style: &IconButton, svg_path: &'static str) -> impl Element {
@@ -633,4 +696,249 @@ impl View for ContactsPanel {
.with_style(theme.container)
.boxed()
}
+
+ fn on_focus(&mut self, cx: &mut ViewContext<Self>) {
+ cx.focus(&self.filter_editor);
+ }
+
+ fn keymap_context(&self, _: &gpui::AppContext) -> gpui::keymap::Context {
+ let mut cx = Self::default_keymap_context();
+ cx.set.insert("menu".into());
+ cx
+ }
+}
+
+impl PartialEq for ContactEntry {
+ fn eq(&self, other: &Self) -> bool {
+ match self {
+ ContactEntry::Header(name_1) => {
+ if let ContactEntry::Header(name_2) = other {
+ return name_1 == name_2;
+ }
+ }
+ ContactEntry::IncomingRequest(user_1) => {
+ if let ContactEntry::IncomingRequest(user_2) = other {
+ return user_1.id == user_2.id;
+ }
+ }
+ ContactEntry::OutgoingRequest(user_1) => {
+ if let ContactEntry::OutgoingRequest(user_2) = other {
+ return user_1.id == user_2.id;
+ }
+ }
+ ContactEntry::Contact(contact_1) => {
+ if let ContactEntry::Contact(contact_2) = other {
+ return contact_1.user.id == contact_2.user.id;
+ }
+ }
+ ContactEntry::ContactProject(contact_1, ix_1) => {
+ if let ContactEntry::ContactProject(contact_2, ix_2) = other {
+ return contact_1.user.id == contact_2.user.id && ix_1 == ix_2;
+ }
+ }
+ }
+ false
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use client::{proto, test::FakeServer, ChannelList, Client};
+ use gpui::TestAppContext;
+ use language::LanguageRegistry;
+ use theme::ThemeRegistry;
+
+ #[gpui::test]
+ async fn test_contact_panel(cx: &mut TestAppContext) {
+ let (app_state, server) = init(cx).await;
+ let panel = cx.add_view(0, |cx| ContactsPanel::new(app_state.clone(), cx));
+
+ let get_users_request = server.receive::<proto::GetUsers>().await.unwrap();
+ server
+ .respond(
+ get_users_request.receipt(),
+ proto::UsersResponse {
+ users: [
+ "user_zero",
+ "user_one",
+ "user_two",
+ "user_three",
+ "user_four",
+ "user_five",
+ ]
+ .into_iter()
+ .enumerate()
+ .map(|(id, name)| proto::User {
+ id: id as u64,
+ github_login: name.to_string(),
+ ..Default::default()
+ })
+ .collect(),
+ },
+ )
+ .await;
+
+ server.send(proto::UpdateContacts {
+ incoming_requests: vec![proto::IncomingContactRequest {
+ requester_id: 1,
+ should_notify: false,
+ }],
+ outgoing_requests: vec![2],
+ contacts: vec![
+ proto::Contact {
+ user_id: 3,
+ online: true,
+ projects: vec![proto::ProjectMetadata {
+ id: 101,
+ worktree_root_names: vec!["dir1".to_string()],
+ is_shared: true,
+ guests: vec![2],
+ }],
+ },
+ proto::Contact {
+ user_id: 4,
+ online: true,
+ projects: vec![proto::ProjectMetadata {
+ id: 102,
+ worktree_root_names: vec!["dir2".to_string()],
+ is_shared: true,
+ guests: vec![2],
+ }],
+ },
+ proto::Contact {
+ user_id: 5,
+ online: false,
+ projects: vec![],
+ },
+ ],
+ ..Default::default()
+ });
+
+ cx.foreground().run_until_parked();
+ assert_eq!(
+ render_to_strings(&panel, cx),
+ &[
+ "+",
+ "v Requests",
+ " incoming user_one <=== selected",
+ " outgoing user_two",
+ "v Online",
+ " user_four",
+ " dir2",
+ " user_three",
+ " dir1",
+ "v Offline",
+ " user_five",
+ ]
+ );
+
+ panel.update(cx, |panel, cx| {
+ panel
+ .filter_editor
+ .update(cx, |editor, cx| editor.set_text("f", cx))
+ });
+ cx.foreground().run_until_parked();
+ assert_eq!(
+ render_to_strings(&panel, cx),
+ &[
+ "+",
+ "Online",
+ " user_four <=== selected",
+ " dir2",
+ "Offline",
+ " user_five",
+ ]
+ );
+
+ panel.update(cx, |panel, cx| {
+ panel.select_next(&Default::default(), cx);
+ });
+ assert_eq!(
+ render_to_strings(&panel, cx),
+ &[
+ "+",
+ "Online",
+ " user_four",
+ " dir2 <=== selected",
+ "Offline",
+ " user_five",
+ ]
+ );
+
+ panel.update(cx, |panel, cx| {
+ panel.select_next(&Default::default(), cx);
+ });
+ assert_eq!(
+ render_to_strings(&panel, cx),
+ &[
+ "+",
+ "Online",
+ " user_four",
+ " dir2",
+ "Offline",
+ " user_five <=== selected",
+ ]
+ );
+ }
+
+ fn render_to_strings(panel: &ViewHandle<ContactsPanel>, cx: &TestAppContext) -> Vec<String> {
+ panel.read_with(cx, |panel, _| {
+ let mut entries = Vec::new();
+ entries.push("+".to_string());
+ entries.extend(panel.entries.iter().map(|entry| match entry {
+ ContactEntry::Header(name) => {
+ format!("{}", name)
+ }
+ ContactEntry::IncomingRequest(user) => {
+ format!(" incoming {}", user.github_login)
+ }
+ ContactEntry::OutgoingRequest(user) => {
+ format!(" outgoing {}", user.github_login)
+ }
+ ContactEntry::Contact(contact) => {
+ format!(" {}", contact.user.github_login)
+ }
+ ContactEntry::ContactProject(contact, project_ix) => {
+ format!(
+ " {}",
+ contact.projects[*project_ix].worktree_root_names.join(", ")
+ )
+ }
+ }));
+ entries
+ })
+ }
+
+ async fn init(cx: &mut TestAppContext) -> (Arc<AppState>, FakeServer) {
+ cx.update(|cx| cx.set_global(Settings::test(cx)));
+ let themes = ThemeRegistry::new((), cx.font_cache());
+ let fs = project::FakeFs::new(cx.background().clone());
+ let languages = Arc::new(LanguageRegistry::test());
+ let http_client = client::test::FakeHttpClient::with_404_response();
+ let mut client = Client::new(http_client.clone());
+ let server = FakeServer::for_client(100, &mut client, &cx).await;
+ let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http_client, cx));
+ let channel_list =
+ cx.add_model(|cx| ChannelList::new(user_store.clone(), client.clone(), cx));
+
+ let get_channels = server.receive::<proto::GetChannels>().await.unwrap();
+ server
+ .respond(get_channels.receipt(), Default::default())
+ .await;
+
+ (
+ Arc::new(AppState {
+ languages,
+ themes,
+ client,
+ user_store: user_store.clone(),
+ fs,
+ channel_list,
+ build_window_options: || unimplemented!(),
+ build_workspace: |_, _, _| unimplemented!(),
+ }),
+ server,
+ )
+ }
}
@@ -235,11 +235,13 @@ pub struct CommandPalette {
pub struct ContactsPanel {
#[serde(flatten)]
pub container: ContainerStyle,
- pub header: ContainedText,
pub user_query_editor: FieldEditor,
pub user_query_editor_height: f32,
pub add_contact_button: IconButton,
- pub row: ContainerStyle,
+ pub header_row: Interactive<ContainedText>,
+ pub contact_row: Interactive<ContainerStyle>,
+ pub shared_project_row: Interactive<ProjectRow>,
+ pub unshared_project_row: Interactive<ProjectRow>,
pub row_height: f32,
pub contact_avatar: ImageStyle,
pub contact_username: ContainedText,
@@ -247,10 +249,6 @@ pub struct ContactsPanel {
pub disabled_contact_button: IconButton,
pub tree_branch_width: f32,
pub tree_branch_color: Color,
- pub shared_project: ProjectRow,
- pub hovered_shared_project: ProjectRow,
- pub unshared_project: ProjectRow,
- pub hovered_unshared_project: ProjectRow,
}
#[derive(Deserialize, Default)]
@@ -21,16 +21,6 @@ export default function contactsPanel(theme: Theme) {
},
};
- const sharedProject = {
- ...project,
- background: backgroundColor(theme, 300),
- cornerRadius: 6,
- name: {
- ...project.name,
- ...text(theme, "mono", "secondary", { size: "sm" }),
- },
- };
-
const contactButton = {
background: backgroundColor(theme, 100),
color: iconColor(theme, "primary"),
@@ -62,14 +52,21 @@ export default function contactsPanel(theme: Theme) {
buttonWidth: 8,
iconWidth: 8,
},
- row: {
- padding: { left: 8 },
- },
- rowHeight: 28,
- header: {
+ headerRow: {
...text(theme, "mono", "secondary", { size: "sm" }),
margin: { top: 8 },
+ active: {
+ ...text(theme, "mono", "primary", { size: "sm" }),
+ background: backgroundColor(theme, 100, "active"),
+ }
+ },
+ contactRow: {
+ padding: { left: 8 },
+ active: {
+ background: backgroundColor(theme, 100, "active"),
+ }
},
+ rowHeight: 28,
treeBranchColor: borderColor(theme, "muted"),
treeBranchWidth: 1,
contactAvatar: {
@@ -93,17 +90,35 @@ export default function contactsPanel(theme: Theme) {
background: backgroundColor(theme, 100),
color: iconColor(theme, "muted"),
},
- project,
- sharedProject,
- hoveredSharedProject: {
- ...sharedProject,
- background: backgroundColor(theme, 300, "hovered"),
+ sharedProjectRow: {
+ ...project,
+ background: backgroundColor(theme, 300),
cornerRadius: 6,
+ name: {
+ ...project.name,
+ ...text(theme, "mono", "secondary", { size: "sm" }),
+ },
+ hover: {
+ background: backgroundColor(theme, 300, "hovered"),
+ },
+ active: {
+ background: backgroundColor(theme, 300, "active"),
+ }
},
- unsharedProject: project,
- hoveredUnsharedProject: {
+ unsharedProjectRow: {
...project,
+ background: backgroundColor(theme, 300),
cornerRadius: 6,
- },
+ name: {
+ ...project.name,
+ ...text(theme, "mono", "secondary", { size: "sm" }),
+ },
+ hover: {
+ background: backgroundColor(theme, 300, "hovered"),
+ },
+ active: {
+ background: backgroundColor(theme, 300, "active"),
+ }
+ }
}
}