From aac71fdcfef70557cfb186441cfb88e77b3c4232 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 9 Jun 2023 08:42:16 -0700 Subject: [PATCH 01/63] Remove border from sign in button Co-authored-by: Piotr --- styles/src/styleTree/workspace.ts | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index ae8de178f88c5abfb3fb76af4cda4e386ff748d1..bf0c5d3af34824fcb617169790b622b95655afe2 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -42,6 +42,33 @@ export default function workspace(colorScheme: ColorScheme) { border: border(layer, "variant", "active"), }, } + const signInButton = { + cornerRadius: 6, + padding: { + top: 1, + bottom: 1, + left: 8, + right: 8, + }, + ...text(layer, "sans", "variant", { size: "xs" }), + background: background(layer, "variant"), + //border: border(layer), + hover: { + ...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"), + }, + active: { + ...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 @@ -205,7 +232,7 @@ export default function workspace(colorScheme: ColorScheme) { margin: { left: itemSpacing, }, - ...titlebarButton, + ...signInButton, }, // Offline Indicator From 47ef800dc6e5f6391e0716717a5927d1d44c62cc Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 9 Jun 2023 09:00:38 -0700 Subject: [PATCH 02/63] WIP: Add face to right hand menu --- crates/collab_ui/src/collab_titlebar_item.rs | 33 ++++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 720a73f477e1c5ceb4e8888de95afefe937f1589..cffdb2a18faacaa33247694409dc4094a1c1b18d 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -92,10 +92,10 @@ impl View for CollabTitlebarItem { let status = workspace.read(cx).client().status(); let status = &*status.borrow(); - if matches!(status, client::Status::Connected { .. }) { right_container.add_child(self.render_toggle_contacts_button(&theme, cx)); - right_container.add_child(self.render_user_menu_button(&theme, cx)); + let avatar = user.as_ref().map(|user| user.avatar.clone()).flatten(); + right_container.add_child(self.render_user_menu_button(&theme, avatar, cx)); } else { right_container.add_children(self.render_connection_status(status, cx)); right_container.add_child(self.render_sign_in_button(&theme, cx)); @@ -504,24 +504,31 @@ impl CollabTitlebarItem { fn render_user_menu_button( &self, theme: &Theme, + avatar: Option>, cx: &mut ViewContext, ) -> AnyElement { let titlebar = &theme.workspace.titlebar; - + let avatar_style = &theme.workspace.titlebar.leader_avatar; Stack::new() .with_child( MouseEventHandler::::new(0, cx, |state, _| { let style = titlebar.call_control.style_for(state, false); - Svg::new("icons/ellipsis_14.svg") - .with_color(style.color) - .constrained() - .with_width(style.icon_width) - .aligned() - .constrained() - .with_width(style.button_width) - .with_height(style.button_width) - .contained() - .with_style(style.container) + + if let Some(avatar_img) = avatar { + Self::render_face(avatar_img, *avatar_style, Color::transparent_black()) + } else { + Svg::new("icons/ellipsis_14.svg") + .with_color(style.color) + .constrained() + .with_width(style.icon_width) + .aligned() + .constrained() + .with_width(style.button_width) + .with_height(style.button_width) + .contained() + .with_style(style.container) + .into_any() + } }) .with_cursor_style(CursorStyle::PointingHand) .on_click(MouseButton::Left, move |_, this, cx| { From 5f7fdd25eb98e64c7d57de68b77bd74dbcc1c6a1 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 9 Jun 2023 18:05:23 +0200 Subject: [PATCH 03/63] Fix compile error (use of moved value) --- crates/collab_ui/src/collab_titlebar_item.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index cffdb2a18faacaa33247694409dc4094a1c1b18d..405eb20decdb196e67f1290a2155d4c4cfa10427 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -78,6 +78,7 @@ impl View for CollabTitlebarItem { let user = self.user_store.read(cx).current_user(); let peer_id = self.client.peer_id(); if let Some(((user, peer_id), room)) = user + .as_ref() .zip(peer_id) .zip(ActiveCall::global(cx).read(cx).room().cloned()) { From 0fe65b945f6de2c66a6ab2f2371c82f79083a833 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Sat, 10 Jun 2023 01:35:18 +0200 Subject: [PATCH 04/63] Remove user avatar from dropdown menu Add new options in context menu --- Cargo.lock | 1 + crates/collab_ui/Cargo.toml | 1 + crates/collab_ui/src/collab_titlebar_item.rs | 38 +++++++------------- 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 24fd67f90ec17ecc7d0440fa9d6dc52996a939b2..9bf504bc15c663205f131455bcbbe68a010efc1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1325,6 +1325,7 @@ dependencies = [ "serde_derive", "settings", "theme", + "theme_selector", "util", "workspace", ] diff --git a/crates/collab_ui/Cargo.toml b/crates/collab_ui/Cargo.toml index 16cc6b52772e2772aab691f1e9e2b8dbf0e3b726..9865f8a9c8de9623fd74024ddc8d27abbba7c288 100644 --- a/crates/collab_ui/Cargo.toml +++ b/crates/collab_ui/Cargo.toml @@ -37,6 +37,7 @@ picker = { path = "../picker" } project = { path = "../project" } settings = { path = "../settings" } theme = { path = "../theme" } +theme_selector = { path = "../theme_selector" } util = { path = "../util" } workspace = { path = "../workspace" } diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 405eb20decdb196e67f1290a2155d4c4cfa10427..d9127e707f8c8d17ad08452f467f5d645baaaf74 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -99,7 +99,7 @@ impl View for CollabTitlebarItem { right_container.add_child(self.render_user_menu_button(&theme, avatar, cx)); } else { right_container.add_children(self.render_connection_status(status, cx)); - right_container.add_child(self.render_sign_in_button(&theme, cx)); + right_container.add_child(self.render_user_menu_button(&theme, None, cx)); } Stack::new() @@ -298,42 +298,28 @@ impl CollabTitlebarItem { } pub fn toggle_user_menu(&mut self, _: &ToggleUserMenu, cx: &mut ViewContext) { - let theme = theme::current(cx).clone(); - let avatar_style = theme.workspace.titlebar.leader_avatar.clone(); - let item_style = theme.context_menu.item.disabled_style().clone(); self.user_menu.update(cx, |user_menu, cx| { - let items = if let Some(user) = self.user_store.read(cx).current_user() { + let items = if let Some(_) = self.user_store.read(cx).current_user() { vec![ - ContextMenuItem::Static(Box::new(move |_| { - Flex::row() - .with_children(user.avatar.clone().map(|avatar| { - Self::render_face( - avatar, - avatar_style.clone(), - Color::transparent_black(), - ) - })) - .with_child(Label::new( - user.github_login.clone(), - item_style.label.clone(), - )) - .contained() - .with_style(item_style.container) - .into_any() - })), - ContextMenuItem::action("Sign out", SignOut), + ContextMenuItem::action("Settings", SignIn), + ContextMenuItem::action("Theme", theme_selector::Toggle), + ContextMenuItem::separator(), ContextMenuItem::action( - "Send Feedback", + "Share Feedback", feedback::feedback_editor::GiveFeedback, ), + ContextMenuItem::action("Sign out", SignOut), ] } else { vec![ - ContextMenuItem::action("Sign in", SignIn), + ContextMenuItem::action("Settings", SignIn), + ContextMenuItem::action("Theme", theme_selector::Toggle), + ContextMenuItem::separator(), ContextMenuItem::action( - "Send Feedback", + "Share Feedback", feedback::feedback_editor::GiveFeedback, ), + ContextMenuItem::action("Sign in", SignIn), ] }; From 4b87ce8952a2954055e702ac830139baf2b7e3d2 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 12 Jun 2023 11:51:39 +0200 Subject: [PATCH 05/63] add zed-actions crate --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + crates/zed-actions/Cargo.toml | 9 +++++++++ crates/zed-actions/src/lib.rs | 14 ++++++++++++++ 4 files changed, 31 insertions(+) create mode 100644 crates/zed-actions/Cargo.toml create mode 100644 crates/zed-actions/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 9bf504bc15c663205f131455bcbbe68a010efc1f..13d194440cf2e7fffae6cfba883008ae1ddbe148 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8909,6 +8909,13 @@ dependencies = [ "workspace", ] +[[package]] +name = "zed-actions" +version = "0.1.0" +dependencies = [ + "gpui", +] + [[package]] name = "zeroize" version = "1.3.0" diff --git a/Cargo.toml b/Cargo.toml index fca735596489a222208e2f65874efc4fcd04ffd5..34533da51cd184be8c3127317828baa878f54be4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,6 +67,7 @@ members = [ "crates/workspace", "crates/welcome", "crates/zed", + "crates/zed-actions" ] default-members = ["crates/zed"] resolver = "2" diff --git a/crates/zed-actions/Cargo.toml b/crates/zed-actions/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..c6868b1546f78a8220a7cbc180555525fe7cb8f5 --- /dev/null +++ b/crates/zed-actions/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "zed-actions" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +gpui = { path = "../gpui" } diff --git a/crates/zed-actions/src/lib.rs b/crates/zed-actions/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..7d12d9af8195bf5e19d10c7b592b359ccd014149 --- /dev/null +++ b/crates/zed-actions/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} From 092cf93dae709025421b296f5178963cb5d96e01 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 12 Jun 2023 13:00:08 +0200 Subject: [PATCH 06/63] Move zed actions to zed-actions --- Cargo.lock | 2 + crates/collab_ui/Cargo.toml | 1 + crates/collab_ui/src/collab_titlebar_item.rs | 4 +- crates/zed-actions/src/lib.rs | 40 +++++++++++++------- crates/zed/Cargo.toml | 2 +- crates/zed/src/main.rs | 2 +- crates/zed/src/zed.rs | 28 +------------- 7 files changed, 35 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13d194440cf2e7fffae6cfba883008ae1ddbe148..6d953d8dc09d7bcdfcbbffaaa077287a26b910ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1328,6 +1328,7 @@ dependencies = [ "theme_selector", "util", "workspace", + "zed-actions", ] [[package]] @@ -8907,6 +8908,7 @@ dependencies = [ "vim", "welcome", "workspace", + "zed-actions", ] [[package]] diff --git a/crates/collab_ui/Cargo.toml b/crates/collab_ui/Cargo.toml index 9865f8a9c8de9623fd74024ddc8d27abbba7c288..ee410ccba7a57e68af7601e2ea3fd0fc654f653d 100644 --- a/crates/collab_ui/Cargo.toml +++ b/crates/collab_ui/Cargo.toml @@ -40,6 +40,7 @@ theme = { path = "../theme" } theme_selector = { path = "../theme_selector" } util = { path = "../util" } workspace = { path = "../workspace" } +zed-actions = {path = "../zed-actions"} anyhow.workspace = true futures.workspace = true diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index d9127e707f8c8d17ad08452f467f5d645baaaf74..d2a9dda48038f94f87db8bfb68c565fe1471c386 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -301,7 +301,7 @@ impl CollabTitlebarItem { self.user_menu.update(cx, |user_menu, cx| { let items = if let Some(_) = self.user_store.read(cx).current_user() { vec![ - ContextMenuItem::action("Settings", SignIn), + ContextMenuItem::action("Settings", zed_actions::OpenSettings), ContextMenuItem::action("Theme", theme_selector::Toggle), ContextMenuItem::separator(), ContextMenuItem::action( @@ -312,7 +312,7 @@ impl CollabTitlebarItem { ] } else { vec![ - ContextMenuItem::action("Settings", SignIn), + ContextMenuItem::action("Settings", zed_actions::OpenSettings), ContextMenuItem::action("Theme", theme_selector::Toggle), ContextMenuItem::separator(), ContextMenuItem::action( diff --git a/crates/zed-actions/src/lib.rs b/crates/zed-actions/src/lib.rs index 7d12d9af8195bf5e19d10c7b592b359ccd014149..bcd086924d2d0b36000bd4b67d2567dbc19c589d 100644 --- a/crates/zed-actions/src/lib.rs +++ b/crates/zed-actions/src/lib.rs @@ -1,14 +1,28 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} +use gpui::actions; -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} +actions!( + zed, + [ + About, + Hide, + HideOthers, + ShowAll, + Minimize, + Zoom, + ToggleFullScreen, + Quit, + DebugElements, + OpenLog, + OpenLicenses, + OpenTelemetryLog, + OpenKeymap, + OpenSettings, + OpenLocalSettings, + OpenDefaultSettings, + OpenDefaultKeymap, + IncreaseBufferFontSize, + DecreaseBufferFontSize, + ResetBufferFontSize, + ResetDatabase, + ] +); diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index d8e47d1c3ea6a0ce2fe099a11a37ee53d66158b2..e97005ec7eebb0d89138bab72cd76c18ec4863d1 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -67,7 +67,7 @@ util = { path = "../util" } vim = { path = "../vim" } workspace = { path = "../workspace" } welcome = { path = "../welcome" } - +zed-actions = {path = "../zed-actions"} anyhow.workspace = true async-compression = { version = "0.3", features = ["gzip", "futures-bufread"] } async-tar = "0.4.2" diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index dcdf5c1ea5f542339cfac3ef7edeac61c5ab34c4..5d013a6849871c7c6aac6922384d08447feacfdf 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -871,6 +871,6 @@ pub fn background_actions() -> &'static [(&'static str, &'static dyn Action)] { ("Go to file", &file_finder::Toggle), ("Open command palette", &command_palette::Toggle), ("Open recent projects", &recent_projects::OpenRecent), - ("Change your settings", &zed::OpenSettings), + ("Change your settings", &zed_actions::OpenSettings), ] } diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index bcdfe57a469013251994b4112500daa4a7489027..9f3b1457937ec80d74b9b4d7dd24dd8dd02870e3 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -50,6 +50,7 @@ use workspace::{ notifications::simple_message_notification::MessageNotification, open_new, AppState, NewFile, NewWindow, Workspace, WorkspaceSettings, }; +use zed_actions::*; #[derive(Deserialize, Clone, PartialEq)] pub struct OpenBrowser { @@ -58,33 +59,6 @@ pub struct OpenBrowser { impl_actions!(zed, [OpenBrowser]); -actions!( - zed, - [ - About, - Hide, - HideOthers, - ShowAll, - Minimize, - Zoom, - ToggleFullScreen, - Quit, - DebugElements, - OpenLog, - OpenLicenses, - OpenTelemetryLog, - OpenKeymap, - OpenSettings, - OpenLocalSettings, - OpenDefaultSettings, - OpenDefaultKeymap, - IncreaseBufferFontSize, - DecreaseBufferFontSize, - ResetBufferFontSize, - ResetDatabase, - ] -); - pub fn init(app_state: &Arc, cx: &mut gpui::AppContext) { cx.add_action(about); cx.add_global_action(|_: &Hide, cx: &mut gpui::AppContext| { From 433c5d30f57c6f973b24f87ad4bd7ce1511558b1 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 12 Jun 2023 19:38:01 +0200 Subject: [PATCH 07/63] Add Sign in button for an unregistered user --- crates/collab_ui/src/collab_titlebar_item.rs | 2 +- crates/zed-actions/Cargo.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index d2a9dda48038f94f87db8bfb68c565fe1471c386..54caf9b26f3be9e741b4514a912fb8faed0d7c31 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -99,6 +99,7 @@ impl View for CollabTitlebarItem { right_container.add_child(self.render_user_menu_button(&theme, avatar, cx)); } else { right_container.add_children(self.render_connection_status(status, cx)); + right_container.add_child(self.render_sign_in_button(&theme, cx)); right_container.add_child(self.render_user_menu_button(&theme, None, cx)); } @@ -319,7 +320,6 @@ impl CollabTitlebarItem { "Share Feedback", feedback::feedback_editor::GiveFeedback, ), - ContextMenuItem::action("Sign in", SignIn), ] }; diff --git a/crates/zed-actions/Cargo.toml b/crates/zed-actions/Cargo.toml index c6868b1546f78a8220a7cbc180555525fe7cb8f5..b3fe3cbb53c46457c6855a916dcc6ef650e6be50 100644 --- a/crates/zed-actions/Cargo.toml +++ b/crates/zed-actions/Cargo.toml @@ -2,6 +2,7 @@ name = "zed-actions" version = "0.1.0" edition = "2021" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 83c1bb07bbb1824419fa3428279558ee8ea77c6c Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 12 Jun 2023 19:55:52 +0200 Subject: [PATCH 08/63] Add background to user avatar --- crates/collab_ui/src/collab_titlebar_item.rs | 27 +++++++++++--------- crates/zed/src/zed.rs | 5 ++-- styles/src/styleTree/workspace.ts | 4 +++ 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 54caf9b26f3be9e741b4514a912fb8faed0d7c31..de4bb3e1b5f268d4dc0a0fcb10ceb1fb55e2403b 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -495,27 +495,30 @@ impl CollabTitlebarItem { cx: &mut ViewContext, ) -> AnyElement { let titlebar = &theme.workspace.titlebar; - let avatar_style = &theme.workspace.titlebar.leader_avatar; + let avatar_style = &theme.workspace.titlebar.follower_avatar; + let active = self.user_menu.read(cx).visible(); Stack::new() .with_child( MouseEventHandler::::new(0, cx, |state, _| { - let style = titlebar.call_control.style_for(state, false); + let style = titlebar.call_control.style_for(state, active); - if let Some(avatar_img) = avatar { + let img = if let Some(avatar_img) = avatar { Self::render_face(avatar_img, *avatar_style, Color::transparent_black()) } else { Svg::new("icons/ellipsis_14.svg") .with_color(style.color) - .constrained() - .with_width(style.icon_width) - .aligned() - .constrained() - .with_width(style.button_width) - .with_height(style.button_width) - .contained() - .with_style(style.container) .into_any() - } + }; + + img.constrained() + .with_width(style.icon_width) + .aligned() + .constrained() + .with_width(style.button_width) + .with_height(style.button_width) + .contained() + .with_style(style.container) + .into_any() }) .with_cursor_style(CursorStyle::PointingHand) .on_click(MouseButton::Left, move |_, this, cx| { diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 9f3b1457937ec80d74b9b4d7dd24dd8dd02870e3..8dbc81f62f5ffb3e49ad4adf72a9d3edec908f03 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -20,7 +20,6 @@ use feedback::{ }; use futures::{channel::mpsc, StreamExt}; use gpui::{ - actions, anyhow::{self, Result}, geometry::vector::vec2f, impl_actions, @@ -715,8 +714,8 @@ mod tests { use editor::{scroll::autoscroll::Autoscroll, DisplayPoint, Editor}; use fs::{FakeFs, Fs}; use gpui::{ - elements::Empty, executor::Deterministic, Action, AnyElement, AppContext, AssetSource, - Element, Entity, TestAppContext, View, ViewHandle, + actions, elements::Empty, executor::Deterministic, Action, AnyElement, AppContext, + AssetSource, Element, Entity, TestAppContext, View, ViewHandle, }; use language::LanguageRegistry; use node_runtime::NodeRuntime; diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index bf0c5d3af34824fcb617169790b622b95655afe2..15bcbcc27c33693b0fb808d19732bbe85b42ed8d 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -270,6 +270,10 @@ export default function workspace(colorScheme: ColorScheme) { background: background(layer, "variant", "hovered"), color: foreground(layer, "variant", "hovered"), }, + active: { + background: background(layer, "variant", "active"), + color: foreground(layer, "variant", "active"), + }, }, toggleContactsButton: { margin: { left: itemSpacing }, From d079a0eb2090650aff716e2f7cf4d7808032e2c6 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 12 Jun 2023 20:19:09 +0200 Subject: [PATCH 09/63] Render user avatar only if an user is not in a call --- crates/collab_ui/src/collab_titlebar_item.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index de4bb3e1b5f268d4dc0a0fcb10ceb1fb55e2403b..2100160a6f064a1439d324ba9d847b4e940e2332 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -85,9 +85,9 @@ impl View for CollabTitlebarItem { left_container .add_children(self.render_in_call_share_unshare_button(&workspace, &theme, cx)); - right_container.add_children(self.render_collaborators(&workspace, &theme, &room, cx)); - right_container + left_container .add_child(self.render_current_user(&workspace, &theme, &user, peer_id, cx)); + left_container.add_children(self.render_collaborators(&workspace, &theme, &room, cx)); right_container.add_child(self.render_toggle_screen_sharing_button(&theme, &room, cx)); } @@ -95,7 +95,13 @@ impl View for CollabTitlebarItem { let status = &*status.borrow(); if matches!(status, client::Status::Connected { .. }) { right_container.add_child(self.render_toggle_contacts_button(&theme, cx)); - let avatar = user.as_ref().map(|user| user.avatar.clone()).flatten(); + let avatar = ActiveCall::global(cx) + .read(cx) + .room() + .is_none() + .then(|| user.as_ref()) + .flatten() + .and_then(|user| user.avatar.clone()); right_container.add_child(self.render_user_menu_button(&theme, avatar, cx)); } else { right_container.add_children(self.render_connection_status(status, cx)); From ae68be64c05903c6231197322876a396f76b619b Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 13 Jun 2023 12:51:11 +0200 Subject: [PATCH 10/63] Move share button to the right hand side --- crates/collab_ui/src/collab_titlebar_item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 2100160a6f064a1439d324ba9d847b4e940e2332..797a4f706692840536fde2edfd2ef53990ad59da 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -82,7 +82,7 @@ impl View for CollabTitlebarItem { .zip(peer_id) .zip(ActiveCall::global(cx).read(cx).room().cloned()) { - left_container + right_container .add_children(self.render_in_call_share_unshare_button(&workspace, &theme, cx)); left_container From dedc117cca57dd2b52d1171b28435759de2ae4f3 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 16 Jun 2023 10:13:27 -0700 Subject: [PATCH 11/63] Add audio APIs to Zed Share mic on joining room --- crates/call/src/participant.rs | 4 +- crates/call/src/room.rs | 199 ++++++++++++++++--- crates/collab/src/tests/integration_tests.rs | 6 +- crates/collab_ui/src/contact_list.rs | 4 +- crates/live_kit_client/src/test.rs | 1 + crates/workspace/src/workspace.rs | 2 +- 6 files changed, 186 insertions(+), 30 deletions(-) diff --git a/crates/call/src/participant.rs b/crates/call/src/participant.rs index 4b9e7ba034fb23d118cb5963d335e5c16201d590..90f256489d2d40f39ad1d49f6266980cc13951bb 100644 --- a/crates/call/src/participant.rs +++ b/crates/call/src/participant.rs @@ -3,6 +3,7 @@ use client::{proto, User}; use collections::HashMap; use gpui::WeakModelHandle; pub use live_kit_client::Frame; +use live_kit_client::RemoteAudioTrack; use project::Project; use std::{fmt, sync::Arc}; @@ -42,7 +43,8 @@ pub struct RemoteParticipant { pub peer_id: proto::PeerId, pub projects: Vec, pub location: ParticipantLocation, - pub tracks: HashMap>, + pub video_tracks: HashMap>, + pub audio_tracks: HashMap>, } #[derive(Clone)] diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 775342359f4af8c68ea1caa1bf25affb31c4ba8d..257a612f08162e70c0f5ec752758f27fa969362f 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -12,7 +12,9 @@ use fs::Fs; use futures::{FutureExt, StreamExt}; use gpui::{AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Task, WeakModelHandle}; use language::LanguageRegistry; -use live_kit_client::{LocalTrackPublication, LocalVideoTrack, RemoteVideoTrackUpdate}; +use live_kit_client::{ + LocalAudioTrack, LocalTrackPublication, LocalVideoTrack, RemoteVideoTrackUpdate, RemoteAudioTrackUpdate, +}; use postage::stream::Stream; use project::Project; use std::{future::Future, mem, pin::Pin, sync::Arc, time::Duration}; @@ -28,6 +30,9 @@ pub enum Event { RemoteVideoTracksChanged { participant_id: proto::PeerId, }, + RemoteAudioTracksChanged { + participant_id: proto::PeerId, + }, RemoteProjectShared { owner: Arc, project_id: u64, @@ -112,9 +117,9 @@ impl Room { } }); - let mut track_changes = room.remote_video_track_updates(); - let _maintain_tracks = cx.spawn_weak(|this, mut cx| async move { - while let Some(track_change) = track_changes.next().await { + let mut track_video_changes = room.remote_video_track_updates(); + let _maintain_video_tracks = cx.spawn_weak(|this, mut cx| async move { + while let Some(track_change) = track_video_changes.next().await { let this = if let Some(this) = this.upgrade(&cx) { this } else { @@ -127,16 +132,32 @@ impl Room { } }); + let mut track_audio_changes = room.remote_audio_track_updates(); + let _maintain_audio_tracks = cx.spawn_weak(|this, mut cx| async move { + while let Some(track_change) = track_audio_changes.next().await { + let this = if let Some(this) = this.upgrade(&cx) { + this + } else { + break; + }; + + this.update(&mut cx, |this, cx| { + this.remote_audio_track_updated(track_change, cx).log_err() + }); + } + }); + cx.foreground() .spawn(room.connect(&connection_info.server_url, &connection_info.token)) .detach_and_log_err(cx); Some(LiveKitRoom { room, - screen_track: ScreenTrack::None, + screen_track: Track::None, + microphone_track: Track::None, next_publish_id: 0, _maintain_room, - _maintain_tracks, + _maintain_tracks: [_maintain_video_tracks, _maintain_audio_tracks], }) } else { None @@ -197,6 +218,12 @@ impl Room { None }; + let share_mic = room.update(&mut cx, |room, cx| { + room.share_mic(cx) + }); + + cx.background().spawn(share_mic).detach(); + match room .update(&mut cx, |room, cx| { room.leave_when_empty = true; @@ -618,20 +645,26 @@ impl Room { peer_id, projects: participant.projects, location, - tracks: Default::default(), + video_tracks: Default::default(), + audio_tracks: Default::default(), }, ); if let Some(live_kit) = this.live_kit.as_ref() { - let tracks = + let video_tracks = live_kit.room.remote_video_tracks(&user.id.to_string()); - for track in tracks { + let audio_tracks = live_kit.room.remote_audio_tracks(&user.id.to_string()); + for track in video_tracks { this.remote_video_track_updated( RemoteVideoTrackUpdate::Subscribed(track), cx, ) .log_err(); } + for track in audio_tracks { + this.remote_audio_track_updated(RemoteAudioTrackUpdate::Subscribed(track), cx) + .log_err(); + } } } } @@ -706,7 +739,7 @@ impl Room { .remote_participants .get_mut(&user_id) .ok_or_else(|| anyhow!("subscribed to track by unknown participant"))?; - participant.tracks.insert( + participant.video_tracks.insert( track_id.clone(), Arc::new(RemoteVideoTrack { live_kit_track: track, @@ -725,7 +758,7 @@ impl Room { .remote_participants .get_mut(&user_id) .ok_or_else(|| anyhow!("unsubscribed from track by unknown participant"))?; - participant.tracks.remove(&track_id); + participant.video_tracks.remove(&track_id); cx.emit(Event::RemoteVideoTracksChanged { participant_id: participant.peer_id, }); @@ -736,6 +769,47 @@ impl Room { Ok(()) } + fn remote_audio_track_updated( + &mut self, + change: RemoteAudioTrackUpdate, + cx: &mut ModelContext, + ) -> Result<()> { + match change { + RemoteAudioTrackUpdate::Subscribed(track) => { + let user_id = track.publisher_id().parse()?; + let track_id = track.sid().to_string(); + let participant = self + .remote_participants + .get_mut(&user_id) + .ok_or_else(|| anyhow!("subscribed to track by unknown participant"))?; + participant.audio_tracks.insert( + track_id.clone(), + track, + ); + cx.emit(Event::RemoteAudioTracksChanged { + participant_id: participant.peer_id, + }); + } + RemoteAudioTrackUpdate::Unsubscribed { + publisher_id, + track_id, + } => { + let user_id = publisher_id.parse()?; + let participant = self + .remote_participants + .get_mut(&user_id) + .ok_or_else(|| anyhow!("unsubscribed from track by unknown participant"))?; + participant.audio_tracks.remove(&track_id); + cx.emit(Event::RemoteAudioTracksChanged { + participant_id: participant.peer_id, + }); + } + } + + cx.notify(); + Ok(()) + } + fn check_invariants(&self) { #[cfg(any(test, feature = "test-support"))] { @@ -908,7 +982,85 @@ impl Room { pub fn is_screen_sharing(&self) -> bool { self.live_kit.as_ref().map_or(false, |live_kit| { - !matches!(live_kit.screen_track, ScreenTrack::None) + !matches!(live_kit.screen_track, Track::None) + }) + } + + pub fn is_sharing_mic(&self) -> bool { + self.live_kit.as_ref().map_or(false, |live_kit| { + !matches!(live_kit.microphone_track, Track::None) + }) + } + + pub fn share_mic(&mut self, cx: &mut ModelContext) -> Task> { + if self.status.is_offline() { + return Task::ready(Err(anyhow!("room is offline"))); + } else if self.is_sharing_mic() { + return Task::ready(Err(anyhow!("microphone was already shared"))); + } + + let publish_id = if let Some(live_kit) = self.live_kit.as_mut() { + let publish_id = post_inc(&mut live_kit.next_publish_id); + live_kit.microphone_track = Track::Pending { publish_id }; + cx.notify(); + publish_id + } else { + return Task::ready(Err(anyhow!("live-kit was not initialized"))); + }; + + cx.spawn_weak(|this, mut cx| async move { + let publish_track = async { + let track = LocalAudioTrack::create(); + this.upgrade(&cx) + .ok_or_else(|| anyhow!("room was dropped"))? + .read_with(&cx, |this, _| { + this.live_kit + .as_ref() + .map(|live_kit| live_kit.room.publish_audio_track(&track)) + }) + .ok_or_else(|| anyhow!("live-kit was not initialized"))? + .await + }; + + let publication = publish_track.await; + this.upgrade(&cx) + .ok_or_else(|| anyhow!("room was dropped"))? + .update(&mut cx, |this, cx| { + let live_kit = this + .live_kit + .as_mut() + .ok_or_else(|| anyhow!("live-kit was not initialized"))?; + + let canceled = if let Track::Pending { + publish_id: cur_publish_id, + } = &live_kit.microphone_track + { + *cur_publish_id != publish_id + } else { + true + }; + + match publication { + Ok(publication) => { + if canceled { + live_kit.room.unpublish_track(publication); + } else { + live_kit.microphone_track = Track::Published(publication); + cx.notify(); + } + Ok(()) + } + Err(error) => { + if canceled { + Ok(()) + } else { + live_kit.microphone_track = Track::None; + cx.notify(); + Err(error) + } + } + } + }) }) } @@ -921,7 +1073,7 @@ impl Room { let (displays, publish_id) = if let Some(live_kit) = self.live_kit.as_mut() { let publish_id = post_inc(&mut live_kit.next_publish_id); - live_kit.screen_track = ScreenTrack::Pending { publish_id }; + live_kit.screen_track = Track::Pending { publish_id }; cx.notify(); (live_kit.room.display_sources(), publish_id) } else { @@ -955,7 +1107,7 @@ impl Room { .as_mut() .ok_or_else(|| anyhow!("live-kit was not initialized"))?; - let canceled = if let ScreenTrack::Pending { + let canceled = if let Track::Pending { publish_id: cur_publish_id, } = &live_kit.screen_track { @@ -969,7 +1121,7 @@ impl Room { if canceled { live_kit.room.unpublish_track(publication); } else { - live_kit.screen_track = ScreenTrack::Published(publication); + live_kit.screen_track = Track::Published(publication); cx.notify(); } Ok(()) @@ -978,7 +1130,7 @@ impl Room { if canceled { Ok(()) } else { - live_kit.screen_track = ScreenTrack::None; + live_kit.screen_track = Track::None; cx.notify(); Err(error) } @@ -998,12 +1150,12 @@ impl Room { .as_mut() .ok_or_else(|| anyhow!("live-kit was not initialized"))?; match mem::take(&mut live_kit.screen_track) { - ScreenTrack::None => Err(anyhow!("screen was not shared")), - ScreenTrack::Pending { .. } => { + Track::None => Err(anyhow!("screen was not shared")), + Track::Pending { .. } => { cx.notify(); Ok(()) } - ScreenTrack::Published(track) => { + Track::Published(track) => { live_kit.room.unpublish_track(track); cx.notify(); Ok(()) @@ -1023,19 +1175,20 @@ impl Room { struct LiveKitRoom { room: Arc, - screen_track: ScreenTrack, + screen_track: Track, + microphone_track: Track, next_publish_id: usize, _maintain_room: Task<()>, - _maintain_tracks: Task<()>, + _maintain_tracks: [Task<()>; 2], } -enum ScreenTrack { +enum Track { None, Pending { publish_id: usize }, Published(LocalTrackPublication), } -impl Default for ScreenTrack { +impl Default for Track { fn default() -> Self { Self::None } diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 92b63478cbf1d20bf0597857a96ef88e0590efe2..b2c85f268d577aef4c518be93e902fd654e46b8e 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -257,7 +257,7 @@ async fn test_basic_calls( room_b.read_with(cx_b, |room, _| { assert_eq!( room.remote_participants()[&client_a.user_id().unwrap()] - .tracks + .video_tracks .len(), 1 ); @@ -274,7 +274,7 @@ async fn test_basic_calls( room_c.read_with(cx_c, |room, _| { assert_eq!( room.remote_participants()[&client_a.user_id().unwrap()] - .tracks + .video_tracks .len(), 1 ); @@ -6993,7 +6993,7 @@ async fn test_join_call_after_screen_was_shared( room.remote_participants() .get(&client_a.user_id().unwrap()) .unwrap() - .tracks + .video_tracks .len(), 1 ); diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index e8dae210c4c5ed196207fefb285c21c5a25bd1e1..2dc1fe3f1ba93068853122fb151388b8dc87ccab 100644 --- a/crates/collab_ui/src/contact_list.rs +++ b/crates/collab_ui/src/contact_list.rs @@ -514,10 +514,10 @@ impl ContactList { project_id: project.id, worktree_root_names: project.worktree_root_names.clone(), host_user_id: participant.user.id, - is_last: projects.peek().is_none() && participant.tracks.is_empty(), + is_last: projects.peek().is_none() && participant.video_tracks.is_empty(), }); } - if !participant.tracks.is_empty() { + if !participant.video_tracks.is_empty() { participant_entries.push(ContactEntry::ParticipantScreen { peer_id: participant.peer_id, is_last: true, diff --git a/crates/live_kit_client/src/test.rs b/crates/live_kit_client/src/test.rs index 2f89617363db7a9e9f51251ebf70b5e8b0eea482..232fc7cf4b6f2e8d4f57b1e6bed58bf9f0b0c671 100644 --- a/crates/live_kit_client/src/test.rs +++ b/crates/live_kit_client/src/test.rs @@ -517,6 +517,7 @@ impl RemoteVideoTrack { } } +#[derive(Debug)] pub struct RemoteAudioTrack { sid: Sid, publisher_id: Sid, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index f813635941d0bea70c6d6b4abb527f8f74b89ef5..85f2580a9af70fd6a381f2aea26aa3abb13bf129 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -2750,7 +2750,7 @@ impl Workspace { let call = self.active_call()?; let room = call.read(cx).room()?.read(cx); let participant = room.remote_participant_for_peer_id(peer_id)?; - let track = participant.tracks.values().next()?.clone(); + let track = participant.video_tracks.values().next()?.clone(); let user = participant.user.clone(); for item in pane.read(cx).items_of_type::() { From 53062e84222a4cc39176c2a958344fd96c9f867c Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 16 Jun 2023 10:44:00 -0700 Subject: [PATCH 12/63] turn mic off by default in dev builds, add enviroment variable for turning it back on --- crates/call/src/room.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 257a612f08162e70c0f5ec752758f27fa969362f..3b76a0bb378110a864b14a7e5bc536f87455e397 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -13,12 +13,13 @@ use futures::{FutureExt, StreamExt}; use gpui::{AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Task, WeakModelHandle}; use language::LanguageRegistry; use live_kit_client::{ - LocalAudioTrack, LocalTrackPublication, LocalVideoTrack, RemoteVideoTrackUpdate, RemoteAudioTrackUpdate, + LocalAudioTrack, LocalTrackPublication, LocalVideoTrack, RemoteAudioTrackUpdate, + RemoteVideoTrackUpdate, }; use postage::stream::Stream; use project::Project; use std::{future::Future, mem, pin::Pin, sync::Arc, time::Duration}; -use util::{post_inc, ResultExt, TryFutureExt}; +use util::{channel::ReleaseChannel, post_inc, ResultExt, TryFutureExt}; pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30); @@ -218,11 +219,12 @@ impl Room { None }; - let share_mic = room.update(&mut cx, |room, cx| { - room.share_mic(cx) - }); - - cx.background().spawn(share_mic).detach(); + if option_env!("START_MIC").is_some() + || &*util::channel::RELEASE_CHANNEL != &ReleaseChannel::Dev + { + let share_mic = room.update(&mut cx, |room, cx| room.share_mic(cx)); + cx.background().spawn(share_mic).detach(); + } match room .update(&mut cx, |room, cx| { @@ -653,7 +655,8 @@ impl Room { if let Some(live_kit) = this.live_kit.as_ref() { let video_tracks = live_kit.room.remote_video_tracks(&user.id.to_string()); - let audio_tracks = live_kit.room.remote_audio_tracks(&user.id.to_string()); + let audio_tracks = + live_kit.room.remote_audio_tracks(&user.id.to_string()); for track in video_tracks { this.remote_video_track_updated( RemoteVideoTrackUpdate::Subscribed(track), @@ -662,8 +665,11 @@ impl Room { .log_err(); } for track in audio_tracks { - this.remote_audio_track_updated(RemoteAudioTrackUpdate::Subscribed(track), cx) - .log_err(); + this.remote_audio_track_updated( + RemoteAudioTrackUpdate::Subscribed(track), + cx, + ) + .log_err(); } } } @@ -782,10 +788,7 @@ impl Room { .remote_participants .get_mut(&user_id) .ok_or_else(|| anyhow!("subscribed to track by unknown participant"))?; - participant.audio_tracks.insert( - track_id.clone(), - track, - ); + participant.audio_tracks.insert(track_id.clone(), track); cx.emit(Event::RemoteAudioTracksChanged { participant_id: participant.peer_id, }); From ecd2129c2f48f71af4ba2da2f7e3f6088d4062e3 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 16 Jun 2023 11:16:36 -0700 Subject: [PATCH 13/63] Add deafen and mute stubs --- crates/call/src/room.rs | 11 +++++++++++ crates/collab_ui/src/collab_ui.rs | 26 +++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 3b76a0bb378110a864b14a7e5bc536f87455e397..aa0cb1f20ef02c98e7d8eb4d7f317c885836497a 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -1143,6 +1143,17 @@ impl Room { }) } + pub fn toggle_mute(&mut self, cx: &mut ModelContext) -> Task> { + // https://docs.livekit.io/client/publish/ + // Should be acessible from local participant / publication + todo!(); + } + + pub fn toggle_deafen(&mut self, cx: &mut ModelContext) -> Task> { + // iterate through publications and mute (?????) + todo!(); + } + pub fn unshare_screen(&mut self, cx: &mut ModelContext) -> Result<()> { if self.status.is_offline() { return Err(anyhow!("room is offline")); diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index c0734388b1512b2e9cac5014c460bf1a8c09650b..9a426b0879f00a44ae7e2852a4c5074daaf63946 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -15,7 +15,7 @@ use gpui::{actions, AppContext, Task}; use std::sync::Arc; use workspace::AppState; -actions!(collab, [ToggleScreenSharing]); +actions!(collab, [ToggleScreenSharing, ToggleMute, ToggleDeafen]); pub fn init(app_state: &Arc, cx: &mut AppContext) { collab_titlebar_item::init(cx); @@ -27,6 +27,8 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { sharing_status_indicator::init(cx); cx.add_global_action(toggle_screen_sharing); + cx.add_global_action(toggle_mute); + cx.add_global_action(toggle_deafen); } pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) { @@ -41,3 +43,25 @@ pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) { toggle_screen_sharing.detach_and_log_err(cx); } } + +pub fn toggle_mute(_: &ToggleMute, cx: &mut AppContext) { + if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { + let toggle_mut = room.update(cx, |room, cx| { + if room.is_sharing_mic() { + room.toggle_mute(cx) + } else { + room.share_mic(cx) + } + }); + toggle_mut.detach_and_log_err(cx); + } +} + +pub fn toggle_deafen(_: &ToggleDeafen, cx: &mut AppContext) { + if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { + let toggle_deafan = room.update(cx, |room, cx| { + room.toggle_deafen(cx) + }); + toggle_deafan.detach_and_log_err(cx); + } +} From 91f2f31daa16e36febd0880655bd16344bc3ef02 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 19 Jun 2023 12:06:42 +0200 Subject: [PATCH 14/63] Split git/project label into a flex row --- crates/collab_ui/src/collab_titlebar_item.rs | 62 ++++++++------------ 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 797a4f706692840536fde2edfd2ef53990ad59da..919e712ad13e37bd60719d8d1e1e3e42e6f5ddfa 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -17,7 +17,7 @@ use gpui::{ AppContext, Entity, ImageData, LayoutContext, ModelHandle, SceneBuilder, Subscription, View, ViewContext, ViewHandle, WeakViewHandle, }; -use project::Project; +use project::{Project, RepositoryEntry}; use std::{ops::Range, sync::Arc}; use theme::{AvatarStyle, Theme}; use util::ResultExt; @@ -193,37 +193,16 @@ impl CollabTitlebarItem { theme: Arc, cx: &ViewContext, ) -> AnyElement { - let names_and_branches = project.visible_worktrees(cx).map(|worktree| { + let mut names_and_branches = project.visible_worktrees(cx).map(|worktree| { let worktree = worktree.read(cx); (worktree.root_name(), worktree.root_git_entry()) }); - fn push_str(buffer: &mut String, index: &mut usize, str: &str) { - buffer.push_str(str); - *index += str.chars().count(); - } - - let mut indices = Vec::new(); - let mut index = 0; - let mut title = String::new(); - let mut names_and_branches = names_and_branches.peekable(); - while let Some((name, entry)) = names_and_branches.next() { - let pre_index = index; - push_str(&mut title, &mut index, name); - indices.extend((pre_index..index).into_iter()); - if let Some(branch) = entry.and_then(|entry| entry.branch()) { - push_str(&mut title, &mut index, "/"); - push_str(&mut title, &mut index, &branch); - } - if names_and_branches.peek().is_some() { - push_str(&mut title, &mut index, ", "); - if index >= MAX_TITLE_LENGTH { - title.push_str(" …"); - break; - } - } - } - + let (name, entry) = names_and_branches.next().unwrap_or(("", None)); + let branch_prepended = entry + .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; @@ -234,14 +213,25 @@ impl CollabTitlebarItem { text: text_style, highlight_text: Some(highlight), }; - - Label::new(title, style) - .with_highlights(indices) - .contained() - .with_margin_right(item_spacing) - .aligned() - .left() - .into_any_named("title-with-git-information") + let mut ret = Flex::row().with_child( + Label::new(name.to_owned(), style.clone()) + .with_highlights((0..name.len()).into_iter().collect()) + .contained() + .aligned() + .left() + .into_any_named("title-project-name"), + ); + if let Some(git_branch) = branch_prepended { + ret = ret.with_child( + Label::new(git_branch, style) + .contained() + .with_margin_right(item_spacing) + .aligned() + .left() + .into_any_named("title-project-branch"), + ) + } + ret.into_any() } fn window_activation_changed(&mut self, active: bool, cx: &mut ViewContext) { From 3e3079b513699964166a00205edc7c1a1fe829d9 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 19 Jun 2023 12:07:02 +0200 Subject: [PATCH 15/63] cargo fmt --- crates/collab_ui/src/collab_ui.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index 9a426b0879f00a44ae7e2852a4c5074daaf63946..d6e62d146ff4b8152b0299e9818d3b715c44c897 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -59,9 +59,7 @@ pub fn toggle_mute(_: &ToggleMute, cx: &mut AppContext) { pub fn toggle_deafen(_: &ToggleDeafen, cx: &mut AppContext) { if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - let toggle_deafan = room.update(cx, |room, cx| { - room.toggle_deafen(cx) - }); + let toggle_deafan = room.update(cx, |room, cx| room.toggle_deafen(cx)); toggle_deafan.detach_and_log_err(cx); } } From e58f0ac72fce79b4e4f45a813e4b31cee3427cf3 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 20 Jun 2023 09:32:16 -0700 Subject: [PATCH 16/63] Add mute toggling controls --- crates/call/src/room.rs | 110 +++++++++++++----- crates/collab_ui/src/collab_ui.rs | 15 +-- .../Sources/LiveKitBridge/LiveKitBridge.swift | 44 ++++--- crates/live_kit_client/src/prod.rs | 67 ++++++++++- crates/live_kit_client/src/test.rs | 14 +++ 5 files changed, 189 insertions(+), 61 deletions(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index aa0cb1f20ef02c98e7d8eb4d7f317c885836497a..b8da95bfb532acc50f9bb390cb7ec4e8ebffe3d2 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -154,8 +154,8 @@ impl Room { Some(LiveKitRoom { room, - screen_track: Track::None, - microphone_track: Track::None, + screen_track: LocalTrack::None, + microphone_track: LocalTrack::None, next_publish_id: 0, _maintain_room, _maintain_tracks: [_maintain_video_tracks, _maintain_audio_tracks], @@ -985,13 +985,13 @@ impl Room { pub fn is_screen_sharing(&self) -> bool { self.live_kit.as_ref().map_or(false, |live_kit| { - !matches!(live_kit.screen_track, Track::None) + !matches!(live_kit.screen_track, LocalTrack::None) }) } pub fn is_sharing_mic(&self) -> bool { self.live_kit.as_ref().map_or(false, |live_kit| { - !matches!(live_kit.microphone_track, Track::None) + !matches!(live_kit.microphone_track, LocalTrack::None) }) } @@ -1004,7 +1004,10 @@ impl Room { let publish_id = if let Some(live_kit) = self.live_kit.as_mut() { let publish_id = post_inc(&mut live_kit.next_publish_id); - live_kit.microphone_track = Track::Pending { publish_id }; + live_kit.microphone_track = LocalTrack::Pending { + publish_id, + muted: false, + }; cx.notify(); publish_id } else { @@ -1034,13 +1037,14 @@ impl Room { .as_mut() .ok_or_else(|| anyhow!("live-kit was not initialized"))?; - let canceled = if let Track::Pending { + let (canceled, muted) = if let LocalTrack::Pending { publish_id: cur_publish_id, + muted } = &live_kit.microphone_track { - *cur_publish_id != publish_id + (*cur_publish_id != publish_id, *muted) } else { - true + (true, false) }; match publication { @@ -1048,7 +1052,13 @@ impl Room { if canceled { live_kit.room.unpublish_track(publication); } else { - live_kit.microphone_track = Track::Published(publication); + if muted { + cx.background().spawn(publication.mute()).detach(); + } + live_kit.microphone_track = LocalTrack::Published { + track_publication: publication, + muted + }; cx.notify(); } Ok(()) @@ -1057,7 +1067,7 @@ impl Room { if canceled { Ok(()) } else { - live_kit.microphone_track = Track::None; + live_kit.microphone_track = LocalTrack::None; cx.notify(); Err(error) } @@ -1076,7 +1086,10 @@ impl Room { let (displays, publish_id) = if let Some(live_kit) = self.live_kit.as_mut() { let publish_id = post_inc(&mut live_kit.next_publish_id); - live_kit.screen_track = Track::Pending { publish_id }; + live_kit.screen_track = LocalTrack::Pending { + publish_id, + muted: false, + }; cx.notify(); (live_kit.room.display_sources(), publish_id) } else { @@ -1110,13 +1123,14 @@ impl Room { .as_mut() .ok_or_else(|| anyhow!("live-kit was not initialized"))?; - let canceled = if let Track::Pending { + let (canceled, muted) = if let LocalTrack::Pending { publish_id: cur_publish_id, + muted, } = &live_kit.screen_track { - *cur_publish_id != publish_id + (*cur_publish_id != publish_id, *muted) } else { - true + (true, false) }; match publication { @@ -1124,7 +1138,13 @@ impl Room { if canceled { live_kit.room.unpublish_track(publication); } else { - live_kit.screen_track = Track::Published(publication); + if muted { + cx.background().spawn(publication.mute()).detach(); + } + live_kit.screen_track = LocalTrack::Published { + track_publication: publication, + muted, + }; cx.notify(); } Ok(()) @@ -1133,7 +1153,7 @@ impl Room { if canceled { Ok(()) } else { - live_kit.screen_track = Track::None; + live_kit.screen_track = LocalTrack::None; cx.notify(); Err(error) } @@ -1143,13 +1163,33 @@ impl Room { }) } - pub fn toggle_mute(&mut self, cx: &mut ModelContext) -> Task> { - // https://docs.livekit.io/client/publish/ - // Should be acessible from local participant / publication - todo!(); + pub fn toggle_mute(&mut self, cx: &mut ModelContext) -> Result>> { + if let Some(live_kit) = self.live_kit.as_mut() { + match &mut live_kit.microphone_track { + LocalTrack::None => Err(anyhow!("microphone was not shared")), + LocalTrack::Pending { muted, .. } => { + *muted = !*muted; + Ok(Task::Ready(Some(Ok(())))) + } + LocalTrack::Published { + track_publication, + muted, + } => { + *muted = !*muted; + + if *muted { + Ok(cx.background().spawn(track_publication.mute())) + } else { + Ok(cx.background().spawn(track_publication.unmute())) + } + } + } + } else { + Err(anyhow!("LiveKit not started")) + } } - pub fn toggle_deafen(&mut self, cx: &mut ModelContext) -> Task> { + pub fn toggle_deafen(&mut self, _cx: &mut ModelContext) -> Task> { // iterate through publications and mute (?????) todo!(); } @@ -1164,13 +1204,15 @@ impl Room { .as_mut() .ok_or_else(|| anyhow!("live-kit was not initialized"))?; match mem::take(&mut live_kit.screen_track) { - Track::None => Err(anyhow!("screen was not shared")), - Track::Pending { .. } => { + LocalTrack::None => Err(anyhow!("screen was not shared")), + LocalTrack::Pending { .. } => { cx.notify(); Ok(()) } - Track::Published(track) => { - live_kit.room.unpublish_track(track); + LocalTrack::Published { + track_publication, .. + } => { + live_kit.room.unpublish_track(track_publication); cx.notify(); Ok(()) } @@ -1189,20 +1231,26 @@ impl Room { struct LiveKitRoom { room: Arc, - screen_track: Track, - microphone_track: Track, + screen_track: LocalTrack, + microphone_track: LocalTrack, next_publish_id: usize, _maintain_room: Task<()>, _maintain_tracks: [Task<()>; 2], } -enum Track { +enum LocalTrack { None, - Pending { publish_id: usize }, - Published(LocalTrackPublication), + Pending { + publish_id: usize, + muted: bool, + }, + Published { + track_publication: LocalTrackPublication, + muted: bool, + }, } -impl Default for Track { +impl Default for LocalTrack { fn default() -> Self { Self::None } diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index d6e62d146ff4b8152b0299e9818d3b715c44c897..9de8cbf9dde9a57b9f983ffba06d90143416b589 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -9,9 +9,10 @@ mod notifications; mod project_shared_notification; mod sharing_status_indicator; -use call::ActiveCall; +use call::{ActiveCall, Room}; pub use collab_titlebar_item::{CollabTitlebarItem, ToggleContactsMenu}; use gpui::{actions, AppContext, Task}; +use util::ResultExt; use std::sync::Arc; use workspace::AppState; @@ -46,20 +47,12 @@ pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) { pub fn toggle_mute(_: &ToggleMute, cx: &mut AppContext) { if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - let toggle_mut = room.update(cx, |room, cx| { - if room.is_sharing_mic() { - room.toggle_mute(cx) - } else { - room.share_mic(cx) - } - }); - toggle_mut.detach_and_log_err(cx); + room.update(cx, Room::toggle_mute).map(Task::detach).log_err(); } } pub fn toggle_deafen(_: &ToggleDeafen, cx: &mut AppContext) { if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - let toggle_deafan = room.update(cx, |room, cx| room.toggle_deafen(cx)); - toggle_deafan.detach_and_log_err(cx); + room.update(cx, Room::toggle_deafen).detach_and_log_err(cx); } } diff --git a/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift b/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift index 40c1319e8f9111dac6139e723699ba76fd8d6111..d28dc828f15749ea34c635e95fd3b073310ba7a4 100644 --- a/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift +++ b/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift @@ -201,19 +201,6 @@ public func LKCreateScreenShareTrackForDisplay(display: UnsafeMutableRawPointer) return Unmanaged.passRetained(track).toOpaque() } -@_cdecl("LKRemoteAudioTrackStart") -public func LKRemoteAudioTrackStart(track: UnsafeRawPointer, onStart: @escaping @convention(c) (UnsafeRawPointer, Bool) -> Void, callbackData: UnsafeRawPointer) { - let track = Unmanaged.fromOpaque(track).takeUnretainedValue() as! RemoteAudioTrack - - track.start().then { success in - onStart(callbackData, success) - } - .catch { _ in - onStart(callbackData, false) - } -} - - @_cdecl("LKVideoRendererCreate") public func LKVideoRendererCreate(data: UnsafeRawPointer, onFrame: @escaping @convention(c) (UnsafeRawPointer, CVPixelBuffer) -> Bool, onDrop: @escaping @convention(c) (UnsafeRawPointer) -> Void) -> UnsafeMutableRawPointer { Unmanaged.passRetained(LKVideoRenderer(data: data, onFrame: onFrame, onDrop: onDrop)).toOpaque() @@ -247,3 +234,34 @@ public func LKDisplaySources(data: UnsafeRawPointer, callback: @escaping @conven callback(data, nil, error.localizedDescription as CFString) } } + +@_cdecl("LKLocalTrackPublicationMute") +public func LKLocalTrackPublicationMute( + publication: UnsafeRawPointer, + on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, + callback_data: UnsafeRawPointer +) { + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + + publication.mute().then { + on_complete(callback_data, nil) + }.catch { error in + on_complete(callback_data, error.localizedDescription as CFString) + } + +} + +@_cdecl("LKLocalTrackPublicationUnmute") +public func LKLocalTrackPublicationUnmute( + publication: UnsafeRawPointer, + on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, + callback_data: UnsafeRawPointer +) { + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + + publication.unmute().then { + on_complete(callback_data, nil) + }.catch { error in + on_complete(callback_data, error.localizedDescription as CFString) + } +} diff --git a/crates/live_kit_client/src/prod.rs b/crates/live_kit_client/src/prod.rs index 6ae493d306136f66f3a6212ccf23ec93b2f50f93..46516d49be0d57f6cc9637e01b3c05c4d3e1193f 100644 --- a/crates/live_kit_client/src/prod.rs +++ b/crates/live_kit_client/src/prod.rs @@ -84,12 +84,6 @@ extern "C" { ) -> *const c_void; fn LKRemoteAudioTrackGetSid(track: *const c_void) -> CFStringRef; - // fn LKRemoteAudioTrackStart( - // track: *const c_void, - // callback: extern "C" fn(*mut c_void, bool), - // callback_data: *mut c_void - // ); - fn LKVideoTrackAddRenderer(track: *const c_void, renderer: *const c_void); fn LKRemoteVideoTrackGetSid(track: *const c_void) -> CFStringRef; @@ -103,6 +97,17 @@ extern "C" { ); fn LKCreateScreenShareTrackForDisplay(display: *const c_void) -> *const c_void; fn LKLocalAudioTrackCreateTrack() -> *const c_void; + + fn LKLocalTrackPublicationMute( + publication: *const c_void, + on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef), + callback_data: *mut c_void, + ); + fn LKLocalTrackPublicationUnmute( + publication: *const c_void, + on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef), + callback_data: *mut c_void, + ); } pub type Sid = String; @@ -525,6 +530,56 @@ impl Drop for LocalVideoTrack { pub struct LocalTrackPublication(*const c_void); +impl LocalTrackPublication { + pub fn mute(&self) -> impl Future> { + let (tx, rx) = futures::channel::oneshot::channel(); + + extern "C" fn complete_callback(callback_data: *mut c_void, error: CFStringRef) { + let tx = unsafe { Box::from_raw(callback_data as *mut oneshot::Sender>) }; + if error.is_null() { + tx.send(Ok(())).ok(); + } else { + let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; + tx.send(Err(anyhow!(error))).ok(); + } + } + + unsafe { + LKLocalTrackPublicationMute( + self.0, + complete_callback, + Box::into_raw(Box::new(tx)) as *mut c_void, + ) + } + + async move { rx.await.unwrap() } + } + + pub fn unmute(&self) -> impl Future> { + let (tx, rx) = futures::channel::oneshot::channel(); + + extern "C" fn complete_callback(callback_data: *mut c_void, error: CFStringRef) { + let tx = unsafe { Box::from_raw(callback_data as *mut oneshot::Sender>) }; + if error.is_null() { + tx.send(Ok(())).ok(); + } else { + let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; + tx.send(Err(anyhow!(error))).ok(); + } + } + + unsafe { + LKLocalTrackPublicationUnmute( + self.0, + complete_callback, + Box::into_raw(Box::new(tx)) as *mut c_void, + ) + } + + async move { rx.await.unwrap() } + } +} + impl Drop for LocalTrackPublication { fn drop(&mut self) { unsafe { CFRelease(self.0) } diff --git a/crates/live_kit_client/src/test.rs b/crates/live_kit_client/src/test.rs index 232fc7cf4b6f2e8d4f57b1e6bed58bf9f0b0c671..21211ce473060e78489e73b144a53ff83a461e82 100644 --- a/crates/live_kit_client/src/test.rs +++ b/crates/live_kit_client/src/test.rs @@ -475,6 +475,20 @@ impl Drop for Room { pub struct LocalTrackPublication; +impl LocalTrackPublication { + pub fn mute(&self) -> impl Future> { + async { + Ok(()) + } + } + + pub fn unmute(&self) -> impl Future> { + async { + Ok(()) + } + } +} + #[derive(Clone)] pub struct LocalVideoTrack { frames_rx: async_broadcast::Receiver, From b828a74ad66e6b1367d98263f8cd4e144fbe26c8 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 20 Jun 2023 12:34:32 -0700 Subject: [PATCH 17/63] Add deafen controls --- crates/call/src/room.rs | 49 +++++++++---- crates/collab_ui/src/collab_titlebar_item.rs | 2 +- crates/collab_ui/src/collab_ui.rs | 4 +- crates/gpui/src/executor.rs | 6 +- .../Sources/LiveKitBridge/LiveKitBridge.swift | 46 +++++++++--- crates/live_kit_client/src/prod.rs | 70 +++++++++++++++++-- crates/live_kit_client/src/test.rs | 43 +++++++++--- 7 files changed, 176 insertions(+), 44 deletions(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index b8da95bfb532acc50f9bb390cb7ec4e8ebffe3d2..613a52a908d6e79c2f91e8b6ab94c932f363b78b 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -157,6 +157,7 @@ impl Room { screen_track: LocalTrack::None, microphone_track: LocalTrack::None, next_publish_id: 0, + deafened: false, _maintain_room, _maintain_tracks: [_maintain_video_tracks, _maintain_audio_tracks], }) @@ -223,7 +224,9 @@ impl Room { || &*util::channel::RELEASE_CHANNEL != &ReleaseChannel::Dev { let share_mic = room.update(&mut cx, |room, cx| room.share_mic(cx)); - cx.background().spawn(share_mic).detach(); + cx.update(|cx| { + cx.background().spawn(share_mic).detach_and_log_err(cx); + }); } match room @@ -1039,7 +1042,7 @@ impl Room { let (canceled, muted) = if let LocalTrack::Pending { publish_id: cur_publish_id, - muted + muted, } = &live_kit.microphone_track { (*cur_publish_id != publish_id, *muted) @@ -1053,11 +1056,11 @@ impl Room { live_kit.room.unpublish_track(publication); } else { if muted { - cx.background().spawn(publication.mute()).detach(); + cx.background().spawn(publication.set_mute(muted)).detach(); } live_kit.microphone_track = LocalTrack::Published { track_publication: publication, - muted + muted, }; cx.notify(); } @@ -1139,7 +1142,7 @@ impl Room { live_kit.room.unpublish_track(publication); } else { if muted { - cx.background().spawn(publication.mute()).detach(); + cx.background().spawn(publication.set_mute(muted)).detach(); } live_kit.screen_track = LocalTrack::Published { track_publication: publication, @@ -1177,11 +1180,7 @@ impl Room { } => { *muted = !*muted; - if *muted { - Ok(cx.background().spawn(track_publication.mute())) - } else { - Ok(cx.background().spawn(track_publication.unmute())) - } + Ok(cx.background().spawn(track_publication.set_mute(*muted))) } } } else { @@ -1189,9 +1188,32 @@ impl Room { } } - pub fn toggle_deafen(&mut self, _cx: &mut ModelContext) -> Task> { - // iterate through publications and mute (?????) - todo!(); + pub fn toggle_deafen(&mut self, cx: &mut ModelContext) -> Result>> { + if let Some(live_kit) = &mut self.live_kit { + (*live_kit).deafened = !live_kit.deafened + } + + if let Some(live_kit) = &self.live_kit { + let mut tasks = Vec::with_capacity(self.remote_participants.len()); + + for participant in self.remote_participants.values() { + for track in live_kit + .room + .remote_audio_track_publications(&participant.user.id.to_string()) + { + tasks.push(cx.background().spawn(track.set_enabled(live_kit.deafened))); + } + } + + Ok(cx.background().spawn(async move { + for task in tasks { + task.await?; + } + Ok(()) + })) + } else { + Err(anyhow!("LiveKit not started")) + } } pub fn unshare_screen(&mut self, cx: &mut ModelContext) -> Result<()> { @@ -1233,6 +1255,7 @@ struct LiveKitRoom { room: Arc, screen_track: LocalTrack, microphone_track: LocalTrack, + deafened: bool, next_publish_id: usize, _maintain_room: Task<()>, _maintain_tracks: [Task<()>; 2], diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 919e712ad13e37bd60719d8d1e1e3e42e6f5ddfa..87fd7470d6aaefe4e4dda923e6880f21d36a20db 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -23,7 +23,7 @@ use theme::{AvatarStyle, Theme}; use util::ResultExt; use workspace::{FollowNextCollaborator, Workspace}; -const MAX_TITLE_LENGTH: usize = 75; +// const MAX_TITLE_LENGTH: usize = 75; actions!( collab, diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index 9de8cbf9dde9a57b9f983ffba06d90143416b589..940700a52698b5562f6f093773c273bdfa38d983 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -47,12 +47,12 @@ pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) { pub fn toggle_mute(_: &ToggleMute, cx: &mut AppContext) { if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - room.update(cx, Room::toggle_mute).map(Task::detach).log_err(); + room.update(cx, Room::toggle_mute).map(|task| task.detach_and_log_err(cx)).log_err(); } } pub fn toggle_deafen(_: &ToggleDeafen, cx: &mut AppContext) { if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - room.update(cx, Room::toggle_deafen).detach_and_log_err(cx); + room.update(cx, Room::toggle_deafen).map(|task| task.detach_and_log_err(cx)).log_err(); } } diff --git a/crates/gpui/src/executor.rs b/crates/gpui/src/executor.rs index 365766fb9dd0b080642a4b1e344d985dd312d22c..0923826a093edf5b35a52773ca70e2286d669ea4 100644 --- a/crates/gpui/src/executor.rs +++ b/crates/gpui/src/executor.rs @@ -12,7 +12,7 @@ use std::{ sync::Arc, task::{Context, Poll}, thread, - time::Duration, + time::Duration, panic::Location, }; use crate::{ @@ -965,10 +965,12 @@ impl Task { } impl Task> { + #[track_caller] pub fn detach_and_log_err(self, cx: &mut AppContext) { cx.spawn(|_| async move { if let Err(err) = self.await { - log::error!("{:#}", err); + let caller = Location::caller(); + log::error!("{}:{}: {:#}", caller.file(), caller.line(), err); } }) .detach(); diff --git a/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift b/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift index d28dc828f15749ea34c635e95fd3b073310ba7a4..666da3d5332d9506054bfe2bf86bd9824fe3bf8f 100644 --- a/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift +++ b/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift @@ -169,6 +169,18 @@ public func LKRoomAudioTracksForRemoteParticipant(room: UnsafeRawPointer, partic return nil; } +@_cdecl("LKRoomAudioTrackPublicationsForRemoteParticipant") +public func LKRoomAudioTrackPublicationsForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + + for (_, participant) in room.remoteParticipants { + if participant.identity == participantId as String { + return participant.audioTracks.compactMap { $0 as? RemoteTrackPublication } as CFArray? + } + } + + return nil; +} @_cdecl("LKRoomVideoTracksForRemoteParticipant") public func LKRoomVideoTracksForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? { @@ -235,33 +247,45 @@ public func LKDisplaySources(data: UnsafeRawPointer, callback: @escaping @conven } } -@_cdecl("LKLocalTrackPublicationMute") -public func LKLocalTrackPublicationMute( +@_cdecl("LKLocalTrackPublicationSetMute") +public func LKLocalTrackPublicationSetMute( publication: UnsafeRawPointer, + muted: Bool, on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, callback_data: UnsafeRawPointer ) { let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() - publication.mute().then { - on_complete(callback_data, nil) - }.catch { error in - on_complete(callback_data, error.localizedDescription as CFString) + if muted { + publication.mute().then { + on_complete(callback_data, nil) + }.catch { error in + on_complete(callback_data, error.localizedDescription as CFString) + } + } else { + publication.unmute().then { + on_complete(callback_data, nil) + }.catch { error in + on_complete(callback_data, error.localizedDescription as CFString) + } } - } -@_cdecl("LKLocalTrackPublicationUnmute") -public func LKLocalTrackPublicationUnmute( +@_cdecl("LKRemoteTrackPublicationSetEnabled") +public func LKRemoteTrackPublicationSetEnabled( publication: UnsafeRawPointer, + enabled: Bool, on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, callback_data: UnsafeRawPointer ) { - let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() - publication.unmute().then { + publication.set(enabled: enabled).then { on_complete(callback_data, nil) }.catch { error in on_complete(callback_data, error.localizedDescription as CFString) } } + + + diff --git a/crates/live_kit_client/src/prod.rs b/crates/live_kit_client/src/prod.rs index 46516d49be0d57f6cc9637e01b3c05c4d3e1193f..76f06b562ff1fa387fbc7c2c81dddce8e4976541 100644 --- a/crates/live_kit_client/src/prod.rs +++ b/crates/live_kit_client/src/prod.rs @@ -72,6 +72,11 @@ extern "C" { participant_id: CFStringRef, ) -> CFArrayRef; + fn LKRoomAudioTrackPublicationsForRemoteParticipant( + room: *const c_void, + participant_id: CFStringRef, + ) -> CFArrayRef; + fn LKRoomVideoTracksForRemoteParticipant( room: *const c_void, participant_id: CFStringRef, @@ -98,13 +103,16 @@ extern "C" { fn LKCreateScreenShareTrackForDisplay(display: *const c_void) -> *const c_void; fn LKLocalAudioTrackCreateTrack() -> *const c_void; - fn LKLocalTrackPublicationMute( + fn LKLocalTrackPublicationSetMute( publication: *const c_void, + muted: bool, on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef), callback_data: *mut c_void, ); - fn LKLocalTrackPublicationUnmute( + + fn LKRemoteTrackPublicationSetEnabled( publication: *const c_void, + enabled: bool, on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef), callback_data: *mut c_void, ); @@ -318,6 +326,29 @@ impl Room { } } + pub fn remote_audio_track_publications(&self, participant_id: &str) -> Vec> { + unsafe { + let tracks = LKRoomAudioTrackPublicationsForRemoteParticipant( + self.native_room, + CFString::new(participant_id).as_concrete_TypeRef(), + ); + + if tracks.is_null() { + Vec::new() + } else { + let tracks = CFArray::wrap_under_get_rule(tracks); + tracks + .into_iter() + .map(|native_track_publication| { + let native_track_publication = *native_track_publication; + Arc::new(RemoteTrackPublication(native_track_publication)) + }) + .collect() + } + } + } + + pub fn remote_audio_track_updates(&self) -> mpsc::UnboundedReceiver { let (tx, rx) = mpsc::unbounded(); self.remote_audio_track_subscribers.lock().push(tx); @@ -531,7 +562,7 @@ impl Drop for LocalVideoTrack { pub struct LocalTrackPublication(*const c_void); impl LocalTrackPublication { - pub fn mute(&self) -> impl Future> { + pub fn set_mute(&self, muted: bool) -> impl Future> { let (tx, rx) = futures::channel::oneshot::channel(); extern "C" fn complete_callback(callback_data: *mut c_void, error: CFStringRef) { @@ -545,8 +576,9 @@ impl LocalTrackPublication { } unsafe { - LKLocalTrackPublicationMute( + LKLocalTrackPublicationSetMute( self.0, + muted, complete_callback, Box::into_raw(Box::new(tx)) as *mut c_void, ) @@ -554,8 +586,18 @@ impl LocalTrackPublication { async move { rx.await.unwrap() } } +} + +impl Drop for LocalTrackPublication { + fn drop(&mut self) { + unsafe { CFRelease(self.0) } + } +} + +pub struct RemoteTrackPublication(*const c_void); - pub fn unmute(&self) -> impl Future> { +impl RemoteTrackPublication { + pub fn set_enabled(&self, enabled: bool) -> impl Future> { let (tx, rx) = futures::channel::oneshot::channel(); extern "C" fn complete_callback(callback_data: *mut c_void, error: CFStringRef) { @@ -569,8 +611,9 @@ impl LocalTrackPublication { } unsafe { - LKLocalTrackPublicationUnmute( + LKRemoteTrackPublicationSetEnabled( self.0, + enabled, complete_callback, Box::into_raw(Box::new(tx)) as *mut c_void, ) @@ -580,12 +623,13 @@ impl LocalTrackPublication { } } -impl Drop for LocalTrackPublication { +impl Drop for RemoteTrackPublication { fn drop(&mut self) { unsafe { CFRelease(self.0) } } } + #[derive(Debug)] pub struct RemoteAudioTrack { _native_track: *const c_void, @@ -612,6 +656,18 @@ impl RemoteAudioTrack { pub fn publisher_id(&self) -> &str { &self.publisher_id } + + pub fn enable(&self) -> impl Future> { + async { + Ok(()) + } + } + + pub fn disable(&self) -> impl Future> { + async { + Ok(()) + } + } } #[derive(Debug)] diff --git a/crates/live_kit_client/src/test.rs b/crates/live_kit_client/src/test.rs index 21211ce473060e78489e73b144a53ff83a461e82..e8c5247f53cce581eda719486bb8f8538f98a9b7 100644 --- a/crates/live_kit_client/src/test.rs +++ b/crates/live_kit_client/src/test.rs @@ -410,6 +410,25 @@ impl Room { .collect() } + pub fn remote_audio_track_publications( + &self, + publisher_id: &str, + ) -> Vec> { + if !self.is_connected() { + return Vec::new(); + } + + self.test_server() + .audio_tracks(self.token()) + .unwrap() + .into_iter() + .filter(|track| track.publisher_id() == publisher_id) + .map(|_track| { + Arc::new(RemoteTrackPublication {}) + }) + .collect() + } + pub fn remote_video_tracks(&self, publisher_id: &str) -> Vec> { if !self.is_connected() { return Vec::new(); @@ -476,16 +495,16 @@ impl Drop for Room { pub struct LocalTrackPublication; impl LocalTrackPublication { - pub fn mute(&self) -> impl Future> { - async { - Ok(()) - } + pub fn set_mute(&self, _mute: bool) -> impl Future> { + async { Ok(()) } } +} - pub fn unmute(&self) -> impl Future> { - async { - Ok(()) - } +pub struct RemoteTrackPublication; + +impl RemoteTrackPublication { + pub fn set_enabled(&self, _enabled: bool) -> impl Future> { + async { Ok(()) } } } @@ -545,6 +564,14 @@ impl RemoteAudioTrack { pub fn publisher_id(&self) -> &str { &self.publisher_id } + + pub fn enable(&self) -> impl Future> { + async { Ok(()) } + } + + pub fn disable(&self) -> impl Future> { + async { Ok(()) } + } } #[derive(Clone)] From dbd95e35cfa21f5e01b881eedd2251720aea20f2 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 20 Jun 2023 12:36:36 -0700 Subject: [PATCH 18/63] fmt --- crates/collab_ui/src/collab_ui.rs | 10 +++++++--- crates/gpui/src/executor.rs | 3 ++- crates/live_kit_client/src/prod.rs | 15 ++++++--------- crates/live_kit_client/src/test.rs | 6 ++---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index 940700a52698b5562f6f093773c273bdfa38d983..36ee58242a5928a3fe8304fde5bf6782d60b2ef9 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -12,8 +12,8 @@ mod sharing_status_indicator; use call::{ActiveCall, Room}; pub use collab_titlebar_item::{CollabTitlebarItem, ToggleContactsMenu}; use gpui::{actions, AppContext, Task}; -use util::ResultExt; use std::sync::Arc; +use util::ResultExt; use workspace::AppState; actions!(collab, [ToggleScreenSharing, ToggleMute, ToggleDeafen]); @@ -47,12 +47,16 @@ pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) { pub fn toggle_mute(_: &ToggleMute, cx: &mut AppContext) { if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - room.update(cx, Room::toggle_mute).map(|task| task.detach_and_log_err(cx)).log_err(); + room.update(cx, Room::toggle_mute) + .map(|task| task.detach_and_log_err(cx)) + .log_err(); } } pub fn toggle_deafen(_: &ToggleDeafen, cx: &mut AppContext) { if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - room.update(cx, Room::toggle_deafen).map(|task| task.detach_and_log_err(cx)).log_err(); + room.update(cx, Room::toggle_deafen) + .map(|task| task.detach_and_log_err(cx)) + .log_err(); } } diff --git a/crates/gpui/src/executor.rs b/crates/gpui/src/executor.rs index 0923826a093edf5b35a52773ca70e2286d669ea4..fb175d9d5d10c679b2fe2dee2cda86b06f77b1fb 100644 --- a/crates/gpui/src/executor.rs +++ b/crates/gpui/src/executor.rs @@ -7,12 +7,13 @@ use std::{ fmt::{self, Display}, marker::PhantomData, mem, + panic::Location, pin::Pin, rc::Rc, sync::Arc, task::{Context, Poll}, thread, - time::Duration, panic::Location, + time::Duration, }; use crate::{ diff --git a/crates/live_kit_client/src/prod.rs b/crates/live_kit_client/src/prod.rs index 76f06b562ff1fa387fbc7c2c81dddce8e4976541..ed040fd5ccb9b39480a5259f55ba710e575efefd 100644 --- a/crates/live_kit_client/src/prod.rs +++ b/crates/live_kit_client/src/prod.rs @@ -326,7 +326,10 @@ impl Room { } } - pub fn remote_audio_track_publications(&self, participant_id: &str) -> Vec> { + pub fn remote_audio_track_publications( + &self, + participant_id: &str, + ) -> Vec> { unsafe { let tracks = LKRoomAudioTrackPublicationsForRemoteParticipant( self.native_room, @@ -348,7 +351,6 @@ impl Room { } } - pub fn remote_audio_track_updates(&self) -> mpsc::UnboundedReceiver { let (tx, rx) = mpsc::unbounded(); self.remote_audio_track_subscribers.lock().push(tx); @@ -629,7 +631,6 @@ impl Drop for RemoteTrackPublication { } } - #[derive(Debug)] pub struct RemoteAudioTrack { _native_track: *const c_void, @@ -658,15 +659,11 @@ impl RemoteAudioTrack { } pub fn enable(&self) -> impl Future> { - async { - Ok(()) - } + async { Ok(()) } } pub fn disable(&self) -> impl Future> { - async { - Ok(()) - } + async { Ok(()) } } } diff --git a/crates/live_kit_client/src/test.rs b/crates/live_kit_client/src/test.rs index e8c5247f53cce581eda719486bb8f8538f98a9b7..9db57a329452b98893dc9815e8c3b3bb505de7b6 100644 --- a/crates/live_kit_client/src/test.rs +++ b/crates/live_kit_client/src/test.rs @@ -423,9 +423,7 @@ impl Room { .unwrap() .into_iter() .filter(|track| track.publisher_id() == publisher_id) - .map(|_track| { - Arc::new(RemoteTrackPublication {}) - }) + .map(|_track| Arc::new(RemoteTrackPublication {})) .collect() } @@ -495,7 +493,7 @@ impl Drop for Room { pub struct LocalTrackPublication; impl LocalTrackPublication { - pub fn set_mute(&self, _mute: bool) -> impl Future> { + pub fn set_mute(&self, _mute: bool) -> impl Future> { async { Ok(()) } } } From cf4251fb55f833555dba3dc6a5ef3f260281b8e5 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 20 Jun 2023 15:17:49 -0700 Subject: [PATCH 19/63] Fix deafened -> enabled mistranslation Fix mislocation of caller query in detach_and_log_error Fix incorrect wording on livekit integration Add share_mic action for manually enabling the microphone Make mic sharing wait until the room has been fully established --- crates/call/src/room.rs | 24 +++++++++++++----------- crates/collab_ui/src/collab_ui.rs | 9 ++++++++- crates/gpui/src/executor.rs | 2 +- crates/live_kit_client/src/prod.rs | 2 +- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 613a52a908d6e79c2f91e8b6ab94c932f363b78b..b673a0a874d3bd1ee0c0e69cf9b52663e3647d7c 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -220,15 +220,6 @@ impl Room { None }; - if option_env!("START_MIC").is_some() - || &*util::channel::RELEASE_CHANNEL != &ReleaseChannel::Dev - { - let share_mic = room.update(&mut cx, |room, cx| room.share_mic(cx)); - cx.update(|cx| { - cx.background().spawn(share_mic).detach_and_log_err(cx); - }); - } - match room .update(&mut cx, |room, cx| { room.leave_when_empty = true; @@ -236,7 +227,18 @@ impl Room { }) .await { - Ok(()) => Ok(room), + Ok(()) => { + if option_env!("START_MIC").is_some() + || &*util::channel::RELEASE_CHANNEL != &ReleaseChannel::Dev + { + let share_mic = room.update(&mut cx, |room, cx| room.share_mic(cx)); + cx.update(|cx| { + cx.background().spawn(share_mic).detach_and_log_err(cx); + }); + } + + Ok(room) + }, Err(error) => Err(anyhow!("room creation failed: {:?}", error)), } }) @@ -1201,7 +1203,7 @@ impl Room { .room .remote_audio_track_publications(&participant.user.id.to_string()) { - tasks.push(cx.background().spawn(track.set_enabled(live_kit.deafened))); + tasks.push(cx.background().spawn(track.set_enabled(!live_kit.deafened))); } } diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index 36ee58242a5928a3fe8304fde5bf6782d60b2ef9..4b5deaa0be64bbcceabe84b72256c4d01f6214bb 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -16,7 +16,7 @@ use std::sync::Arc; use util::ResultExt; use workspace::AppState; -actions!(collab, [ToggleScreenSharing, ToggleMute, ToggleDeafen]); +actions!(collab, [ToggleScreenSharing, ToggleMute, ToggleDeafen, ShareMic]); pub fn init(app_state: &Arc, cx: &mut AppContext) { collab_titlebar_item::init(cx); @@ -30,6 +30,7 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { cx.add_global_action(toggle_screen_sharing); cx.add_global_action(toggle_mute); cx.add_global_action(toggle_deafen); + cx.add_global_action(share_mic); } pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) { @@ -60,3 +61,9 @@ pub fn toggle_deafen(_: &ToggleDeafen, cx: &mut AppContext) { .log_err(); } } + +pub fn share_mic(_: &ShareMic, cx: &mut AppContext) { + if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { + room.update(cx, Room::share_mic).detach_and_log_err(cx) + } +} diff --git a/crates/gpui/src/executor.rs b/crates/gpui/src/executor.rs index fb175d9d5d10c679b2fe2dee2cda86b06f77b1fb..712c8544884af838a6d5cccdc5f6555a77b8014f 100644 --- a/crates/gpui/src/executor.rs +++ b/crates/gpui/src/executor.rs @@ -968,9 +968,9 @@ impl Task { impl Task> { #[track_caller] pub fn detach_and_log_err(self, cx: &mut AppContext) { + let caller = Location::caller(); cx.spawn(|_| async move { if let Err(err) = self.await { - let caller = Location::caller(); log::error!("{}:{}: {:#}", caller.file(), caller.line(), err); } }) diff --git a/crates/live_kit_client/src/prod.rs b/crates/live_kit_client/src/prod.rs index ed040fd5ccb9b39480a5259f55ba710e575efefd..2ec4f96dd5999e46bca92bbacb2bb0899e03bf9a 100644 --- a/crates/live_kit_client/src/prod.rs +++ b/crates/live_kit_client/src/prod.rs @@ -259,7 +259,7 @@ impl Room { Box::into_raw(Box::new(tx)) as *mut c_void, ); } - async { rx.await.unwrap().context("error publishing video track") } + async { rx.await.unwrap().context("error publishing audio track") } } pub fn unpublish_track(&self, publication: LocalTrackPublication) { From 8273e08d4a064158b28710c79ba87015318628c7 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 20 Jun 2023 15:23:06 -0700 Subject: [PATCH 20/63] Add is_muted and is_deafened --- crates/call/src/room.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index b673a0a874d3bd1ee0c0e69cf9b52663e3647d7c..a2ef65915625842eb4b705f64392ccab3182e7bb 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -1000,6 +1000,22 @@ impl Room { }) } + pub fn is_muted(&self) -> Option { + self.live_kit.as_ref().and_then(|live_kit| { + match &live_kit.microphone_track { + LocalTrack::None => None, + LocalTrack::Pending { muted, .. } => Some(*muted), + LocalTrack::Published { muted, .. } => Some(*muted), + } + }) + } + + pub fn is_deafened(&self) -> Option { + self.live_kit.as_ref().map(|live_kit| { + live_kit.deafened + }) + } + pub fn share_mic(&mut self, cx: &mut ModelContext) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); From 9b77cafd7b4e9a65f31bf1006751097a5b32c3ae Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 20 Jun 2023 15:35:19 -0700 Subject: [PATCH 21/63] Add a mic sharing to room joining --- crates/call/src/room.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index a2ef65915625842eb4b705f64392ccab3182e7bb..9f9a64c1acf4a1c0f1a57be87ae2c3372ae1e4c1 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -238,7 +238,7 @@ impl Room { } Ok(room) - }, + } Err(error) => Err(anyhow!("room creation failed: {:?}", error)), } }) @@ -266,6 +266,14 @@ impl Room { room.update(&mut cx, |room, cx| { room.leave_when_empty = true; room.apply_room_update(room_proto, cx)?; + + if option_env!("START_MIC").is_some() + || &*util::channel::RELEASE_CHANNEL != &ReleaseChannel::Dev + { + let share_mic = room.share_mic(cx); + cx.background().spawn(share_mic).detach_and_log_err(cx); + } + anyhow::Ok(()) })?; Ok(room) @@ -1001,19 +1009,17 @@ impl Room { } pub fn is_muted(&self) -> Option { - self.live_kit.as_ref().and_then(|live_kit| { - match &live_kit.microphone_track { + self.live_kit + .as_ref() + .and_then(|live_kit| match &live_kit.microphone_track { LocalTrack::None => None, LocalTrack::Pending { muted, .. } => Some(*muted), LocalTrack::Published { muted, .. } => Some(*muted), - } - }) + }) } pub fn is_deafened(&self) -> Option { - self.live_kit.as_ref().map(|live_kit| { - live_kit.deafened - }) + self.live_kit.as_ref().map(|live_kit| live_kit.deafened) } pub fn share_mic(&mut self, cx: &mut ModelContext) -> Task> { From 5ffe74f47e2a51d0f8e3ede963896157d2c1f215 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 21 Jun 2023 08:50:33 -0700 Subject: [PATCH 22/63] Fix race condition in sharing mic on connection co-authored-by: antonio --- crates/call/src/room.rs | 32 ++++++------------- crates/collab_ui/src/collab_ui.rs | 8 ++--- .../Sources/LiveKitBridge/LiveKitBridge.swift | 9 ++---- 3 files changed, 17 insertions(+), 32 deletions(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 9f9a64c1acf4a1c0f1a57be87ae2c3372ae1e4c1..22e59ac4671d8a8032c6e0a1b166ea1fb7be860e 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -148,8 +148,13 @@ impl Room { } }); - cx.foreground() - .spawn(room.connect(&connection_info.server_url, &connection_info.token)) + let connect = room.connect(&connection_info.server_url, &connection_info.token); + cx.spawn(|this, mut cx| async move { + connect.await?; + this.update(&mut cx, |this, cx| this.share_microphone(cx)).await?; + + anyhow::Ok(()) + }) .detach_and_log_err(cx); Some(LiveKitRoom { @@ -228,15 +233,6 @@ impl Room { .await { Ok(()) => { - if option_env!("START_MIC").is_some() - || &*util::channel::RELEASE_CHANNEL != &ReleaseChannel::Dev - { - let share_mic = room.update(&mut cx, |room, cx| room.share_mic(cx)); - cx.update(|cx| { - cx.background().spawn(share_mic).detach_and_log_err(cx); - }); - } - Ok(room) } Err(error) => Err(anyhow!("room creation failed: {:?}", error)), @@ -266,14 +262,6 @@ impl Room { room.update(&mut cx, |room, cx| { room.leave_when_empty = true; room.apply_room_update(room_proto, cx)?; - - if option_env!("START_MIC").is_some() - || &*util::channel::RELEASE_CHANNEL != &ReleaseChannel::Dev - { - let share_mic = room.share_mic(cx); - cx.background().spawn(share_mic).detach_and_log_err(cx); - } - anyhow::Ok(()) })?; Ok(room) @@ -1022,7 +1010,7 @@ impl Room { self.live_kit.as_ref().map(|live_kit| live_kit.deafened) } - pub fn share_mic(&mut self, cx: &mut ModelContext) -> Task> { + pub fn share_microphone(&mut self, cx: &mut ModelContext) -> Task> { if self.status.is_offline() { return Task::ready(Err(anyhow!("room is offline"))); } else if self.is_sharing_mic() { @@ -1225,11 +1213,11 @@ impl Room { .room .remote_audio_track_publications(&participant.user.id.to_string()) { - tasks.push(cx.background().spawn(track.set_enabled(!live_kit.deafened))); + tasks.push(cx.foreground().spawn(track.set_enabled(!live_kit.deafened))); } } - Ok(cx.background().spawn(async move { + Ok(cx.foreground().spawn(async move { for task in tasks { task.await?; } diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index 4b5deaa0be64bbcceabe84b72256c4d01f6214bb..e9c2bcf7f91595e93c2de4d5edeb2546a2494714 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -16,7 +16,7 @@ use std::sync::Arc; use util::ResultExt; use workspace::AppState; -actions!(collab, [ToggleScreenSharing, ToggleMute, ToggleDeafen, ShareMic]); +actions!(collab, [ToggleScreenSharing, ToggleMute, ToggleDeafen, ShareMicrophone]); pub fn init(app_state: &Arc, cx: &mut AppContext) { collab_titlebar_item::init(cx); @@ -30,7 +30,7 @@ pub fn init(app_state: &Arc, cx: &mut AppContext) { cx.add_global_action(toggle_screen_sharing); cx.add_global_action(toggle_mute); cx.add_global_action(toggle_deafen); - cx.add_global_action(share_mic); + cx.add_global_action(share_microphone); } pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) { @@ -62,8 +62,8 @@ pub fn toggle_deafen(_: &ToggleDeafen, cx: &mut AppContext) { } } -pub fn share_mic(_: &ShareMic, cx: &mut AppContext) { +pub fn share_microphone(_: &ShareMicrophone, cx: &mut AppContext) { if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - room.update(cx, Room::share_mic).detach_and_log_err(cx) + room.update(cx, Room::share_microphone).detach_and_log_err(cx) } } diff --git a/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift b/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift index 666da3d5332d9506054bfe2bf86bd9824fe3bf8f..74d43d78659d12cd1587914f2814185a82e01f68 100644 --- a/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift +++ b/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift @@ -10,7 +10,7 @@ class LKRoomDelegate: RoomDelegate { var onDidUnsubscribeFromRemoteAudioTrack: @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void var onDidSubscribeToRemoteVideoTrack: @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer) -> Void var onDidUnsubscribeFromRemoteVideoTrack: @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void - + init( data: UnsafeRawPointer, onDidDisconnect: @escaping @convention(c) (UnsafeRawPointer) -> Void, @@ -40,7 +40,7 @@ class LKRoomDelegate: RoomDelegate { self.onDidSubscribeToRemoteAudioTrack(self.data, participant.identity as CFString, track.sid! as CFString, Unmanaged.passUnretained(track).toOpaque()) } } - + func room(_ room: Room, participant: RemoteParticipant, didUnsubscribe publication: RemoteTrackPublication, track: Track) { if track.kind == .video { self.onDidUnsubscribeFromRemoteVideoTrack(self.data, participant.identity as CFString, track.sid! as CFString) @@ -279,13 +279,10 @@ public func LKRemoteTrackPublicationSetEnabled( callback_data: UnsafeRawPointer ) { let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() - + publication.set(enabled: enabled).then { on_complete(callback_data, nil) }.catch { error in on_complete(callback_data, error.localizedDescription as CFString) } } - - - From 05c97ed355b3c255f4322c5823c05a96c43a1b26 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 21 Jun 2023 09:05:36 -0700 Subject: [PATCH 23/63] Fix segfault with remote track publications co-authored-by: antonio --- crates/live_kit_client/src/prod.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/crates/live_kit_client/src/prod.rs b/crates/live_kit_client/src/prod.rs index 2ec4f96dd5999e46bca92bbacb2bb0899e03bf9a..dbd9e1917e6ee2151b701728afcdebee7f98dfb5 100644 --- a/crates/live_kit_client/src/prod.rs +++ b/crates/live_kit_client/src/prod.rs @@ -219,7 +219,7 @@ impl Room { let tx = unsafe { Box::from_raw(tx as *mut oneshot::Sender>) }; if error.is_null() { - let _ = tx.send(Ok(LocalTrackPublication(publication))); + let _ = tx.send(Ok(LocalTrackPublication::new(publication))); } else { let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; let _ = tx.send(Err(anyhow!(error))); @@ -245,7 +245,7 @@ impl Room { let tx = unsafe { Box::from_raw(tx as *mut oneshot::Sender>) }; if error.is_null() { - let _ = tx.send(Ok(LocalTrackPublication(publication))); + let _ = tx.send(Ok(LocalTrackPublication::new(publication))); } else { let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; let _ = tx.send(Err(anyhow!(error))); @@ -344,7 +344,7 @@ impl Room { .into_iter() .map(|native_track_publication| { let native_track_publication = *native_track_publication; - Arc::new(RemoteTrackPublication(native_track_publication)) + Arc::new(RemoteTrackPublication::new(native_track_publication)) }) .collect() } @@ -564,6 +564,13 @@ impl Drop for LocalVideoTrack { pub struct LocalTrackPublication(*const c_void); impl LocalTrackPublication { + pub fn new(native_track_publication: *const c_void) -> Self { + unsafe { + CFRetain(native_track_publication); + } + Self(native_track_publication) + } + pub fn set_mute(&self, muted: bool) -> impl Future> { let (tx, rx) = futures::channel::oneshot::channel(); @@ -599,6 +606,13 @@ impl Drop for LocalTrackPublication { pub struct RemoteTrackPublication(*const c_void); impl RemoteTrackPublication { + pub fn new(native_track_publication: *const c_void) -> Self { + unsafe { + CFRetain(native_track_publication); + } + Self(native_track_publication) + } + pub fn set_enabled(&self, enabled: bool) -> impl Future> { let (tx, rx) = futures::channel::oneshot::channel(); From 4583d22ede058bce747142df33fc2f93625fa3ba Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 22 Jun 2023 13:49:36 +0200 Subject: [PATCH 24/63] cargo fmt --- crates/call/src/room.rs | 15 +++++++-------- crates/collab_ui/src/collab_ui.rs | 13 +++++++++++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 22e59ac4671d8a8032c6e0a1b166ea1fb7be860e..77f22ea2ca1e14cc659955adb3651d8746aed450 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -150,12 +150,13 @@ impl Room { let connect = room.connect(&connection_info.server_url, &connection_info.token); cx.spawn(|this, mut cx| async move { - connect.await?; - this.update(&mut cx, |this, cx| this.share_microphone(cx)).await?; + connect.await?; + this.update(&mut cx, |this, cx| this.share_microphone(cx)) + .await?; - anyhow::Ok(()) - }) - .detach_and_log_err(cx); + anyhow::Ok(()) + }) + .detach_and_log_err(cx); Some(LiveKitRoom { room, @@ -232,9 +233,7 @@ impl Room { }) .await { - Ok(()) => { - Ok(room) - } + Ok(()) => Ok(room), Err(error) => Err(anyhow!("room creation failed: {:?}", error)), } }) diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index e9c2bcf7f91595e93c2de4d5edeb2546a2494714..38a39762f4c4e34317d1c78ad041b9d988cef75d 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -16,7 +16,15 @@ use std::sync::Arc; use util::ResultExt; use workspace::AppState; -actions!(collab, [ToggleScreenSharing, ToggleMute, ToggleDeafen, ShareMicrophone]); +actions!( + collab, + [ + ToggleScreenSharing, + ToggleMute, + ToggleDeafen, + ShareMicrophone + ] +); pub fn init(app_state: &Arc, cx: &mut AppContext) { collab_titlebar_item::init(cx); @@ -64,6 +72,7 @@ pub fn toggle_deafen(_: &ToggleDeafen, cx: &mut AppContext) { pub fn share_microphone(_: &ShareMicrophone, cx: &mut AppContext) { if let Some(room) = ActiveCall::global(cx).read(cx).room().cloned() { - room.update(cx, Room::share_microphone).detach_and_log_err(cx) + room.update(cx, Room::share_microphone) + .detach_and_log_err(cx) } } From 85d1c89d34868b9de3fec5f7e5166e5f368fce53 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 22 Jun 2023 13:52:21 +0200 Subject: [PATCH 25/63] Remove unused import --- crates/call/src/room.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 77f22ea2ca1e14cc659955adb3651d8746aed450..0c0855fd6cb48a3fc3f62ea3f3c2f7ab448f5702 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -19,7 +19,7 @@ use live_kit_client::{ use postage::stream::Stream; use project::Project; use std::{future::Future, mem, pin::Pin, sync::Arc, time::Duration}; -use util::{channel::ReleaseChannel, post_inc, ResultExt, TryFutureExt}; +use util::{post_inc, ResultExt, TryFutureExt}; pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30); From bdccdaca1c679dcd3bd8cdedf17d65cce8d77fe4 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 22 Jun 2023 13:57:41 +0200 Subject: [PATCH 26/63] Remove unused variable --- crates/collab_ui/src/collab_titlebar_item.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 80af71f06e019eb121fb5b36ed26a09f07bddc95..740af0254d7927e7cf450a19c06acbe861155c4a 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -505,7 +505,6 @@ impl CollabTitlebarItem { ) -> AnyElement { let titlebar = &theme.workspace.titlebar; let avatar_style = &theme.workspace.titlebar.follower_avatar; - let active = self.user_menu.read(cx).visible(); Stack::new() .with_child( MouseEventHandler::::new(0, cx, |state, _| { From bee6c591546d8a86220fa92a9a56e6bd8724b4cf Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 22 Jun 2023 16:28:05 +0200 Subject: [PATCH 27/63] Add caret next to user avatar --- crates/collab_ui/src/collab_titlebar_item.rs | 27 ++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 740af0254d7927e7cf450a19c06acbe861155c4a..1d7884fcb7ba99c1b5a0fb78259076a03d2a4409 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -510,19 +510,26 @@ impl CollabTitlebarItem { MouseEventHandler::::new(0, cx, |state, _| { let style = titlebar.call_control.style_for(state); - let img = if let Some(avatar_img) = avatar { - Self::render_face(avatar_img, *avatar_style, Color::transparent_black()) - } else { - Svg::new("icons/ellipsis_14.svg") - .with_color(style.color) - .into_any() + let mut dropdown = Flex::row().align_children_center(); + + if let Some(avatar_img) = avatar { + dropdown = dropdown.with_child(Self::render_face( + avatar_img, + *avatar_style, + Color::transparent_black(), + )); }; - - img.constrained() - .with_width(style.icon_width) + dropdown + .with_child( + Svg::new("icons/caret_down_8.svg") + .with_color(style.color) + .constrained() + .with_width(style.icon_width) + .contained() + .into_any(), + ) .aligned() .constrained() - .with_width(style.button_width) .with_height(style.button_width) .contained() .with_style(style.container) From b16b6dcec7ac8852d93a88028d6ddf11d5eb60e4 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 22 Jun 2023 17:40:29 +0200 Subject: [PATCH 28/63] Render microphone toggle --- assets/icons/microphone_active_12.svg | 4 ++ assets/icons/microphone_inactive_12.svg | 5 ++ crates/collab_ui/src/collab_titlebar_item.rs | 54 ++++++++++++++++++-- 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 assets/icons/microphone_active_12.svg create mode 100644 assets/icons/microphone_inactive_12.svg diff --git a/assets/icons/microphone_active_12.svg b/assets/icons/microphone_active_12.svg new file mode 100644 index 0000000000000000000000000000000000000000..797e64820b5b7b358e6951fe1d6178b7ca1a6908 --- /dev/null +++ b/assets/icons/microphone_active_12.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/icons/microphone_inactive_12.svg b/assets/icons/microphone_inactive_12.svg new file mode 100644 index 0000000000000000000000000000000000000000..90ac393fc20fe9bb8877f82b416728887da72757 --- /dev/null +++ b/assets/icons/microphone_inactive_12.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 1d7884fcb7ba99c1b5a0fb78259076a03d2a4409..c0603421bc961312a4927fa9127f0f7dfcac5c19 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -1,6 +1,6 @@ use crate::{ - contact_notification::ContactNotification, contacts_popover, face_pile::FacePile, - toggle_screen_sharing, ToggleScreenSharing, + contact_notification::ContactNotification, contacts_popover, face_pile::FacePile, toggle_mute, + toggle_screen_sharing, ToggleMute, ToggleScreenSharing, }; use call::{ActiveCall, ParticipantLocation, Room}; use client::{proto::PeerId, Client, ContactEventKind, SignIn, SignOut, User, UserStore}; @@ -88,6 +88,7 @@ impl View for CollabTitlebarItem { left_container .add_child(self.render_current_user(&workspace, &theme, &user, peer_id, cx)); left_container.add_children(self.render_collaborators(&workspace, &theme, &room, cx)); + right_container.add_child(self.render_toggle_microphone(&theme, &room, cx)); right_container.add_child(self.render_toggle_screen_sharing_button(&theme, &room, cx)); } @@ -396,7 +397,6 @@ impl CollabTitlebarItem { .with_children(self.render_contacts_popover_host(titlebar, cx)) .into_any() } - fn render_toggle_screen_sharing_button( &self, theme: &Theme, @@ -441,6 +441,54 @@ impl CollabTitlebarItem { .aligned() .into_any() } + fn render_toggle_microphone( + &self, + theme: &Theme, + room: &ModelHandle, + cx: &mut ViewContext, + ) -> AnyElement { + let icon; + let tooltip; + let background; + if room.read(cx).is_muted().unwrap_or(false) { + icon = "icons/microphone_inactive_12.svg"; + tooltip = "Unmute microphone\nRight click for options"; + background = Color::red(); + } else { + icon = "icons/microphone_active_12.svg"; + tooltip = "Mute microphone\nRight click for options"; + background = Color::transparent_black(); + } + + let titlebar = &theme.workspace.titlebar; + MouseEventHandler::::new(0, cx, |state, _| { + let style = titlebar.call_control.style_for(state); + Svg::new(icon) + .with_color(style.color) + .constrained() + .with_width(style.icon_width) + .aligned() + .constrained() + .with_width(style.button_width) + .with_height(style.button_width) + .contained() + .with_style(style.container) + .with_background_color(background) + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, move |_, _, cx| { + toggle_mute(&Default::default(), cx) + }) + .with_tooltip::( + 0, + tooltip.into(), + Some(Box::new(ToggleMute)), + theme.tooltip.clone(), + cx, + ) + .aligned() + .into_any() + } fn render_in_call_share_unshare_button( &self, From 05730afdf0d12945ad63534809d419db37a59d95 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 22 Jun 2023 11:58:51 -0400 Subject: [PATCH 29/63] Add radix icons There are a lot of them, but they add less than 350kb to the app --- assets/icons/radix/accessibility.svg | 8 ++ assets/icons/radix/activity-log.svg | 8 ++ assets/icons/radix/align-baseline.svg | 8 ++ assets/icons/radix/align-bottom.svg | 8 ++ .../icons/radix/align-center-horizontally.svg | 8 ++ .../icons/radix/align-center-vertically.svg | 8 ++ assets/icons/radix/align-center.svg | 8 ++ assets/icons/radix/align-end.svg | 8 ++ .../icons/radix/align-horizontal-centers.svg | 8 ++ assets/icons/radix/align-left.svg | 8 ++ assets/icons/radix/align-right.svg | 8 ++ assets/icons/radix/align-start.svg | 8 ++ assets/icons/radix/align-stretch.svg | 8 ++ assets/icons/radix/align-top.svg | 8 ++ assets/icons/radix/align-vertical-centers.svg | 8 ++ assets/icons/radix/all-sides.svg | 8 ++ assets/icons/radix/angle.svg | 8 ++ assets/icons/radix/archive.svg | 8 ++ assets/icons/radix/arrow-bottom-left.svg | 8 ++ assets/icons/radix/arrow-bottom-right.svg | 8 ++ assets/icons/radix/arrow-down.svg | 8 ++ assets/icons/radix/arrow-left.svg | 8 ++ assets/icons/radix/arrow-right.svg | 8 ++ assets/icons/radix/arrow-top-left.svg | 8 ++ assets/icons/radix/arrow-top-right.svg | 8 ++ assets/icons/radix/arrow-up.svg | 8 ++ assets/icons/radix/aspect-ratio.svg | 8 ++ assets/icons/radix/avatar.svg | 8 ++ assets/icons/radix/backpack.svg | 8 ++ assets/icons/radix/badge.svg | 8 ++ assets/icons/radix/bar-chart.svg | 8 ++ assets/icons/radix/bell.svg | 8 ++ assets/icons/radix/blending-mode.svg | 8 ++ assets/icons/radix/bookmark-filled.svg | 8 ++ assets/icons/radix/bookmark.svg | 8 ++ assets/icons/radix/border-all.svg | 17 ++++ assets/icons/radix/border-bottom.svg | 29 +++++++ assets/icons/radix/border-dashed.svg | 8 ++ assets/icons/radix/border-dotted.svg | 8 ++ assets/icons/radix/border-left.svg | 29 +++++++ assets/icons/radix/border-none.svg | 35 +++++++++ assets/icons/radix/border-right.svg | 29 +++++++ assets/icons/radix/border-solid.svg | 8 ++ assets/icons/radix/border-split.svg | 21 +++++ assets/icons/radix/border-style.svg | 8 ++ assets/icons/radix/border-top.svg | 29 +++++++ assets/icons/radix/border-width.svg | 8 ++ assets/icons/radix/box-model.svg | 8 ++ assets/icons/radix/box.svg | 8 ++ assets/icons/radix/button.svg | 8 ++ assets/icons/radix/calendar.svg | 8 ++ assets/icons/radix/camera.svg | 8 ++ assets/icons/radix/card-stack-minus.svg | 8 ++ assets/icons/radix/card-stack-plus.svg | 8 ++ assets/icons/radix/card-stack.svg | 8 ++ assets/icons/radix/caret-down.svg | 8 ++ assets/icons/radix/caret-left.svg | 8 ++ assets/icons/radix/caret-right.svg | 8 ++ assets/icons/radix/caret-sort.svg | 8 ++ assets/icons/radix/caret-up.svg | 8 ++ assets/icons/radix/chat-bubble.svg | 8 ++ assets/icons/radix/check-circled.svg | 8 ++ assets/icons/radix/check.svg | 8 ++ assets/icons/radix/checkbox.svg | 8 ++ assets/icons/radix/chevron-down.svg | 8 ++ assets/icons/radix/chevron-left.svg | 8 ++ assets/icons/radix/chevron-right.svg | 8 ++ assets/icons/radix/chevron-up.svg | 8 ++ assets/icons/radix/circle-backslash.svg | 8 ++ assets/icons/radix/circle.svg | 8 ++ assets/icons/radix/clipboard-copy.svg | 8 ++ assets/icons/radix/clipboard.svg | 8 ++ assets/icons/radix/clock.svg | 8 ++ assets/icons/radix/code.svg | 8 ++ assets/icons/radix/codesandbox-logo.svg | 8 ++ assets/icons/radix/color-wheel.svg | 8 ++ assets/icons/radix/column-spacing.svg | 8 ++ assets/icons/radix/columns.svg | 8 ++ assets/icons/radix/commit.svg | 8 ++ assets/icons/radix/component-1.svg | 8 ++ assets/icons/radix/component-2.svg | 8 ++ assets/icons/radix/component-boolean.svg | 8 ++ assets/icons/radix/component-instance.svg | 8 ++ assets/icons/radix/component-none.svg | 8 ++ assets/icons/radix/component-placeholder.svg | 12 +++ assets/icons/radix/container.svg | 8 ++ assets/icons/radix/cookie.svg | 8 ++ assets/icons/radix/copy.svg | 8 ++ assets/icons/radix/corner-bottom-left.svg | 8 ++ assets/icons/radix/corner-bottom-right.svg | 8 ++ assets/icons/radix/corner-top-left.svg | 8 ++ assets/icons/radix/corner-top-right.svg | 8 ++ assets/icons/radix/corners.svg | 8 ++ assets/icons/radix/countdown-timer.svg | 8 ++ .../icons/radix/counter-clockwise-clock.svg | 8 ++ assets/icons/radix/crop.svg | 8 ++ assets/icons/radix/cross-1.svg | 8 ++ assets/icons/radix/cross-2.svg | 8 ++ assets/icons/radix/cross-circled.svg | 8 ++ assets/icons/radix/crosshair-1.svg | 8 ++ assets/icons/radix/crosshair-2.svg | 8 ++ assets/icons/radix/crumpled-paper.svg | 8 ++ assets/icons/radix/cube.svg | 8 ++ assets/icons/radix/cursor-arrow.svg | 8 ++ assets/icons/radix/cursor-text.svg | 8 ++ assets/icons/radix/dash.svg | 8 ++ assets/icons/radix/dashboard.svg | 8 ++ assets/icons/radix/desktop.svg | 8 ++ assets/icons/radix/dimensions.svg | 8 ++ assets/icons/radix/disc.svg | 8 ++ assets/icons/radix/discord-logo.svg | 13 ++++ assets/icons/radix/divider-horizontal.svg | 8 ++ assets/icons/radix/divider-vertical.svg | 8 ++ assets/icons/radix/dot-filled.svg | 6 ++ assets/icons/radix/dot-solid.svg | 6 ++ assets/icons/radix/dot.svg | 8 ++ assets/icons/radix/dots-horizontal.svg | 8 ++ assets/icons/radix/dots-vertical.svg | 8 ++ assets/icons/radix/double-arrow-down.svg | 8 ++ assets/icons/radix/double-arrow-left.svg | 8 ++ assets/icons/radix/double-arrow-right.svg | 8 ++ assets/icons/radix/double-arrow-up.svg | 8 ++ assets/icons/radix/download.svg | 8 ++ assets/icons/radix/drag-handle-dots-1.svg | 26 +++++++ assets/icons/radix/drag-handle-dots-2.svg | 8 ++ assets/icons/radix/drag-handle-horizontal.svg | 8 ++ assets/icons/radix/drag-handle-vertical.svg | 8 ++ assets/icons/radix/drawing-pin-filled.svg | 14 ++++ assets/icons/radix/drawing-pin-solid.svg | 14 ++++ assets/icons/radix/drawing-pin.svg | 8 ++ assets/icons/radix/dropdown-menu.svg | 8 ++ assets/icons/radix/enter-full-screen.svg | 8 ++ assets/icons/radix/enter.svg | 8 ++ assets/icons/radix/envelope-closed.svg | 8 ++ assets/icons/radix/envelope-open.svg | 8 ++ assets/icons/radix/eraser.svg | 8 ++ assets/icons/radix/exclamation-triangle.svg | 8 ++ assets/icons/radix/exit-full-screen.svg | 8 ++ assets/icons/radix/exit.svg | 8 ++ assets/icons/radix/external-link.svg | 8 ++ assets/icons/radix/eye-closed.svg | 8 ++ assets/icons/radix/eye-none.svg | 8 ++ assets/icons/radix/eye-open.svg | 8 ++ assets/icons/radix/face.svg | 8 ++ assets/icons/radix/figma-logo.svg | 8 ++ assets/icons/radix/file-minus.svg | 8 ++ assets/icons/radix/file-plus.svg | 8 ++ assets/icons/radix/file-text.svg | 8 ++ assets/icons/radix/file.svg | 8 ++ assets/icons/radix/font-bold.svg | 6 ++ assets/icons/radix/font-family.svg | 6 ++ assets/icons/radix/font-italic.svg | 8 ++ assets/icons/radix/font-roman.svg | 8 ++ assets/icons/radix/font-size.svg | 8 ++ assets/icons/radix/font-style.svg | 8 ++ assets/icons/radix/frame.svg | 8 ++ assets/icons/radix/framer-logo.svg | 8 ++ assets/icons/radix/gear.svg | 8 ++ assets/icons/radix/github-logo.svg | 8 ++ assets/icons/radix/globe.svg | 26 +++++++ assets/icons/radix/grid.svg | 8 ++ assets/icons/radix/group.svg | 8 ++ assets/icons/radix/half-1.svg | 8 ++ assets/icons/radix/half-2.svg | 8 ++ assets/icons/radix/hamburger-menu.svg | 8 ++ assets/icons/radix/hand.svg | 8 ++ assets/icons/radix/heading.svg | 8 ++ assets/icons/radix/heart-filled.svg | 8 ++ assets/icons/radix/heart.svg | 8 ++ assets/icons/radix/height.svg | 8 ++ assets/icons/radix/hobby-knife.svg | 8 ++ assets/icons/radix/home.svg | 8 ++ assets/icons/radix/iconjar-logo.svg | 8 ++ assets/icons/radix/id-card.svg | 8 ++ assets/icons/radix/image.svg | 8 ++ assets/icons/radix/info-circled.svg | 8 ++ assets/icons/radix/inner-shadow.svg | 78 +++++++++++++++++++ assets/icons/radix/input.svg | 8 ++ assets/icons/radix/instagram-logo.svg | 8 ++ assets/icons/radix/justify-center.svg | 8 ++ assets/icons/radix/justify-end.svg | 8 ++ assets/icons/radix/justify-start.svg | 8 ++ assets/icons/radix/justify-stretch.svg | 8 ++ assets/icons/radix/keyboard.svg | 7 ++ assets/icons/radix/lap-timer.svg | 8 ++ assets/icons/radix/laptop.svg | 8 ++ assets/icons/radix/layers.svg | 8 ++ assets/icons/radix/layout.svg | 8 ++ assets/icons/radix/letter-case-capitalize.svg | 8 ++ assets/icons/radix/letter-case-lowercase.svg | 8 ++ assets/icons/radix/letter-case-toggle.svg | 8 ++ assets/icons/radix/letter-case-uppercase.svg | 8 ++ assets/icons/radix/letter-spacing.svg | 8 ++ assets/icons/radix/lightning-bolt.svg | 8 ++ assets/icons/radix/line-height.svg | 8 ++ assets/icons/radix/link-1.svg | 8 ++ assets/icons/radix/link-2.svg | 8 ++ assets/icons/radix/link-break-1.svg | 8 ++ assets/icons/radix/link-break-2.svg | 8 ++ assets/icons/radix/link-none-1.svg | 8 ++ assets/icons/radix/link-none-2.svg | 8 ++ assets/icons/radix/linkedin-logo.svg | 8 ++ assets/icons/radix/list-bullet.svg | 8 ++ assets/icons/radix/lock-closed.svg | 8 ++ assets/icons/radix/lock-open-1.svg | 8 ++ assets/icons/radix/lock-open-2.svg | 8 ++ assets/icons/radix/loop.svg | 8 ++ assets/icons/radix/magic-wand.svg | 8 ++ assets/icons/radix/magnifying-glass.svg | 8 ++ assets/icons/radix/margin.svg | 8 ++ assets/icons/radix/mask-off.svg | 8 ++ assets/icons/radix/mask-on.svg | 8 ++ assets/icons/radix/minus-circled.svg | 8 ++ assets/icons/radix/minus.svg | 8 ++ assets/icons/radix/mix.svg | 8 ++ assets/icons/radix/mixer-horizontal.svg | 8 ++ assets/icons/radix/mixer-vertical.svg | 8 ++ assets/icons/radix/mobile.svg | 8 ++ assets/icons/radix/modulz-logo.svg | 8 ++ assets/icons/radix/moon.svg | 8 ++ assets/icons/radix/move.svg | 8 ++ assets/icons/radix/notion-logo.svg | 6 ++ assets/icons/radix/opacity.svg | 8 ++ assets/icons/radix/open-in-new-window.svg | 10 +++ assets/icons/radix/outer-shadow.svg | 43 ++++++++++ assets/icons/radix/overline.svg | 8 ++ assets/icons/radix/padding.svg | 8 ++ assets/icons/radix/paper-plane.svg | 8 ++ assets/icons/radix/pause.svg | 8 ++ assets/icons/radix/pencil-1.svg | 8 ++ assets/icons/radix/pencil-2.svg | 8 ++ assets/icons/radix/person.svg | 8 ++ assets/icons/radix/pie-chart.svg | 8 ++ assets/icons/radix/pilcrow.svg | 8 ++ assets/icons/radix/pin-bottom.svg | 8 ++ assets/icons/radix/pin-left.svg | 8 ++ assets/icons/radix/pin-right.svg | 8 ++ assets/icons/radix/pin-top.svg | 8 ++ assets/icons/radix/play.svg | 8 ++ assets/icons/radix/plus-circled.svg | 8 ++ assets/icons/radix/plus.svg | 8 ++ assets/icons/radix/question-mark-circled.svg | 8 ++ assets/icons/radix/question-mark.svg | 8 ++ assets/icons/radix/quote.svg | 8 ++ assets/icons/radix/radiobutton.svg | 8 ++ assets/icons/radix/reader.svg | 8 ++ assets/icons/radix/reload.svg | 8 ++ assets/icons/radix/reset.svg | 8 ++ assets/icons/radix/resume.svg | 8 ++ assets/icons/radix/rocket.svg | 8 ++ .../icons/radix/rotate-counter-clockwise.svg | 8 ++ assets/icons/radix/row-spacing.svg | 8 ++ assets/icons/radix/rows.svg | 8 ++ assets/icons/radix/ruler-horizontal.svg | 8 ++ assets/icons/radix/ruler-square.svg | 8 ++ assets/icons/radix/scissors.svg | 8 ++ assets/icons/radix/section.svg | 8 ++ assets/icons/radix/sewing-pin-filled.svg | 8 ++ assets/icons/radix/sewing-pin-solid.svg | 8 ++ assets/icons/radix/sewing-pin.svg | 8 ++ assets/icons/radix/shadow-inner.svg | 78 +++++++++++++++++++ assets/icons/radix/shadow-none.svg | 78 +++++++++++++++++++ assets/icons/radix/shadow-outer.svg | 43 ++++++++++ assets/icons/radix/shadow.svg | 78 +++++++++++++++++++ assets/icons/radix/share-1.svg | 8 ++ assets/icons/radix/share-2.svg | 8 ++ assets/icons/radix/shuffle.svg | 8 ++ assets/icons/radix/size.svg | 8 ++ assets/icons/radix/sketch-logo.svg | 8 ++ assets/icons/radix/slash.svg | 8 ++ assets/icons/radix/slider.svg | 8 ++ .../radix/space-between-horizontally.svg | 8 ++ .../icons/radix/space-between-vertically.svg | 8 ++ .../icons/radix/space-evenly-horizontally.svg | 8 ++ .../icons/radix/space-evenly-vertically.svg | 8 ++ assets/icons/radix/speaker-loud.svg | 8 ++ assets/icons/radix/speaker-moderate.svg | 8 ++ assets/icons/radix/speaker-off.svg | 8 ++ assets/icons/radix/speaker-quiet.svg | 8 ++ assets/icons/radix/square.svg | 8 ++ assets/icons/radix/stack.svg | 8 ++ assets/icons/radix/star-filled.svg | 6 ++ assets/icons/radix/star.svg | 8 ++ assets/icons/radix/stitches-logo.svg | 8 ++ assets/icons/radix/stop.svg | 8 ++ assets/icons/radix/stopwatch.svg | 8 ++ assets/icons/radix/stretch-horizontally.svg | 8 ++ assets/icons/radix/stretch-vertically.svg | 8 ++ assets/icons/radix/strikethrough.svg | 8 ++ assets/icons/radix/sun.svg | 8 ++ assets/icons/radix/switch.svg | 8 ++ assets/icons/radix/symbol.svg | 8 ++ assets/icons/radix/table.svg | 8 ++ assets/icons/radix/target.svg | 8 ++ assets/icons/radix/text-align-bottom.svg | 8 ++ assets/icons/radix/text-align-center.svg | 8 ++ assets/icons/radix/text-align-justify.svg | 8 ++ assets/icons/radix/text-align-left.svg | 8 ++ assets/icons/radix/text-align-middle.svg | 8 ++ assets/icons/radix/text-align-right.svg | 8 ++ assets/icons/radix/text-align-top.svg | 8 ++ assets/icons/radix/text-none.svg | 8 ++ assets/icons/radix/text.svg | 8 ++ assets/icons/radix/thick-arrow-down.svg | 8 ++ assets/icons/radix/thick-arrow-left.svg | 8 ++ assets/icons/radix/thick-arrow-right.svg | 8 ++ assets/icons/radix/thick-arrow-up.svg | 8 ++ assets/icons/radix/timer.svg | 8 ++ assets/icons/radix/tokens.svg | 8 ++ assets/icons/radix/track-next.svg | 8 ++ assets/icons/radix/track-previous.svg | 8 ++ assets/icons/radix/transform.svg | 8 ++ assets/icons/radix/transparency-grid.svg | 9 +++ assets/icons/radix/trash.svg | 8 ++ assets/icons/radix/triangle-down.svg | 3 + assets/icons/radix/triangle-left.svg | 3 + assets/icons/radix/triangle-right.svg | 3 + assets/icons/radix/triangle-up.svg | 3 + assets/icons/radix/twitter-logo.svg | 8 ++ assets/icons/radix/underline.svg | 8 ++ assets/icons/radix/update.svg | 8 ++ assets/icons/radix/upload.svg | 8 ++ assets/icons/radix/value-none.svg | 8 ++ assets/icons/radix/value.svg | 8 ++ assets/icons/radix/vercel-logo.svg | 8 ++ assets/icons/radix/video.svg | 8 ++ assets/icons/radix/view-grid.svg | 8 ++ assets/icons/radix/view-horizontal.svg | 8 ++ assets/icons/radix/view-none.svg | 8 ++ assets/icons/radix/view-vertical.svg | 8 ++ assets/icons/radix/width.svg | 8 ++ assets/icons/radix/zoom-in.svg | 8 ++ assets/icons/radix/zoom-out.svg | 8 ++ 333 files changed, 3174 insertions(+) create mode 100644 assets/icons/radix/accessibility.svg create mode 100644 assets/icons/radix/activity-log.svg create mode 100644 assets/icons/radix/align-baseline.svg create mode 100644 assets/icons/radix/align-bottom.svg create mode 100644 assets/icons/radix/align-center-horizontally.svg create mode 100644 assets/icons/radix/align-center-vertically.svg create mode 100644 assets/icons/radix/align-center.svg create mode 100644 assets/icons/radix/align-end.svg create mode 100644 assets/icons/radix/align-horizontal-centers.svg create mode 100644 assets/icons/radix/align-left.svg create mode 100644 assets/icons/radix/align-right.svg create mode 100644 assets/icons/radix/align-start.svg create mode 100644 assets/icons/radix/align-stretch.svg create mode 100644 assets/icons/radix/align-top.svg create mode 100644 assets/icons/radix/align-vertical-centers.svg create mode 100644 assets/icons/radix/all-sides.svg create mode 100644 assets/icons/radix/angle.svg create mode 100644 assets/icons/radix/archive.svg create mode 100644 assets/icons/radix/arrow-bottom-left.svg create mode 100644 assets/icons/radix/arrow-bottom-right.svg create mode 100644 assets/icons/radix/arrow-down.svg create mode 100644 assets/icons/radix/arrow-left.svg create mode 100644 assets/icons/radix/arrow-right.svg create mode 100644 assets/icons/radix/arrow-top-left.svg create mode 100644 assets/icons/radix/arrow-top-right.svg create mode 100644 assets/icons/radix/arrow-up.svg create mode 100644 assets/icons/radix/aspect-ratio.svg create mode 100644 assets/icons/radix/avatar.svg create mode 100644 assets/icons/radix/backpack.svg create mode 100644 assets/icons/radix/badge.svg create mode 100644 assets/icons/radix/bar-chart.svg create mode 100644 assets/icons/radix/bell.svg create mode 100644 assets/icons/radix/blending-mode.svg create mode 100644 assets/icons/radix/bookmark-filled.svg create mode 100644 assets/icons/radix/bookmark.svg create mode 100644 assets/icons/radix/border-all.svg create mode 100644 assets/icons/radix/border-bottom.svg create mode 100644 assets/icons/radix/border-dashed.svg create mode 100644 assets/icons/radix/border-dotted.svg create mode 100644 assets/icons/radix/border-left.svg create mode 100644 assets/icons/radix/border-none.svg create mode 100644 assets/icons/radix/border-right.svg create mode 100644 assets/icons/radix/border-solid.svg create mode 100644 assets/icons/radix/border-split.svg create mode 100644 assets/icons/radix/border-style.svg create mode 100644 assets/icons/radix/border-top.svg create mode 100644 assets/icons/radix/border-width.svg create mode 100644 assets/icons/radix/box-model.svg create mode 100644 assets/icons/radix/box.svg create mode 100644 assets/icons/radix/button.svg create mode 100644 assets/icons/radix/calendar.svg create mode 100644 assets/icons/radix/camera.svg create mode 100644 assets/icons/radix/card-stack-minus.svg create mode 100644 assets/icons/radix/card-stack-plus.svg create mode 100644 assets/icons/radix/card-stack.svg create mode 100644 assets/icons/radix/caret-down.svg create mode 100644 assets/icons/radix/caret-left.svg create mode 100644 assets/icons/radix/caret-right.svg create mode 100644 assets/icons/radix/caret-sort.svg create mode 100644 assets/icons/radix/caret-up.svg create mode 100644 assets/icons/radix/chat-bubble.svg create mode 100644 assets/icons/radix/check-circled.svg create mode 100644 assets/icons/radix/check.svg create mode 100644 assets/icons/radix/checkbox.svg create mode 100644 assets/icons/radix/chevron-down.svg create mode 100644 assets/icons/radix/chevron-left.svg create mode 100644 assets/icons/radix/chevron-right.svg create mode 100644 assets/icons/radix/chevron-up.svg create mode 100644 assets/icons/radix/circle-backslash.svg create mode 100644 assets/icons/radix/circle.svg create mode 100644 assets/icons/radix/clipboard-copy.svg create mode 100644 assets/icons/radix/clipboard.svg create mode 100644 assets/icons/radix/clock.svg create mode 100644 assets/icons/radix/code.svg create mode 100644 assets/icons/radix/codesandbox-logo.svg create mode 100644 assets/icons/radix/color-wheel.svg create mode 100644 assets/icons/radix/column-spacing.svg create mode 100644 assets/icons/radix/columns.svg create mode 100644 assets/icons/radix/commit.svg create mode 100644 assets/icons/radix/component-1.svg create mode 100644 assets/icons/radix/component-2.svg create mode 100644 assets/icons/radix/component-boolean.svg create mode 100644 assets/icons/radix/component-instance.svg create mode 100644 assets/icons/radix/component-none.svg create mode 100644 assets/icons/radix/component-placeholder.svg create mode 100644 assets/icons/radix/container.svg create mode 100644 assets/icons/radix/cookie.svg create mode 100644 assets/icons/radix/copy.svg create mode 100644 assets/icons/radix/corner-bottom-left.svg create mode 100644 assets/icons/radix/corner-bottom-right.svg create mode 100644 assets/icons/radix/corner-top-left.svg create mode 100644 assets/icons/radix/corner-top-right.svg create mode 100644 assets/icons/radix/corners.svg create mode 100644 assets/icons/radix/countdown-timer.svg create mode 100644 assets/icons/radix/counter-clockwise-clock.svg create mode 100644 assets/icons/radix/crop.svg create mode 100644 assets/icons/radix/cross-1.svg create mode 100644 assets/icons/radix/cross-2.svg create mode 100644 assets/icons/radix/cross-circled.svg create mode 100644 assets/icons/radix/crosshair-1.svg create mode 100644 assets/icons/radix/crosshair-2.svg create mode 100644 assets/icons/radix/crumpled-paper.svg create mode 100644 assets/icons/radix/cube.svg create mode 100644 assets/icons/radix/cursor-arrow.svg create mode 100644 assets/icons/radix/cursor-text.svg create mode 100644 assets/icons/radix/dash.svg create mode 100644 assets/icons/radix/dashboard.svg create mode 100644 assets/icons/radix/desktop.svg create mode 100644 assets/icons/radix/dimensions.svg create mode 100644 assets/icons/radix/disc.svg create mode 100644 assets/icons/radix/discord-logo.svg create mode 100644 assets/icons/radix/divider-horizontal.svg create mode 100644 assets/icons/radix/divider-vertical.svg create mode 100644 assets/icons/radix/dot-filled.svg create mode 100644 assets/icons/radix/dot-solid.svg create mode 100644 assets/icons/radix/dot.svg create mode 100644 assets/icons/radix/dots-horizontal.svg create mode 100644 assets/icons/radix/dots-vertical.svg create mode 100644 assets/icons/radix/double-arrow-down.svg create mode 100644 assets/icons/radix/double-arrow-left.svg create mode 100644 assets/icons/radix/double-arrow-right.svg create mode 100644 assets/icons/radix/double-arrow-up.svg create mode 100644 assets/icons/radix/download.svg create mode 100644 assets/icons/radix/drag-handle-dots-1.svg create mode 100644 assets/icons/radix/drag-handle-dots-2.svg create mode 100644 assets/icons/radix/drag-handle-horizontal.svg create mode 100644 assets/icons/radix/drag-handle-vertical.svg create mode 100644 assets/icons/radix/drawing-pin-filled.svg create mode 100644 assets/icons/radix/drawing-pin-solid.svg create mode 100644 assets/icons/radix/drawing-pin.svg create mode 100644 assets/icons/radix/dropdown-menu.svg create mode 100644 assets/icons/radix/enter-full-screen.svg create mode 100644 assets/icons/radix/enter.svg create mode 100644 assets/icons/radix/envelope-closed.svg create mode 100644 assets/icons/radix/envelope-open.svg create mode 100644 assets/icons/radix/eraser.svg create mode 100644 assets/icons/radix/exclamation-triangle.svg create mode 100644 assets/icons/radix/exit-full-screen.svg create mode 100644 assets/icons/radix/exit.svg create mode 100644 assets/icons/radix/external-link.svg create mode 100644 assets/icons/radix/eye-closed.svg create mode 100644 assets/icons/radix/eye-none.svg create mode 100644 assets/icons/radix/eye-open.svg create mode 100644 assets/icons/radix/face.svg create mode 100644 assets/icons/radix/figma-logo.svg create mode 100644 assets/icons/radix/file-minus.svg create mode 100644 assets/icons/radix/file-plus.svg create mode 100644 assets/icons/radix/file-text.svg create mode 100644 assets/icons/radix/file.svg create mode 100644 assets/icons/radix/font-bold.svg create mode 100644 assets/icons/radix/font-family.svg create mode 100644 assets/icons/radix/font-italic.svg create mode 100644 assets/icons/radix/font-roman.svg create mode 100644 assets/icons/radix/font-size.svg create mode 100644 assets/icons/radix/font-style.svg create mode 100644 assets/icons/radix/frame.svg create mode 100644 assets/icons/radix/framer-logo.svg create mode 100644 assets/icons/radix/gear.svg create mode 100644 assets/icons/radix/github-logo.svg create mode 100644 assets/icons/radix/globe.svg create mode 100644 assets/icons/radix/grid.svg create mode 100644 assets/icons/radix/group.svg create mode 100644 assets/icons/radix/half-1.svg create mode 100644 assets/icons/radix/half-2.svg create mode 100644 assets/icons/radix/hamburger-menu.svg create mode 100644 assets/icons/radix/hand.svg create mode 100644 assets/icons/radix/heading.svg create mode 100644 assets/icons/radix/heart-filled.svg create mode 100644 assets/icons/radix/heart.svg create mode 100644 assets/icons/radix/height.svg create mode 100644 assets/icons/radix/hobby-knife.svg create mode 100644 assets/icons/radix/home.svg create mode 100644 assets/icons/radix/iconjar-logo.svg create mode 100644 assets/icons/radix/id-card.svg create mode 100644 assets/icons/radix/image.svg create mode 100644 assets/icons/radix/info-circled.svg create mode 100644 assets/icons/radix/inner-shadow.svg create mode 100644 assets/icons/radix/input.svg create mode 100644 assets/icons/radix/instagram-logo.svg create mode 100644 assets/icons/radix/justify-center.svg create mode 100644 assets/icons/radix/justify-end.svg create mode 100644 assets/icons/radix/justify-start.svg create mode 100644 assets/icons/radix/justify-stretch.svg create mode 100644 assets/icons/radix/keyboard.svg create mode 100644 assets/icons/radix/lap-timer.svg create mode 100644 assets/icons/radix/laptop.svg create mode 100644 assets/icons/radix/layers.svg create mode 100644 assets/icons/radix/layout.svg create mode 100644 assets/icons/radix/letter-case-capitalize.svg create mode 100644 assets/icons/radix/letter-case-lowercase.svg create mode 100644 assets/icons/radix/letter-case-toggle.svg create mode 100644 assets/icons/radix/letter-case-uppercase.svg create mode 100644 assets/icons/radix/letter-spacing.svg create mode 100644 assets/icons/radix/lightning-bolt.svg create mode 100644 assets/icons/radix/line-height.svg create mode 100644 assets/icons/radix/link-1.svg create mode 100644 assets/icons/radix/link-2.svg create mode 100644 assets/icons/radix/link-break-1.svg create mode 100644 assets/icons/radix/link-break-2.svg create mode 100644 assets/icons/radix/link-none-1.svg create mode 100644 assets/icons/radix/link-none-2.svg create mode 100644 assets/icons/radix/linkedin-logo.svg create mode 100644 assets/icons/radix/list-bullet.svg create mode 100644 assets/icons/radix/lock-closed.svg create mode 100644 assets/icons/radix/lock-open-1.svg create mode 100644 assets/icons/radix/lock-open-2.svg create mode 100644 assets/icons/radix/loop.svg create mode 100644 assets/icons/radix/magic-wand.svg create mode 100644 assets/icons/radix/magnifying-glass.svg create mode 100644 assets/icons/radix/margin.svg create mode 100644 assets/icons/radix/mask-off.svg create mode 100644 assets/icons/radix/mask-on.svg create mode 100644 assets/icons/radix/minus-circled.svg create mode 100644 assets/icons/radix/minus.svg create mode 100644 assets/icons/radix/mix.svg create mode 100644 assets/icons/radix/mixer-horizontal.svg create mode 100644 assets/icons/radix/mixer-vertical.svg create mode 100644 assets/icons/radix/mobile.svg create mode 100644 assets/icons/radix/modulz-logo.svg create mode 100644 assets/icons/radix/moon.svg create mode 100644 assets/icons/radix/move.svg create mode 100644 assets/icons/radix/notion-logo.svg create mode 100644 assets/icons/radix/opacity.svg create mode 100644 assets/icons/radix/open-in-new-window.svg create mode 100644 assets/icons/radix/outer-shadow.svg create mode 100644 assets/icons/radix/overline.svg create mode 100644 assets/icons/radix/padding.svg create mode 100644 assets/icons/radix/paper-plane.svg create mode 100644 assets/icons/radix/pause.svg create mode 100644 assets/icons/radix/pencil-1.svg create mode 100644 assets/icons/radix/pencil-2.svg create mode 100644 assets/icons/radix/person.svg create mode 100644 assets/icons/radix/pie-chart.svg create mode 100644 assets/icons/radix/pilcrow.svg create mode 100644 assets/icons/radix/pin-bottom.svg create mode 100644 assets/icons/radix/pin-left.svg create mode 100644 assets/icons/radix/pin-right.svg create mode 100644 assets/icons/radix/pin-top.svg create mode 100644 assets/icons/radix/play.svg create mode 100644 assets/icons/radix/plus-circled.svg create mode 100644 assets/icons/radix/plus.svg create mode 100644 assets/icons/radix/question-mark-circled.svg create mode 100644 assets/icons/radix/question-mark.svg create mode 100644 assets/icons/radix/quote.svg create mode 100644 assets/icons/radix/radiobutton.svg create mode 100644 assets/icons/radix/reader.svg create mode 100644 assets/icons/radix/reload.svg create mode 100644 assets/icons/radix/reset.svg create mode 100644 assets/icons/radix/resume.svg create mode 100644 assets/icons/radix/rocket.svg create mode 100644 assets/icons/radix/rotate-counter-clockwise.svg create mode 100644 assets/icons/radix/row-spacing.svg create mode 100644 assets/icons/radix/rows.svg create mode 100644 assets/icons/radix/ruler-horizontal.svg create mode 100644 assets/icons/radix/ruler-square.svg create mode 100644 assets/icons/radix/scissors.svg create mode 100644 assets/icons/radix/section.svg create mode 100644 assets/icons/radix/sewing-pin-filled.svg create mode 100644 assets/icons/radix/sewing-pin-solid.svg create mode 100644 assets/icons/radix/sewing-pin.svg create mode 100644 assets/icons/radix/shadow-inner.svg create mode 100644 assets/icons/radix/shadow-none.svg create mode 100644 assets/icons/radix/shadow-outer.svg create mode 100644 assets/icons/radix/shadow.svg create mode 100644 assets/icons/radix/share-1.svg create mode 100644 assets/icons/radix/share-2.svg create mode 100644 assets/icons/radix/shuffle.svg create mode 100644 assets/icons/radix/size.svg create mode 100644 assets/icons/radix/sketch-logo.svg create mode 100644 assets/icons/radix/slash.svg create mode 100644 assets/icons/radix/slider.svg create mode 100644 assets/icons/radix/space-between-horizontally.svg create mode 100644 assets/icons/radix/space-between-vertically.svg create mode 100644 assets/icons/radix/space-evenly-horizontally.svg create mode 100644 assets/icons/radix/space-evenly-vertically.svg create mode 100644 assets/icons/radix/speaker-loud.svg create mode 100644 assets/icons/radix/speaker-moderate.svg create mode 100644 assets/icons/radix/speaker-off.svg create mode 100644 assets/icons/radix/speaker-quiet.svg create mode 100644 assets/icons/radix/square.svg create mode 100644 assets/icons/radix/stack.svg create mode 100644 assets/icons/radix/star-filled.svg create mode 100644 assets/icons/radix/star.svg create mode 100644 assets/icons/radix/stitches-logo.svg create mode 100644 assets/icons/radix/stop.svg create mode 100644 assets/icons/radix/stopwatch.svg create mode 100644 assets/icons/radix/stretch-horizontally.svg create mode 100644 assets/icons/radix/stretch-vertically.svg create mode 100644 assets/icons/radix/strikethrough.svg create mode 100644 assets/icons/radix/sun.svg create mode 100644 assets/icons/radix/switch.svg create mode 100644 assets/icons/radix/symbol.svg create mode 100644 assets/icons/radix/table.svg create mode 100644 assets/icons/radix/target.svg create mode 100644 assets/icons/radix/text-align-bottom.svg create mode 100644 assets/icons/radix/text-align-center.svg create mode 100644 assets/icons/radix/text-align-justify.svg create mode 100644 assets/icons/radix/text-align-left.svg create mode 100644 assets/icons/radix/text-align-middle.svg create mode 100644 assets/icons/radix/text-align-right.svg create mode 100644 assets/icons/radix/text-align-top.svg create mode 100644 assets/icons/radix/text-none.svg create mode 100644 assets/icons/radix/text.svg create mode 100644 assets/icons/radix/thick-arrow-down.svg create mode 100644 assets/icons/radix/thick-arrow-left.svg create mode 100644 assets/icons/radix/thick-arrow-right.svg create mode 100644 assets/icons/radix/thick-arrow-up.svg create mode 100644 assets/icons/radix/timer.svg create mode 100644 assets/icons/radix/tokens.svg create mode 100644 assets/icons/radix/track-next.svg create mode 100644 assets/icons/radix/track-previous.svg create mode 100644 assets/icons/radix/transform.svg create mode 100644 assets/icons/radix/transparency-grid.svg create mode 100644 assets/icons/radix/trash.svg create mode 100644 assets/icons/radix/triangle-down.svg create mode 100644 assets/icons/radix/triangle-left.svg create mode 100644 assets/icons/radix/triangle-right.svg create mode 100644 assets/icons/radix/triangle-up.svg create mode 100644 assets/icons/radix/twitter-logo.svg create mode 100644 assets/icons/radix/underline.svg create mode 100644 assets/icons/radix/update.svg create mode 100644 assets/icons/radix/upload.svg create mode 100644 assets/icons/radix/value-none.svg create mode 100644 assets/icons/radix/value.svg create mode 100644 assets/icons/radix/vercel-logo.svg create mode 100644 assets/icons/radix/video.svg create mode 100644 assets/icons/radix/view-grid.svg create mode 100644 assets/icons/radix/view-horizontal.svg create mode 100644 assets/icons/radix/view-none.svg create mode 100644 assets/icons/radix/view-vertical.svg create mode 100644 assets/icons/radix/width.svg create mode 100644 assets/icons/radix/zoom-in.svg create mode 100644 assets/icons/radix/zoom-out.svg diff --git a/assets/icons/radix/accessibility.svg b/assets/icons/radix/accessibility.svg new file mode 100644 index 0000000000000000000000000000000000000000..32d78f2d8da1c317727810706a892a63f588463e --- /dev/null +++ b/assets/icons/radix/accessibility.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/activity-log.svg b/assets/icons/radix/activity-log.svg new file mode 100644 index 0000000000000000000000000000000000000000..8feab7d44942915ef6d49602e272b03125ee8ea4 --- /dev/null +++ b/assets/icons/radix/activity-log.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/align-baseline.svg b/assets/icons/radix/align-baseline.svg new file mode 100644 index 0000000000000000000000000000000000000000..07213dc1ae61fbf49d3f72b107082b07892fa0c1 --- /dev/null +++ b/assets/icons/radix/align-baseline.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/align-bottom.svg b/assets/icons/radix/align-bottom.svg new file mode 100644 index 0000000000000000000000000000000000000000..7d11c0cd5a6e11be048bcfc04c782fcd3e61f2ee --- /dev/null +++ b/assets/icons/radix/align-bottom.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/align-center-horizontally.svg b/assets/icons/radix/align-center-horizontally.svg new file mode 100644 index 0000000000000000000000000000000000000000..69509a7d097821d2c0169ae468efc8d74a7e90c9 --- /dev/null +++ b/assets/icons/radix/align-center-horizontally.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/align-center-vertically.svg b/assets/icons/radix/align-center-vertically.svg new file mode 100644 index 0000000000000000000000000000000000000000..4f1b50cc4366775a792bef2b4475ec864856a3a7 --- /dev/null +++ b/assets/icons/radix/align-center-vertically.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/align-center.svg b/assets/icons/radix/align-center.svg new file mode 100644 index 0000000000000000000000000000000000000000..caaec36477fbbf2bcfef558aa682092d0bbd9a01 --- /dev/null +++ b/assets/icons/radix/align-center.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/align-end.svg b/assets/icons/radix/align-end.svg new file mode 100644 index 0000000000000000000000000000000000000000..18f1b6491233806086baf55ab67c5d7f4e10ff54 --- /dev/null +++ b/assets/icons/radix/align-end.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/align-horizontal-centers.svg b/assets/icons/radix/align-horizontal-centers.svg new file mode 100644 index 0000000000000000000000000000000000000000..2d1d64ea4b82ef5e0d933b9bf0ec439c9998dd98 --- /dev/null +++ b/assets/icons/radix/align-horizontal-centers.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/align-left.svg b/assets/icons/radix/align-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..0d5dba095c7d0756d489d415276064a91d4fd3ce --- /dev/null +++ b/assets/icons/radix/align-left.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/align-right.svg b/assets/icons/radix/align-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..1b6b3f0ffa9c649b005739baafa9d973013af076 --- /dev/null +++ b/assets/icons/radix/align-right.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/align-start.svg b/assets/icons/radix/align-start.svg new file mode 100644 index 0000000000000000000000000000000000000000..ada50e1079e481cde5f0f9ee5884a7030ebb0bc6 --- /dev/null +++ b/assets/icons/radix/align-start.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/align-stretch.svg b/assets/icons/radix/align-stretch.svg new file mode 100644 index 0000000000000000000000000000000000000000..3cb28605cbf1b1a8470fabd1257370d74b3e5682 --- /dev/null +++ b/assets/icons/radix/align-stretch.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/align-top.svg b/assets/icons/radix/align-top.svg new file mode 100644 index 0000000000000000000000000000000000000000..23db80f4dd0ebb04ee703fe74d4b535abbd01da1 --- /dev/null +++ b/assets/icons/radix/align-top.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/align-vertical-centers.svg b/assets/icons/radix/align-vertical-centers.svg new file mode 100644 index 0000000000000000000000000000000000000000..07eaee7bf7d9274c402bb3f4bfaa0dea486eb09b --- /dev/null +++ b/assets/icons/radix/align-vertical-centers.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/all-sides.svg b/assets/icons/radix/all-sides.svg new file mode 100644 index 0000000000000000000000000000000000000000..8ace7df03f4d17ba1e8f858b94d418eb63618ea6 --- /dev/null +++ b/assets/icons/radix/all-sides.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/angle.svg b/assets/icons/radix/angle.svg new file mode 100644 index 0000000000000000000000000000000000000000..a0d93f3460ca940a1bf5e7ad94c46f56d40ccc7b --- /dev/null +++ b/assets/icons/radix/angle.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/archive.svg b/assets/icons/radix/archive.svg new file mode 100644 index 0000000000000000000000000000000000000000..74063f1d1e2346c09ee2a6a5297c30ef7e0c74ad --- /dev/null +++ b/assets/icons/radix/archive.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/arrow-bottom-left.svg b/assets/icons/radix/arrow-bottom-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..7a4511aa2d69b39c305cd80c291c868007cba491 --- /dev/null +++ b/assets/icons/radix/arrow-bottom-left.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/arrow-bottom-right.svg b/assets/icons/radix/arrow-bottom-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..2ba9fef1019774f1e5094f5654d89df848cdbb5b --- /dev/null +++ b/assets/icons/radix/arrow-bottom-right.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/arrow-down.svg b/assets/icons/radix/arrow-down.svg new file mode 100644 index 0000000000000000000000000000000000000000..5dc21a66890fb27f537b4400e96d48b7f7ce84a6 --- /dev/null +++ b/assets/icons/radix/arrow-down.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/arrow-left.svg b/assets/icons/radix/arrow-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..3a64c8394f0825b3708634c2d003a648877c35cd --- /dev/null +++ b/assets/icons/radix/arrow-left.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/arrow-right.svg b/assets/icons/radix/arrow-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..e3d30988d5e7b4547393281c7bdad60c3006f4f3 --- /dev/null +++ b/assets/icons/radix/arrow-right.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/arrow-top-left.svg b/assets/icons/radix/arrow-top-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..69fef41dee621d3f8cf681e630c0ce623d65124d --- /dev/null +++ b/assets/icons/radix/arrow-top-left.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/arrow-top-right.svg b/assets/icons/radix/arrow-top-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..c1016376e3232ead02dde954379ce74b7bfb68f7 --- /dev/null +++ b/assets/icons/radix/arrow-top-right.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/arrow-up.svg b/assets/icons/radix/arrow-up.svg new file mode 100644 index 0000000000000000000000000000000000000000..ba426119e901d0a1132d0e47b34c0beebaec22ce --- /dev/null +++ b/assets/icons/radix/arrow-up.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/aspect-ratio.svg b/assets/icons/radix/aspect-ratio.svg new file mode 100644 index 0000000000000000000000000000000000000000..0851f2e1e9f46d52cd2974b77a65e3a8b95b339e --- /dev/null +++ b/assets/icons/radix/aspect-ratio.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/avatar.svg b/assets/icons/radix/avatar.svg new file mode 100644 index 0000000000000000000000000000000000000000..cb229c77fe827f64054b6bfa05f2ad2aaf17c2d3 --- /dev/null +++ b/assets/icons/radix/avatar.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/backpack.svg b/assets/icons/radix/backpack.svg new file mode 100644 index 0000000000000000000000000000000000000000..a5c9cedbd32dd589c825852f447e8c6125c2a8fb --- /dev/null +++ b/assets/icons/radix/backpack.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/badge.svg b/assets/icons/radix/badge.svg new file mode 100644 index 0000000000000000000000000000000000000000..aa764d4726f449c163b00e1bd993d12c5aa95c24 --- /dev/null +++ b/assets/icons/radix/badge.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/bar-chart.svg b/assets/icons/radix/bar-chart.svg new file mode 100644 index 0000000000000000000000000000000000000000..f8054781d9ec2ee79f0652ae20753e3e80752bff --- /dev/null +++ b/assets/icons/radix/bar-chart.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/bell.svg b/assets/icons/radix/bell.svg new file mode 100644 index 0000000000000000000000000000000000000000..ea1c6dd42e8821b632f6de97d143a7b9f4b97fd2 --- /dev/null +++ b/assets/icons/radix/bell.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/blending-mode.svg b/assets/icons/radix/blending-mode.svg new file mode 100644 index 0000000000000000000000000000000000000000..bd58cf4ee38ee66e9860df11a9f4150899a9c8a8 --- /dev/null +++ b/assets/icons/radix/blending-mode.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/bookmark-filled.svg b/assets/icons/radix/bookmark-filled.svg new file mode 100644 index 0000000000000000000000000000000000000000..5b725cd88dbf9337d52095a7567a2bc12e15439a --- /dev/null +++ b/assets/icons/radix/bookmark-filled.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/bookmark.svg b/assets/icons/radix/bookmark.svg new file mode 100644 index 0000000000000000000000000000000000000000..90c4d827f13cd47a83a030c833a02e15492dc084 --- /dev/null +++ b/assets/icons/radix/bookmark.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/border-all.svg b/assets/icons/radix/border-all.svg new file mode 100644 index 0000000000000000000000000000000000000000..3bfde7d59baa675eeae72eac6f7245eadbe10821 --- /dev/null +++ b/assets/icons/radix/border-all.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/assets/icons/radix/border-bottom.svg b/assets/icons/radix/border-bottom.svg new file mode 100644 index 0000000000000000000000000000000000000000..f2d3c3d554e09837c464ff425c3af74413db4eb6 --- /dev/null +++ b/assets/icons/radix/border-bottom.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/radix/border-dashed.svg b/assets/icons/radix/border-dashed.svg new file mode 100644 index 0000000000000000000000000000000000000000..85fdcdfe5d7f3905f2056912a5bc56d229ca5ee0 --- /dev/null +++ b/assets/icons/radix/border-dashed.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/border-dotted.svg b/assets/icons/radix/border-dotted.svg new file mode 100644 index 0000000000000000000000000000000000000000..5eb514ed2a60093e0c4eb904b4cc5c6d18b9a62f --- /dev/null +++ b/assets/icons/radix/border-dotted.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/border-left.svg b/assets/icons/radix/border-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..5deb197da51a7db874b57e1a473d4287b2a3cd49 --- /dev/null +++ b/assets/icons/radix/border-left.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/radix/border-none.svg b/assets/icons/radix/border-none.svg new file mode 100644 index 0000000000000000000000000000000000000000..1ad3f59d7c9b93101657ad1523a2939d02f504d8 --- /dev/null +++ b/assets/icons/radix/border-none.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/radix/border-right.svg b/assets/icons/radix/border-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..c939095ad78a75eeb5f8b2e31f57e56b201b8a4c --- /dev/null +++ b/assets/icons/radix/border-right.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/radix/border-solid.svg b/assets/icons/radix/border-solid.svg new file mode 100644 index 0000000000000000000000000000000000000000..5c0d26a0583140b8ba0b47e937bc0dedc81e4fb5 --- /dev/null +++ b/assets/icons/radix/border-solid.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/border-split.svg b/assets/icons/radix/border-split.svg new file mode 100644 index 0000000000000000000000000000000000000000..7fdf6cc34e73e6543fa34e9b52e22382130d6f1a --- /dev/null +++ b/assets/icons/radix/border-split.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/assets/icons/radix/border-style.svg b/assets/icons/radix/border-style.svg new file mode 100644 index 0000000000000000000000000000000000000000..f729cb993babfa12140deabc9451eceee6b7885a --- /dev/null +++ b/assets/icons/radix/border-style.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/border-top.svg b/assets/icons/radix/border-top.svg new file mode 100644 index 0000000000000000000000000000000000000000..bde739d75539be17496a8ce65b875b4f4b943940 --- /dev/null +++ b/assets/icons/radix/border-top.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/radix/border-width.svg b/assets/icons/radix/border-width.svg new file mode 100644 index 0000000000000000000000000000000000000000..37c270756ec4ec5a8a42b81b64bfbbe8e24f892a --- /dev/null +++ b/assets/icons/radix/border-width.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/box-model.svg b/assets/icons/radix/box-model.svg new file mode 100644 index 0000000000000000000000000000000000000000..45d1a7ce415aa508a8a8f8d39f8032a22c2b4e5a --- /dev/null +++ b/assets/icons/radix/box-model.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/box.svg b/assets/icons/radix/box.svg new file mode 100644 index 0000000000000000000000000000000000000000..6e035c21ed8fd3ad1eca7297921da359262e8445 --- /dev/null +++ b/assets/icons/radix/box.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/button.svg b/assets/icons/radix/button.svg new file mode 100644 index 0000000000000000000000000000000000000000..31622bcf159a83dbf7dbc7960da3c490711a14ff --- /dev/null +++ b/assets/icons/radix/button.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/calendar.svg b/assets/icons/radix/calendar.svg new file mode 100644 index 0000000000000000000000000000000000000000..2adbe0bc2868392e36079a5860ddf706543b210e --- /dev/null +++ b/assets/icons/radix/calendar.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/camera.svg b/assets/icons/radix/camera.svg new file mode 100644 index 0000000000000000000000000000000000000000..d7cccf74c2e416dd8abcd45be121f73eccea3c12 --- /dev/null +++ b/assets/icons/radix/camera.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/card-stack-minus.svg b/assets/icons/radix/card-stack-minus.svg new file mode 100644 index 0000000000000000000000000000000000000000..04d8e51178a0a8ea38a5354aa421e20bd4091298 --- /dev/null +++ b/assets/icons/radix/card-stack-minus.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/card-stack-plus.svg b/assets/icons/radix/card-stack-plus.svg new file mode 100644 index 0000000000000000000000000000000000000000..a184f4bc1aff9b3b212fc3cce7265cf58bba3948 --- /dev/null +++ b/assets/icons/radix/card-stack-plus.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/card-stack.svg b/assets/icons/radix/card-stack.svg new file mode 100644 index 0000000000000000000000000000000000000000..defea0e1654f9267fa91a8b66e2bf1191b95aadd --- /dev/null +++ b/assets/icons/radix/card-stack.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/caret-down.svg b/assets/icons/radix/caret-down.svg new file mode 100644 index 0000000000000000000000000000000000000000..ff8b8c3b88b8885b52a090eeca3f21526bb0a456 --- /dev/null +++ b/assets/icons/radix/caret-down.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/caret-left.svg b/assets/icons/radix/caret-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..969bc3b95c2194b922c1858ddf89b5d2461f11d3 --- /dev/null +++ b/assets/icons/radix/caret-left.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/caret-right.svg b/assets/icons/radix/caret-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..75c55d8676eebdc09961d63b870e12fc0a91c5c5 --- /dev/null +++ b/assets/icons/radix/caret-right.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/caret-sort.svg b/assets/icons/radix/caret-sort.svg new file mode 100644 index 0000000000000000000000000000000000000000..a65e20b660481333e4e27e32203c9a5d12a5f150 --- /dev/null +++ b/assets/icons/radix/caret-sort.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/caret-up.svg b/assets/icons/radix/caret-up.svg new file mode 100644 index 0000000000000000000000000000000000000000..53026b83d8b36505b4b0f32c6e6d4a4c690c7beb --- /dev/null +++ b/assets/icons/radix/caret-up.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/chat-bubble.svg b/assets/icons/radix/chat-bubble.svg new file mode 100644 index 0000000000000000000000000000000000000000..5766f46de868ad91fc0ff057691a7dea474a0dae --- /dev/null +++ b/assets/icons/radix/chat-bubble.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/check-circled.svg b/assets/icons/radix/check-circled.svg new file mode 100644 index 0000000000000000000000000000000000000000..19ee22eb511b987dd3acfc5c7c833d6561a4662d --- /dev/null +++ b/assets/icons/radix/check-circled.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/check.svg b/assets/icons/radix/check.svg new file mode 100644 index 0000000000000000000000000000000000000000..476a3baa18e42bb05edfd7ec0c3a2aef155cc003 --- /dev/null +++ b/assets/icons/radix/check.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/checkbox.svg b/assets/icons/radix/checkbox.svg new file mode 100644 index 0000000000000000000000000000000000000000..d6bb3c7ef2f0e97b823bffb1d4ea1edd38609da9 --- /dev/null +++ b/assets/icons/radix/checkbox.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/chevron-down.svg b/assets/icons/radix/chevron-down.svg new file mode 100644 index 0000000000000000000000000000000000000000..175c1312fd37417cba0bbcd9230b4dffa24821e4 --- /dev/null +++ b/assets/icons/radix/chevron-down.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/chevron-left.svg b/assets/icons/radix/chevron-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..d7628202f29edf1642deb44bf93ff540aa728475 --- /dev/null +++ b/assets/icons/radix/chevron-left.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/chevron-right.svg b/assets/icons/radix/chevron-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..e3ebd73d9909a53e3fb721f2ea686f1dca0b477b --- /dev/null +++ b/assets/icons/radix/chevron-right.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/chevron-up.svg b/assets/icons/radix/chevron-up.svg new file mode 100644 index 0000000000000000000000000000000000000000..0e8e796dab46c9de345166aa4dba818305b68857 --- /dev/null +++ b/assets/icons/radix/chevron-up.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/circle-backslash.svg b/assets/icons/radix/circle-backslash.svg new file mode 100644 index 0000000000000000000000000000000000000000..40c4dd5398b454220d4d22dbbec08bcdb335be71 --- /dev/null +++ b/assets/icons/radix/circle-backslash.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/circle.svg b/assets/icons/radix/circle.svg new file mode 100644 index 0000000000000000000000000000000000000000..ba4a8f22fe574008e076c7983dfc5f743d03f2df --- /dev/null +++ b/assets/icons/radix/circle.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/clipboard-copy.svg b/assets/icons/radix/clipboard-copy.svg new file mode 100644 index 0000000000000000000000000000000000000000..5293fdc493f5577936977562c9457bbfa809f012 --- /dev/null +++ b/assets/icons/radix/clipboard-copy.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/clipboard.svg b/assets/icons/radix/clipboard.svg new file mode 100644 index 0000000000000000000000000000000000000000..e18b32943be09aca0c53294e8e65187564ba1224 --- /dev/null +++ b/assets/icons/radix/clipboard.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/clock.svg b/assets/icons/radix/clock.svg new file mode 100644 index 0000000000000000000000000000000000000000..ac3b526fbbda03c5984d7c9dfaf937be520910a2 --- /dev/null +++ b/assets/icons/radix/clock.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/code.svg b/assets/icons/radix/code.svg new file mode 100644 index 0000000000000000000000000000000000000000..70fe381b68c5b95065275b5163af76dabaa5b22e --- /dev/null +++ b/assets/icons/radix/code.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/codesandbox-logo.svg b/assets/icons/radix/codesandbox-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..4a3f549c2f6d7271e9a8fb225e18285d90312df8 --- /dev/null +++ b/assets/icons/radix/codesandbox-logo.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/color-wheel.svg b/assets/icons/radix/color-wheel.svg new file mode 100644 index 0000000000000000000000000000000000000000..2153b84428f354843aa7ffd3be174680440be90c --- /dev/null +++ b/assets/icons/radix/color-wheel.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/column-spacing.svg b/assets/icons/radix/column-spacing.svg new file mode 100644 index 0000000000000000000000000000000000000000..aafcf555cb1ca06550c39419d20c257b02ea1934 --- /dev/null +++ b/assets/icons/radix/column-spacing.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/columns.svg b/assets/icons/radix/columns.svg new file mode 100644 index 0000000000000000000000000000000000000000..e1607611b1a24957c7983041a540806b4275d289 --- /dev/null +++ b/assets/icons/radix/columns.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/commit.svg b/assets/icons/radix/commit.svg new file mode 100644 index 0000000000000000000000000000000000000000..ac128a2b083d6b94f17ee065d88226ff7dc53da3 --- /dev/null +++ b/assets/icons/radix/commit.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/component-1.svg b/assets/icons/radix/component-1.svg new file mode 100644 index 0000000000000000000000000000000000000000..e3e9f38af1fba0b278ed2c48bfc76cb2a6783307 --- /dev/null +++ b/assets/icons/radix/component-1.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/component-2.svg b/assets/icons/radix/component-2.svg new file mode 100644 index 0000000000000000000000000000000000000000..df2091d1437ba51b4d1d6647dfa4d16ebd7dac53 --- /dev/null +++ b/assets/icons/radix/component-2.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/component-boolean.svg b/assets/icons/radix/component-boolean.svg new file mode 100644 index 0000000000000000000000000000000000000000..942e8832eb4e99cd3af0dc61a1bde6ea01574cb8 --- /dev/null +++ b/assets/icons/radix/component-boolean.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/component-instance.svg b/assets/icons/radix/component-instance.svg new file mode 100644 index 0000000000000000000000000000000000000000..048c40129134426ed628de6d386be9017b484d32 --- /dev/null +++ b/assets/icons/radix/component-instance.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/component-none.svg b/assets/icons/radix/component-none.svg new file mode 100644 index 0000000000000000000000000000000000000000..a622c3ee960ac4b61d03f4d7b755d98576e37b0d --- /dev/null +++ b/assets/icons/radix/component-none.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/component-placeholder.svg b/assets/icons/radix/component-placeholder.svg new file mode 100644 index 0000000000000000000000000000000000000000..b8892d5d23632fd251938af55c0ae34a112ba058 --- /dev/null +++ b/assets/icons/radix/component-placeholder.svg @@ -0,0 +1,12 @@ + + + + diff --git a/assets/icons/radix/container.svg b/assets/icons/radix/container.svg new file mode 100644 index 0000000000000000000000000000000000000000..1c2a4fd0e18cf47ee793eb6196f6b21e99bda6c0 --- /dev/null +++ b/assets/icons/radix/container.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/cookie.svg b/assets/icons/radix/cookie.svg new file mode 100644 index 0000000000000000000000000000000000000000..8c165601a2a8af711ce771ea31b829405bccdfba --- /dev/null +++ b/assets/icons/radix/cookie.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/copy.svg b/assets/icons/radix/copy.svg new file mode 100644 index 0000000000000000000000000000000000000000..bf2b504ecfcb378b1a93cf893b4eb070da9471fb --- /dev/null +++ b/assets/icons/radix/copy.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/corner-bottom-left.svg b/assets/icons/radix/corner-bottom-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..26df9dbad8c28a6bd041e14bde9cb23624cf66ca --- /dev/null +++ b/assets/icons/radix/corner-bottom-left.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/corner-bottom-right.svg b/assets/icons/radix/corner-bottom-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..15e395712342d3f4d5625d6159f3c1a5ba78e108 --- /dev/null +++ b/assets/icons/radix/corner-bottom-right.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/corner-top-left.svg b/assets/icons/radix/corner-top-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..8fc1b84b825e7ed1d63ac0dee1b93c768ae42048 --- /dev/null +++ b/assets/icons/radix/corner-top-left.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/corner-top-right.svg b/assets/icons/radix/corner-top-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..533ea6c678c2edb2355862ed4ab2712f2b338bab --- /dev/null +++ b/assets/icons/radix/corner-top-right.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/corners.svg b/assets/icons/radix/corners.svg new file mode 100644 index 0000000000000000000000000000000000000000..c41c4e01839621c0f3a3ec8c6a7c02d7345e97b2 --- /dev/null +++ b/assets/icons/radix/corners.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/countdown-timer.svg b/assets/icons/radix/countdown-timer.svg new file mode 100644 index 0000000000000000000000000000000000000000..58494bd416ab93113128a113c3dbaa5b5f268b2a --- /dev/null +++ b/assets/icons/radix/countdown-timer.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/counter-clockwise-clock.svg b/assets/icons/radix/counter-clockwise-clock.svg new file mode 100644 index 0000000000000000000000000000000000000000..0b3acbcebf2d7d71a23d9b89648df9ac532ae847 --- /dev/null +++ b/assets/icons/radix/counter-clockwise-clock.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/crop.svg b/assets/icons/radix/crop.svg new file mode 100644 index 0000000000000000000000000000000000000000..008457fff6861d102469ef46a234080e6fb0c634 --- /dev/null +++ b/assets/icons/radix/crop.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/cross-1.svg b/assets/icons/radix/cross-1.svg new file mode 100644 index 0000000000000000000000000000000000000000..62135d27edf689ce7a06092a95248ffeb67b8f9e --- /dev/null +++ b/assets/icons/radix/cross-1.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/cross-2.svg b/assets/icons/radix/cross-2.svg new file mode 100644 index 0000000000000000000000000000000000000000..4c557009286712b14e716f7e69309b0eb197d768 --- /dev/null +++ b/assets/icons/radix/cross-2.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/cross-circled.svg b/assets/icons/radix/cross-circled.svg new file mode 100644 index 0000000000000000000000000000000000000000..df3cb896c8f20de3614ce7adfd4a6774bead4ee5 --- /dev/null +++ b/assets/icons/radix/cross-circled.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/crosshair-1.svg b/assets/icons/radix/crosshair-1.svg new file mode 100644 index 0000000000000000000000000000000000000000..05b22f8461a6d1a513b74aeb0ea976936e42f253 --- /dev/null +++ b/assets/icons/radix/crosshair-1.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/crosshair-2.svg b/assets/icons/radix/crosshair-2.svg new file mode 100644 index 0000000000000000000000000000000000000000..f5ee0a92af713fb3bd8c366f7400194d291ee7b5 --- /dev/null +++ b/assets/icons/radix/crosshair-2.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/crumpled-paper.svg b/assets/icons/radix/crumpled-paper.svg new file mode 100644 index 0000000000000000000000000000000000000000..33e9b65581b6a35b7f8c687f1b9dbab9edbb32cf --- /dev/null +++ b/assets/icons/radix/crumpled-paper.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/cube.svg b/assets/icons/radix/cube.svg new file mode 100644 index 0000000000000000000000000000000000000000..b327158be4afc35744fe0c2e84b5f73662a93472 --- /dev/null +++ b/assets/icons/radix/cube.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/cursor-arrow.svg b/assets/icons/radix/cursor-arrow.svg new file mode 100644 index 0000000000000000000000000000000000000000..b0227e4ded7aef4a78baebcf10a511e0c5659f6c --- /dev/null +++ b/assets/icons/radix/cursor-arrow.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/cursor-text.svg b/assets/icons/radix/cursor-text.svg new file mode 100644 index 0000000000000000000000000000000000000000..05939503b8a5c4caed24fe8ab938fbef8406ffdd --- /dev/null +++ b/assets/icons/radix/cursor-text.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/dash.svg b/assets/icons/radix/dash.svg new file mode 100644 index 0000000000000000000000000000000000000000..d70daf7fed6ec8e6346e5800ef89249d7cf62984 --- /dev/null +++ b/assets/icons/radix/dash.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/dashboard.svg b/assets/icons/radix/dashboard.svg new file mode 100644 index 0000000000000000000000000000000000000000..38008c64e41e2addfea23f4c5f88bc04a2a49e86 --- /dev/null +++ b/assets/icons/radix/dashboard.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/desktop.svg b/assets/icons/radix/desktop.svg new file mode 100644 index 0000000000000000000000000000000000000000..ad252e64cf5c73d4cd6ae48dd0abede47d3323e6 --- /dev/null +++ b/assets/icons/radix/desktop.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/dimensions.svg b/assets/icons/radix/dimensions.svg new file mode 100644 index 0000000000000000000000000000000000000000..767d1d289641510dca8f75431192786f294be2a1 --- /dev/null +++ b/assets/icons/radix/dimensions.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/disc.svg b/assets/icons/radix/disc.svg new file mode 100644 index 0000000000000000000000000000000000000000..6e19caab3504eef094cd4cffbe43b657dc1913ad --- /dev/null +++ b/assets/icons/radix/disc.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/discord-logo.svg b/assets/icons/radix/discord-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..50567c212eda4dca3f87df399dd0e6d0dc076c2b --- /dev/null +++ b/assets/icons/radix/discord-logo.svg @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/assets/icons/radix/divider-horizontal.svg b/assets/icons/radix/divider-horizontal.svg new file mode 100644 index 0000000000000000000000000000000000000000..59e43649c93b1767739548a6bc8122886c6061ad --- /dev/null +++ b/assets/icons/radix/divider-horizontal.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/divider-vertical.svg b/assets/icons/radix/divider-vertical.svg new file mode 100644 index 0000000000000000000000000000000000000000..95f5cc8f2f45dabe00fd376a8ac2db99155e686f --- /dev/null +++ b/assets/icons/radix/divider-vertical.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/dot-filled.svg b/assets/icons/radix/dot-filled.svg new file mode 100644 index 0000000000000000000000000000000000000000..0c1a17b3bd8a904d7274a18b5a4432681fb867ca --- /dev/null +++ b/assets/icons/radix/dot-filled.svg @@ -0,0 +1,6 @@ + + + diff --git a/assets/icons/radix/dot-solid.svg b/assets/icons/radix/dot-solid.svg new file mode 100644 index 0000000000000000000000000000000000000000..0c1a17b3bd8a904d7274a18b5a4432681fb867ca --- /dev/null +++ b/assets/icons/radix/dot-solid.svg @@ -0,0 +1,6 @@ + + + diff --git a/assets/icons/radix/dot.svg b/assets/icons/radix/dot.svg new file mode 100644 index 0000000000000000000000000000000000000000..c553a1422dbd52775efacadede6863d2dc0256c9 --- /dev/null +++ b/assets/icons/radix/dot.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/dots-horizontal.svg b/assets/icons/radix/dots-horizontal.svg new file mode 100644 index 0000000000000000000000000000000000000000..347d1ae13d84eaef1bf4ab33d65a9dfcf11292d5 --- /dev/null +++ b/assets/icons/radix/dots-horizontal.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/dots-vertical.svg b/assets/icons/radix/dots-vertical.svg new file mode 100644 index 0000000000000000000000000000000000000000..5ca1a181e3887e4b5459c899aedb25acf60d4bed --- /dev/null +++ b/assets/icons/radix/dots-vertical.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/double-arrow-down.svg b/assets/icons/radix/double-arrow-down.svg new file mode 100644 index 0000000000000000000000000000000000000000..8b86db2f8a0baa6350a0ad772c083b22fd520be9 --- /dev/null +++ b/assets/icons/radix/double-arrow-down.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/double-arrow-left.svg b/assets/icons/radix/double-arrow-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..0ef30ff9554c558469c75252ef56a828cad2c777 --- /dev/null +++ b/assets/icons/radix/double-arrow-left.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/double-arrow-right.svg b/assets/icons/radix/double-arrow-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..9997fdc40398d3cf1c6ce30c78ae4d5b4f319457 --- /dev/null +++ b/assets/icons/radix/double-arrow-right.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/double-arrow-up.svg b/assets/icons/radix/double-arrow-up.svg new file mode 100644 index 0000000000000000000000000000000000000000..8d571fcd66980e46d4e26eaf96870df6ff469408 --- /dev/null +++ b/assets/icons/radix/double-arrow-up.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/download.svg b/assets/icons/radix/download.svg new file mode 100644 index 0000000000000000000000000000000000000000..49a05d5f47f7c07faa1403c5320268e6df2581a5 --- /dev/null +++ b/assets/icons/radix/download.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/drag-handle-dots-1.svg b/assets/icons/radix/drag-handle-dots-1.svg new file mode 100644 index 0000000000000000000000000000000000000000..fc046bb9d9b03b5bdd5ea49dc1bedab8aacab656 --- /dev/null +++ b/assets/icons/radix/drag-handle-dots-1.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/radix/drag-handle-dots-2.svg b/assets/icons/radix/drag-handle-dots-2.svg new file mode 100644 index 0000000000000000000000000000000000000000..aed0e702d7635421fc6674e2daafbccb0573314c --- /dev/null +++ b/assets/icons/radix/drag-handle-dots-2.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/drag-handle-horizontal.svg b/assets/icons/radix/drag-handle-horizontal.svg new file mode 100644 index 0000000000000000000000000000000000000000..c1bb138a244147fc61333952ee898979ce67351f --- /dev/null +++ b/assets/icons/radix/drag-handle-horizontal.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/drag-handle-vertical.svg b/assets/icons/radix/drag-handle-vertical.svg new file mode 100644 index 0000000000000000000000000000000000000000..8d48c7894afcb4949b1784f93c062014dcd207c6 --- /dev/null +++ b/assets/icons/radix/drag-handle-vertical.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/drawing-pin-filled.svg b/assets/icons/radix/drawing-pin-filled.svg new file mode 100644 index 0000000000000000000000000000000000000000..e1894619c34441eb228587b9c50fc6af61193a44 --- /dev/null +++ b/assets/icons/radix/drawing-pin-filled.svg @@ -0,0 +1,14 @@ + + + + diff --git a/assets/icons/radix/drawing-pin-solid.svg b/assets/icons/radix/drawing-pin-solid.svg new file mode 100644 index 0000000000000000000000000000000000000000..e1894619c34441eb228587b9c50fc6af61193a44 --- /dev/null +++ b/assets/icons/radix/drawing-pin-solid.svg @@ -0,0 +1,14 @@ + + + + diff --git a/assets/icons/radix/drawing-pin.svg b/assets/icons/radix/drawing-pin.svg new file mode 100644 index 0000000000000000000000000000000000000000..5625e7588f1f33f057bf8ad15bc261c45072b1a9 --- /dev/null +++ b/assets/icons/radix/drawing-pin.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/dropdown-menu.svg b/assets/icons/radix/dropdown-menu.svg new file mode 100644 index 0000000000000000000000000000000000000000..c938052be8e21698e89e8a0f57215c71410492c9 --- /dev/null +++ b/assets/icons/radix/dropdown-menu.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/enter-full-screen.svg b/assets/icons/radix/enter-full-screen.svg new file mode 100644 index 0000000000000000000000000000000000000000..d368a6d415fc340db7595a06b5686cbb920ad48a --- /dev/null +++ b/assets/icons/radix/enter-full-screen.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/enter.svg b/assets/icons/radix/enter.svg new file mode 100644 index 0000000000000000000000000000000000000000..cc57d74ceae76b56074e8be073916301a280b9a2 --- /dev/null +++ b/assets/icons/radix/enter.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/envelope-closed.svg b/assets/icons/radix/envelope-closed.svg new file mode 100644 index 0000000000000000000000000000000000000000..4b5e0378401cd9f8530355d84da28d7ca507d0a2 --- /dev/null +++ b/assets/icons/radix/envelope-closed.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/envelope-open.svg b/assets/icons/radix/envelope-open.svg new file mode 100644 index 0000000000000000000000000000000000000000..df1e3fea9515984d0207b80e3ab03b39511d52db --- /dev/null +++ b/assets/icons/radix/envelope-open.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/eraser.svg b/assets/icons/radix/eraser.svg new file mode 100644 index 0000000000000000000000000000000000000000..bb448d4d23511c57ab4216dd28af17232949c0b4 --- /dev/null +++ b/assets/icons/radix/eraser.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/exclamation-triangle.svg b/assets/icons/radix/exclamation-triangle.svg new file mode 100644 index 0000000000000000000000000000000000000000..210d4c45c666164985e0f1998201d444c9a5f2a7 --- /dev/null +++ b/assets/icons/radix/exclamation-triangle.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/exit-full-screen.svg b/assets/icons/radix/exit-full-screen.svg new file mode 100644 index 0000000000000000000000000000000000000000..9b6439b043b367c5c300949f511ecb9866f2eaca --- /dev/null +++ b/assets/icons/radix/exit-full-screen.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/exit.svg b/assets/icons/radix/exit.svg new file mode 100644 index 0000000000000000000000000000000000000000..2cc6ce120dc9af17a642ac3bf2f2451209cb5e5e --- /dev/null +++ b/assets/icons/radix/exit.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/external-link.svg b/assets/icons/radix/external-link.svg new file mode 100644 index 0000000000000000000000000000000000000000..0ee7420162a88fa92afc958ec9a61242a9a8640c --- /dev/null +++ b/assets/icons/radix/external-link.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/eye-closed.svg b/assets/icons/radix/eye-closed.svg new file mode 100644 index 0000000000000000000000000000000000000000..f824fe55f9e2f45e7e12b77420eaeb24d6e9c913 --- /dev/null +++ b/assets/icons/radix/eye-closed.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/eye-none.svg b/assets/icons/radix/eye-none.svg new file mode 100644 index 0000000000000000000000000000000000000000..d4beecd33a4a4a305407e1adfa2f4584c4359635 --- /dev/null +++ b/assets/icons/radix/eye-none.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/eye-open.svg b/assets/icons/radix/eye-open.svg new file mode 100644 index 0000000000000000000000000000000000000000..d39d26b2c1bbc40af8548cafe219f7cef2373373 --- /dev/null +++ b/assets/icons/radix/eye-open.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/face.svg b/assets/icons/radix/face.svg new file mode 100644 index 0000000000000000000000000000000000000000..81b14dd8d7932f9db417843798c726422890b32e --- /dev/null +++ b/assets/icons/radix/face.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/figma-logo.svg b/assets/icons/radix/figma-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..6c19276554908b11c8742deb0ab4e971bf6856a7 --- /dev/null +++ b/assets/icons/radix/figma-logo.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/file-minus.svg b/assets/icons/radix/file-minus.svg new file mode 100644 index 0000000000000000000000000000000000000000..bd1a841881c0cfa6a52364dfe57fd55e5a539fa0 --- /dev/null +++ b/assets/icons/radix/file-minus.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/file-plus.svg b/assets/icons/radix/file-plus.svg new file mode 100644 index 0000000000000000000000000000000000000000..2396e20015984b69e2c194c2c9e8552b1a2cc3b5 --- /dev/null +++ b/assets/icons/radix/file-plus.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/file-text.svg b/assets/icons/radix/file-text.svg new file mode 100644 index 0000000000000000000000000000000000000000..f341ab8abfdba5a9aaac3a81b709c75def92e46c --- /dev/null +++ b/assets/icons/radix/file-text.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/file.svg b/assets/icons/radix/file.svg new file mode 100644 index 0000000000000000000000000000000000000000..5f256b42e1fde343b8194d199f52921e8ad01b7c --- /dev/null +++ b/assets/icons/radix/file.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/font-bold.svg b/assets/icons/radix/font-bold.svg new file mode 100644 index 0000000000000000000000000000000000000000..7dc6caf3b052c956c9bb9ad4adc9ca245cfcf083 --- /dev/null +++ b/assets/icons/radix/font-bold.svg @@ -0,0 +1,6 @@ + + + diff --git a/assets/icons/radix/font-family.svg b/assets/icons/radix/font-family.svg new file mode 100644 index 0000000000000000000000000000000000000000..9134b9086dd5ddb9aa40a01875033392b2f92f89 --- /dev/null +++ b/assets/icons/radix/font-family.svg @@ -0,0 +1,6 @@ + + + diff --git a/assets/icons/radix/font-italic.svg b/assets/icons/radix/font-italic.svg new file mode 100644 index 0000000000000000000000000000000000000000..6e6288d6bc3ffae240721c50c1a85c1a80270aa2 --- /dev/null +++ b/assets/icons/radix/font-italic.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/font-roman.svg b/assets/icons/radix/font-roman.svg new file mode 100644 index 0000000000000000000000000000000000000000..c595b790fc5065d5e4b276d4e73be1ccdeba7be2 --- /dev/null +++ b/assets/icons/radix/font-roman.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/font-size.svg b/assets/icons/radix/font-size.svg new file mode 100644 index 0000000000000000000000000000000000000000..e389a58d73bc4997d64b78426be26e964fd5b2b8 --- /dev/null +++ b/assets/icons/radix/font-size.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/font-style.svg b/assets/icons/radix/font-style.svg new file mode 100644 index 0000000000000000000000000000000000000000..31c3730130fad5367eb87f1b5ce52b243ee4c1f5 --- /dev/null +++ b/assets/icons/radix/font-style.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/frame.svg b/assets/icons/radix/frame.svg new file mode 100644 index 0000000000000000000000000000000000000000..ec61a48efabfc82a55a749860976dd694aee7a83 --- /dev/null +++ b/assets/icons/radix/frame.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/framer-logo.svg b/assets/icons/radix/framer-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..68be3b317b90d2fa990622857645bf21c1768c74 --- /dev/null +++ b/assets/icons/radix/framer-logo.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/gear.svg b/assets/icons/radix/gear.svg new file mode 100644 index 0000000000000000000000000000000000000000..52f9e17312fb364b410edbcb21f3aa4b6f3c133c --- /dev/null +++ b/assets/icons/radix/gear.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/github-logo.svg b/assets/icons/radix/github-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..e46612cf566f59ffc8d8b8b6f4a8bcecd8779b12 --- /dev/null +++ b/assets/icons/radix/github-logo.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/globe.svg b/assets/icons/radix/globe.svg new file mode 100644 index 0000000000000000000000000000000000000000..4728b827df862d2e4db3363d9d518cebc860986a --- /dev/null +++ b/assets/icons/radix/globe.svg @@ -0,0 +1,26 @@ + + + + + + diff --git a/assets/icons/radix/grid.svg b/assets/icons/radix/grid.svg new file mode 100644 index 0000000000000000000000000000000000000000..5d9af3357295415ea824128b9806d1ca895e8bb6 --- /dev/null +++ b/assets/icons/radix/grid.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/group.svg b/assets/icons/radix/group.svg new file mode 100644 index 0000000000000000000000000000000000000000..c3c91d211f47df42ad1c89911fc63e60499d3db6 --- /dev/null +++ b/assets/icons/radix/group.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/half-1.svg b/assets/icons/radix/half-1.svg new file mode 100644 index 0000000000000000000000000000000000000000..9890e26bb815242173bf8a60a01194a9130a361f --- /dev/null +++ b/assets/icons/radix/half-1.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/half-2.svg b/assets/icons/radix/half-2.svg new file mode 100644 index 0000000000000000000000000000000000000000..4db1d564cba5c32aae6260095811291c0614fdcf --- /dev/null +++ b/assets/icons/radix/half-2.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/hamburger-menu.svg b/assets/icons/radix/hamburger-menu.svg new file mode 100644 index 0000000000000000000000000000000000000000..039168055b20d615f19400c4324857d0c038806e --- /dev/null +++ b/assets/icons/radix/hamburger-menu.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/hand.svg b/assets/icons/radix/hand.svg new file mode 100644 index 0000000000000000000000000000000000000000..12afac8f5f9fdff743a7b628437ebfb4424fba2a --- /dev/null +++ b/assets/icons/radix/hand.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/heading.svg b/assets/icons/radix/heading.svg new file mode 100644 index 0000000000000000000000000000000000000000..0a5e2caaf1b10b271da7664dc3636528c6c00942 --- /dev/null +++ b/assets/icons/radix/heading.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/heart-filled.svg b/assets/icons/radix/heart-filled.svg new file mode 100644 index 0000000000000000000000000000000000000000..94928accd7e353b655baf5840ca2be8fb4afd49c --- /dev/null +++ b/assets/icons/radix/heart-filled.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/heart.svg b/assets/icons/radix/heart.svg new file mode 100644 index 0000000000000000000000000000000000000000..91cbc450fd0418c590a1519da9834b6cdb72ff5e --- /dev/null +++ b/assets/icons/radix/heart.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/height.svg b/assets/icons/radix/height.svg new file mode 100644 index 0000000000000000000000000000000000000000..28424f4d51e008fafd30347e06e1deb8b3a6942f --- /dev/null +++ b/assets/icons/radix/height.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/hobby-knife.svg b/assets/icons/radix/hobby-knife.svg new file mode 100644 index 0000000000000000000000000000000000000000..c2ed3fb1ed89ef2b9ba74e1c94ec778af5dbc7cd --- /dev/null +++ b/assets/icons/radix/hobby-knife.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/home.svg b/assets/icons/radix/home.svg new file mode 100644 index 0000000000000000000000000000000000000000..733bd791138444e03cb01f52b2e7428f93fbbc36 --- /dev/null +++ b/assets/icons/radix/home.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/iconjar-logo.svg b/assets/icons/radix/iconjar-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..c154b4e86413741786fa3d608f6e466e91c01aab --- /dev/null +++ b/assets/icons/radix/iconjar-logo.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/id-card.svg b/assets/icons/radix/id-card.svg new file mode 100644 index 0000000000000000000000000000000000000000..efde9ffa7e612179911c972a3c048fd389fe3276 --- /dev/null +++ b/assets/icons/radix/id-card.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/image.svg b/assets/icons/radix/image.svg new file mode 100644 index 0000000000000000000000000000000000000000..0ff44752528fa0d4b31613a72446ed9164c419cb --- /dev/null +++ b/assets/icons/radix/image.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/info-circled.svg b/assets/icons/radix/info-circled.svg new file mode 100644 index 0000000000000000000000000000000000000000..4ab1b260e3d35f9a6243e44ebf0f903add40b6b8 --- /dev/null +++ b/assets/icons/radix/info-circled.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/inner-shadow.svg b/assets/icons/radix/inner-shadow.svg new file mode 100644 index 0000000000000000000000000000000000000000..1056a7bffc268fef67c209f4c81f606d40fa66d6 --- /dev/null +++ b/assets/icons/radix/inner-shadow.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + diff --git a/assets/icons/radix/input.svg b/assets/icons/radix/input.svg new file mode 100644 index 0000000000000000000000000000000000000000..4ed4605b2c60da836327a7064469425d5233858d --- /dev/null +++ b/assets/icons/radix/input.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/instagram-logo.svg b/assets/icons/radix/instagram-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..5d7893796655c947c0e6bc0dba60c6e82c86bd65 --- /dev/null +++ b/assets/icons/radix/instagram-logo.svg @@ -0,0 +1,8 @@ + + + + + diff --git a/assets/icons/radix/justify-center.svg b/assets/icons/radix/justify-center.svg new file mode 100644 index 0000000000000000000000000000000000000000..7999a4ea468e87d9f0cd793e80c2a43454c4aeac --- /dev/null +++ b/assets/icons/radix/justify-center.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/justify-end.svg b/assets/icons/radix/justify-end.svg new file mode 100644 index 0000000000000000000000000000000000000000..bb52f493d75d79f91e3a6f34e103023e2cc8b87c --- /dev/null +++ b/assets/icons/radix/justify-end.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/justify-start.svg b/assets/icons/radix/justify-start.svg new file mode 100644 index 0000000000000000000000000000000000000000..648ca0b60324f4b92a617f377d890b8f1e1adf13 --- /dev/null +++ b/assets/icons/radix/justify-start.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/justify-stretch.svg b/assets/icons/radix/justify-stretch.svg new file mode 100644 index 0000000000000000000000000000000000000000..83df0a8959381ef48a3bd97b53f63f8d9a8bba0f --- /dev/null +++ b/assets/icons/radix/justify-stretch.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/keyboard.svg b/assets/icons/radix/keyboard.svg new file mode 100644 index 0000000000000000000000000000000000000000..fc6f86bfc2b48bdd4fb7acf8e9e08422fed2e91e --- /dev/null +++ b/assets/icons/radix/keyboard.svg @@ -0,0 +1,7 @@ + + + + diff --git a/assets/icons/radix/lap-timer.svg b/assets/icons/radix/lap-timer.svg new file mode 100644 index 0000000000000000000000000000000000000000..1de0b3be6ce99de994a905cfbaf5e342754bb651 --- /dev/null +++ b/assets/icons/radix/lap-timer.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/laptop.svg b/assets/icons/radix/laptop.svg new file mode 100644 index 0000000000000000000000000000000000000000..6aff5d6d446ea46b131bdea1efbd183bc0010381 --- /dev/null +++ b/assets/icons/radix/laptop.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/layers.svg b/assets/icons/radix/layers.svg new file mode 100644 index 0000000000000000000000000000000000000000..821993fc70c13ebdb18a997d849db95424399d82 --- /dev/null +++ b/assets/icons/radix/layers.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/layout.svg b/assets/icons/radix/layout.svg new file mode 100644 index 0000000000000000000000000000000000000000..8e4a352f5022fe33402bd5267f32f925958a2a01 --- /dev/null +++ b/assets/icons/radix/layout.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/letter-case-capitalize.svg b/assets/icons/radix/letter-case-capitalize.svg new file mode 100644 index 0000000000000000000000000000000000000000..16617ecf7e052db05c5bccfe1da0bb378835f686 --- /dev/null +++ b/assets/icons/radix/letter-case-capitalize.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/letter-case-lowercase.svg b/assets/icons/radix/letter-case-lowercase.svg new file mode 100644 index 0000000000000000000000000000000000000000..61aefb9aadd3c45a338e5c8048749d62c2c1bfe6 --- /dev/null +++ b/assets/icons/radix/letter-case-lowercase.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/letter-case-toggle.svg b/assets/icons/radix/letter-case-toggle.svg new file mode 100644 index 0000000000000000000000000000000000000000..a021a2b9225d8eda5657a713b94f7145757206a3 --- /dev/null +++ b/assets/icons/radix/letter-case-toggle.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/letter-case-uppercase.svg b/assets/icons/radix/letter-case-uppercase.svg new file mode 100644 index 0000000000000000000000000000000000000000..ccd2be04e7757db3050e7675f093288b6d9a5748 --- /dev/null +++ b/assets/icons/radix/letter-case-uppercase.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/letter-spacing.svg b/assets/icons/radix/letter-spacing.svg new file mode 100644 index 0000000000000000000000000000000000000000..073023e0f4df60364dede352b60fdc151e6f05d2 --- /dev/null +++ b/assets/icons/radix/letter-spacing.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/lightning-bolt.svg b/assets/icons/radix/lightning-bolt.svg new file mode 100644 index 0000000000000000000000000000000000000000..7c35df9cfea2b54cfffa84161902126234ba3234 --- /dev/null +++ b/assets/icons/radix/lightning-bolt.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/line-height.svg b/assets/icons/radix/line-height.svg new file mode 100644 index 0000000000000000000000000000000000000000..1c302d1ffc1f1b7e1abb1f4a7553b69be224aac2 --- /dev/null +++ b/assets/icons/radix/line-height.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/link-1.svg b/assets/icons/radix/link-1.svg new file mode 100644 index 0000000000000000000000000000000000000000..d5682b113ee37a34a42a65897f501af0ee04ffe3 --- /dev/null +++ b/assets/icons/radix/link-1.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/link-2.svg b/assets/icons/radix/link-2.svg new file mode 100644 index 0000000000000000000000000000000000000000..be8370606e7fe33fd9eda9e440433236cc3f6d68 --- /dev/null +++ b/assets/icons/radix/link-2.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/link-break-1.svg b/assets/icons/radix/link-break-1.svg new file mode 100644 index 0000000000000000000000000000000000000000..05ae93e47a4f16ce18cbe2ca3a709b3abc62d15b --- /dev/null +++ b/assets/icons/radix/link-break-1.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/link-break-2.svg b/assets/icons/radix/link-break-2.svg new file mode 100644 index 0000000000000000000000000000000000000000..78f28f98e815d7fdd822d4a8710d686ad314ccdd --- /dev/null +++ b/assets/icons/radix/link-break-2.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/link-none-1.svg b/assets/icons/radix/link-none-1.svg new file mode 100644 index 0000000000000000000000000000000000000000..6ea56a386fa133bf983a3a7f06b70bd12189e05d --- /dev/null +++ b/assets/icons/radix/link-none-1.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/link-none-2.svg b/assets/icons/radix/link-none-2.svg new file mode 100644 index 0000000000000000000000000000000000000000..0b19d940d109bca37ade399a36b8b10c2812faf8 --- /dev/null +++ b/assets/icons/radix/link-none-2.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/linkedin-logo.svg b/assets/icons/radix/linkedin-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..0f0138bdf6cade2297362c820831a995f7a4e02f --- /dev/null +++ b/assets/icons/radix/linkedin-logo.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/list-bullet.svg b/assets/icons/radix/list-bullet.svg new file mode 100644 index 0000000000000000000000000000000000000000..2630b95ef029e231be2a854efa2cf4c50dbeeb95 --- /dev/null +++ b/assets/icons/radix/list-bullet.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/lock-closed.svg b/assets/icons/radix/lock-closed.svg new file mode 100644 index 0000000000000000000000000000000000000000..3871b5d5ada8020c7d7f56510158bd89c4ab5ff2 --- /dev/null +++ b/assets/icons/radix/lock-closed.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/lock-open-1.svg b/assets/icons/radix/lock-open-1.svg new file mode 100644 index 0000000000000000000000000000000000000000..8f6bfd5bbf82007be6d65ada0beb4914b450faf2 --- /dev/null +++ b/assets/icons/radix/lock-open-1.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/lock-open-2.svg b/assets/icons/radix/lock-open-2.svg new file mode 100644 index 0000000000000000000000000000000000000000..ce69f67f2920b6890eb4446dd6b260484e68178d --- /dev/null +++ b/assets/icons/radix/lock-open-2.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/loop.svg b/assets/icons/radix/loop.svg new file mode 100644 index 0000000000000000000000000000000000000000..bfa90ed0841f6ca8d26c1eef72e00d893d5efe0c --- /dev/null +++ b/assets/icons/radix/loop.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/magic-wand.svg b/assets/icons/radix/magic-wand.svg new file mode 100644 index 0000000000000000000000000000000000000000..bbc9826aa54afbf202153a170e642bb64f235298 --- /dev/null +++ b/assets/icons/radix/magic-wand.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/magnifying-glass.svg b/assets/icons/radix/magnifying-glass.svg new file mode 100644 index 0000000000000000000000000000000000000000..a3a89bfa5059192bdb481a043cdde6d7e42c2f24 --- /dev/null +++ b/assets/icons/radix/magnifying-glass.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/margin.svg b/assets/icons/radix/margin.svg new file mode 100644 index 0000000000000000000000000000000000000000..1a513b37d6846849b260a409b9993d3c708bfe30 --- /dev/null +++ b/assets/icons/radix/margin.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/mask-off.svg b/assets/icons/radix/mask-off.svg new file mode 100644 index 0000000000000000000000000000000000000000..5f847668e8986d4ba9be5cba4b6ddab65e61f0d2 --- /dev/null +++ b/assets/icons/radix/mask-off.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/mask-on.svg b/assets/icons/radix/mask-on.svg new file mode 100644 index 0000000000000000000000000000000000000000..684c1b934dce4e99b1485593bb8995576eae186b --- /dev/null +++ b/assets/icons/radix/mask-on.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/minus-circled.svg b/assets/icons/radix/minus-circled.svg new file mode 100644 index 0000000000000000000000000000000000000000..2c6df4cebf1ea279fdc43598fff062ea5db72cb7 --- /dev/null +++ b/assets/icons/radix/minus-circled.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/minus.svg b/assets/icons/radix/minus.svg new file mode 100644 index 0000000000000000000000000000000000000000..2b396029795aa7b9bcfb2f9dbb703cb491bf88f2 --- /dev/null +++ b/assets/icons/radix/minus.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/mix.svg b/assets/icons/radix/mix.svg new file mode 100644 index 0000000000000000000000000000000000000000..9412a018438b79130fbba167176860d2cef38106 --- /dev/null +++ b/assets/icons/radix/mix.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/mixer-horizontal.svg b/assets/icons/radix/mixer-horizontal.svg new file mode 100644 index 0000000000000000000000000000000000000000..f29ba25548a32eae3979249cd915f074444a0f51 --- /dev/null +++ b/assets/icons/radix/mixer-horizontal.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/mixer-vertical.svg b/assets/icons/radix/mixer-vertical.svg new file mode 100644 index 0000000000000000000000000000000000000000..dc85d3a9e7a3c3a5ba9d016bb88368b2b35cdcaa --- /dev/null +++ b/assets/icons/radix/mixer-vertical.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/mobile.svg b/assets/icons/radix/mobile.svg new file mode 100644 index 0000000000000000000000000000000000000000..b62b6506ff4f7838e025ea98f93caac228fdd88e --- /dev/null +++ b/assets/icons/radix/mobile.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/modulz-logo.svg b/assets/icons/radix/modulz-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..754b229db6b03264c0258553b18d5eea2473a316 --- /dev/null +++ b/assets/icons/radix/modulz-logo.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/moon.svg b/assets/icons/radix/moon.svg new file mode 100644 index 0000000000000000000000000000000000000000..1dac2ca2120eb3deebf39e9fdf8a353d14e0fb1e --- /dev/null +++ b/assets/icons/radix/moon.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/move.svg b/assets/icons/radix/move.svg new file mode 100644 index 0000000000000000000000000000000000000000..3d0a0e56c9063858f9d71c0cad7c43cdf448c84d --- /dev/null +++ b/assets/icons/radix/move.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/notion-logo.svg b/assets/icons/radix/notion-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..c2df1526195d99956c0edb1e8c01a5ac641cbaca --- /dev/null +++ b/assets/icons/radix/notion-logo.svg @@ -0,0 +1,6 @@ + + + diff --git a/assets/icons/radix/opacity.svg b/assets/icons/radix/opacity.svg new file mode 100644 index 0000000000000000000000000000000000000000..a2d01bff82923948a67ac243df677fc3d7331706 --- /dev/null +++ b/assets/icons/radix/opacity.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/open-in-new-window.svg b/assets/icons/radix/open-in-new-window.svg new file mode 100644 index 0000000000000000000000000000000000000000..22baf82cff73662895c6aae20d426319b9ea32a4 --- /dev/null +++ b/assets/icons/radix/open-in-new-window.svg @@ -0,0 +1,10 @@ + + + + + diff --git a/assets/icons/radix/outer-shadow.svg b/assets/icons/radix/outer-shadow.svg new file mode 100644 index 0000000000000000000000000000000000000000..b44e3d553c040d855204ac3d543cfa6539db7612 --- /dev/null +++ b/assets/icons/radix/outer-shadow.svg @@ -0,0 +1,43 @@ + + + + + + + + diff --git a/assets/icons/radix/overline.svg b/assets/icons/radix/overline.svg new file mode 100644 index 0000000000000000000000000000000000000000..57262c76e6df8a60a11aa2dddde8a437824ef8e3 --- /dev/null +++ b/assets/icons/radix/overline.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/padding.svg b/assets/icons/radix/padding.svg new file mode 100644 index 0000000000000000000000000000000000000000..483a25a27ea1e7c94b21c91b15d929c5cd95ed81 --- /dev/null +++ b/assets/icons/radix/padding.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/paper-plane.svg b/assets/icons/radix/paper-plane.svg new file mode 100644 index 0000000000000000000000000000000000000000..37ad0703004b817ff2dd52dae5680dabdd5574db --- /dev/null +++ b/assets/icons/radix/paper-plane.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/pause.svg b/assets/icons/radix/pause.svg new file mode 100644 index 0000000000000000000000000000000000000000..b399fb2f5a7ba00e088e9fc2ac10042452879e46 --- /dev/null +++ b/assets/icons/radix/pause.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/pencil-1.svg b/assets/icons/radix/pencil-1.svg new file mode 100644 index 0000000000000000000000000000000000000000..decf0122ef482aab10c213cad07a008e492b2e86 --- /dev/null +++ b/assets/icons/radix/pencil-1.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/pencil-2.svg b/assets/icons/radix/pencil-2.svg new file mode 100644 index 0000000000000000000000000000000000000000..2559a393a9fc2368697619724887a7c7eb8b5a1e --- /dev/null +++ b/assets/icons/radix/pencil-2.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/person.svg b/assets/icons/radix/person.svg new file mode 100644 index 0000000000000000000000000000000000000000..051abcc7033796d6ad5e65d2d0d5955b6bb51759 --- /dev/null +++ b/assets/icons/radix/person.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/pie-chart.svg b/assets/icons/radix/pie-chart.svg new file mode 100644 index 0000000000000000000000000000000000000000..bb58e4727465e6c2cebb84e6c7a38b884b9ef13c --- /dev/null +++ b/assets/icons/radix/pie-chart.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/pilcrow.svg b/assets/icons/radix/pilcrow.svg new file mode 100644 index 0000000000000000000000000000000000000000..6996765fd60b2e1c09182156b2ba8e19b3cca5f5 --- /dev/null +++ b/assets/icons/radix/pilcrow.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/pin-bottom.svg b/assets/icons/radix/pin-bottom.svg new file mode 100644 index 0000000000000000000000000000000000000000..ad0842054f082e24c4ab145471c302d00cb9fea6 --- /dev/null +++ b/assets/icons/radix/pin-bottom.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/pin-left.svg b/assets/icons/radix/pin-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..eb89b2912f0735b57f655fe08a33d6efdb5340de --- /dev/null +++ b/assets/icons/radix/pin-left.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/pin-right.svg b/assets/icons/radix/pin-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..89a98bae4ea00e8562392aa2dda764d1d6203f40 --- /dev/null +++ b/assets/icons/radix/pin-right.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/pin-top.svg b/assets/icons/radix/pin-top.svg new file mode 100644 index 0000000000000000000000000000000000000000..edfeb64d5d87b0df6c25509d2077054613c4f543 --- /dev/null +++ b/assets/icons/radix/pin-top.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/play.svg b/assets/icons/radix/play.svg new file mode 100644 index 0000000000000000000000000000000000000000..92af9e1ae7f125fd9f36e1b67f43b9c71aa54296 --- /dev/null +++ b/assets/icons/radix/play.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/plus-circled.svg b/assets/icons/radix/plus-circled.svg new file mode 100644 index 0000000000000000000000000000000000000000..808ddc4c2ce157903747ff88672425d9c39d5f71 --- /dev/null +++ b/assets/icons/radix/plus-circled.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/plus.svg b/assets/icons/radix/plus.svg new file mode 100644 index 0000000000000000000000000000000000000000..57ce90219bc6f72d92e55011f6dcb9f20ba320eb --- /dev/null +++ b/assets/icons/radix/plus.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/question-mark-circled.svg b/assets/icons/radix/question-mark-circled.svg new file mode 100644 index 0000000000000000000000000000000000000000..be99968787df16246e5fb2bbeee617b27393496f --- /dev/null +++ b/assets/icons/radix/question-mark-circled.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/question-mark.svg b/assets/icons/radix/question-mark.svg new file mode 100644 index 0000000000000000000000000000000000000000..577aae53496676a657164f0406c50e41566dae3a --- /dev/null +++ b/assets/icons/radix/question-mark.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/quote.svg b/assets/icons/radix/quote.svg new file mode 100644 index 0000000000000000000000000000000000000000..50205479c300e789b302cb1dcd687aaf7f9353f8 --- /dev/null +++ b/assets/icons/radix/quote.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/radiobutton.svg b/assets/icons/radix/radiobutton.svg new file mode 100644 index 0000000000000000000000000000000000000000..f0c3a60aee6f499a3dffd30d5d731612de3d90db --- /dev/null +++ b/assets/icons/radix/radiobutton.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/reader.svg b/assets/icons/radix/reader.svg new file mode 100644 index 0000000000000000000000000000000000000000..e893cfa68510377d91301e796366babcc2cbb7aa --- /dev/null +++ b/assets/icons/radix/reader.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/reload.svg b/assets/icons/radix/reload.svg new file mode 100644 index 0000000000000000000000000000000000000000..cf1dfb7fa20bd8233e8ea75c51061b11f73302f5 --- /dev/null +++ b/assets/icons/radix/reload.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/reset.svg b/assets/icons/radix/reset.svg new file mode 100644 index 0000000000000000000000000000000000000000..f21a508514cac8c8da0626237726148ee8833953 --- /dev/null +++ b/assets/icons/radix/reset.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/resume.svg b/assets/icons/radix/resume.svg new file mode 100644 index 0000000000000000000000000000000000000000..79cdec2374c2e06a3f0afced560a27a9042cc63b --- /dev/null +++ b/assets/icons/radix/resume.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/rocket.svg b/assets/icons/radix/rocket.svg new file mode 100644 index 0000000000000000000000000000000000000000..2226aacb1a7e497f377fbbd607f125782b150f7e --- /dev/null +++ b/assets/icons/radix/rocket.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/rotate-counter-clockwise.svg b/assets/icons/radix/rotate-counter-clockwise.svg new file mode 100644 index 0000000000000000000000000000000000000000..c43c90b90ba001df326c83df80b7d25152782cc3 --- /dev/null +++ b/assets/icons/radix/rotate-counter-clockwise.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/row-spacing.svg b/assets/icons/radix/row-spacing.svg new file mode 100644 index 0000000000000000000000000000000000000000..e155bd59479ceaf31dcde7155b0503aa6f305a34 --- /dev/null +++ b/assets/icons/radix/row-spacing.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/rows.svg b/assets/icons/radix/rows.svg new file mode 100644 index 0000000000000000000000000000000000000000..fb4ca0f9e3acb960fdeba9d86c973736eda25573 --- /dev/null +++ b/assets/icons/radix/rows.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/ruler-horizontal.svg b/assets/icons/radix/ruler-horizontal.svg new file mode 100644 index 0000000000000000000000000000000000000000..db6f1ef488b20f66fe89538461b72ba0b7827b54 --- /dev/null +++ b/assets/icons/radix/ruler-horizontal.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/ruler-square.svg b/assets/icons/radix/ruler-square.svg new file mode 100644 index 0000000000000000000000000000000000000000..7de70cc5dc1e852283f89a5048cc730e146ddd4a --- /dev/null +++ b/assets/icons/radix/ruler-square.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/scissors.svg b/assets/icons/radix/scissors.svg new file mode 100644 index 0000000000000000000000000000000000000000..2893b347123f0a29be96b52ee0886ba716f365a0 --- /dev/null +++ b/assets/icons/radix/scissors.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/section.svg b/assets/icons/radix/section.svg new file mode 100644 index 0000000000000000000000000000000000000000..1e939e2b2f31f4eef53496154dc4e7c086b28162 --- /dev/null +++ b/assets/icons/radix/section.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/sewing-pin-filled.svg b/assets/icons/radix/sewing-pin-filled.svg new file mode 100644 index 0000000000000000000000000000000000000000..97f6f1120d988746a9ad95d33e8d24b237bec58b --- /dev/null +++ b/assets/icons/radix/sewing-pin-filled.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/sewing-pin-solid.svg b/assets/icons/radix/sewing-pin-solid.svg new file mode 100644 index 0000000000000000000000000000000000000000..97f6f1120d988746a9ad95d33e8d24b237bec58b --- /dev/null +++ b/assets/icons/radix/sewing-pin-solid.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/sewing-pin.svg b/assets/icons/radix/sewing-pin.svg new file mode 100644 index 0000000000000000000000000000000000000000..068dfd7bdfca25e8ac4834f7011e96b377a3ca49 --- /dev/null +++ b/assets/icons/radix/sewing-pin.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/shadow-inner.svg b/assets/icons/radix/shadow-inner.svg new file mode 100644 index 0000000000000000000000000000000000000000..4d073bf35f87e99198fc44258c8af746ff95e0b6 --- /dev/null +++ b/assets/icons/radix/shadow-inner.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + diff --git a/assets/icons/radix/shadow-none.svg b/assets/icons/radix/shadow-none.svg new file mode 100644 index 0000000000000000000000000000000000000000..b02d3466adeb08e3ddbf4ecc3b6c554f1dd5872d --- /dev/null +++ b/assets/icons/radix/shadow-none.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + diff --git a/assets/icons/radix/shadow-outer.svg b/assets/icons/radix/shadow-outer.svg new file mode 100644 index 0000000000000000000000000000000000000000..dc7ea840878699d22280f6edf481b7c8ea51fa64 --- /dev/null +++ b/assets/icons/radix/shadow-outer.svg @@ -0,0 +1,43 @@ + + + + + + + + diff --git a/assets/icons/radix/shadow.svg b/assets/icons/radix/shadow.svg new file mode 100644 index 0000000000000000000000000000000000000000..c991af6156cb38d143c574bcfb925364768c4f3f --- /dev/null +++ b/assets/icons/radix/shadow.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + diff --git a/assets/icons/radix/share-1.svg b/assets/icons/radix/share-1.svg new file mode 100644 index 0000000000000000000000000000000000000000..58328e4d1ee1091b8f909ecdfb22b836cb167a93 --- /dev/null +++ b/assets/icons/radix/share-1.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/share-2.svg b/assets/icons/radix/share-2.svg new file mode 100644 index 0000000000000000000000000000000000000000..1302ea5fbe198800c08b2abc0cb79a2f4136d3b0 --- /dev/null +++ b/assets/icons/radix/share-2.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/shuffle.svg b/assets/icons/radix/shuffle.svg new file mode 100644 index 0000000000000000000000000000000000000000..8670e1a04898e130c357c933f7edac966e2cfac9 --- /dev/null +++ b/assets/icons/radix/shuffle.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/size.svg b/assets/icons/radix/size.svg new file mode 100644 index 0000000000000000000000000000000000000000..dece8c51820fb451e57bf6efd313a00ce6050e22 --- /dev/null +++ b/assets/icons/radix/size.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/sketch-logo.svg b/assets/icons/radix/sketch-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..6c54c4c8252e96ec9d762ffbbab596a72c163303 --- /dev/null +++ b/assets/icons/radix/sketch-logo.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/slash.svg b/assets/icons/radix/slash.svg new file mode 100644 index 0000000000000000000000000000000000000000..aa7dac30c1af6717056c15f4abafe2b3a1bb09ef --- /dev/null +++ b/assets/icons/radix/slash.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/slider.svg b/assets/icons/radix/slider.svg new file mode 100644 index 0000000000000000000000000000000000000000..66e0452bc0a0469ff6f7ff789f2db55a4fca4e17 --- /dev/null +++ b/assets/icons/radix/slider.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/space-between-horizontally.svg b/assets/icons/radix/space-between-horizontally.svg new file mode 100644 index 0000000000000000000000000000000000000000..a71638d52b0c90597a696e4671ce17f1c342681f --- /dev/null +++ b/assets/icons/radix/space-between-horizontally.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/space-between-vertically.svg b/assets/icons/radix/space-between-vertically.svg new file mode 100644 index 0000000000000000000000000000000000000000..bae247222fac0ed744593dcc97befe6051483101 --- /dev/null +++ b/assets/icons/radix/space-between-vertically.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/space-evenly-horizontally.svg b/assets/icons/radix/space-evenly-horizontally.svg new file mode 100644 index 0000000000000000000000000000000000000000..70169492e4072dc561370d6185db255a229dd8e2 --- /dev/null +++ b/assets/icons/radix/space-evenly-horizontally.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/space-evenly-vertically.svg b/assets/icons/radix/space-evenly-vertically.svg new file mode 100644 index 0000000000000000000000000000000000000000..469b4c05d4eda8045d2534b0a5e8847d0b423851 --- /dev/null +++ b/assets/icons/radix/space-evenly-vertically.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/speaker-loud.svg b/assets/icons/radix/speaker-loud.svg new file mode 100644 index 0000000000000000000000000000000000000000..68982ee5e92a85f193d80c6f7aa285722d1d78d8 --- /dev/null +++ b/assets/icons/radix/speaker-loud.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/speaker-moderate.svg b/assets/icons/radix/speaker-moderate.svg new file mode 100644 index 0000000000000000000000000000000000000000..0f1d1b4210991ec8d8718bef86c9959bec264c58 --- /dev/null +++ b/assets/icons/radix/speaker-moderate.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/speaker-off.svg b/assets/icons/radix/speaker-off.svg new file mode 100644 index 0000000000000000000000000000000000000000..f60c35de7f3f5bb7eecf405c6370391aed6f3ae3 --- /dev/null +++ b/assets/icons/radix/speaker-off.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/speaker-quiet.svg b/assets/icons/radix/speaker-quiet.svg new file mode 100644 index 0000000000000000000000000000000000000000..eb68cefcee916e168d25a58be9c4015fe131ecf4 --- /dev/null +++ b/assets/icons/radix/speaker-quiet.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/square.svg b/assets/icons/radix/square.svg new file mode 100644 index 0000000000000000000000000000000000000000..82843f51c3b7c98cade0ed914ca18095e3d385fe --- /dev/null +++ b/assets/icons/radix/square.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/stack.svg b/assets/icons/radix/stack.svg new file mode 100644 index 0000000000000000000000000000000000000000..92426ffb0d3aac123f647a9c3bcf07932de91407 --- /dev/null +++ b/assets/icons/radix/stack.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/star-filled.svg b/assets/icons/radix/star-filled.svg new file mode 100644 index 0000000000000000000000000000000000000000..2b17b7f5792c663e533d3fbe8def8ed44f12b7ff --- /dev/null +++ b/assets/icons/radix/star-filled.svg @@ -0,0 +1,6 @@ + + + diff --git a/assets/icons/radix/star.svg b/assets/icons/radix/star.svg new file mode 100644 index 0000000000000000000000000000000000000000..23f09ad7b271cb11e9660901a5d9d819a40ec9a5 --- /dev/null +++ b/assets/icons/radix/star.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/stitches-logo.svg b/assets/icons/radix/stitches-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..319a1481f3e89c5c24535ecc03fffa89c83de737 --- /dev/null +++ b/assets/icons/radix/stitches-logo.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/stop.svg b/assets/icons/radix/stop.svg new file mode 100644 index 0000000000000000000000000000000000000000..57aac59cab28050f94d5cb93877e8d967f4661c5 --- /dev/null +++ b/assets/icons/radix/stop.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/stopwatch.svg b/assets/icons/radix/stopwatch.svg new file mode 100644 index 0000000000000000000000000000000000000000..ce5661e5cc9b983676fc97ae0d9c08e78878ee74 --- /dev/null +++ b/assets/icons/radix/stopwatch.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/stretch-horizontally.svg b/assets/icons/radix/stretch-horizontally.svg new file mode 100644 index 0000000000000000000000000000000000000000..37977363b3046bc59bfd6eb74673a5a49d43d2f8 --- /dev/null +++ b/assets/icons/radix/stretch-horizontally.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/stretch-vertically.svg b/assets/icons/radix/stretch-vertically.svg new file mode 100644 index 0000000000000000000000000000000000000000..c4b1fe79ce21f963ad70a17278be8bef7804e43c --- /dev/null +++ b/assets/icons/radix/stretch-vertically.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/strikethrough.svg b/assets/icons/radix/strikethrough.svg new file mode 100644 index 0000000000000000000000000000000000000000..b814ef420acc8a4a385eaf29d52a5a167171860f --- /dev/null +++ b/assets/icons/radix/strikethrough.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/sun.svg b/assets/icons/radix/sun.svg new file mode 100644 index 0000000000000000000000000000000000000000..1807a51b4c60c764a6af190dbd957b6c2ebd0d91 --- /dev/null +++ b/assets/icons/radix/sun.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/switch.svg b/assets/icons/radix/switch.svg new file mode 100644 index 0000000000000000000000000000000000000000..6dea528ce9bd25a06962d5ecc64f1ca4b1c9d754 --- /dev/null +++ b/assets/icons/radix/switch.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/symbol.svg b/assets/icons/radix/symbol.svg new file mode 100644 index 0000000000000000000000000000000000000000..b529b2b08b42a17027566a47d20f8ae93d61ae35 --- /dev/null +++ b/assets/icons/radix/symbol.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/table.svg b/assets/icons/radix/table.svg new file mode 100644 index 0000000000000000000000000000000000000000..8ff059b847b30b73fc31577d88a9a5bc639e6371 --- /dev/null +++ b/assets/icons/radix/table.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/target.svg b/assets/icons/radix/target.svg new file mode 100644 index 0000000000000000000000000000000000000000..d67989e01fb7b70c728fdcf85360ac41ac8f2ff5 --- /dev/null +++ b/assets/icons/radix/target.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/text-align-bottom.svg b/assets/icons/radix/text-align-bottom.svg new file mode 100644 index 0000000000000000000000000000000000000000..862a5aeb883e236e076caee3bec650d79b9b2cd4 --- /dev/null +++ b/assets/icons/radix/text-align-bottom.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/text-align-center.svg b/assets/icons/radix/text-align-center.svg new file mode 100644 index 0000000000000000000000000000000000000000..673cf8cd0aa97a1ffd39409152efd6fe5cc1ef12 --- /dev/null +++ b/assets/icons/radix/text-align-center.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/text-align-justify.svg b/assets/icons/radix/text-align-justify.svg new file mode 100644 index 0000000000000000000000000000000000000000..df877f95134803f7d07627ec1b22e6d076c6b595 --- /dev/null +++ b/assets/icons/radix/text-align-justify.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/text-align-left.svg b/assets/icons/radix/text-align-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..b7a64fbd439720429ebe73c82340619e3d950391 --- /dev/null +++ b/assets/icons/radix/text-align-left.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/text-align-middle.svg b/assets/icons/radix/text-align-middle.svg new file mode 100644 index 0000000000000000000000000000000000000000..e739d04efabdf1edada6c848c14c0e3ad3f62832 --- /dev/null +++ b/assets/icons/radix/text-align-middle.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/text-align-right.svg b/assets/icons/radix/text-align-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..e7609908ff9436a9e9c4b366ad54b891c9868b64 --- /dev/null +++ b/assets/icons/radix/text-align-right.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/text-align-top.svg b/assets/icons/radix/text-align-top.svg new file mode 100644 index 0000000000000000000000000000000000000000..21660fe7d307f5e78cf997778d0bc68f9a83f705 --- /dev/null +++ b/assets/icons/radix/text-align-top.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/text-none.svg b/assets/icons/radix/text-none.svg new file mode 100644 index 0000000000000000000000000000000000000000..2a87f9372a66fd9e3b56807d0adde8fbb29a568c --- /dev/null +++ b/assets/icons/radix/text-none.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/text.svg b/assets/icons/radix/text.svg new file mode 100644 index 0000000000000000000000000000000000000000..bd41d8ac191905eb40201c7779c247d86783bf67 --- /dev/null +++ b/assets/icons/radix/text.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/thick-arrow-down.svg b/assets/icons/radix/thick-arrow-down.svg new file mode 100644 index 0000000000000000000000000000000000000000..32923bec58192f66bcce7f067208103d768f5a74 --- /dev/null +++ b/assets/icons/radix/thick-arrow-down.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/thick-arrow-left.svg b/assets/icons/radix/thick-arrow-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..0cfd863903b3ae25d89ca93561d81ec245686913 --- /dev/null +++ b/assets/icons/radix/thick-arrow-left.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/thick-arrow-right.svg b/assets/icons/radix/thick-arrow-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..a0cb605693638380d37ad3b6ff09c07d5b7cf3c4 --- /dev/null +++ b/assets/icons/radix/thick-arrow-right.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/thick-arrow-up.svg b/assets/icons/radix/thick-arrow-up.svg new file mode 100644 index 0000000000000000000000000000000000000000..68687be28da3d3500c2ca98113578f65b9465b44 --- /dev/null +++ b/assets/icons/radix/thick-arrow-up.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/timer.svg b/assets/icons/radix/timer.svg new file mode 100644 index 0000000000000000000000000000000000000000..20c52dff95ae423ef3decf9f88b6e13d7c42cbcc --- /dev/null +++ b/assets/icons/radix/timer.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/tokens.svg b/assets/icons/radix/tokens.svg new file mode 100644 index 0000000000000000000000000000000000000000..2bbbc82030a9ebe9b9871ec1cd18a572e688ef25 --- /dev/null +++ b/assets/icons/radix/tokens.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/track-next.svg b/assets/icons/radix/track-next.svg new file mode 100644 index 0000000000000000000000000000000000000000..24fd40e36f3d1110f34a4ffb2cc5397f9aa6766a --- /dev/null +++ b/assets/icons/radix/track-next.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/track-previous.svg b/assets/icons/radix/track-previous.svg new file mode 100644 index 0000000000000000000000000000000000000000..d99e7ab53f45d3e749b7d37d76829d8c083979cc --- /dev/null +++ b/assets/icons/radix/track-previous.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/transform.svg b/assets/icons/radix/transform.svg new file mode 100644 index 0000000000000000000000000000000000000000..e913ccc9a7a4297c47e82f978e5a4bda03d1f319 --- /dev/null +++ b/assets/icons/radix/transform.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/transparency-grid.svg b/assets/icons/radix/transparency-grid.svg new file mode 100644 index 0000000000000000000000000000000000000000..6559ef8c2b9e5ba003c6e3712f502a22416d6f04 --- /dev/null +++ b/assets/icons/radix/transparency-grid.svg @@ -0,0 +1,9 @@ + + + diff --git a/assets/icons/radix/trash.svg b/assets/icons/radix/trash.svg new file mode 100644 index 0000000000000000000000000000000000000000..18780e492c9a91b117148e72fd4fc0739f671d1e --- /dev/null +++ b/assets/icons/radix/trash.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/triangle-down.svg b/assets/icons/radix/triangle-down.svg new file mode 100644 index 0000000000000000000000000000000000000000..ebfd8f2a1236e39910eafb25a13e6466caa016db --- /dev/null +++ b/assets/icons/radix/triangle-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/radix/triangle-left.svg b/assets/icons/radix/triangle-left.svg new file mode 100644 index 0000000000000000000000000000000000000000..0014139716308461f550febfc71a83ec3f6506b3 --- /dev/null +++ b/assets/icons/radix/triangle-left.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/radix/triangle-right.svg b/assets/icons/radix/triangle-right.svg new file mode 100644 index 0000000000000000000000000000000000000000..aed1393b9c99cf654f3744bc92853c7b222725d4 --- /dev/null +++ b/assets/icons/radix/triangle-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/radix/triangle-up.svg b/assets/icons/radix/triangle-up.svg new file mode 100644 index 0000000000000000000000000000000000000000..5eb1b416d389bfcc405056f1e5da510cbe4aa272 --- /dev/null +++ b/assets/icons/radix/triangle-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/radix/twitter-logo.svg b/assets/icons/radix/twitter-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..7dcf2f58eb1d15dbe19a53626496a1ef7d87f975 --- /dev/null +++ b/assets/icons/radix/twitter-logo.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/underline.svg b/assets/icons/radix/underline.svg new file mode 100644 index 0000000000000000000000000000000000000000..334468509777c7ab550ea690cdc76f8627478e74 --- /dev/null +++ b/assets/icons/radix/underline.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/update.svg b/assets/icons/radix/update.svg new file mode 100644 index 0000000000000000000000000000000000000000..b529b2b08b42a17027566a47d20f8ae93d61ae35 --- /dev/null +++ b/assets/icons/radix/update.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/upload.svg b/assets/icons/radix/upload.svg new file mode 100644 index 0000000000000000000000000000000000000000..a7f6bddb2e818210222895de24e072736eef14a2 --- /dev/null +++ b/assets/icons/radix/upload.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/value-none.svg b/assets/icons/radix/value-none.svg new file mode 100644 index 0000000000000000000000000000000000000000..a86c08be1a10c961aeb5a61412b891ad3bc9929d --- /dev/null +++ b/assets/icons/radix/value-none.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/value.svg b/assets/icons/radix/value.svg new file mode 100644 index 0000000000000000000000000000000000000000..59dd7d9373ccdd355d3c6dc581bdfb18e6624072 --- /dev/null +++ b/assets/icons/radix/value.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/vercel-logo.svg b/assets/icons/radix/vercel-logo.svg new file mode 100644 index 0000000000000000000000000000000000000000..5466fd9f0ebd8ffa94382d899bb250d2cb405872 --- /dev/null +++ b/assets/icons/radix/vercel-logo.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/video.svg b/assets/icons/radix/video.svg new file mode 100644 index 0000000000000000000000000000000000000000..e405396bef1c9898d024df78304034d0ad7d8212 --- /dev/null +++ b/assets/icons/radix/video.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/view-grid.svg b/assets/icons/radix/view-grid.svg new file mode 100644 index 0000000000000000000000000000000000000000..04825a870bb77b3179e51e2b7fedd7a7197ba9e5 --- /dev/null +++ b/assets/icons/radix/view-grid.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/view-horizontal.svg b/assets/icons/radix/view-horizontal.svg new file mode 100644 index 0000000000000000000000000000000000000000..2ca7336b99efb11f67addcc31aca81f43f7078ae --- /dev/null +++ b/assets/icons/radix/view-horizontal.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/view-none.svg b/assets/icons/radix/view-none.svg new file mode 100644 index 0000000000000000000000000000000000000000..71b08a46d2917d9057d7331131ef6849f9335867 --- /dev/null +++ b/assets/icons/radix/view-none.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/view-vertical.svg b/assets/icons/radix/view-vertical.svg new file mode 100644 index 0000000000000000000000000000000000000000..0c8f8164b4016a6724945cff0fb76700c2bea724 --- /dev/null +++ b/assets/icons/radix/view-vertical.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/width.svg b/assets/icons/radix/width.svg new file mode 100644 index 0000000000000000000000000000000000000000..3ae2b56e3dbd78152ed91966b6b3a2474fc7c1e4 --- /dev/null +++ b/assets/icons/radix/width.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/zoom-in.svg b/assets/icons/radix/zoom-in.svg new file mode 100644 index 0000000000000000000000000000000000000000..caac722ad07771ec72005752a124f1b86f080a70 --- /dev/null +++ b/assets/icons/radix/zoom-in.svg @@ -0,0 +1,8 @@ + + + diff --git a/assets/icons/radix/zoom-out.svg b/assets/icons/radix/zoom-out.svg new file mode 100644 index 0000000000000000000000000000000000000000..62046a9e0f1f51239c1587aef16317d325ebef07 --- /dev/null +++ b/assets/icons/radix/zoom-out.svg @@ -0,0 +1,8 @@ + + + From 10798384436ac46f2dc30205a086338214a93af0 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 22 Jun 2023 12:00:42 -0400 Subject: [PATCH 30/63] Add mic and mic-mute icons --- assets/icons/radix/mic-mute.svg | 3 +++ assets/icons/radix/mic.svg | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 assets/icons/radix/mic-mute.svg create mode 100644 assets/icons/radix/mic.svg diff --git a/assets/icons/radix/mic-mute.svg b/assets/icons/radix/mic-mute.svg new file mode 100644 index 0000000000000000000000000000000000000000..fe5f8201cc4da5e2cf6a1b770c538d421994e1c4 --- /dev/null +++ b/assets/icons/radix/mic-mute.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/radix/mic.svg b/assets/icons/radix/mic.svg new file mode 100644 index 0000000000000000000000000000000000000000..01f4c9bf669ba253edaa43dc641fdb9a1b7c51d1 --- /dev/null +++ b/assets/icons/radix/mic.svg @@ -0,0 +1,3 @@ + + + From 1a0b2bfef8a91db86555c657727fa5bffad10fab Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 22 Jun 2023 12:21:59 -0400 Subject: [PATCH 31/63] Update stream control icons --- assets/icons/radix/desktop-mute.svg | 4 ++++ crates/collab_ui/src/collab_titlebar_item.rs | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 assets/icons/radix/desktop-mute.svg diff --git a/assets/icons/radix/desktop-mute.svg b/assets/icons/radix/desktop-mute.svg new file mode 100644 index 0000000000000000000000000000000000000000..83d249176fbf067a2732fa4379740cfa54bd018a --- /dev/null +++ b/assets/icons/radix/desktop-mute.svg @@ -0,0 +1,4 @@ + + + + diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index c0603421bc961312a4927fa9127f0f7dfcac5c19..0bdca280376310b528d06ac1c42a63ea08c11cc9 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -370,7 +370,7 @@ impl CollabTitlebarItem { .toggle_contacts_button .in_state(self.contacts_popover.is_some()) .style_for(state); - Svg::new("icons/user_plus_16.svg") + Svg::new("icons/radix/person.svg") .with_color(style.color) .constrained() .with_width(style.icon_width) @@ -406,10 +406,10 @@ impl CollabTitlebarItem { let icon; let tooltip; if room.read(cx).is_screen_sharing() { - icon = "icons/enable_screen_sharing_12.svg"; + icon = "icons/radix/desktop-mute.svg"; tooltip = "Stop Sharing Screen" } else { - icon = "icons/disable_screen_sharing_12.svg"; + icon = "icons/radix/desktop.svg"; tooltip = "Share Screen"; } @@ -451,11 +451,11 @@ impl CollabTitlebarItem { let tooltip; let background; if room.read(cx).is_muted().unwrap_or(false) { - icon = "icons/microphone_inactive_12.svg"; + icon = "icons/radix/mic-mute.svg"; tooltip = "Unmute microphone\nRight click for options"; background = Color::red(); } else { - icon = "icons/microphone_active_12.svg"; + icon = "icons/radix/mic.svg"; tooltip = "Mute microphone\nRight click for options"; background = Color::transparent_black(); } @@ -502,9 +502,9 @@ impl CollabTitlebarItem { } let is_shared = project.read(cx).is_shared(); - let label = if is_shared { "Unshare" } else { "Share" }; + let label = if is_shared { "Stop Sharing" } else { "Share" }; let tooltip = if is_shared { - "Unshare project from call participants" + "Stop sharing project with call participants" } else { "Share project with call participants" }; From 18c4d43ee718172cab2179100017fcc28ba172b3 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 22 Jun 2023 18:49:18 +0200 Subject: [PATCH 32/63] Add deafen button --- assets/icons/speakers_active_12.svg | 1 + assets/icons/speakers_inactive_12.svg | 1 + crates/collab_ui/src/collab_titlebar_item.rs | 53 ++++++++++++++++++-- 3 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 assets/icons/speakers_active_12.svg create mode 100644 assets/icons/speakers_inactive_12.svg diff --git a/assets/icons/speakers_active_12.svg b/assets/icons/speakers_active_12.svg new file mode 100644 index 0000000000000000000000000000000000000000..10416a8f79248d09a28e47d9e117cebf524a5179 --- /dev/null +++ b/assets/icons/speakers_active_12.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/speakers_inactive_12.svg b/assets/icons/speakers_inactive_12.svg new file mode 100644 index 0000000000000000000000000000000000000000..a74990d983e3cbae0822b3a6780074e7e227cd10 --- /dev/null +++ b/assets/icons/speakers_inactive_12.svg @@ -0,0 +1 @@ + diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 0bdca280376310b528d06ac1c42a63ea08c11cc9..ddc3f538018842586a71f7c19f480991688259f6 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -1,6 +1,7 @@ use crate::{ - contact_notification::ContactNotification, contacts_popover, face_pile::FacePile, toggle_mute, - toggle_screen_sharing, ToggleMute, ToggleScreenSharing, + contact_notification::ContactNotification, contacts_popover, face_pile::FacePile, + toggle_deafen, toggle_mute, toggle_screen_sharing, ToggleDeafen, ToggleMute, + ToggleScreenSharing, }; use call::{ActiveCall, ParticipantLocation, Room}; use client::{proto::PeerId, Client, ContactEventKind, SignIn, SignOut, User, UserStore}; @@ -88,7 +89,8 @@ impl View for CollabTitlebarItem { left_container .add_child(self.render_current_user(&workspace, &theme, &user, peer_id, cx)); left_container.add_children(self.render_collaborators(&workspace, &theme, &room, cx)); - right_container.add_child(self.render_toggle_microphone(&theme, &room, cx)); + right_container.add_child(self.render_toggle_mute(&theme, &room, cx)); + right_container.add_child(self.render_toggle_deafen(&theme, &room, cx)); right_container.add_child(self.render_toggle_screen_sharing_button(&theme, &room, cx)); } @@ -441,7 +443,7 @@ impl CollabTitlebarItem { .aligned() .into_any() } - fn render_toggle_microphone( + fn render_toggle_mute( &self, theme: &Theme, room: &ModelHandle, @@ -489,7 +491,50 @@ impl CollabTitlebarItem { .aligned() .into_any() } + fn render_toggle_deafen( + &self, + theme: &Theme, + room: &ModelHandle, + cx: &mut ViewContext, + ) -> AnyElement { + let icon; + let tooltip; + if room.read(cx).is_deafened().unwrap_or(false) { + icon = "icons/speakers_inactive_12.svg"; + tooltip = "Unmute speakers\nRight click for options"; + } else { + icon = "icons/speakers_active_12.svg"; + tooltip = "Mute speakers\nRight click for options"; + } + let titlebar = &theme.workspace.titlebar; + MouseEventHandler::::new(0, cx, |state, _| { + let style = titlebar.call_control.style_for(state); + Svg::new(icon) + .with_color(style.color) + .constrained() + .with_width(style.icon_width) + .aligned() + .constrained() + .with_width(style.button_width) + .with_height(style.button_width) + .contained() + .with_style(style.container) + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, move |_, _, cx| { + toggle_deafen(&Default::default(), cx) + }) + .with_tooltip::( + 0, + tooltip.into(), + Some(Box::new(ToggleDeafen)), + theme.tooltip.clone(), + cx, + ) + .aligned() + .into_any() + } fn render_in_call_share_unshare_button( &self, workspace: &ViewHandle, From f774dbfe2e5db9c6fd79b17e2879b397fbaa65c1 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 22 Jun 2023 18:58:11 +0200 Subject: [PATCH 33/63] Use new icons, delete old ones --- assets/icons/microphone_active_12.svg | 4 ---- assets/icons/microphone_inactive_12.svg | 5 ----- assets/icons/speakers_active_12.svg | 1 - assets/icons/speakers_inactive_12.svg | 1 - crates/collab_ui/src/collab_titlebar_item.rs | 4 ++-- 5 files changed, 2 insertions(+), 13 deletions(-) delete mode 100644 assets/icons/microphone_active_12.svg delete mode 100644 assets/icons/microphone_inactive_12.svg delete mode 100644 assets/icons/speakers_active_12.svg delete mode 100644 assets/icons/speakers_inactive_12.svg diff --git a/assets/icons/microphone_active_12.svg b/assets/icons/microphone_active_12.svg deleted file mode 100644 index 797e64820b5b7b358e6951fe1d6178b7ca1a6908..0000000000000000000000000000000000000000 --- a/assets/icons/microphone_active_12.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/assets/icons/microphone_inactive_12.svg b/assets/icons/microphone_inactive_12.svg deleted file mode 100644 index 90ac393fc20fe9bb8877f82b416728887da72757..0000000000000000000000000000000000000000 --- a/assets/icons/microphone_inactive_12.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/assets/icons/speakers_active_12.svg b/assets/icons/speakers_active_12.svg deleted file mode 100644 index 10416a8f79248d09a28e47d9e117cebf524a5179..0000000000000000000000000000000000000000 --- a/assets/icons/speakers_active_12.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/assets/icons/speakers_inactive_12.svg b/assets/icons/speakers_inactive_12.svg deleted file mode 100644 index a74990d983e3cbae0822b3a6780074e7e227cd10..0000000000000000000000000000000000000000 --- a/assets/icons/speakers_inactive_12.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index ddc3f538018842586a71f7c19f480991688259f6..1cfa18f432367e1859a4948099032a7fa9a6526a 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -500,10 +500,10 @@ impl CollabTitlebarItem { let icon; let tooltip; if room.read(cx).is_deafened().unwrap_or(false) { - icon = "icons/speakers_inactive_12.svg"; + icon = "icons/radix/speaker-off.svg"; tooltip = "Unmute speakers\nRight click for options"; } else { - icon = "icons/speakers_active_12.svg"; + icon = "icons/radix/speaker-loud.svg"; tooltip = "Mute speakers\nRight click for options"; } From 8bd9fe1fb087be224bf082ab9ee989d49645570e Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 22 Jun 2023 20:05:06 +0200 Subject: [PATCH 34/63] Deafen now also mutes microphone --- crates/call/src/room.rs | 42 +++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 0c0855fd6cb48a3fc3f62ea3f3c2f7ab448f5702..714a1b19b57014f97c077542510297095d7d0bc0 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -1176,24 +1176,31 @@ impl Room { }) }) } + fn set_mute( + live_kit: &mut LiveKitRoom, + should_mute: bool, + cx: &mut ModelContext, + ) -> Result>> { + match &mut live_kit.microphone_track { + LocalTrack::None => Err(anyhow!("microphone was not shared")), + LocalTrack::Pending { muted, .. } => { + *muted = should_mute; + Ok(Task::Ready(Some(Ok(())))) + } + LocalTrack::Published { + track_publication, + muted, + } => { + *muted = should_mute; + Ok(cx.background().spawn(track_publication.set_mute(*muted))) + } + } + } pub fn toggle_mute(&mut self, cx: &mut ModelContext) -> Result>> { + let should_mute = self.is_muted().unwrap_or(false); if let Some(live_kit) = self.live_kit.as_mut() { - match &mut live_kit.microphone_track { - LocalTrack::None => Err(anyhow!("microphone was not shared")), - LocalTrack::Pending { muted, .. } => { - *muted = !*muted; - Ok(Task::Ready(Some(Ok(())))) - } - LocalTrack::Published { - track_publication, - muted, - } => { - *muted = !*muted; - - Ok(cx.background().spawn(track_publication.set_mute(*muted))) - } - } + Self::set_mute(live_kit, !should_mute, cx) } else { Err(anyhow!("LiveKit not started")) } @@ -1204,9 +1211,9 @@ impl Room { (*live_kit).deafened = !live_kit.deafened } - if let Some(live_kit) = &self.live_kit { + if let Some(live_kit) = self.live_kit.as_mut() { let mut tasks = Vec::with_capacity(self.remote_participants.len()); - + let _ = Self::set_mute(live_kit, live_kit.deafened, cx)?; // todo (osiewicz): we probably want to schedule it on fg/bg? for participant in self.remote_participants.values() { for track in live_kit .room @@ -1215,7 +1222,6 @@ impl Room { tasks.push(cx.foreground().spawn(track.set_enabled(!live_kit.deafened))); } } - Ok(cx.foreground().spawn(async move { for task in tasks { task.await?; From 437e41f99d9d712cbe8e2a886c6619fc05cf610b Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 23 Jun 2023 11:52:06 +0200 Subject: [PATCH 35/63] Add styles for microphone and speakers buttons --- crates/collab_ui/src/collab_titlebar_item.rs | 29 ++++++--- crates/theme/src/theme.rs | 2 + styles/src/styleTree/workspace.ts | 64 ++++++++++++++++++++ 3 files changed, 85 insertions(+), 10 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 1cfa18f432367e1859a4948099032a7fa9a6526a..17f4f06ff9de67d9c75ad57d204729e719938636 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -451,21 +451,22 @@ impl CollabTitlebarItem { ) -> AnyElement { let icon; let tooltip; - let background; - if room.read(cx).is_muted().unwrap_or(false) { + let is_muted = room.read(cx).is_muted().unwrap_or(false); + if is_muted { icon = "icons/radix/mic-mute.svg"; tooltip = "Unmute microphone\nRight click for options"; - background = Color::red(); } else { icon = "icons/radix/mic.svg"; tooltip = "Mute microphone\nRight click for options"; - background = Color::transparent_black(); } let titlebar = &theme.workspace.titlebar; MouseEventHandler::::new(0, cx, |state, _| { - let style = titlebar.call_control.style_for(state); - Svg::new(icon) + let style = titlebar + .toggle_microphone_button + .in_state(is_muted) + .style_for(state); + let image = Svg::new(icon) .with_color(style.color) .constrained() .with_width(style.icon_width) @@ -474,8 +475,12 @@ impl CollabTitlebarItem { .with_width(style.button_width) .with_height(style.button_width) .contained() - .with_style(style.container) - .with_background_color(background) + .with_style(style.container); + if let Some(color) = style.container.background_color { + image.with_background_color(color) + } else { + image + } }) .with_cursor_style(CursorStyle::PointingHand) .on_click(MouseButton::Left, move |_, _, cx| { @@ -499,7 +504,8 @@ impl CollabTitlebarItem { ) -> AnyElement { let icon; let tooltip; - if room.read(cx).is_deafened().unwrap_or(false) { + let is_deafened = room.read(cx).is_deafened().unwrap_or(false); + if is_deafened { icon = "icons/radix/speaker-off.svg"; tooltip = "Unmute speakers\nRight click for options"; } else { @@ -509,7 +515,10 @@ impl CollabTitlebarItem { let titlebar = &theme.workspace.titlebar; MouseEventHandler::::new(0, cx, |state, _| { - let style = titlebar.call_control.style_for(state); + let style = titlebar + .toggle_speakers_button + .in_state(is_deafened) + .style_for(state); Svg::new(icon) .with_color(style.color) .constrained() diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 69c06c85addfe84ff8fda996abcab1f84a271966..bccb74a7ac2bda3cd5daabf11e1d75eac15cee98 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -133,6 +133,8 @@ pub struct Titlebar { pub share_button: Toggleable>, pub call_control: Interactive, pub toggle_contacts_button: Toggleable>, + pub toggle_microphone_button: Toggleable>, + pub toggle_speakers_button: Toggleable>, pub user_menu_button: Toggleable>, pub toggle_contacts_badge: ContainerStyle, } diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index d7f994d98ea5a515c1a62f9a2a3914868daf1c7e..0e00f6f5bc2785c55384e0da759c5faf280fdcf7 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -343,6 +343,70 @@ export default function workspace(colorScheme: ColorScheme) { }, }, }), + toggleMicrophoneButton: toggleable({ + base: interactive({ + base: { + margin: { left: itemSpacing }, + cornerRadius: 6, + color: foreground(layer, "variant"), + iconWidth: 14, + buttonWidth: 20, + }, + state: { + clicked: { + background: background(layer, "variant", "pressed"), + }, + hovered: { + background: background(layer, "variant", "hovered"), + }, + }, + }), + state: { + active: { + default: { + background: background(layer, "on", "default"), + }, + hovered: { + background: background(layer, "on", "hovered"), + }, + clicked: { + background: background(layer, "on", "pressed"), + }, + }, + }, + }), + toggleSpeakersButton: toggleable({ + base: interactive({ + base: { + margin: { left: itemSpacing }, + cornerRadius: 6, + color: foreground(layer, "variant"), + iconWidth: 14, + buttonWidth: 20, + }, + state: { + clicked: { + background: background(layer, "variant", "pressed"), + }, + hovered: { + background: background(layer, "variant", "hovered"), + }, + }, + }), + state: { + active: { + default: { + background: background(layer, "on", "default"), + }, + hovered: { + background: background(layer, "on", "hovered"), + }, + clicked: { + background: background(layer, "on", "pressed"), + }, + }, + }, + }), userMenuButton: merge(titlebarButton, { inactive: { default: { From 62786cd508c62beb63309d4c2843f4d52fa0a78f Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 23 Jun 2023 13:15:25 +0200 Subject: [PATCH 36/63] Add button --- crates/collab_ui/src/collab_titlebar_item.rs | 41 +++++++++++++++++++- crates/collab_ui/src/collab_ui.rs | 1 + 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 17f4f06ff9de67d9c75ad57d204729e719938636..81e27361640807ab9647264c7bd3f3283b08d094 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -1,6 +1,6 @@ use crate::{ contact_notification::ContactNotification, contacts_popover, face_pile::FacePile, - toggle_deafen, toggle_mute, toggle_screen_sharing, ToggleDeafen, ToggleMute, + toggle_deafen, toggle_mute, toggle_screen_sharing, LeaveCall, ToggleDeafen, ToggleMute, ToggleScreenSharing, }; use call::{ActiveCall, ParticipantLocation, Room}; @@ -85,7 +85,7 @@ impl View for CollabTitlebarItem { { right_container .add_children(self.render_in_call_share_unshare_button(&workspace, &theme, cx)); - + right_container.add_child(self.render_leave_call(&theme, cx)); left_container .add_child(self.render_current_user(&workspace, &theme, &user, peer_id, cx)); left_container.add_children(self.render_collaborators(&workspace, &theme, &room, cx)); @@ -544,6 +544,43 @@ impl CollabTitlebarItem { .aligned() .into_any() } + fn render_leave_call(&self, theme: &Theme, cx: &mut ViewContext) -> AnyElement { + let icon = "icons/radix/exit.svg"; + let tooltip = "Leave call"; + + let titlebar = &theme.workspace.titlebar; + MouseEventHandler::::new(0, cx, |state, _| { + let style = titlebar + .toggle_speakers_button + .in_state(false) + .style_for(state); + Svg::new(icon) + .with_color(style.color) + .constrained() + .with_width(style.icon_width) + .aligned() + .constrained() + .with_width(style.button_width) + .with_height(style.button_width) + .contained() + .with_style(style.container) + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, move |_, _, cx| { + ActiveCall::global(cx) + .update(cx, |call, cx| call.hang_up(cx)) + .detach_and_log_err(cx); + }) + .with_tooltip::( + 0, + tooltip.into(), + Some(Box::new(LeaveCall)), + theme.tooltip.clone(), + cx, + ) + .aligned() + .into_any() + } fn render_in_call_share_unshare_button( &self, workspace: &ViewHandle, diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index 38a39762f4c4e34317d1c78ad041b9d988cef75d..a809b9c7e6d54b2504aa1f4a95e7257396e930c4 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -22,6 +22,7 @@ actions!( ToggleScreenSharing, ToggleMute, ToggleDeafen, + LeaveCall, ShareMicrophone ] ); From 6c676121f286fc85a7ca652a3b8c5d7d3aa6db85 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 23 Jun 2023 13:22:33 +0200 Subject: [PATCH 37/63] Fixed mic's state not being updated in titlebar if user mutes a mic via command palette --- crates/call/src/room.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 714a1b19b57014f97c077542510297095d7d0bc0..00c6b43eb3d7cae39c64569d4d1811597f4925ff 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -1185,6 +1185,7 @@ impl Room { LocalTrack::None => Err(anyhow!("microphone was not shared")), LocalTrack::Pending { muted, .. } => { *muted = should_mute; + cx.notify(); Ok(Task::Ready(Some(Ok(())))) } LocalTrack::Published { @@ -1192,7 +1193,7 @@ impl Room { muted, } => { *muted = should_mute; - + cx.notify(); Ok(cx.background().spawn(track_publication.set_mute(*muted))) } } @@ -1207,11 +1208,9 @@ impl Room { } pub fn toggle_deafen(&mut self, cx: &mut ModelContext) -> Result>> { - if let Some(live_kit) = &mut self.live_kit { - (*live_kit).deafened = !live_kit.deafened - } - if let Some(live_kit) = self.live_kit.as_mut() { + (*live_kit).deafened = !live_kit.deafened; + cx.notify(); let mut tasks = Vec::with_capacity(self.remote_participants.len()); let _ = Self::set_mute(live_kit, live_kit.deafened, cx)?; // todo (osiewicz): we probably want to schedule it on fg/bg? for participant in self.remote_participants.values() { From 4b52ff65c138042a6b23ee0de9f94f8f71574a8a Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Fri, 23 Jun 2023 13:30:40 +0200 Subject: [PATCH 38/63] Add styles for button --- crates/collab_ui/src/collab_titlebar_item.rs | 5 +---- crates/theme/src/theme.rs | 1 + styles/src/styleTree/workspace.ts | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 81e27361640807ab9647264c7bd3f3283b08d094..cb696dab9d9a0259f91cb282f9e3be60e3c17dbe 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -550,10 +550,7 @@ impl CollabTitlebarItem { let titlebar = &theme.workspace.titlebar; MouseEventHandler::::new(0, cx, |state, _| { - let style = titlebar - .toggle_speakers_button - .in_state(false) - .style_for(state); + let style = titlebar.leave_call_button.style_for(state); Svg::new(icon) .with_color(style.color) .constrained() diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index bccb74a7ac2bda3cd5daabf11e1d75eac15cee98..b4a4ba69fd88df8bcc016d46871e951a1402fa8e 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -135,6 +135,7 @@ pub struct Titlebar { pub toggle_contacts_button: Toggleable>, pub toggle_microphone_button: Toggleable>, pub toggle_speakers_button: Toggleable>, + pub leave_call_button: Interactive, pub user_menu_button: Toggleable>, pub toggle_contacts_badge: ContainerStyle, } diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index 0e00f6f5bc2785c55384e0da759c5faf280fdcf7..abc237468a1f304bb51dfd3b62575526e81e068e 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -407,6 +407,24 @@ export default function workspace(colorScheme: ColorScheme) { }, }, }), + leaveCallButton: interactive({ + base: { + margin: { left: itemSpacing }, + cornerRadius: 6, + color: foreground(layer, "variant"), + iconWidth: 14, + buttonWidth: 20, + }, + state: { + clicked: { + background: background(layer, "variant", "pressed"), + }, + hovered: { + background: background(layer, "variant", "hovered"), + }, + }, + }), + userMenuButton: merge(titlebarButton, { inactive: { default: { From a9b5c1d867b35531d1c15b888401609b86dee657 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 26 Jun 2023 12:45:50 +0200 Subject: [PATCH 39/63] Remove unnecessary call to context.notify --- crates/call/src/room.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 00c6b43eb3d7cae39c64569d4d1811597f4925ff..48a35b29f67cd970303685d551f47e44b066d9ae 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -1210,8 +1210,9 @@ impl Room { pub fn toggle_deafen(&mut self, cx: &mut ModelContext) -> Result>> { if let Some(live_kit) = self.live_kit.as_mut() { (*live_kit).deafened = !live_kit.deafened; - cx.notify(); + let mut tasks = Vec::with_capacity(self.remote_participants.len()); + // Context notification is sent within set_mute itself. let _ = Self::set_mute(live_kit, live_kit.deafened, cx)?; // todo (osiewicz): we probably want to schedule it on fg/bg? for participant in self.remote_participants.values() { for track in live_kit From 55f06dcdb54914c2d8570d5a091cc846be597bce Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 26 Jun 2023 13:31:46 +0200 Subject: [PATCH 40/63] Add headers and footers to file finder --- crates/picker/src/picker.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index 69f16e494933ed0a47bc8bf45c08e046b3e55372..ee1eaf3bc9540f1fe4b7cd06c3b665c502712e95 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -45,6 +45,12 @@ pub trait PickerDelegate: Sized + 'static { fn center_selection_after_match_updates(&self) -> bool { false } + fn render_header(&self, cx: &AppContext) -> Option>> { + None + } + fn render_footer(&self, cx: &AppContext) -> Option>> { + None + } } impl Entity for Picker { @@ -77,6 +83,7 @@ impl View for Picker { .contained() .with_style(editor_style), ) + .with_children(self.delegate.render_header(cx)) .with_children(if match_count == 0 { if query.is_empty() { None @@ -118,6 +125,7 @@ impl View for Picker { .into_any(), ) }) + .with_children(self.delegate.render_footer(cx)) .contained() .with_style(container_style) .constrained() From f6edc6861397c07c166bd6d074fb928663b248e6 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 26 Jun 2023 17:07:33 +0200 Subject: [PATCH 41/63] picker: fix warnings --- crates/picker/src/picker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index ee1eaf3bc9540f1fe4b7cd06c3b665c502712e95..33d6e842415f9f4cba317f64ab9ff58b926608d8 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -45,10 +45,10 @@ pub trait PickerDelegate: Sized + 'static { fn center_selection_after_match_updates(&self) -> bool { false } - fn render_header(&self, cx: &AppContext) -> Option>> { + fn render_header(&self, _cx: &AppContext) -> Option>> { None } - fn render_footer(&self, cx: &AppContext) -> Option>> { + fn render_footer(&self, _cx: &AppContext) -> Option>> { None } } From 71c0b7d74ded6f93c96830c71e653c5639d5a391 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Mon, 26 Jun 2023 18:56:30 +0200 Subject: [PATCH 42/63] Add styles for user menu --- crates/collab_ui/src/collab_titlebar_item.rs | 22 +++--- crates/theme/src/theme.rs | 11 +++ styles/src/styleTree/app.ts | 2 + styles/src/styleTree/titlebar.ts | 81 ++++++++++++++++++++ 4 files changed, 107 insertions(+), 9 deletions(-) create mode 100644 styles/src/styleTree/titlebar.ts diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index cb696dab9d9a0259f91cb282f9e3be60e3c17dbe..52f0bc7d6180277dd601eee8517419769721853a 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -639,12 +639,17 @@ impl CollabTitlebarItem { avatar: Option>, cx: &mut ViewContext, ) -> AnyElement { - let titlebar = &theme.workspace.titlebar; - let avatar_style = &theme.workspace.titlebar.follower_avatar; + let tooltip = theme.tooltip.clone(); + let user_menu_button = &theme.titlebar; + let avatar_style = &user_menu_button.user_menu_button.avatar; Stack::new() .with_child( MouseEventHandler::::new(0, cx, |state, _| { - let style = titlebar.call_control.style_for(state); + let style = user_menu_button + .user_menu_button + .user_menu + .inactive_state() + .style_for(state); let mut dropdown = Flex::row().align_children_center(); @@ -658,15 +663,15 @@ impl CollabTitlebarItem { dropdown .with_child( Svg::new("icons/caret_down_8.svg") - .with_color(style.color) + .with_color(theme.titlebar.user_menu_button.icon.color) .constrained() - .with_width(style.icon_width) + .with_width(theme.titlebar.user_menu_button.icon.width) .contained() .into_any(), ) .aligned() .constrained() - .with_height(style.button_width) + .with_height(style.width) .contained() .with_style(style.container) .into_any() @@ -679,11 +684,10 @@ impl CollabTitlebarItem { 0, "Toggle user menu".to_owned(), Some(Box::new(ToggleUserMenu)), - theme.tooltip.clone(), + tooltip, cx, ) - .contained() - .with_margin_left(theme.workspace.titlebar.item_spacing), + .contained(), ) .with_child( ChildView::new(&self.user_menu, cx) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index b4a4ba69fd88df8bcc016d46871e951a1402fa8e..7de10db6c5684d46607d928ecf8f751e606b0ea2 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -65,6 +65,7 @@ pub struct Theme { pub feedback: FeedbackStyle, pub welcome: WelcomeStyle, pub color_scheme: ColorScheme, + pub titlebar: UserMenu, } #[derive(Deserialize, Default, Clone)] @@ -140,6 +141,16 @@ pub struct Titlebar { pub toggle_contacts_badge: ContainerStyle, } +#[derive(Clone, Deserialize, Default)] +pub struct UserMenu { + pub user_menu_button: UserMenuButton, +} +#[derive(Clone, Deserialize, Default)] +pub struct UserMenuButton { + pub user_menu: Toggleable>, + pub avatar: AvatarStyle, + pub icon: Icon, +} #[derive(Copy, Clone, Deserialize, Default)] pub struct AvatarStyle { #[serde(flatten)] diff --git a/styles/src/styleTree/app.ts b/styles/src/styleTree/app.ts index 754443cc5fb068c07df47f7672521dc68bc9ff17..d98e00383fe019c3fbf5f16168df519140b1c964 100644 --- a/styles/src/styleTree/app.ts +++ b/styles/src/styleTree/app.ts @@ -23,6 +23,7 @@ import feedback from "./feedback" import welcome from "./welcome" import copilot from "./copilot" import assistant from "./assistant" +import { titlebar } from "./titlebar" export default function app(colorScheme: ColorScheme): Object { return { @@ -36,6 +37,7 @@ export default function app(colorScheme: ColorScheme): Object { incomingCallNotification: incomingCallNotification(colorScheme), picker: picker(colorScheme), workspace: workspace(colorScheme), + titlebar: titlebar(colorScheme), copilot: copilot(colorScheme), welcome: welcome(colorScheme), contextMenu: contextMenu(colorScheme), diff --git a/styles/src/styleTree/titlebar.ts b/styles/src/styleTree/titlebar.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c2c2147f846d2c00625bfdf10bb804cee4780fd --- /dev/null +++ b/styles/src/styleTree/titlebar.ts @@ -0,0 +1,81 @@ +import { ColorScheme } from "../common"; +import { interactive, toggleable } from "../element" +import { background, foreground, text } from "./components"; + +const titlebarButton = (theme: ColorScheme) => toggleable({ + base: interactive({ + base: { + cornerRadius: 6, + height: 24, + width: 24, + padding: { + top: 4, + bottom: 4, + left: 4, + right: 4, + }, + ...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"), + }, + }, + } +}); + +/** +* Opens the User Menu when toggled +* +* When logged in shows the user's avatar and a chevron, +* When logged out only shows a chevron. +*/ +function userMenuButton(theme: ColorScheme) { + return { + userMenu: titlebarButton(theme), + avatar: { + icon_width: 16, + icon_height: 16, + cornerRadius: 4, + outerWidth: 10, + outerCornerRadius: 10 + }, + icon: { + width: 11, + height: 11, + color: foreground(theme.lowest) + } + } +} + +export function titlebar(theme: ColorScheme) { + return { + userMenuButton: userMenuButton(theme) + } +} From 3104275d87af9b4abd9cd8a927d3c389e8583249 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Tue, 27 Jun 2023 17:19:18 +0200 Subject: [PATCH 43/63] Keep users muted once they undeafen themselves --- crates/call/src/room.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 48a35b29f67cd970303685d551f47e44b066d9ae..3c94feae4c4a9bb2268fc601b9aee002644faf7a 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -1213,7 +1213,11 @@ impl Room { let mut tasks = Vec::with_capacity(self.remote_participants.len()); // Context notification is sent within set_mute itself. - let _ = Self::set_mute(live_kit, live_kit.deafened, cx)?; // todo (osiewicz): we probably want to schedule it on fg/bg? + if live_kit.deafened { + // Unmute microphone only if we're going from unmuted -> muted state. + // We don't want to unmute user automatically. + let _ = Self::set_mute(live_kit, live_kit.deafened, cx)?; // todo (osiewicz): we probably want to schedule it on fg/bg? + } for participant in self.remote_participants.values() { for track in live_kit .room From 331800c14d174a3a54848a79a81890b294180a07 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 27 Jun 2023 11:34:12 -0400 Subject: [PATCH 44/63] Use `icon_button` for leave call --- styles/src/component/icon_button.ts | 54 +++++++++++++++++++++++++++++ styles/src/element/index.ts | 4 +-- styles/src/element/interactive.ts | 2 +- styles/src/styleTree/titlebar.ts | 4 ++- styles/src/styleTree/workspace.ts | 22 +++--------- 5 files changed, 65 insertions(+), 21 deletions(-) create mode 100644 styles/src/component/icon_button.ts diff --git a/styles/src/component/icon_button.ts b/styles/src/component/icon_button.ts new file mode 100644 index 0000000000000000000000000000000000000000..d71996042b1fa0397a67ab7ed3f32059bf5fece4 --- /dev/null +++ b/styles/src/component/icon_button.ts @@ -0,0 +1,54 @@ +import { ColorScheme } from "../common"; +import { interactive } from "../element"; +import { background, foreground } from "../styleTree/components"; +import { Margin } from "../types/zed"; + +interface IconButtonOptions { + color?: keyof ColorScheme['lowest']; + margin?: Partial; +} + +export function icon_button(theme: ColorScheme, { color, margin }: IconButtonOptions) { + if (!color) + color = "base"; + + const m = { + top: margin?.top ?? 0, + bottom: margin?.bottom ?? 0, + left: margin?.left ?? 0, + right: margin?.right ?? 0, + } + + return interactive({ + base: { + corner_radius: 4, + padding: { + top: 2, + bottom: 2, + left: 4, + right: 4, + }, + margin: m, + icon_width: 15, + icon_height: 15, + button_width: 23, + button_height: 19, + }, + state: { + default: { + background: background(theme.lowest, color), + color: foreground(theme.lowest, color), + }, + hovered: { + background: background(theme.lowest, color, "hovered"), + color: foreground(theme.lowest, color, "hovered"), + + }, + clicked: { + background: background(theme.lowest, color, "pressed"), + color: foreground(theme.lowest, color, "pressed"), + + }, + }, + }); +} diff --git a/styles/src/element/index.ts b/styles/src/element/index.ts index b1e3cfe415f402ff1ca45ca97addda32ac1bf0ca..81c911c7bd6852a0919afadcd2ca27114de152f6 100644 --- a/styles/src/element/index.ts +++ b/styles/src/element/index.ts @@ -1,4 +1,4 @@ -import { interactive } from "./interactive" +import { interactive, Interactive } from "./interactive" import { toggleable } from "./toggle" -export { interactive, toggleable } +export { interactive, Interactive, toggleable } diff --git a/styles/src/element/interactive.ts b/styles/src/element/interactive.ts index 1c0f393cff5041e27fb4e295b4ead5f1a2c43c75..79fee70cb938d4ff85954d932abd526ca7491892 100644 --- a/styles/src/element/interactive.ts +++ b/styles/src/element/interactive.ts @@ -8,7 +8,7 @@ type InteractiveState = | "selected" | "disabled" -type Interactive = { +export type Interactive = { default: T hovered?: T clicked?: T diff --git a/styles/src/styleTree/titlebar.ts b/styles/src/styleTree/titlebar.ts index 4c2c2147f846d2c00625bfdf10bb804cee4780fd..3aa41359fa1b5ae95a9079e333e02057fca98b64 100644 --- a/styles/src/styleTree/titlebar.ts +++ b/styles/src/styleTree/titlebar.ts @@ -58,11 +58,13 @@ const titlebarButton = (theme: ColorScheme) => toggleable({ */ function userMenuButton(theme: ColorScheme) { return { - userMenu: titlebarButton(theme), + user_menu: titlebarButton(theme), avatar: { icon_width: 16, icon_height: 16, cornerRadius: 4, + outer_corner_radius: 0, + outer_width: 0, outerWidth: 10, outerCornerRadius: 10 }, diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index abc237468a1f304bb51dfd3b62575526e81e068e..a500988bf716a7d4cacf05f9bcfd368884f204e1 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -13,6 +13,7 @@ import statusBar from "./statusBar" import tabBar from "./tabBar" import { interactive } from "../element" import merge from "ts-deepmerge" +import { icon_button } from "../component/icon_button" export default function workspace(colorScheme: ColorScheme) { const layer = colorScheme.lowest const isLight = colorScheme.isLight @@ -252,7 +253,7 @@ export default function workspace(colorScheme: ColorScheme) { }, avatarRibbon: { height: 3, - width: 12, + width: 11, // TODO: Chore: Make avatarRibbon colors driven by the theme rather than being hard coded. }, @@ -407,22 +408,9 @@ export default function workspace(colorScheme: ColorScheme) { }, }, }), - leaveCallButton: interactive({ - base: { - margin: { left: itemSpacing }, - cornerRadius: 6, - color: foreground(layer, "variant"), - iconWidth: 14, - buttonWidth: 20, - }, - state: { - clicked: { - background: background(layer, "variant", "pressed"), - }, - hovered: { - background: background(layer, "variant", "hovered"), - }, - }, + + leaveCallButton: icon_button(colorScheme, { + margin: { left: itemSpacing }, }), userMenuButton: merge(titlebarButton, { From 5af33407f03c2b311f6db604707132899ded3cb7 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 27 Jun 2023 11:34:26 -0400 Subject: [PATCH 45/63] Add script for building theme types --- script/build-theme-types | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 script/build-theme-types diff --git a/script/build-theme-types b/script/build-theme-types new file mode 100755 index 0000000000000000000000000000000000000000..b78631f3d16bbedfa3f62aa4129440f7b945844b --- /dev/null +++ b/script/build-theme-types @@ -0,0 +1,10 @@ +#!/bin/bash + +echo "running xtask" +(cd crates/theme && cargo xtask build-theme-types) + +echo "updating theme packages" +(cd styles && npm install) + +echo "building theme types" +(cd styles && npm run build-types) From b4f9faee3bca19a35577686cc5c335223f1a0c45 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 27 Jun 2023 12:24:19 -0400 Subject: [PATCH 46/63] Update share, call control buttons --- styles/src/component/icon_button.ts | 33 ++++-- styles/src/component/text_button.ts | 74 +++++++++++++ styles/src/styleTree/workspace.ts | 159 ++++++---------------------- 3 files changed, 131 insertions(+), 135 deletions(-) create mode 100644 styles/src/component/text_button.ts diff --git a/styles/src/component/icon_button.ts b/styles/src/component/icon_button.ts index d71996042b1fa0397a67ab7ed3f32059bf5fece4..47953a56d34c3aa438b4197d9891429f42d06678 100644 --- a/styles/src/component/icon_button.ts +++ b/styles/src/component/icon_button.ts @@ -1,14 +1,17 @@ import { ColorScheme } from "../common"; -import { interactive } from "../element"; +import { interactive, toggleable } from "../element"; import { background, foreground } from "../styleTree/components"; import { Margin } from "../types/zed"; interface IconButtonOptions { + layer?: ColorScheme['lowest'] | ColorScheme['middle'] | ColorScheme['highest']; color?: keyof ColorScheme['lowest']; margin?: Partial; } -export function icon_button(theme: ColorScheme, { color, margin }: IconButtonOptions) { +type ToggleableIconButtonOptions = IconButtonOptions & { active_color?: keyof ColorScheme['lowest'] }; + +export function icon_button(theme: ColorScheme, { color, margin, layer }: IconButtonOptions) { if (!color) color = "base"; @@ -21,7 +24,7 @@ export function icon_button(theme: ColorScheme, { color, margin }: IconButtonOpt return interactive({ base: { - corner_radius: 4, + corner_radius: 6, padding: { top: 2, bottom: 2, @@ -36,19 +39,31 @@ export function icon_button(theme: ColorScheme, { color, margin }: IconButtonOpt }, state: { default: { - background: background(theme.lowest, color), - color: foreground(theme.lowest, color), + background: background(layer ?? theme.lowest, color), + color: foreground(layer ?? theme.lowest, color), }, hovered: { - background: background(theme.lowest, color, "hovered"), - color: foreground(theme.lowest, color, "hovered"), + background: background(layer ?? theme.lowest, color, "hovered"), + color: foreground(layer ?? theme.lowest, color, "hovered"), }, clicked: { - background: background(theme.lowest, color, "pressed"), - color: foreground(theme.lowest, color, "pressed"), + background: background(layer ?? theme.lowest, color, "pressed"), + color: foreground(layer ?? theme.lowest, color, "pressed"), }, }, }); } + +export function toggleable_icon_button(theme: ColorScheme, { color, active_color, margin }: ToggleableIconButtonOptions) { + if (!color) + color = "base"; + + return toggleable({ + state: { + inactive: icon_button(theme, { color, margin }), + active: icon_button(theme, { color: active_color ? active_color : color, margin, layer: theme.middle }), + } + }) +} diff --git a/styles/src/component/text_button.ts b/styles/src/component/text_button.ts new file mode 100644 index 0000000000000000000000000000000000000000..921ecc639fcc44e06aaeb90afe2ff441086717a3 --- /dev/null +++ b/styles/src/component/text_button.ts @@ -0,0 +1,74 @@ +import { ColorScheme } from "../common"; +import { interactive, toggleable } from "../element"; +import { TextProperties, background, foreground, text } from "../styleTree/components"; +import { Margin } from "../types/zed"; + +interface TextButtonOptions { + layer?: ColorScheme['lowest'] | ColorScheme['middle'] | ColorScheme['highest']; + color?: keyof ColorScheme['lowest']; + margin?: Partial; + text_properties?: TextProperties; +} + +type ToggleableTextButtonOptions = TextButtonOptions & { active_color?: keyof ColorScheme['lowest'] }; + +export function text_button(theme: ColorScheme, { color, layer, margin, text_properties }: TextButtonOptions) { + if (!color) + color = "base"; + + const text_options: TextProperties = { + size: "xs", + weight: "normal", + ...text_properties + } + + const m = { + top: margin?.top ?? 0, + bottom: margin?.bottom ?? 0, + left: margin?.left ?? 0, + right: margin?.right ?? 0, + } + + return interactive({ + base: { + corner_radius: 6, + padding: { + top: 1, + bottom: 1, + left: 6, + right: 6, + }, + margin: m, + button_height: 22, + ...text(layer ?? theme.lowest, "sans", color, text_options) + }, + state: { + default: { + background: background(layer ?? theme.lowest, color), + color: foreground(layer ?? theme.lowest, color), + }, + hovered: { + background: background(layer ?? theme.lowest, color, "hovered"), + color: foreground(layer ?? theme.lowest, color, "hovered"), + + }, + clicked: { + background: background(layer ?? theme.lowest, color, "pressed"), + color: foreground(layer ?? theme.lowest, color, "pressed"), + + }, + }, + }); +} + +export function toggleable_text_button(theme: ColorScheme, { color, active_color, margin }: ToggleableTextButtonOptions) { + if (!color) + color = "base"; + + return toggleable({ + state: { + inactive: text_button(theme, { color, margin }), + active: text_button(theme, { color: active_color ? active_color : color, margin, layer: theme.middle }), + } + }) +} diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index a500988bf716a7d4cacf05f9bcfd368884f204e1..da1ad1fe1872a1844228342f8c428b79e4f7335f 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -13,7 +13,8 @@ import statusBar from "./statusBar" import tabBar from "./tabBar" import { interactive } from "../element" import merge from "ts-deepmerge" -import { icon_button } from "../component/icon_button" +import { icon_button, toggleable_icon_button } from "../component/icon_button" +import { text_button, toggleable_text_button } from "../component/text_button" export default function workspace(colorScheme: ColorScheme) { const layer = colorScheme.lowest const isLight = colorScheme.isLight @@ -298,137 +299,45 @@ export default function workspace(colorScheme: ColorScheme) { }, cornerRadius: 6, }, - callControl: interactive({ - base: { - cornerRadius: 6, - color: foreground(layer, "variant"), - iconWidth: 12, - buttonWidth: 20, - }, - state: { - hovered: { - background: background(layer, "variant", "hovered"), - color: foreground(layer, "variant", "hovered"), - }, - }, + + call_control: icon_button(colorScheme, { + margin: { left: itemSpacing / 2 }, }), - toggleContactsButton: toggleable({ - base: interactive({ - base: { - margin: { left: itemSpacing }, - cornerRadius: 6, - color: foreground(layer, "variant"), - iconWidth: 14, - buttonWidth: 20, - }, - state: { - clicked: { - background: background(layer, "variant", "pressed"), - }, - hovered: { - background: background(layer, "variant", "hovered"), - }, - }, - }), - state: { - active: { - default: { - background: background(layer, "on", "default"), - }, - hovered: { - background: background(layer, "on", "hovered"), - }, - clicked: { - background: background(layer, "on", "pressed"), - }, - }, - }, + + toggle_contacts_button: toggleable_icon_button(colorScheme, { + margin: { left: itemSpacing } }), - toggleMicrophoneButton: toggleable({ - base: interactive({ - base: { - margin: { left: itemSpacing }, - cornerRadius: 6, - color: foreground(layer, "variant"), - iconWidth: 14, - buttonWidth: 20, - }, - state: { - clicked: { - background: background(layer, "variant", "pressed"), - }, - hovered: { - background: background(layer, "variant", "hovered"), - }, - }, - }), - state: { - active: { - default: { - background: background(layer, "on", "default"), - }, - hovered: { - background: background(layer, "on", "hovered"), - }, - clicked: { - background: background(layer, "on", "pressed"), - }, - }, - }, + + toggle_microphone_button: toggleable_icon_button(colorScheme, { + margin: { left: itemSpacing }, + active_color: 'negative' }), - toggleSpeakersButton: toggleable({ - base: interactive({ - base: { - margin: { left: itemSpacing }, - cornerRadius: 6, - color: foreground(layer, "variant"), - iconWidth: 14, - buttonWidth: 20, - }, - state: { - clicked: { - background: background(layer, "variant", "pressed"), - }, - hovered: { - background: background(layer, "variant", "hovered"), - }, - }, - }), - state: { - active: { - default: { - background: background(layer, "on", "default"), - }, - hovered: { - background: background(layer, "on", "hovered"), - }, - clicked: { - background: background(layer, "on", "pressed"), - }, - }, - }, + + toggle_speakers_button: toggleable_icon_button(colorScheme, { + margin: { left: itemSpacing / 2 }, }), - leaveCallButton: icon_button(colorScheme, { + leave_call_button: icon_button(colorScheme, { margin: { left: itemSpacing }, }), - userMenuButton: merge(titlebarButton, { - inactive: { - default: { - buttonWidth: 20, - iconWidth: 12, + 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"), - } - }, - }), + active: { + default: { + iconWidth: 12, + button_width: 20, + background: background(layer, "variant", "active"), + color: foreground(layer, "variant", "active"), + } + }, + }), toggleContactsBadge: { cornerRadius: 3, @@ -437,9 +346,7 @@ export default function workspace(colorScheme: ColorScheme) { border: border(layer), background: foreground(layer, "accent"), }, - shareButton: { - ...titlebarButton, - }, + shareButton: toggleable_text_button(colorScheme, {}), }, toolbar: { From 37cb202c9337fce50a482e63f8963c66eaba5bb6 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 27 Jun 2023 09:56:41 -0700 Subject: [PATCH 47/63] Rename and toggle screenshare --- crates/collab_ui/src/collab_titlebar_item.rs | 2 +- crates/theme/src/theme.rs | 2 +- styles/package.json | 2 +- styles/src/styleTree/workspace.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 52f0bc7d6180277dd601eee8517419769721853a..0a91a488edd895fb4e57559689b80a29e332ebdb 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -417,7 +417,7 @@ impl CollabTitlebarItem { let titlebar = &theme.workspace.titlebar; MouseEventHandler::::new(0, cx, |state, _| { - let style = titlebar.call_control.style_for(state); + let style = titlebar.screen_share_button.style_for(state); Svg::new(icon) .with_color(style.color) .constrained() diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 3fda62ced982424b6d796e4918ab9e4cc1b62bc2..f2e9c4aa3ecd9e9db8dfd3af2d151415965011d4 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -133,7 +133,7 @@ pub struct Titlebar { pub sign_in_prompt: Toggleable>, pub outdated_warning: ContainedText, pub share_button: Toggleable>, - pub call_control: Interactive, + pub screen_share_button: Toggleable>, pub toggle_contacts_button: Toggleable>, pub toggle_microphone_button: Toggleable>, pub toggle_speakers_button: Toggleable>, diff --git a/styles/package.json b/styles/package.json index 8820259e860f5dd84e3cc69a5fb8fe5b3be1c630..b14fb5f527ee53ffcf37b68ae97f65abc2b72faa 100644 --- a/styles/package.json +++ b/styles/package.json @@ -7,7 +7,7 @@ "build": "ts-node ./src/buildThemes.ts", "build-licenses": "ts-node ./src/buildLicenses.ts", "build-tokens": "ts-node ./src/buildTokens.ts", - "build-types": "cd ../crates/theme && cargo test && cd ../../styles && ts-node ./src/buildTypes.ts", + "build-types": "ts-node ./src/buildTypes.ts", "test": "vitest" }, "author": "", diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index da1ad1fe1872a1844228342f8c428b79e4f7335f..ec3776dcb02a6660a05da52c15322915c2ca4582 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -300,7 +300,7 @@ export default function workspace(colorScheme: ColorScheme) { cornerRadius: 6, }, - call_control: icon_button(colorScheme, { + screen_share_button: icon_button(colorScheme, { margin: { left: itemSpacing / 2 }, }), From 60ce58442768efdfbc63dcfd1249825fb97b5697 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 27 Jun 2023 13:12:52 -0700 Subject: [PATCH 48/63] WIP: Add mute icons --- crates/call/src/participant.rs | 1 + crates/call/src/room.rs | 25 +++++++++++++++++++++++-- crates/live_kit_client/src/prod.rs | 1 + crates/live_kit_client/src/test.rs | 1 + 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/crates/call/src/participant.rs b/crates/call/src/participant.rs index 90f256489d2d40f39ad1d49f6266980cc13951bb..9773e837c3269aa42583fe374c8ab5cff5a689b6 100644 --- a/crates/call/src/participant.rs +++ b/crates/call/src/participant.rs @@ -43,6 +43,7 @@ pub struct RemoteParticipant { pub peer_id: proto::PeerId, pub projects: Vec, pub location: ParticipantLocation, + pub muted: bool, pub video_tracks: HashMap>, pub audio_tracks: HashMap>, } diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 3c94feae4c4a9bb2268fc601b9aee002644faf7a..7b7ec89a5ed176564ec4e656bee6c323fd26d3a5 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -647,6 +647,7 @@ impl Room { peer_id, projects: participant.projects, location, + muted: false, video_tracks: Default::default(), audio_tracks: Default::default(), }, @@ -781,6 +782,21 @@ impl Room { cx: &mut ModelContext, ) -> Result<()> { match change { + RemoteAudioTrackUpdate::MuteChanged { track_id, muted } => { + for participant in &mut self.remote_participants.values_mut() { + let mut found = false; + for track in participant.audio_tracks.values() { + if track.sid() == track_id { + found = true; + break; + } + } + if found { + participant.muted = muted; + break; + } + } + } RemoteAudioTrackUpdate::Subscribed(track) => { let user_id = track.publisher_id().parse()?; let track_id = track.sid().to_string(); @@ -1213,11 +1229,12 @@ impl Room { let mut tasks = Vec::with_capacity(self.remote_participants.len()); // Context notification is sent within set_mute itself. + let mut mute_task = None; if live_kit.deafened { // Unmute microphone only if we're going from unmuted -> muted state. // We don't want to unmute user automatically. - let _ = Self::set_mute(live_kit, live_kit.deafened, cx)?; // todo (osiewicz): we probably want to schedule it on fg/bg? - } + mute_task = Some(Self::set_mute(live_kit, live_kit.deafened, cx)?); + }; for participant in self.remote_participants.values() { for track in live_kit .room @@ -1226,7 +1243,11 @@ impl Room { tasks.push(cx.foreground().spawn(track.set_enabled(!live_kit.deafened))); } } + Ok(cx.foreground().spawn(async move { + if let Some(mute_task) = mute_task { + mute_task.await?; + } for task in tasks { task.await?; } diff --git a/crates/live_kit_client/src/prod.rs b/crates/live_kit_client/src/prod.rs index dbd9e1917e6ee2151b701728afcdebee7f98dfb5..96bf40ca4ede083a5ce9a94b12edca4321cddabb 100644 --- a/crates/live_kit_client/src/prod.rs +++ b/crates/live_kit_client/src/prod.rs @@ -761,6 +761,7 @@ pub enum RemoteVideoTrackUpdate { } pub enum RemoteAudioTrackUpdate { + MuteChanged { track_id: Sid, muted: bool}, Subscribed(Arc), Unsubscribed { publisher_id: Sid, track_id: Sid }, } diff --git a/crates/live_kit_client/src/test.rs b/crates/live_kit_client/src/test.rs index 9db57a329452b98893dc9815e8c3b3bb505de7b6..286c7215e9b6b722626c52b1923f13506896bf9b 100644 --- a/crates/live_kit_client/src/test.rs +++ b/crates/live_kit_client/src/test.rs @@ -580,6 +580,7 @@ pub enum RemoteVideoTrackUpdate { #[derive(Clone)] pub enum RemoteAudioTrackUpdate { + MuteChanged { track_id: Sid, muted: bool}, Subscribed(Arc), Unsubscribed { publisher_id: Sid, track_id: Sid }, } From 825a7cb799bf297ba099ba69004eecff2771c832 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 27 Jun 2023 16:20:45 -0400 Subject: [PATCH 49/63] Update screenshare toggle, titlebar spacing --- crates/collab_ui/src/collab_titlebar_item.rs | 11 ++++-- crates/theme/src/theme.rs | 2 +- styles/src/component/icon_button.ts | 12 ++++-- styles/src/component/text_button.ts | 2 +- styles/src/styleTree/workspace.ts | 39 ++++++++++++++------ 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 0a91a488edd895fb4e57559689b80a29e332ebdb..08d63dc1b475c9d18ba3c685a4e6c337fcce27cc 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -408,16 +408,21 @@ impl CollabTitlebarItem { let icon; let tooltip; if room.read(cx).is_screen_sharing() { - icon = "icons/radix/desktop-mute.svg"; + icon = "icons/radix/desktop.svg"; tooltip = "Stop Sharing Screen" } else { icon = "icons/radix/desktop.svg"; tooltip = "Share Screen"; } + let active = room.read(cx).is_screen_sharing(); let titlebar = &theme.workspace.titlebar; MouseEventHandler::::new(0, cx, |state, _| { - let style = titlebar.screen_share_button.style_for(state); + let style = titlebar + .screen_share_button + .in_state(active) + .style_for(state); + Svg::new(icon) .with_color(style.color) .constrained() @@ -701,7 +706,7 @@ impl CollabTitlebarItem { fn render_sign_in_button(&self, theme: &Theme, cx: &mut ViewContext) -> AnyElement { let titlebar = &theme.workspace.titlebar; MouseEventHandler::::new(0, cx, |state, _| { - let style = titlebar.sign_in_prompt.inactive_state().style_for(state); + let style = titlebar.sign_in_button.inactive_state().style_for(state); Label::new("Sign In", style.text.clone()) .contained() .with_style(style.container) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index f2e9c4aa3ecd9e9db8dfd3af2d151415965011d4..49c93f38f3f8e85733f92c61fe2eebe4c8621a03 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -130,7 +130,7 @@ pub struct Titlebar { pub leader_avatar: AvatarStyle, pub follower_avatar: AvatarStyle, pub inactive_avatar_grayscale: bool, - pub sign_in_prompt: Toggleable>, + pub sign_in_button: Toggleable>, pub outdated_warning: ContainedText, pub share_button: Toggleable>, pub screen_share_button: Toggleable>, diff --git a/styles/src/component/icon_button.ts b/styles/src/component/icon_button.ts index 47953a56d34c3aa438b4197d9891429f42d06678..850acc62f9ccf850a977e91b17b79e75a867fdc3 100644 --- a/styles/src/component/icon_button.ts +++ b/styles/src/component/icon_button.ts @@ -1,7 +1,13 @@ import { ColorScheme } from "../common"; import { interactive, toggleable } from "../element"; import { background, foreground } from "../styleTree/components"; -import { Margin } from "../types/zed"; + +export type Margin = { + top: number; + bottom: number; + left: number; + right: number; +} interface IconButtonOptions { layer?: ColorScheme['lowest'] | ColorScheme['middle'] | ColorScheme['highest']; @@ -34,8 +40,8 @@ export function icon_button(theme: ColorScheme, { color, margin, layer }: IconBu margin: m, icon_width: 15, icon_height: 15, - button_width: 23, - button_height: 19, + button_width: 21, + button_height: 17, }, state: { default: { diff --git a/styles/src/component/text_button.ts b/styles/src/component/text_button.ts index 921ecc639fcc44e06aaeb90afe2ff441086717a3..ae7fede900e8c0216b8dd2cda51b10ef583c25de 100644 --- a/styles/src/component/text_button.ts +++ b/styles/src/component/text_button.ts @@ -1,7 +1,7 @@ import { ColorScheme } from "../common"; import { interactive, toggleable } from "../element"; import { TextProperties, background, foreground, text } from "../styleTree/components"; -import { Margin } from "../types/zed"; +import { Margin } from "./icon_button"; interface TextButtonOptions { layer?: ColorScheme['lowest'] | ColorScheme['middle'] | ColorScheme['highest']; diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index ec3776dcb02a6660a05da52c15322915c2ca4582..4b3c5f3b517b7cb64b6659ef1d7ca2489668121b 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -260,7 +260,7 @@ export default function workspace(colorScheme: ColorScheme) { // Sign in buttom // FlatButton, Variant - signInPrompt: merge(titlebarButton, { + sign_in_button: merge(titlebarButton, { inactive: { default: { margin: { @@ -300,25 +300,41 @@ export default function workspace(colorScheme: ColorScheme) { cornerRadius: 6, }, - screen_share_button: icon_button(colorScheme, { - margin: { left: itemSpacing / 2 }, - }), - - toggle_contacts_button: toggleable_icon_button(colorScheme, { - margin: { left: itemSpacing } + leave_call_button: icon_button(colorScheme, { + margin: { + left: itemSpacing / 2, + right: itemSpacing + }, }), toggle_microphone_button: toggleable_icon_button(colorScheme, { - margin: { left: itemSpacing }, + margin: { + left: itemSpacing, + right: itemSpacing / 2 + }, active_color: 'negative' }), toggle_speakers_button: toggleable_icon_button(colorScheme, { - margin: { left: itemSpacing / 2 }, + margin: { + left: itemSpacing / 2, + right: itemSpacing / 2 + }, }), - leave_call_button: icon_button(colorScheme, { - margin: { left: itemSpacing }, + 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: @@ -339,6 +355,7 @@ export default function workspace(colorScheme: ColorScheme) { }, }), + // Jewel that notifies you that there are new contact requests toggleContactsBadge: { cornerRadius: 3, padding: 2, From 19ca6a88752a1ca991f2c0b7f0d241615529b713 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 27 Jun 2023 13:32:42 -0700 Subject: [PATCH 50/63] Seperate online and offline --- crates/collab_ui/src/collab_titlebar_item.rs | 25 ++++++++++---------- crates/theme/src/theme.rs | 3 ++- styles/src/styleTree/titlebar.ts | 8 ++++--- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 08d63dc1b475c9d18ba3c685a4e6c337fcce27cc..6c900f5a07ec84c2f0b06815ad35864e99b800d5 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -98,13 +98,7 @@ impl View for CollabTitlebarItem { let status = &*status.borrow(); if matches!(status, client::Status::Connected { .. }) { right_container.add_child(self.render_toggle_contacts_button(&theme, cx)); - let avatar = ActiveCall::global(cx) - .read(cx) - .room() - .is_none() - .then(|| user.as_ref()) - .flatten() - .and_then(|user| user.avatar.clone()); + let avatar = user.as_ref().and_then(|user| user.avatar.clone()); right_container.add_child(self.render_user_menu_button(&theme, avatar, cx)); } else { right_container.add_children(self.render_connection_status(status, cx)); @@ -645,13 +639,17 @@ impl CollabTitlebarItem { cx: &mut ViewContext, ) -> AnyElement { let tooltip = theme.tooltip.clone(); - let user_menu_button = &theme.titlebar; - let avatar_style = &user_menu_button.user_menu_button.avatar; + let user_menu_button_style = if avatar.is_some() { + &theme.titlebar.user_menu_button_online + } else { + &theme.titlebar.user_menu_button_offline + }; + + let avatar_style = &user_menu_button_style.avatar; Stack::new() .with_child( MouseEventHandler::::new(0, cx, |state, _| { - let style = user_menu_button - .user_menu_button + let style = user_menu_button_style .user_menu .inactive_state() .style_for(state); @@ -665,12 +663,13 @@ impl CollabTitlebarItem { Color::transparent_black(), )); }; + dropdown .with_child( Svg::new("icons/caret_down_8.svg") - .with_color(theme.titlebar.user_menu_button.icon.color) + .with_color(user_menu_button_style.icon.color) .constrained() - .with_width(theme.titlebar.user_menu_button.icon.width) + .with_width(user_menu_button_style.icon.width) .contained() .into_any(), ) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 49c93f38f3f8e85733f92c61fe2eebe4c8621a03..4d7f3340863ee3a52d8e78702ab96dd5694a9215 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -144,7 +144,8 @@ pub struct Titlebar { #[derive(Clone, Deserialize, Default, JsonSchema)] pub struct UserMenu { - pub user_menu_button: UserMenuButton, + pub user_menu_button_online: UserMenuButton, + pub user_menu_button_offline: UserMenuButton, } #[derive(Clone, Deserialize, Default, JsonSchema)] pub struct UserMenuButton { diff --git a/styles/src/styleTree/titlebar.ts b/styles/src/styleTree/titlebar.ts index 3aa41359fa1b5ae95a9079e333e02057fca98b64..881600d76c988ca4a0bb113ecc456d90d96f028f 100644 --- a/styles/src/styleTree/titlebar.ts +++ b/styles/src/styleTree/titlebar.ts @@ -56,7 +56,7 @@ const titlebarButton = (theme: ColorScheme) => toggleable({ * When logged in shows the user's avatar and a chevron, * When logged out only shows a chevron. */ -function userMenuButton(theme: ColorScheme) { +function userMenuButton(theme: ColorScheme, online: boolean) { return { user_menu: titlebarButton(theme), avatar: { @@ -71,13 +71,15 @@ function userMenuButton(theme: ColorScheme) { icon: { width: 11, height: 11, - color: foreground(theme.lowest) + color: online ? foreground(theme.lowest) : background(theme.lowest) } } } export function titlebar(theme: ColorScheme) { return { - userMenuButton: userMenuButton(theme) + userMenuButtonOnline: userMenuButton(theme, true), + userMenuButtonOffline: userMenuButton(theme, false) + } } From 8b2732c3aa33c04d126e629b13e84b25cc3f7716 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 27 Jun 2023 17:27:58 -0400 Subject: [PATCH 51/63] `workspace.titlebar` -> `titlebar` in Theme --- crates/collab_ui/src/collab_titlebar_item.rs | 54 ++-- crates/theme/src/theme.rs | 5 +- crates/workspace/src/workspace.rs | 6 +- styles/src/styleTree/titlebar.ts | 238 +++++++++++++++++- styles/src/styleTree/workspace.ts | 246 +------------------ 5 files changed, 265 insertions(+), 284 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 6c900f5a07ec84c2f0b06815ad35864e99b800d5..708fb89e86bded98d00c60c19a4691137d71ff0a 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -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, ) -> AnyElement { - 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::::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::::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::::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::::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 { 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) -> AnyElement { - let titlebar = &theme.workspace.titlebar; + let titlebar = &theme.titlebar; MouseEventHandler::::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::::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) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 4d7f3340863ee3a52d8e78702ab96dd5694a9215..06c6026e3aafb38e1dceebbfc49be84e63b92195 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -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>, pub toggle_speakers_button: Toggleable>, pub leave_call_button: Interactive, - pub user_menu_button: Toggleable>, pub toggle_contacts_badge: ContainerStyle, + pub user_menu: UserMenu, } #[derive(Clone, Deserialize, Default, JsonSchema)] diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index dfc2f4f7954bfd3463a2f68863f7e2a7c5b277e6..066ea5f8a6a339f7b499bc35f7213fefe690eb8f 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -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") } diff --git a/styles/src/styleTree/titlebar.ts b/styles/src/styleTree/titlebar.ts index 881600d76c988ca4a0bb113ecc456d90d96f028f..5f0fc3f5288da1dc5a3da944dc994bd030eff476 100644 --- a/styles/src/styleTree/titlebar.ts +++ b/styles/src/styleTree/titlebar.ts @@ -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), + } } } diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index 4b3c5f3b517b7cb64b6659ef1d7ca2489668121b..afc2ea4d9869f0ade31bdac1840f80ba131215d6 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -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), From 9a07696240513bee363a14a9d4d5f9e6c3f7ebf1 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 27 Jun 2023 17:56:44 -0400 Subject: [PATCH 52/63] Update titlebar item spacing --- styles/src/styleTree/titlebar.ts | 265 +++++++++++++------------------ 1 file changed, 108 insertions(+), 157 deletions(-) diff --git a/styles/src/styleTree/titlebar.ts b/styles/src/styleTree/titlebar.ts index 5f0fc3f5288da1dc5a3da944dc994bd030eff476..993d421859d3252bd88793e64d27d14570121c75 100644 --- a/styles/src/styleTree/titlebar.ts +++ b/styles/src/styleTree/titlebar.ts @@ -6,11 +6,7 @@ import { withOpacity } from "../theme/color"; import { background, border, foreground, text } from "./components"; const ITEM_SPACING = 8 - -interface SpacingProps { - container_height: number; - spacing: number; -} +const TITLEBAR_HEIGHT = 32 function build_spacing( container_height: number, @@ -18,80 +14,44 @@ function build_spacing( spacing: number ) { return { - group: spacing * 2, + group: spacing, item: spacing / 2, + half_item: spacing / 4, 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 call_controls(theme: ColorScheme) { + const button_height = 19 -function sharing_controls(theme: ColorScheme, { container_height, spacing }: SpacingProps) { - return {} -} - -function call_controls(theme: ColorScheme, { container_height, spacing }: SpacingProps) { - return {} -} + const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING); -const titlebarButton = (theme: ColorScheme) => toggleable({ - base: interactive({ - base: { - cornerRadius: 6, - height: 24, - width: 24, - padding: { - top: 4, - bottom: 4, - left: 4, - right: 4, - }, - ...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), + return { + toggle_microphone_button: toggleable_icon_button(theme, { + margin: { + left: space.group, + right: space.half_item, }, - hovered: { - ...text(theme.lowest, "sans", "active", { size: "xs" }), - background: background(theme.middle, "hovered"), + active_color: 'negative' + }), + + toggle_speakers_button: toggleable_icon_button(theme, { + margin: { + left: space.half_item, + right: space.half_item }, - clicked: { - ...text(theme.lowest, "sans", "active", { size: "xs" }), - background: background(theme.middle, "pressed"), + }), + + screen_share_button: toggleable_icon_button(theme, { + margin: { + left: space.half_item, + right: space.group }, - }, + active_color: 'accent' + }), } -}); +} /** * Opens the User Menu when toggled @@ -99,74 +59,89 @@ const titlebarButton = (theme: ColorScheme) => toggleable({ * When logged in shows the user's avatar and a chevron, * 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, +function user_menu(theme: ColorScheme) { + const button_height = 19 + + const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING); + + const build_button = ({ online }: { online: boolean }) => { + const button = toggleable({ + base: interactive({ + base: { + cornerRadius: 6, + height: button_height, + width: online ? 36 : 23, + padding: { + top: 2, + bottom: 2, + left: 6, + right: 6, + }, + margin: { + left: space.item, + right: space.item, + }, + ...text(theme.lowest, "sans", { size: "xs" }), + background: background(theme.lowest), }, - ...text(theme.lowest, "sans", { size: "xs" }), - background: background(theme.lowest), - }, - state: { - hovered: { - ...text(theme.lowest, "sans", "hovered", { - size: "xs", - }), - background: background(theme.lowest, "hovered"), + 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"), + }, }, - 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: button, + avatar: { + icon_width: 15, + icon_height: 15, + corner_radius: 4, + outer_width: 15, + outer_corner_radius: 15 }, - }), - 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"), + icon: { + margin: { + top: 2, + left: online ? space.item : 0, + right: space.group, + bottom: 2, }, - }, + width: 11, + height: 11, + color: foreground(theme.lowest) + } } - }); - + } return { - user_menu: button, - avatar: { - icon_width: 16, - icon_height: 16, - cornerRadius: 4, - outer_corner_radius: 0, - outer_width: 0, - outerWidth: 16, - outerCornerRadius: 16 - }, - icon: { - margin: { - left: online ? 2 : 0, - }, - width: 11, - height: 11, - color: foreground(theme.lowest) - } + userMenuButtonOnline: build_button({ online: true }), + userMenuButtonOffline: build_button({ online: false }), } } @@ -177,14 +152,14 @@ export function titlebar(theme: ColorScheme) { const followerAvatarOuterWidth = followerAvatarWidth + 4 return { - ITEM_SPACING, + item_spacing: 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. + height: TITLEBAR_HEIGHT, background: background(theme.lowest), border: border(theme.lowest, { bottom: true }), padding: { left: 80, - right: ITEM_SPACING, + right: 0, }, // Project @@ -262,28 +237,7 @@ export function titlebar(theme: ColorScheme) { }, }), - 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' - }), + ...call_controls(theme), toggle_contacts_button: toggleable_icon_button(theme, { margin: { @@ -301,9 +255,6 @@ export function titlebar(theme: ColorScheme) { background: foreground(theme.lowest, "accent"), }, shareButton: toggleable_text_button(theme, {}), - user_menu: { - userMenuButtonOnline: userMenuButton(theme, true), - userMenuButtonOffline: userMenuButton(theme, false), - } + user_menu: user_menu(theme) } } From 5d02b490582f47ebc8641825755ac250d7aad992 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 27 Jun 2023 19:19:08 -0700 Subject: [PATCH 53/63] Added muted and currently speaking tracking --- crates/call/src/participant.rs | 1 + crates/call/src/room.rs | 39 ++++++++++- crates/collab_ui/src/collab_titlebar_item.rs | 31 +++++++-- .../Sources/LiveKitBridge/LiveKitBridge.swift | 21 ++++++ crates/live_kit_client/examples/test_app.rs | 39 ++++++++++- crates/live_kit_client/src/prod.rs | 64 ++++++++++++++++++- crates/live_kit_client/src/test.rs | 1 + script/start-local-collaboration | 2 +- 8 files changed, 185 insertions(+), 13 deletions(-) diff --git a/crates/call/src/participant.rs b/crates/call/src/participant.rs index 9773e837c3269aa42583fe374c8ab5cff5a689b6..e7858869ce63906b75f9cd0cb117cf7b54283efd 100644 --- a/crates/call/src/participant.rs +++ b/crates/call/src/participant.rs @@ -44,6 +44,7 @@ pub struct RemoteParticipant { pub projects: Vec, pub location: ParticipantLocation, pub muted: bool, + pub speaking: bool, pub video_tracks: HashMap>, pub audio_tracks: HashMap>, } diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 7b7ec89a5ed176564ec4e656bee6c323fd26d3a5..e5f000c34b348844684a525f80dadb541aec959f 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -164,6 +164,7 @@ impl Room { microphone_track: LocalTrack::None, next_publish_id: 0, deafened: false, + speaking: false, _maintain_room, _maintain_tracks: [_maintain_video_tracks, _maintain_audio_tracks], }) @@ -648,6 +649,7 @@ impl Room { projects: participant.projects, location, muted: false, + speaking: false, video_tracks: Default::default(), audio_tracks: Default::default(), }, @@ -782,6 +784,30 @@ impl Room { cx: &mut ModelContext, ) -> Result<()> { match change { + RemoteAudioTrackUpdate::ActiveSpeakersChanged { speakers } => { + let mut speaker_ids = speakers + .into_iter() + .filter_map(|speaker_sid| speaker_sid.parse().ok()) + .collect::>(); + speaker_ids.sort_unstable(); + for (sid, participant) in &mut self.remote_participants { + if let Ok(_) = speaker_ids.binary_search(sid) { + participant.speaking = true; + } else { + participant.speaking = false; + } + } + if let Some(id) = self.client.user_id() { + if let Some(room) = &mut self.live_kit { + if let Ok(_) = speaker_ids.binary_search(&id) { + room.speaking = true; + } else { + room.speaking = false; + } + } + } + cx.notify(); + } RemoteAudioTrackUpdate::MuteChanged { track_id, muted } => { for participant in &mut self.remote_participants.values_mut() { let mut found = false; @@ -796,6 +822,7 @@ impl Room { break; } } + cx.notify(); } RemoteAudioTrackUpdate::Subscribed(track) => { let user_id = track.publisher_id().parse()?; @@ -1011,7 +1038,7 @@ impl Room { }) } - pub fn is_muted(&self) -> Option { + pub fn is_muted(&self) -> bool { self.live_kit .as_ref() .and_then(|live_kit| match &live_kit.microphone_track { @@ -1019,6 +1046,13 @@ impl Room { LocalTrack::Pending { muted, .. } => Some(*muted), LocalTrack::Published { muted, .. } => Some(*muted), }) + .unwrap_or(false) + } + + pub fn is_speaking(&self) -> bool { + self.live_kit + .as_ref() + .map_or(false, |live_kit| live_kit.speaking) } pub fn is_deafened(&self) -> Option { @@ -1215,7 +1249,7 @@ impl Room { } } pub fn toggle_mute(&mut self, cx: &mut ModelContext) -> Result>> { - let should_mute = self.is_muted().unwrap_or(false); + let should_mute = self.is_muted(); if let Some(live_kit) = self.live_kit.as_mut() { Self::set_mute(live_kit, !should_mute, cx) } else { @@ -1298,6 +1332,7 @@ struct LiveKitRoom { screen_track: LocalTrack, microphone_track: LocalTrack, deafened: bool, + speaking: bool, next_publish_id: usize, _maintain_room: Task<()>, _maintain_tracks: [Task<()>; 2], diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 708fb89e86bded98d00c60c19a4691137d71ff0a..e23320f827722b8d95a3a6ee942ae2ea3141ed42 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -86,8 +86,10 @@ impl View for CollabTitlebarItem { right_container .add_children(self.render_in_call_share_unshare_button(&workspace, &theme, cx)); right_container.add_child(self.render_leave_call(&theme, cx)); + let muted = room.read(cx).is_muted(); + let speaking = room.read(cx).is_speaking(); left_container - .add_child(self.render_current_user(&workspace, &theme, &user, peer_id, cx)); + .add_child(self.render_current_user(&workspace, &theme, &user, peer_id, muted, speaking, cx)); left_container.add_children(self.render_collaborators(&workspace, &theme, &room, cx)); right_container.add_child(self.render_toggle_mute(&theme, &room, cx)); right_container.add_child(self.render_toggle_deafen(&theme, &room, cx)); @@ -449,7 +451,7 @@ impl CollabTitlebarItem { ) -> AnyElement { let icon; let tooltip; - let is_muted = room.read(cx).is_muted().unwrap_or(false); + let is_muted = room.read(cx).is_muted(); if is_muted { icon = "icons/radix/mic-mute.svg"; tooltip = "Unmute microphone\nRight click for options"; @@ -766,6 +768,8 @@ impl CollabTitlebarItem { replica_id, participant.peer_id, Some(participant.location), + participant.muted, + participant.speaking, workspace, theme, cx, @@ -782,14 +786,19 @@ impl CollabTitlebarItem { theme: &Theme, user: &Arc, peer_id: PeerId, + muted: bool, + speaking: bool, cx: &mut ViewContext, ) -> AnyElement { let replica_id = workspace.read(cx).project().read(cx).replica_id(); + Container::new(self.render_face_pile( user, Some(replica_id), peer_id, None, + muted, + speaking, workspace, theme, cx, @@ -804,6 +813,8 @@ impl CollabTitlebarItem { replica_id: Option, peer_id: PeerId, location: Option, + muted: bool, + speaking: bool, workspace: &ViewHandle, theme: &Theme, cx: &mut ViewContext, @@ -829,11 +840,17 @@ impl CollabTitlebarItem { let leader_style = theme.titlebar.leader_avatar; let follower_style = theme.titlebar.follower_avatar; - let mut background_color = theme - .titlebar - .container - .background_color - .unwrap_or_default(); + let mut background_color = if muted { + gpui::color::Color::red() + } else if speaking { + gpui::color::Color::green() + } else { + theme + .titlebar + .container + .background_color + .unwrap_or_default() + }; if let Some(replica_id) = replica_id { if followed_by_self { let selection = theme.editor.replica_selection_style(replica_id).selection; diff --git a/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift b/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift index 74d43d78659d12cd1587914f2814185a82e01f68..40d3641db23afcbac801b7f5f2daa15411c15f72 100644 --- a/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift +++ b/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift @@ -8,6 +8,8 @@ class LKRoomDelegate: RoomDelegate { var onDidDisconnect: @convention(c) (UnsafeRawPointer) -> Void var onDidSubscribeToRemoteAudioTrack: @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer) -> Void var onDidUnsubscribeFromRemoteAudioTrack: @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void + var onMuteChangedFromRemoteAudioTrack: @convention(c) (UnsafeRawPointer, CFString, Bool) -> Void + var onActiveSpeakersChanged: @convention(c) (UnsafeRawPointer, CFArray) -> Void var onDidSubscribeToRemoteVideoTrack: @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer) -> Void var onDidUnsubscribeFromRemoteVideoTrack: @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void @@ -16,6 +18,8 @@ class LKRoomDelegate: RoomDelegate { onDidDisconnect: @escaping @convention(c) (UnsafeRawPointer) -> Void, onDidSubscribeToRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer) -> Void, onDidUnsubscribeFromRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void, + onMuteChangedFromRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, Bool) -> Void, + onActiveSpeakersChanged: @convention(c) (UnsafeRawPointer, CFArray) -> Void, onDidSubscribeToRemoteVideoTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer) -> Void, onDidUnsubscribeFromRemoteVideoTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void) { @@ -25,6 +29,8 @@ class LKRoomDelegate: RoomDelegate { self.onDidUnsubscribeFromRemoteAudioTrack = onDidUnsubscribeFromRemoteAudioTrack self.onDidSubscribeToRemoteVideoTrack = onDidSubscribeToRemoteVideoTrack self.onDidUnsubscribeFromRemoteVideoTrack = onDidUnsubscribeFromRemoteVideoTrack + self.onMuteChangedFromRemoteAudioTrack = onMuteChangedFromRemoteAudioTrack + self.onActiveSpeakersChanged = onActiveSpeakersChanged } func room(_ room: Room, didUpdate connectionState: ConnectionState, oldValue: ConnectionState) { @@ -41,6 +47,17 @@ class LKRoomDelegate: RoomDelegate { } } + func room(_ room: Room, participant: Participant, didUpdate publication: TrackPublication, muted: Bool) { + if publication.kind == .audio { + self.onMuteChangedFromRemoteAudioTrack(self.data, publication.sid as CFString, muted) + } + } + + func room(_ room: Room, didUpdate speakers: [Participant]) { + guard let speaker_ids = speakers.compactMap({ $0.identity as CFString }) as CFArray? else { return } + self.onActiveSpeakersChanged(self.data, speaker_ids) + } + func room(_ room: Room, participant: RemoteParticipant, didUnsubscribe publication: RemoteTrackPublication, track: Track) { if track.kind == .video { self.onDidUnsubscribeFromRemoteVideoTrack(self.data, participant.identity as CFString, track.sid! as CFString) @@ -89,6 +106,8 @@ public func LKRoomDelegateCreate( onDidDisconnect: @escaping @convention(c) (UnsafeRawPointer) -> Void, onDidSubscribeToRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer) -> Void, onDidUnsubscribeFromRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void, + onMuteChangedFromRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, Bool) -> Void, + onActiveSpeakerChanged: @escaping @convention(c) (UnsafeRawPointer, CFArray) -> Void, onDidSubscribeToRemoteVideoTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer) -> Void, onDidUnsubscribeFromRemoteVideoTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void ) -> UnsafeMutableRawPointer { @@ -97,6 +116,8 @@ public func LKRoomDelegateCreate( onDidDisconnect: onDidDisconnect, onDidSubscribeToRemoteAudioTrack: onDidSubscribeToRemoteAudioTrack, onDidUnsubscribeFromRemoteAudioTrack: onDidUnsubscribeFromRemoteAudioTrack, + onMuteChangedFromRemoteAudioTrack: onMuteChangedFromRemoteAudioTrack, + onActiveSpeakersChanged: onActiveSpeakerChanged, onDidSubscribeToRemoteVideoTrack: onDidSubscribeToRemoteVideoTrack, onDidUnsubscribeFromRemoteVideoTrack: onDidUnsubscribeFromRemoteVideoTrack ) diff --git a/crates/live_kit_client/examples/test_app.rs b/crates/live_kit_client/examples/test_app.rs index faf1b54798f3722fe335fdf0e27748b94e9aba9e..4fc02d9a9da91c74c2b0101bc926aee20ddf1b63 100644 --- a/crates/live_kit_client/examples/test_app.rs +++ b/crates/live_kit_client/examples/test_app.rs @@ -74,19 +74,54 @@ fn main() { panic!("unexpected message"); } + audio_track_publication.set_mute(true).await.unwrap(); + + println!("waiting for mute changed!"); + if let RemoteAudioTrackUpdate::MuteChanged { track_id, muted } = + audio_track_updates.next().await.unwrap() + { + let remote_tracks = room_b.remote_audio_tracks("test-participant-1"); + assert_eq!(remote_tracks[0].sid(), track_id); + assert_eq!(muted, true); + } else { + panic!("unexpected message"); + } + + audio_track_publication.set_mute(false).await.unwrap(); + + if let RemoteAudioTrackUpdate::MuteChanged { track_id, muted } = + audio_track_updates.next().await.unwrap() + { + let remote_tracks = room_b.remote_audio_tracks("test-participant-1"); + assert_eq!(remote_tracks[0].sid(), track_id); + assert_eq!(muted, false); + } else { + panic!("unexpected message"); + } + println!("Pausing for 5 seconds to test audio, make some noise!"); let timer = cx.background().timer(Duration::from_secs(5)); timer.await; - let remote_audio_track = room_b .remote_audio_tracks("test-participant-1") .pop() .unwrap(); room_a.unpublish_track(audio_track_publication); + + // Clear out any active speakers changed messages + let mut next = audio_track_updates.next().await.unwrap(); + while let RemoteAudioTrackUpdate::ActiveSpeakersChanged { + speakers + } = next + { + println!("Speakers changed: {:?}", speakers); + next = audio_track_updates.next().await.unwrap(); + } + if let RemoteAudioTrackUpdate::Unsubscribed { publisher_id, track_id, - } = audio_track_updates.next().await.unwrap() + } = next { assert_eq!(publisher_id, "test-participant-1"); assert_eq!(remote_audio_track.sid(), track_id); diff --git a/crates/live_kit_client/src/prod.rs b/crates/live_kit_client/src/prod.rs index 96bf40ca4ede083a5ce9a94b12edca4321cddabb..bdbba87b51e9e1984fdd0c86276405c33ad3f38e 100644 --- a/crates/live_kit_client/src/prod.rs +++ b/crates/live_kit_client/src/prod.rs @@ -32,6 +32,15 @@ extern "C" { publisher_id: CFStringRef, track_id: CFStringRef, ), + on_mute_changed_from_remote_audio_track: extern "C" fn( + callback_data: *mut c_void, + track_id: CFStringRef, + muted: bool, + ), + on_active_speakers_changed: extern "C" fn( + callback_data: *mut c_void, + participants: CFArrayRef, + ), on_did_subscribe_to_remote_video_track: extern "C" fn( callback_data: *mut c_void, publisher_id: CFStringRef, @@ -381,6 +390,24 @@ impl Room { }); } + fn mute_changed_from_remote_audio_track(&self, track_id: String, muted: bool) { + self.remote_audio_track_subscribers.lock().retain(|tx| { + tx.unbounded_send(RemoteAudioTrackUpdate::MuteChanged { + track_id: track_id.clone(), + muted, + }) + .is_ok() + }); + } + + // A vec of publisher IDs + fn active_speakers_changed(&self, speakers: Vec) { + self.remote_audio_track_subscribers.lock().retain(move |tx| { + tx.unbounded_send(RemoteAudioTrackUpdate::ActiveSpeakersChanged { speakers: speakers.clone() }) + .is_ok() + }); + } + fn did_subscribe_to_remote_video_track(&self, track: RemoteVideoTrack) { let track = Arc::new(track); self.remote_video_track_subscribers.lock().retain(|tx| { @@ -445,6 +472,8 @@ impl RoomDelegate { Self::on_did_disconnect, Self::on_did_subscribe_to_remote_audio_track, Self::on_did_unsubscribe_from_remote_audio_track, + Self::on_mute_change_from_remote_audio_track, + Self::on_active_speakers_changed, Self::on_did_subscribe_to_remote_video_track, Self::on_did_unsubscribe_from_remote_video_track, ) @@ -493,6 +522,38 @@ impl RoomDelegate { let _ = Weak::into_raw(room); } + extern "C" fn on_mute_change_from_remote_audio_track( + room: *mut c_void, + track_id: CFStringRef, + muted: bool, + ) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let track_id = unsafe { CFString::wrap_under_get_rule(track_id).to_string() }; + if let Some(room) = room.upgrade() { + room.mute_changed_from_remote_audio_track(track_id, muted); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_active_speakers_changed(room: *mut c_void, participants: CFArrayRef) { + if participants.is_null() { + return; + } + + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let speakers = unsafe { + CFArray::wrap_under_get_rule(participants) + .into_iter() + .map(|speaker: core_foundation::base::ItemRef<'_, *const c_void>| CFString::wrap_under_get_rule(*speaker as CFStringRef).to_string()) + .collect() + }; + + if let Some(room) = room.upgrade() { + room.active_speakers_changed(speakers); + } + let _ = Weak::into_raw(room); + } + extern "C" fn on_did_subscribe_to_remote_video_track( room: *mut c_void, publisher_id: CFStringRef, @@ -761,7 +822,8 @@ pub enum RemoteVideoTrackUpdate { } pub enum RemoteAudioTrackUpdate { - MuteChanged { track_id: Sid, muted: bool}, + ActiveSpeakersChanged { speakers: Vec }, + MuteChanged { track_id: Sid, muted: bool }, Subscribed(Arc), Unsubscribed { publisher_id: Sid, track_id: Sid }, } diff --git a/crates/live_kit_client/src/test.rs b/crates/live_kit_client/src/test.rs index 286c7215e9b6b722626c52b1923f13506896bf9b..809a1f5d29a7ad9d64fbd1f331fec655d4e566de 100644 --- a/crates/live_kit_client/src/test.rs +++ b/crates/live_kit_client/src/test.rs @@ -580,6 +580,7 @@ pub enum RemoteVideoTrackUpdate { #[derive(Clone)] pub enum RemoteAudioTrackUpdate { + ActiveSpeakersChanged { speakers: Vec }, MuteChanged { track_id: Sid, muted: bool}, Subscribed(Arc), Unsubscribed { publisher_id: Sid, track_id: Sid }, diff --git a/script/start-local-collaboration b/script/start-local-collaboration index b8632c4c229d754fec6ce8c19a4c892eea115c8a..b702fb4e02f9d0e3ae2a70ca99054b7bea2a711b 100755 --- a/script/start-local-collaboration +++ b/script/start-local-collaboration @@ -54,5 +54,5 @@ sleep 0.5 # Start the two Zed child processes. Open the given paths with the first instance. trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT ZED_IMPERSONATE=${username_1} ZED_WINDOW_POSITION=${position_1} target/debug/Zed $@ & -ZED_IMPERSONATE=${username_2} ZED_WINDOW_POSITION=${position_2} target/debug/Zed & +SECOND=true ZED_IMPERSONATE=${username_2} ZED_WINDOW_POSITION=${position_2} target/debug/Zed & wait From 749f60ba8199f64b12fe877082f7f4263d234cf5 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 27 Jun 2023 19:25:46 -0700 Subject: [PATCH 54/63] fmt --- crates/collab_ui/src/collab_titlebar_item.rs | 5 +++-- crates/live_kit_client/examples/test_app.rs | 5 +---- crates/live_kit_client/src/prod.rs | 16 ++++++++++++---- crates/live_kit_client/src/test.rs | 2 +- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index e23320f827722b8d95a3a6ee942ae2ea3141ed42..ae80e59f22b43cd3589347e8440176ea47a9062e 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -88,8 +88,9 @@ impl View for CollabTitlebarItem { right_container.add_child(self.render_leave_call(&theme, cx)); let muted = room.read(cx).is_muted(); let speaking = room.read(cx).is_speaking(); - left_container - .add_child(self.render_current_user(&workspace, &theme, &user, peer_id, muted, speaking, cx)); + left_container.add_child( + self.render_current_user(&workspace, &theme, &user, peer_id, muted, speaking, cx), + ); left_container.add_children(self.render_collaborators(&workspace, &theme, &room, cx)); right_container.add_child(self.render_toggle_mute(&theme, &room, cx)); right_container.add_child(self.render_toggle_deafen(&theme, &room, cx)); diff --git a/crates/live_kit_client/examples/test_app.rs b/crates/live_kit_client/examples/test_app.rs index 4fc02d9a9da91c74c2b0101bc926aee20ddf1b63..f5f6d0e46f123d8015f7674d8c0292f1f35d3d75 100644 --- a/crates/live_kit_client/examples/test_app.rs +++ b/crates/live_kit_client/examples/test_app.rs @@ -110,10 +110,7 @@ fn main() { // Clear out any active speakers changed messages let mut next = audio_track_updates.next().await.unwrap(); - while let RemoteAudioTrackUpdate::ActiveSpeakersChanged { - speakers - } = next - { + while let RemoteAudioTrackUpdate::ActiveSpeakersChanged { speakers } = next { println!("Speakers changed: {:?}", speakers); next = audio_track_updates.next().await.unwrap(); } diff --git a/crates/live_kit_client/src/prod.rs b/crates/live_kit_client/src/prod.rs index bdbba87b51e9e1984fdd0c86276405c33ad3f38e..6daa0601ca95541665dd8bd9c2eeaf526320df8c 100644 --- a/crates/live_kit_client/src/prod.rs +++ b/crates/live_kit_client/src/prod.rs @@ -402,10 +402,14 @@ impl Room { // A vec of publisher IDs fn active_speakers_changed(&self, speakers: Vec) { - self.remote_audio_track_subscribers.lock().retain(move |tx| { - tx.unbounded_send(RemoteAudioTrackUpdate::ActiveSpeakersChanged { speakers: speakers.clone() }) + self.remote_audio_track_subscribers + .lock() + .retain(move |tx| { + tx.unbounded_send(RemoteAudioTrackUpdate::ActiveSpeakersChanged { + speakers: speakers.clone(), + }) .is_ok() - }); + }); } fn did_subscribe_to_remote_video_track(&self, track: RemoteVideoTrack) { @@ -544,7 +548,11 @@ impl RoomDelegate { let speakers = unsafe { CFArray::wrap_under_get_rule(participants) .into_iter() - .map(|speaker: core_foundation::base::ItemRef<'_, *const c_void>| CFString::wrap_under_get_rule(*speaker as CFStringRef).to_string()) + .map( + |speaker: core_foundation::base::ItemRef<'_, *const c_void>| { + CFString::wrap_under_get_rule(*speaker as CFStringRef).to_string() + }, + ) .collect() }; diff --git a/crates/live_kit_client/src/test.rs b/crates/live_kit_client/src/test.rs index 809a1f5d29a7ad9d64fbd1f331fec655d4e566de..3fc046c5a293b105729fb756adfede6951de954b 100644 --- a/crates/live_kit_client/src/test.rs +++ b/crates/live_kit_client/src/test.rs @@ -581,7 +581,7 @@ pub enum RemoteVideoTrackUpdate { #[derive(Clone)] pub enum RemoteAudioTrackUpdate { ActiveSpeakersChanged { speakers: Vec }, - MuteChanged { track_id: Sid, muted: bool}, + MuteChanged { track_id: Sid, muted: bool }, Subscribed(Arc), Unsubscribed { publisher_id: Sid, track_id: Sid }, } From 2ddf0e12bfd214d46efca8d36e8ea4fede4e7a35 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 28 Jun 2023 11:10:56 +0200 Subject: [PATCH 55/63] Undeafen: unmute if user was not muted prior to deafening --- crates/call/src/room.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index e5f000c34b348844684a525f80dadb541aec959f..da298f9ca25757f91f394e217099eb236a275827 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -163,6 +163,7 @@ impl Room { screen_track: LocalTrack::None, microphone_track: LocalTrack::None, next_publish_id: 0, + muted_by_user: false, deafened: false, speaking: false, _maintain_room, @@ -1231,6 +1232,10 @@ impl Room { should_mute: bool, cx: &mut ModelContext, ) -> Result>> { + if !should_mute { + // clear user muting state. + live_kit.muted_by_user = false; + } match &mut live_kit.microphone_track { LocalTrack::None => Err(anyhow!("microphone was not shared")), LocalTrack::Pending { muted, .. } => { @@ -1249,9 +1254,11 @@ impl Room { } } pub fn toggle_mute(&mut self, cx: &mut ModelContext) -> Result>> { - let should_mute = self.is_muted(); + let should_mute = !self.is_muted(); if let Some(live_kit) = self.live_kit.as_mut() { - Self::set_mute(live_kit, !should_mute, cx) + let ret = Self::set_mute(live_kit, should_mute, cx); + live_kit.muted_by_user = should_mute; + ret } else { Err(anyhow!("LiveKit not started")) } @@ -1264,9 +1271,9 @@ impl Room { let mut tasks = Vec::with_capacity(self.remote_participants.len()); // Context notification is sent within set_mute itself. let mut mute_task = None; - if live_kit.deafened { - // Unmute microphone only if we're going from unmuted -> muted state. - // We don't want to unmute user automatically. + // When deafening, mute user's mic as well. + // When undeafening, unmute user's mic unless it was manually muted prior to deafening. + if live_kit.deafened || !live_kit.muted_by_user { mute_task = Some(Self::set_mute(live_kit, live_kit.deafened, cx)?); }; for participant in self.remote_participants.values() { @@ -1331,6 +1338,8 @@ struct LiveKitRoom { room: Arc, screen_track: LocalTrack, microphone_track: LocalTrack, + /// Tracks whether we're currently in a muted state due to auto-mute from deafening or manual mute performed by user. + muted_by_user: bool, deafened: bool, speaking: bool, next_publish_id: usize, From 456be1f86e5415e43090dc39b4f4e0dde0427841 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:19:32 +0200 Subject: [PATCH 56/63] Hide user menu on second click --- crates/collab_ui/src/collab_titlebar_item.rs | 77 ++++++++++---------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index ae80e59f22b43cd3589347e8440176ea47a9062e..6621aed875283f2f5c994d0d03605ee2ff895cd7 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -49,7 +49,7 @@ pub struct CollabTitlebarItem { client: Arc, workspace: WeakViewHandle, contacts_popover: Option>, - user_menu: ViewHandle, + user_menu: Option>, _subscriptions: Vec, } @@ -170,18 +170,13 @@ impl CollabTitlebarItem { }), ); - let view_id = cx.view_id(); Self { workspace: workspace.weak_handle(), project, user_store, client, contacts_popover: None, - user_menu: cx.add_view(|cx| { - let mut menu = ContextMenu::new(view_id, cx); - menu.set_position_mode(OverlayPositionMode::Local); - menu - }), + user_menu: None, _subscriptions: subscriptions, } } @@ -294,32 +289,41 @@ impl CollabTitlebarItem { } pub fn toggle_user_menu(&mut self, _: &ToggleUserMenu, cx: &mut ViewContext) { - self.user_menu.update(cx, |user_menu, cx| { - let items = if let Some(_) = self.user_store.read(cx).current_user() { - vec![ - ContextMenuItem::action("Settings", zed_actions::OpenSettings), - ContextMenuItem::action("Theme", theme_selector::Toggle), - ContextMenuItem::separator(), - ContextMenuItem::action( - "Share Feedback", - feedback::feedback_editor::GiveFeedback, - ), - ContextMenuItem::action("Sign out", SignOut), - ] - } else { - vec![ - ContextMenuItem::action("Settings", zed_actions::OpenSettings), - ContextMenuItem::action("Theme", theme_selector::Toggle), - ContextMenuItem::separator(), - ContextMenuItem::action( - "Share Feedback", - feedback::feedback_editor::GiveFeedback, - ), - ] - }; + if self.user_menu.take().is_none() { + let mut user_menu = cx.add_view(|cx| { + let view_id = cx.view_id(); + let mut menu = ContextMenu::new(view_id, cx); + menu.set_position_mode(OverlayPositionMode::Local); + menu + }); + user_menu.update(cx, |user_menu, cx| { + let items = if let Some(_) = self.user_store.read(cx).current_user() { + vec![ + ContextMenuItem::action("Settings", zed_actions::OpenSettings), + ContextMenuItem::action("Theme", theme_selector::Toggle), + ContextMenuItem::separator(), + ContextMenuItem::action( + "Share Feedback", + feedback::feedback_editor::GiveFeedback, + ), + ContextMenuItem::action("Sign out", SignOut), + ] + } else { + vec![ + ContextMenuItem::action("Settings", zed_actions::OpenSettings), + ContextMenuItem::action("Theme", theme_selector::Toggle), + ContextMenuItem::separator(), + ContextMenuItem::action( + "Share Feedback", + feedback::feedback_editor::GiveFeedback, + ), + ] + }; - user_menu.show(Default::default(), AnchorCorner::TopRight, items, cx); - }); + user_menu.show(Default::default(), AnchorCorner::TopRight, items, cx); + }); + self.user_menu = Some(user_menu); + } } fn render_toggle_contacts_button( @@ -695,11 +699,10 @@ impl CollabTitlebarItem { ) .contained(), ) - .with_child( - ChildView::new(&self.user_menu, cx) - .aligned() - .bottom() - .right(), + .with_children( + self.user_menu + .as_ref() + .map(|menu| ChildView::new(&menu, cx).aligned().bottom().right()), ) .into_any() } From c2f5855fdc21158f28ecebba7cce8146682128cd Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:22:17 +0200 Subject: [PATCH 57/63] Fix warning --- crates/collab_ui/src/collab_titlebar_item.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 6621aed875283f2f5c994d0d03605ee2ff895cd7..e5837330a4f7592a893b0da41438322be7666f42 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -290,7 +290,7 @@ impl CollabTitlebarItem { pub fn toggle_user_menu(&mut self, _: &ToggleUserMenu, cx: &mut ViewContext) { if self.user_menu.take().is_none() { - let mut user_menu = cx.add_view(|cx| { + let user_menu = cx.add_view(|cx| { let view_id = cx.view_id(); let mut menu = ContextMenu::new(view_id, cx); menu.set_position_mode(OverlayPositionMode::Local); From 49ce1977e3409740f29b4d5565345c557c0938e0 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:27:38 +0200 Subject: [PATCH 58/63] Optimize user menu trigger --- crates/collab_ui/src/collab_titlebar_item.rs | 34 +++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index e5837330a4f7592a893b0da41438322be7666f42..76d1741c141cb132f50acfa3b8b90c9d63ad09a3 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -49,7 +49,8 @@ pub struct CollabTitlebarItem { client: Arc, workspace: WeakViewHandle, contacts_popover: Option>, - user_menu: Option>, + user_menu: ViewHandle, + user_menu_is_visible: bool, _subscriptions: Vec, } @@ -176,7 +177,13 @@ impl CollabTitlebarItem { user_store, client, contacts_popover: None, - user_menu: None, + user_menu: cx.add_view(|cx| { + let view_id = cx.view_id(); + let mut menu = ContextMenu::new(view_id, cx); + menu.set_position_mode(OverlayPositionMode::Local); + menu + }), + user_menu_is_visible: false, _subscriptions: subscriptions, } } @@ -289,14 +296,8 @@ impl CollabTitlebarItem { } pub fn toggle_user_menu(&mut self, _: &ToggleUserMenu, cx: &mut ViewContext) { - if self.user_menu.take().is_none() { - let user_menu = cx.add_view(|cx| { - let view_id = cx.view_id(); - let mut menu = ContextMenu::new(view_id, cx); - menu.set_position_mode(OverlayPositionMode::Local); - menu - }); - user_menu.update(cx, |user_menu, cx| { + if !self.user_menu_is_visible { + self.user_menu.update(cx, |user_menu, cx| { let items = if let Some(_) = self.user_store.read(cx).current_user() { vec![ ContextMenuItem::action("Settings", zed_actions::OpenSettings), @@ -322,8 +323,8 @@ impl CollabTitlebarItem { user_menu.show(Default::default(), AnchorCorner::TopRight, items, cx); }); - self.user_menu = Some(user_menu); } + self.user_menu_is_visible = !self.user_menu_is_visible; } fn render_toggle_contacts_button( @@ -699,11 +700,12 @@ impl CollabTitlebarItem { ) .contained(), ) - .with_children( - self.user_menu - .as_ref() - .map(|menu| ChildView::new(&menu, cx).aligned().bottom().right()), - ) + .with_children(self.user_menu_is_visible.then(|| { + ChildView::new(&self.user_menu, cx) + .aligned() + .bottom() + .right() + })) .into_any() } From a889f3db54866ae690516cde8bbf967a99a56383 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Wed, 28 Jun 2023 10:06:12 -0400 Subject: [PATCH 59/63] Reduce the right spacing of the contacts menu --- styles/src/styleTree/titlebar.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/styles/src/styleTree/titlebar.ts b/styles/src/styleTree/titlebar.ts index 993d421859d3252bd88793e64d27d14570121c75..b1971a2e8def8017f2961e2f08076d39e37fab3c 100644 --- a/styles/src/styleTree/titlebar.ts +++ b/styles/src/styleTree/titlebar.ts @@ -200,10 +200,7 @@ export function titlebar(theme: ColorScheme) { // 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, @@ -215,7 +212,7 @@ export function titlebar(theme: ColorScheme) { }, }, - // Notice that the collaboration server is out of date + // When the collaboration server is out of date, show a warning outdatedWarning: { ...text(theme.lowest, "sans", "warning", { size: "xs" }), background: withOpacity(background(theme.lowest, "warning"), 0.3), @@ -242,7 +239,6 @@ export function titlebar(theme: ColorScheme) { toggle_contacts_button: toggleable_icon_button(theme, { margin: { left: ITEM_SPACING, - right: ITEM_SPACING / 2 }, }), From c381e8821ce68e887a2ae92ae798960fb15a84aa Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Wed, 28 Jun 2023 10:19:30 -0400 Subject: [PATCH 60/63] Update icon sizes --- styles/src/component/icon_button.ts | 8 ++++---- styles/src/styleTree/titlebar.ts | 23 +++++++++++++++-------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/styles/src/component/icon_button.ts b/styles/src/component/icon_button.ts index 850acc62f9ccf850a977e91b17b79e75a867fdc3..43f8d0f9c4f361ee25aee5a5baef1f671d1079c8 100644 --- a/styles/src/component/icon_button.ts +++ b/styles/src/component/icon_button.ts @@ -38,10 +38,10 @@ export function icon_button(theme: ColorScheme, { color, margin, layer }: IconBu right: 4, }, margin: m, - icon_width: 15, - icon_height: 15, - button_width: 21, - button_height: 17, + icon_width: 14, + icon_height: 14, + button_width: 20, + button_height: 16, }, state: { default: { diff --git a/styles/src/styleTree/titlebar.ts b/styles/src/styleTree/titlebar.ts index b1971a2e8def8017f2961e2f08076d39e37fab3c..f27c30143337506337989973e95265daa0c83cfb 100644 --- a/styles/src/styleTree/titlebar.ts +++ b/styles/src/styleTree/titlebar.ts @@ -23,13 +23,18 @@ function build_spacing( } function call_controls(theme: ColorScheme) { - const button_height = 19 + const button_height = 18 const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING); + const marginY = { + top: space.marginY, + bottom: space.marginY, + } return { toggle_microphone_button: toggleable_icon_button(theme, { margin: { + ...marginY, left: space.group, right: space.half_item, }, @@ -38,6 +43,7 @@ function call_controls(theme: ColorScheme) { toggle_speakers_button: toggleable_icon_button(theme, { margin: { + ...marginY, left: space.half_item, right: space.half_item }, @@ -45,6 +51,7 @@ function call_controls(theme: ColorScheme) { screen_share_button: toggleable_icon_button(theme, { margin: { + ...marginY, left: space.half_item, right: space.group }, @@ -60,7 +67,7 @@ function call_controls(theme: ColorScheme) { * When logged out only shows a chevron. */ function user_menu(theme: ColorScheme) { - const button_height = 19 + const button_height = 18 const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING); @@ -70,7 +77,7 @@ function user_menu(theme: ColorScheme) { base: { cornerRadius: 6, height: button_height, - width: online ? 36 : 23, + width: online ? 37 : 24, padding: { top: 2, bottom: 2, @@ -120,11 +127,11 @@ function user_menu(theme: ColorScheme) { return { user_menu: button, avatar: { - icon_width: 15, - icon_height: 15, + icon_width: 16, + icon_height: 16, corner_radius: 4, - outer_width: 15, - outer_corner_radius: 15 + outer_width: 16, + outer_corner_radius: 16 }, icon: { margin: { @@ -196,7 +203,7 @@ export function titlebar(theme: ColorScheme) { }, avatarRibbon: { height: 3, - width: 11, + width: 14, // TODO: Chore: Make avatarRibbon colors driven by the theme rather than being hard coded. }, From 9ab0efa1f80714fa50aab6001d64c543f6fa25f5 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 28 Jun 2023 08:41:31 -0700 Subject: [PATCH 61/63] Fix microphone and speaking styles --- crates/collab_ui/src/collab_titlebar_item.rs | 25 +++++++++++++------- crates/theme/src/theme.rs | 3 +++ styles/src/styleTree/titlebar.ts | 5 +++- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 76d1741c141cb132f50acfa3b8b90c9d63ad09a3..72aa247f35295f637e9cc43d9e69c98dee56c9d0 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -668,6 +668,7 @@ impl CollabTitlebarItem { avatar_img, *avatar_style, Color::transparent_black(), + None )); }; @@ -846,17 +847,20 @@ impl CollabTitlebarItem { let leader_style = theme.titlebar.leader_avatar; let follower_style = theme.titlebar.follower_avatar; - let mut background_color = if muted { - gpui::color::Color::red() + let microphone_state = if muted { + Some(theme.titlebar.muted) } else if speaking { - gpui::color::Color::green() + Some(theme.titlebar.speaking) } else { - theme - .titlebar - .container - .background_color - .unwrap_or_default() + None }; + + let mut background_color = theme + .titlebar + .container + .background_color + .unwrap_or_default(); + if let Some(replica_id) = replica_id { if followed_by_self { let selection = theme.editor.replica_selection_style(replica_id).selection; @@ -872,6 +876,7 @@ impl CollabTitlebarItem { avatar.clone(), Self::location_style(workspace, location, leader_style, cx), background_color, + microphone_state )) .with_children( (|| { @@ -903,6 +908,7 @@ impl CollabTitlebarItem { avatar.clone(), follower_style, background_color, + None )) })) })() @@ -1021,12 +1027,13 @@ impl CollabTitlebarItem { avatar: Arc, avatar_style: AvatarStyle, background_color: Color, + microphone_state: Option ) -> AnyElement { Image::from_data(avatar) .with_style(avatar_style.image) .aligned() .contained() - .with_background_color(background_color) + .with_background_color(microphone_state.unwrap_or(background_color)) .with_corner_radius(avatar_style.outer_corner_radius) .constrained() .with_width(avatar_style.outer_width) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 06c6026e3aafb38e1dceebbfc49be84e63b92195..0a62459a3a894ccd41a612d29b3a573df35d22ee 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -132,6 +132,8 @@ pub struct Titlebar { pub sign_in_button: Toggleable>, pub outdated_warning: ContainedText, pub share_button: Toggleable>, + pub muted: Color, + pub speaking: Color, pub screen_share_button: Toggleable>, pub toggle_contacts_button: Toggleable>, pub toggle_microphone_button: Toggleable>, @@ -146,6 +148,7 @@ pub struct UserMenu { pub user_menu_button_online: UserMenuButton, pub user_menu_button_offline: UserMenuButton, } + #[derive(Clone, Deserialize, Default, JsonSchema)] pub struct UserMenuButton { pub user_menu: Toggleable>, diff --git a/styles/src/styleTree/titlebar.ts b/styles/src/styleTree/titlebar.ts index f27c30143337506337989973e95265daa0c83cfb..fe0885c8e7faed63fae597df27d3438f9891b485 100644 --- a/styles/src/styleTree/titlebar.ts +++ b/styles/src/styleTree/titlebar.ts @@ -57,6 +57,9 @@ function call_controls(theme: ColorScheme) { }, active_color: 'accent' }), + + muted: foreground(theme.lowest, "negative"), + speaking: foreground(theme.lowest, "accent"), } } @@ -153,7 +156,7 @@ function user_menu(theme: ColorScheme) { } export function titlebar(theme: ColorScheme) { - const avatarWidth = 18 + const avatarWidth = 15 const avatarOuterWidth = avatarWidth + 4 const followerAvatarWidth = 14 const followerAvatarOuterWidth = followerAvatarWidth + 4 From 88b30dea100137538c86e35ca941fff3b9ff2102 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 28 Jun 2023 08:44:17 -0700 Subject: [PATCH 62/63] fmt --- crates/collab_ui/src/collab_titlebar_item.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 72aa247f35295f637e9cc43d9e69c98dee56c9d0..e76778b2cdfe51c2b2d9ac43523a133aa788481f 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -668,7 +668,7 @@ impl CollabTitlebarItem { avatar_img, *avatar_style, Color::transparent_black(), - None + None, )); }; @@ -876,7 +876,7 @@ impl CollabTitlebarItem { avatar.clone(), Self::location_style(workspace, location, leader_style, cx), background_color, - microphone_state + microphone_state, )) .with_children( (|| { @@ -908,7 +908,7 @@ impl CollabTitlebarItem { avatar.clone(), follower_style, background_color, - None + None, )) })) })() @@ -1027,7 +1027,7 @@ impl CollabTitlebarItem { avatar: Arc, avatar_style: AvatarStyle, background_color: Color, - microphone_state: Option + microphone_state: Option, ) -> AnyElement { Image::from_data(avatar) .with_style(avatar_style.image) From cb782c5a7b0c306056c76734f72997592210248a Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 28 Jun 2023 09:06:06 -0700 Subject: [PATCH 63/63] Remove menu tracking state --- crates/collab_ui/src/collab_titlebar_item.rs | 62 +++++++++----------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index e76778b2cdfe51c2b2d9ac43523a133aa788481f..2ab89281660b5750eb4028ce7a2ed87ccc46851a 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -50,7 +50,6 @@ pub struct CollabTitlebarItem { workspace: WeakViewHandle, contacts_popover: Option>, user_menu: ViewHandle, - user_menu_is_visible: bool, _subscriptions: Vec, } @@ -183,7 +182,6 @@ impl CollabTitlebarItem { menu.set_position_mode(OverlayPositionMode::Local); menu }), - user_menu_is_visible: false, _subscriptions: subscriptions, } } @@ -296,35 +294,31 @@ impl CollabTitlebarItem { } pub fn toggle_user_menu(&mut self, _: &ToggleUserMenu, cx: &mut ViewContext) { - if !self.user_menu_is_visible { - self.user_menu.update(cx, |user_menu, cx| { - let items = if let Some(_) = self.user_store.read(cx).current_user() { - vec![ - ContextMenuItem::action("Settings", zed_actions::OpenSettings), - ContextMenuItem::action("Theme", theme_selector::Toggle), - ContextMenuItem::separator(), - ContextMenuItem::action( - "Share Feedback", - feedback::feedback_editor::GiveFeedback, - ), - ContextMenuItem::action("Sign out", SignOut), - ] - } else { - vec![ - ContextMenuItem::action("Settings", zed_actions::OpenSettings), - ContextMenuItem::action("Theme", theme_selector::Toggle), - ContextMenuItem::separator(), - ContextMenuItem::action( - "Share Feedback", - feedback::feedback_editor::GiveFeedback, - ), - ] - }; - - user_menu.show(Default::default(), AnchorCorner::TopRight, items, cx); - }); - } - self.user_menu_is_visible = !self.user_menu_is_visible; + self.user_menu.update(cx, |user_menu, cx| { + let items = if let Some(_) = self.user_store.read(cx).current_user() { + vec![ + ContextMenuItem::action("Settings", zed_actions::OpenSettings), + ContextMenuItem::action("Theme", theme_selector::Toggle), + ContextMenuItem::separator(), + ContextMenuItem::action( + "Share Feedback", + feedback::feedback_editor::GiveFeedback, + ), + ContextMenuItem::action("Sign out", SignOut), + ] + } else { + vec![ + ContextMenuItem::action("Settings", zed_actions::OpenSettings), + ContextMenuItem::action("Theme", theme_selector::Toggle), + ContextMenuItem::separator(), + ContextMenuItem::action( + "Share Feedback", + feedback::feedback_editor::GiveFeedback, + ), + ] + }; + user_menu.show(Default::default(), AnchorCorner::TopRight, items, cx); + }); } fn render_toggle_contacts_button( @@ -701,12 +695,12 @@ impl CollabTitlebarItem { ) .contained(), ) - .with_children(self.user_menu_is_visible.then(|| { + .with_child( ChildView::new(&self.user_menu, cx) .aligned() .bottom() - .right() - })) + .right(), + ) .into_any() }