diff --git a/Cargo.lock b/Cargo.lock index bc586381c2eb82c09b1a7a82a56d99b96c302c5e..029f9e5ce2dbe1e0cde225ca687440b1428ca710 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1419,8 +1419,10 @@ dependencies = [ "serde_derive", "settings", "theme", + "theme_selector", "util", "workspace", + "zed-actions", ] [[package]] @@ -9017,6 +9019,14 @@ dependencies = [ "vim", "welcome", "workspace", + "zed-actions", +] + +[[package]] +name = "zed-actions" +version = "0.1.0" +dependencies = [ + "gpui", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 640384a79272fdd14df6291dcd076bbba7a18dd7..3f3953096eda1e0e05dad60b3507b1c0a0843295 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,6 +67,7 @@ members = [ "crates/welcome", "crates/xtask", "crates/zed", + "crates/zed-actions" ] default-members = ["crates/zed"] resolver = "2" 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-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/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/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 @@ + + + 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 @@ + + + diff --git a/crates/call/src/participant.rs b/crates/call/src/participant.rs index 4b9e7ba034fb23d118cb5963d335e5c16201d590..e7858869ce63906b75f9cd0cb117cf7b54283efd 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,10 @@ pub struct RemoteParticipant { pub peer_id: proto::PeerId, pub projects: Vec, pub location: ParticipantLocation, - pub tracks: HashMap>, + pub muted: bool, + pub speaking: bool, + 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..da298f9ca25757f91f394e217099eb236a275827 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -12,7 +12,10 @@ 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, RemoteAudioTrackUpdate, + RemoteVideoTrackUpdate, +}; use postage::stream::Stream; use project::Project; use std::{future::Future, mem, pin::Pin, sync::Arc, time::Duration}; @@ -28,6 +31,9 @@ pub enum Event { RemoteVideoTracksChanged { participant_id: proto::PeerId, }, + RemoteAudioTracksChanged { + participant_id: proto::PeerId, + }, RemoteProjectShared { owner: Arc, project_id: u64, @@ -112,9 +118,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 +133,41 @@ impl Room { } }); - cx.foreground() - .spawn(room.connect(&connection_info.server_url, &connection_info.token)) - .detach_and_log_err(cx); + 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() + }); + } + }); + + 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 { room, - screen_track: ScreenTrack::None, + screen_track: LocalTrack::None, + microphone_track: LocalTrack::None, next_publish_id: 0, + muted_by_user: false, + deafened: false, + speaking: false, _maintain_room, - _maintain_tracks, + _maintain_tracks: [_maintain_video_tracks, _maintain_audio_tracks], }) } else { None @@ -618,20 +649,32 @@ impl Room { peer_id, projects: participant.projects, location, - tracks: Default::default(), + muted: false, + speaking: false, + 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 +749,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 +768,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 +779,84 @@ impl Room { Ok(()) } + fn remote_audio_track_updated( + &mut self, + change: RemoteAudioTrackUpdate, + 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; + for track in participant.audio_tracks.values() { + if track.sid() == track_id { + found = true; + break; + } + } + if found { + participant.muted = muted; + break; + } + } + cx.notify(); + } + 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 +1029,116 @@ 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, LocalTrack::None) + }) + } + + pub fn is_sharing_mic(&self) -> bool { + self.live_kit.as_ref().map_or(false, |live_kit| { + !matches!(live_kit.microphone_track, LocalTrack::None) + }) + } + + pub fn is_muted(&self) -> bool { + 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), + }) + .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 { + self.live_kit.as_ref().map(|live_kit| live_kit.deafened) + } + + 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() { + 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 = LocalTrack::Pending { + publish_id, + muted: false, + }; + 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, muted) = if let LocalTrack::Pending { + publish_id: cur_publish_id, + muted, + } = &live_kit.microphone_track + { + (*cur_publish_id != publish_id, *muted) + } else { + (true, false) + }; + + match publication { + Ok(publication) => { + if canceled { + live_kit.room.unpublish_track(publication); + } else { + if muted { + cx.background().spawn(publication.set_mute(muted)).detach(); + } + live_kit.microphone_track = LocalTrack::Published { + track_publication: publication, + muted, + }; + cx.notify(); + } + Ok(()) + } + Err(error) => { + if canceled { + Ok(()) + } else { + live_kit.microphone_track = LocalTrack::None; + cx.notify(); + Err(error) + } + } + } + }) }) } @@ -921,7 +1151,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 = ScreenTrack::Pending { publish_id }; + live_kit.screen_track = LocalTrack::Pending { + publish_id, + muted: false, + }; cx.notify(); (live_kit.room.display_sources(), publish_id) } else { @@ -955,13 +1188,14 @@ impl Room { .as_mut() .ok_or_else(|| anyhow!("live-kit was not initialized"))?; - let canceled = if let ScreenTrack::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 { @@ -969,7 +1203,13 @@ impl Room { if canceled { live_kit.room.unpublish_track(publication); } else { - live_kit.screen_track = ScreenTrack::Published(publication); + if muted { + cx.background().spawn(publication.set_mute(muted)).detach(); + } + live_kit.screen_track = LocalTrack::Published { + track_publication: publication, + muted, + }; cx.notify(); } Ok(()) @@ -978,7 +1218,7 @@ impl Room { if canceled { Ok(()) } else { - live_kit.screen_track = ScreenTrack::None; + live_kit.screen_track = LocalTrack::None; cx.notify(); Err(error) } @@ -987,6 +1227,77 @@ impl Room { }) }) } + fn set_mute( + live_kit: &mut LiveKitRoom, + 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, .. } => { + *muted = should_mute; + cx.notify(); + Ok(Task::Ready(Some(Ok(())))) + } + LocalTrack::Published { + track_publication, + muted, + } => { + *muted = should_mute; + cx.notify(); + 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(); + if let Some(live_kit) = self.live_kit.as_mut() { + let ret = Self::set_mute(live_kit, should_mute, cx); + live_kit.muted_by_user = should_mute; + ret + } else { + Err(anyhow!("LiveKit not started")) + } + } + + 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; + + let mut tasks = Vec::with_capacity(self.remote_participants.len()); + // Context notification is sent within set_mute itself. + let mut mute_task = None; + // 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() { + for track in live_kit + .room + .remote_audio_track_publications(&participant.user.id.to_string()) + { + 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?; + } + Ok(()) + })) + } else { + Err(anyhow!("LiveKit not started")) + } + } pub fn unshare_screen(&mut self, cx: &mut ModelContext) -> Result<()> { if self.status.is_offline() { @@ -998,13 +1309,15 @@ 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 { .. } => { + LocalTrack::None => Err(anyhow!("screen was not shared")), + LocalTrack::Pending { .. } => { cx.notify(); Ok(()) } - ScreenTrack::Published(track) => { - live_kit.room.unpublish_track(track); + LocalTrack::Published { + track_publication, .. + } => { + live_kit.room.unpublish_track(track_publication); cx.notify(); Ok(()) } @@ -1023,19 +1336,30 @@ impl Room { struct LiveKitRoom { room: Arc, - screen_track: ScreenTrack, + 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, _maintain_room: Task<()>, - _maintain_tracks: Task<()>, + _maintain_tracks: [Task<()>; 2], } -enum ScreenTrack { +enum LocalTrack { None, - Pending { publish_id: usize }, - Published(LocalTrackPublication), + Pending { + publish_id: usize, + muted: bool, + }, + Published { + track_publication: LocalTrackPublication, + muted: bool, + }, } -impl Default for ScreenTrack { +impl Default for LocalTrack { fn default() -> Self { Self::None } diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 2211e53263226c74c840be49a657004c172d4a97..3ddef9410427a199a029e8d16b7d0240527527c4 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 ); @@ -7014,7 +7014,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/Cargo.toml b/crates/collab_ui/Cargo.toml index 16cc6b52772e2772aab691f1e9e2b8dbf0e3b726..ee410ccba7a57e68af7601e2ea3fd0fc654f653d 100644 --- a/crates/collab_ui/Cargo.toml +++ b/crates/collab_ui/Cargo.toml @@ -37,8 +37,10 @@ picker = { path = "../picker" } project = { path = "../project" } settings = { path = "../settings" } 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 04fc9650eb82f1177b0290463b04e2601be9640c..2ab89281660b5750eb4028ce7a2ed87ccc46851a 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_screen_sharing, ToggleScreenSharing, + toggle_deafen, toggle_mute, toggle_screen_sharing, LeaveCall, ToggleDeafen, ToggleMute, + ToggleScreenSharing, }; use call::{ActiveCall, ParticipantLocation, Room}; use client::{proto::PeerId, Client, ContactEventKind, SignIn, SignOut, User, UserStore}; @@ -17,13 +18,13 @@ 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; use workspace::{FollowNextCollaborator, Workspace}; -const MAX_TITLE_LENGTH: usize = 75; +// const MAX_TITLE_LENGTH: usize = 75; actions!( collab, @@ -78,27 +79,34 @@ 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()) { - 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 - .add_child(self.render_current_user(&workspace, &theme, &user, peer_id, cx)); + .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, 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)); right_container.add_child(self.render_toggle_screen_sharing_button(&theme, &room, cx)); } 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().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)); 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() @@ -108,7 +116,6 @@ impl View for CollabTitlebarItem { .with_child( right_container.contained().with_background_color( theme - .workspace .titlebar .container .background_color @@ -163,7 +170,6 @@ impl CollabTitlebarItem { }), ); - let view_id = cx.view_id(); Self { workspace: workspace.weak_handle(), project, @@ -171,6 +177,7 @@ impl CollabTitlebarItem { client, contacts_popover: 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 @@ -185,55 +192,45 @@ 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 text_style = theme.workspace.titlebar.title.clone(); - let item_spacing = theme.workspace.titlebar.item_spacing; + 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.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, 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) { @@ -297,50 +294,29 @@ 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 - .inactive_state() - .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", zed_actions::OpenSettings), + 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", zed_actions::OpenSettings), + ContextMenuItem::action("Theme", theme_selector::Toggle), + ContextMenuItem::separator(), ContextMenuItem::action( - "Send Feedback", + "Share Feedback", feedback::feedback_editor::GiveFeedback, ), ] }; - user_menu.show(Default::default(), AnchorCorner::TopRight, items, cx); }); } @@ -350,7 +326,7 @@ impl CollabTitlebarItem { theme: &Theme, cx: &mut ViewContext, ) -> AnyElement { - let titlebar = &theme.workspace.titlebar; + let titlebar = &theme.titlebar; let badge = if self .user_store @@ -391,7 +367,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) @@ -418,7 +394,6 @@ impl CollabTitlebarItem { .with_children(self.render_contacts_popover_host(titlebar, cx)) .into_any() } - fn render_toggle_screen_sharing_button( &self, theme: &Theme, @@ -428,16 +403,21 @@ impl CollabTitlebarItem { let icon; let tooltip; if room.read(cx).is_screen_sharing() { - icon = "icons/enable_screen_sharing_12.svg"; + icon = "icons/radix/desktop.svg"; tooltip = "Stop Sharing Screen" } else { - icon = "icons/disable_screen_sharing_12.svg"; + icon = "icons/radix/desktop.svg"; tooltip = "Share Screen"; } - let titlebar = &theme.workspace.titlebar; + let active = room.read(cx).is_screen_sharing(); + let titlebar = &theme.titlebar; MouseEventHandler::::new(0, cx, |state, _| { - let style = titlebar.call_control.style_for(state); + let style = titlebar + .screen_share_button + .in_state(active) + .style_for(state); + Svg::new(icon) .with_color(style.color) .constrained() @@ -463,7 +443,141 @@ impl CollabTitlebarItem { .aligned() .into_any() } + fn render_toggle_mute( + &self, + theme: &Theme, + room: &ModelHandle, + cx: &mut ViewContext, + ) -> AnyElement { + let icon; + let tooltip; + let is_muted = room.read(cx).is_muted(); + if is_muted { + icon = "icons/radix/mic-mute.svg"; + tooltip = "Unmute microphone\nRight click for options"; + } else { + icon = "icons/radix/mic.svg"; + tooltip = "Mute microphone\nRight click for options"; + } + let titlebar = &theme.titlebar; + MouseEventHandler::::new(0, cx, |state, _| { + 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) + .aligned() + .constrained() + .with_width(style.button_width) + .with_height(style.button_width) + .contained() + .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| { + toggle_mute(&Default::default(), cx) + }) + .with_tooltip::( + 0, + tooltip.into(), + Some(Box::new(ToggleMute)), + theme.tooltip.clone(), + cx, + ) + .aligned() + .into_any() + } + fn render_toggle_deafen( + &self, + theme: &Theme, + room: &ModelHandle, + cx: &mut ViewContext, + ) -> AnyElement { + let icon; + let tooltip; + 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 { + icon = "icons/radix/speaker-loud.svg"; + tooltip = "Mute speakers\nRight click for options"; + } + + let titlebar = &theme.titlebar; + MouseEventHandler::::new(0, cx, |state, _| { + let style = titlebar + .toggle_speakers_button + .in_state(is_deafened) + .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_leave_call(&self, theme: &Theme, cx: &mut ViewContext) -> AnyElement { + let icon = "icons/radix/exit.svg"; + let tooltip = "Leave call"; + + let titlebar = &theme.titlebar; + MouseEventHandler::::new(0, cx, |state, _| { + let style = titlebar.leave_call_button.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, @@ -476,14 +590,14 @@ 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" }; - let titlebar = &theme.workspace.titlebar; + let titlebar = &theme.titlebar; enum ShareUnshare {} Some( @@ -514,7 +628,7 @@ impl CollabTitlebarItem { ) .aligned() .contained() - .with_margin_left(theme.workspace.titlebar.item_spacing) + .with_margin_left(theme.titlebar.item_spacing) .into_any(), ) } @@ -522,24 +636,51 @@ impl CollabTitlebarItem { fn render_user_menu_button( &self, theme: &Theme, + avatar: Option>, cx: &mut ViewContext, ) -> AnyElement { - let titlebar = &theme.workspace.titlebar; + let tooltip = theme.tooltip.clone(); + let user_menu_button_style = if avatar.is_some() { + &theme.titlebar.user_menu.user_menu_button_online + } else { + &theme.titlebar.user_menu.user_menu_button_offline + }; + let avatar_style = &user_menu_button_style.avatar; Stack::new() .with_child( MouseEventHandler::::new(0, cx, |state, _| { - let style = titlebar.call_control.style_for(state); - Svg::new("icons/ellipsis_14.svg") - .with_color(style.color) - .constrained() - .with_width(style.icon_width) + let style = user_menu_button_style + .user_menu + .inactive_state() + .style_for(state); + + 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(), + None, + )); + }; + + dropdown + .with_child( + Svg::new("icons/caret_down_8.svg") + .with_color(user_menu_button_style.icon.color) + .constrained() + .with_width(user_menu_button_style.icon.width) + .contained() + .into_any(), + ) .aligned() .constrained() - .with_width(style.button_width) - .with_height(style.button_width) + .with_height(style.width) .contained() .with_style(style.container) + .into_any() }) .with_cursor_style(CursorStyle::PointingHand) .on_click(MouseButton::Left, move |_, this, cx| { @@ -549,11 +690,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) @@ -565,9 +705,9 @@ 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_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) @@ -629,11 +769,13 @@ impl CollabTitlebarItem { replica_id, participant.peer_id, Some(participant.location), + participant.muted, + participant.speaking, workspace, theme, cx, )) - .with_margin_right(theme.workspace.titlebar.face_pile_spacing), + .with_margin_right(theme.titlebar.face_pile_spacing), ) }) .collect() @@ -645,19 +787,24 @@ 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, )) - .with_margin_right(theme.workspace.titlebar.item_spacing) + .with_margin_right(theme.titlebar.item_spacing) .into_any() } @@ -667,6 +814,8 @@ impl CollabTitlebarItem { replica_id: Option, peer_id: PeerId, location: Option, + muted: bool, + speaking: bool, workspace: &ViewHandle, theme: &Theme, cx: &mut ViewContext, @@ -689,15 +838,23 @@ 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 microphone_state = if muted { + Some(theme.titlebar.muted) + } else if speaking { + Some(theme.titlebar.speaking) + } else { + None + }; let mut background_color = theme - .workspace .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; @@ -708,11 +865,12 @@ 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), background_color, + microphone_state, )) .with_children( (|| { @@ -744,6 +902,7 @@ impl CollabTitlebarItem { avatar.clone(), follower_style, background_color, + None, )) })) })() @@ -753,7 +912,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 { @@ -770,8 +929,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(), ) @@ -862,12 +1021,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) @@ -891,22 +1051,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/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index c0734388b1512b2e9cac5014c460bf1a8c09650b..a809b9c7e6d54b2504aa1f4a95e7257396e930c4 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -9,13 +9,23 @@ 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 std::sync::Arc; +use util::ResultExt; use workspace::AppState; -actions!(collab, [ToggleScreenSharing]); +actions!( + collab, + [ + ToggleScreenSharing, + ToggleMute, + ToggleDeafen, + LeaveCall, + ShareMicrophone + ] +); pub fn init(app_state: &Arc, cx: &mut AppContext) { collab_titlebar_item::init(cx); @@ -27,6 +37,9 @@ 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); + cx.add_global_action(share_microphone); } pub fn toggle_screen_sharing(_: &ToggleScreenSharing, cx: &mut AppContext) { @@ -41,3 +54,26 @@ 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() { + 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(); + } +} + +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) + } +} diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index 0c8b27a1511e075aa734d62001392beb64da56b4..428f2156d116133d063710fed99c890e8ad30869 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/gpui/src/executor.rs b/crates/gpui/src/executor.rs index 365766fb9dd0b080642a4b1e344d985dd312d22c..712c8544884af838a6d5cccdc5f6555a77b8014f 100644 --- a/crates/gpui/src/executor.rs +++ b/crates/gpui/src/executor.rs @@ -7,6 +7,7 @@ use std::{ fmt::{self, Display}, marker::PhantomData, mem, + panic::Location, pin::Pin, rc::Rc, sync::Arc, @@ -965,10 +966,12 @@ 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 { - log::error!("{:#}", err); + 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 40c1319e8f9111dac6139e723699ba76fd8d6111..40d3641db23afcbac801b7f5f2daa15411c15f72 100644 --- a/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift +++ b/crates/live_kit_client/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift @@ -8,14 +8,18 @@ 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 - + init( data: UnsafeRawPointer, 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) { @@ -40,6 +46,17 @@ class LKRoomDelegate: RoomDelegate { self.onDidSubscribeToRemoteAudioTrack(self.data, participant.identity as CFString, track.sid! as CFString, Unmanaged.passUnretained(track).toOpaque()) } } + + 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 { @@ -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 ) @@ -169,6 +190,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? { @@ -201,19 +234,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 +267,43 @@ public func LKDisplaySources(data: UnsafeRawPointer, callback: @escaping @conven callback(data, nil, error.localizedDescription as CFString) } } + +@_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() + + 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("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() + + 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/examples/test_app.rs b/crates/live_kit_client/examples/test_app.rs index faf1b54798f3722fe335fdf0e27748b94e9aba9e..f5f6d0e46f123d8015f7674d8c0292f1f35d3d75 100644 --- a/crates/live_kit_client/examples/test_app.rs +++ b/crates/live_kit_client/examples/test_app.rs @@ -74,19 +74,51 @@ 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 6ae493d306136f66f3a6212ccf23ec93b2f50f93..6daa0601ca95541665dd8bd9c2eeaf526320df8c 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, @@ -72,6 +81,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, @@ -84,12 +98,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 +111,20 @@ extern "C" { ); fn LKCreateScreenShareTrackForDisplay(display: *const c_void) -> *const c_void; fn LKLocalAudioTrackCreateTrack() -> *const c_void; + + 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 LKRemoteTrackPublicationSetEnabled( + publication: *const c_void, + enabled: bool, + on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef), + callback_data: *mut c_void, + ); } pub type Sid = String; @@ -206,7 +228,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))); @@ -232,7 +254,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))); @@ -246,7 +268,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) { @@ -313,6 +335,31 @@ 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::new(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); @@ -343,6 +390,28 @@ 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| { @@ -407,6 +476,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, ) @@ -455,6 +526,42 @@ 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, @@ -525,12 +632,88 @@ 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(); + + 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 { + LKLocalTrackPublicationSetMute( + self.0, + muted, + 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) } } } +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(); + + 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 { + LKRemoteTrackPublicationSetEnabled( + self.0, + enabled, + complete_callback, + Box::into_raw(Box::new(tx)) as *mut c_void, + ) + } + + async move { rx.await.unwrap() } + } +} + +impl Drop for RemoteTrackPublication { + fn drop(&mut self) { + unsafe { CFRelease(self.0) } + } +} + #[derive(Debug)] pub struct RemoteAudioTrack { _native_track: *const c_void, @@ -557,6 +740,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(Debug)] @@ -639,6 +830,8 @@ pub enum RemoteVideoTrackUpdate { } pub enum RemoteAudioTrackUpdate { + 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 2f89617363db7a9e9f51251ebf70b5e8b0eea482..3fc046c5a293b105729fb756adfede6951de954b 100644 --- a/crates/live_kit_client/src/test.rs +++ b/crates/live_kit_client/src/test.rs @@ -410,6 +410,23 @@ 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(); @@ -475,6 +492,20 @@ impl Drop for Room { pub struct LocalTrackPublication; +impl LocalTrackPublication { + pub fn set_mute(&self, _mute: bool) -> impl Future> { + async { Ok(()) } + } +} + +pub struct RemoteTrackPublication; + +impl RemoteTrackPublication { + pub fn set_enabled(&self, _enabled: bool) -> impl Future> { + async { Ok(()) } + } +} + #[derive(Clone)] pub struct LocalVideoTrack { frames_rx: async_broadcast::Receiver, @@ -517,6 +548,7 @@ impl RemoteVideoTrack { } } +#[derive(Debug)] pub struct RemoteAudioTrack { sid: Sid, publisher_id: Sid, @@ -530,6 +562,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)] @@ -540,6 +580,8 @@ 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/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index 69f16e494933ed0a47bc8bf45c08e046b3e55372..33d6e842415f9f4cba317f64ab9ff58b926608d8 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() diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index f93063be2e55854b7fda683c43c23d1ed8e95dd6..0a62459a3a894ccd41a612d29b3a573df35d22ee 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -66,6 +66,7 @@ pub struct Theme { pub feedback: FeedbackStyle, pub welcome: WelcomeStyle, pub color_scheme: ColorScheme, + pub titlebar: Titlebar, } #[derive(Deserialize, Default, Clone, JsonSchema)] @@ -80,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, @@ -129,13 +129,31 @@ 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 call_control: Interactive, + pub muted: Color, + pub speaking: Color, + pub screen_share_button: Toggleable>, pub toggle_contacts_button: Toggleable>, - pub user_menu_button: Toggleable>, + pub toggle_microphone_button: Toggleable>, + pub toggle_speakers_button: Toggleable>, + pub leave_call_button: Interactive, pub toggle_contacts_badge: ContainerStyle, + pub user_menu: UserMenu, +} + +#[derive(Clone, Deserialize, Default, JsonSchema)] +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>, + pub avatar: AvatarStyle, + pub icon: Icon, } #[derive(Copy, Clone, Deserialize, Default, JsonSchema)] diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 8b1092fad0f0b53c2bcd6fc03621006286e205ab..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") } @@ -2765,7 +2765,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::() { diff --git a/crates/zed-actions/Cargo.toml b/crates/zed-actions/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..b3fe3cbb53c46457c6855a916dcc6ef650e6be50 --- /dev/null +++ b/crates/zed-actions/Cargo.toml @@ -0,0 +1,10 @@ +[package] +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 + +[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..bcd086924d2d0b36000bd4b67d2567dbc19c589d --- /dev/null +++ b/crates/zed-actions/src/lib.rs @@ -0,0 +1,28 @@ +use gpui::actions; + +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 3bf500057f1f98ade9f2599bbd14614fa721c24b..f00346510d2c71e45a1cf9c94888c977a9114b4e 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -66,7 +66,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 58229d395167125b543215d60a539af837eecfda..6cf524c9e0aea025b6168072bf2e8f6aee300b4e 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -889,6 +889,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 cbd67a84cf944bc28daf5bc5cb036ce2fad79453..9b204374d1f7ceb39258b6c0d29f30f28c0cbad5 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, @@ -50,6 +49,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 +58,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| { @@ -735,8 +708,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/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) 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 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/component/icon_button.ts b/styles/src/component/icon_button.ts new file mode 100644 index 0000000000000000000000000000000000000000..43f8d0f9c4f361ee25aee5a5baef1f671d1079c8 --- /dev/null +++ b/styles/src/component/icon_button.ts @@ -0,0 +1,75 @@ +import { ColorScheme } from "../common"; +import { interactive, toggleable } from "../element"; +import { background, foreground } from "../styleTree/components"; + +export type Margin = { + top: number; + bottom: number; + left: number; + right: number; +} + +interface IconButtonOptions { + layer?: ColorScheme['lowest'] | ColorScheme['middle'] | ColorScheme['highest']; + color?: keyof ColorScheme['lowest']; + margin?: Partial; +} + +type ToggleableIconButtonOptions = IconButtonOptions & { active_color?: keyof ColorScheme['lowest'] }; + +export function icon_button(theme: ColorScheme, { color, margin, layer }: 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: 6, + padding: { + top: 2, + bottom: 2, + left: 4, + right: 4, + }, + margin: m, + icon_width: 14, + icon_height: 14, + button_width: 20, + button_height: 16, + }, + 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_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..ae7fede900e8c0216b8dd2cda51b10ef583c25de --- /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 "./icon_button"; + +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/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/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..fe0885c8e7faed63fae597df27d3438f9891b485 --- /dev/null +++ b/styles/src/styleTree/titlebar.ts @@ -0,0 +1,266 @@ +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 { withOpacity } from "../theme/color"; +import { background, border, foreground, text } from "./components"; + +const ITEM_SPACING = 8 +const TITLEBAR_HEIGHT = 32 + +function build_spacing( + container_height: number, + element_height: number, + spacing: number +) { + return { + group: spacing, + item: spacing / 2, + half_item: spacing / 4, + marginY: (container_height - element_height) / 2, + marginX: (container_height - element_height) / 2, + } +} + +function call_controls(theme: ColorScheme) { + 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, + }, + active_color: 'negative' + }), + + toggle_speakers_button: toggleable_icon_button(theme, { + margin: { + ...marginY, + left: space.half_item, + right: space.half_item + }, + }), + + screen_share_button: toggleable_icon_button(theme, { + margin: { + ...marginY, + left: space.half_item, + right: space.group + }, + active_color: 'accent' + }), + + muted: foreground(theme.lowest, "negative"), + speaking: foreground(theme.lowest, "accent"), + } +} + +/** +* 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 user_menu(theme: ColorScheme) { + const button_height = 18 + + 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 ? 37 : 24, + 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), + }, + 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: button, + avatar: { + icon_width: 16, + icon_height: 16, + corner_radius: 4, + outer_width: 16, + outer_corner_radius: 16 + }, + icon: { + margin: { + top: 2, + left: online ? space.item : 0, + right: space.group, + bottom: 2, + }, + width: 11, + height: 11, + color: foreground(theme.lowest) + } + } + } + return { + userMenuButtonOnline: build_button({ online: true }), + userMenuButtonOffline: build_button({ online: false }), + } +} + +export function titlebar(theme: ColorScheme) { + const avatarWidth = 15 + const avatarOuterWidth = avatarWidth + 4 + const followerAvatarWidth = 14 + const followerAvatarOuterWidth = followerAvatarWidth + 4 + + return { + item_spacing: ITEM_SPACING, + facePileSpacing: 2, + height: TITLEBAR_HEIGHT, + background: background(theme.lowest), + border: border(theme.lowest, { bottom: true }), + padding: { + left: 80, + right: 0, + }, + + // 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: 14, + // TODO: Chore: Make avatarRibbon colors driven by the theme rather than being hard coded. + }, + + sign_in_button: toggleable_text_button(theme, {}), + offlineIcon: { + color: foreground(theme.lowest, "variant"), + width: 16, + margin: { + left: ITEM_SPACING, + }, + padding: { + right: 4, + }, + }, + + // 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), + 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 + }, + }), + + ...call_controls(theme), + + toggle_contacts_button: toggleable_icon_button(theme, { + margin: { + left: ITEM_SPACING, + }, + }), + + // 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: user_menu(theme) + } +} diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index bd14a3af727beb28252c6b30c928d98d963fe92a..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,56 +11,11 @@ import { import statusBar from "./statusBar" import tabBar from "./tabBar" import { interactive } from "../element" -import merge from "ts-deepmerge" + +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 avatarWidth = 18 - const avatarOuterWidth = avatarWidth + 4 - const followerAvatarWidth = 14 - const followerAvatarOuterWidth = followerAvatarWidth + 4 return { background: background(colorScheme.lowest), @@ -171,167 +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: 12, - // TODO: Chore: Make avatarRibbon colors driven by the theme rather than being hard coded. - }, - - // Sign in buttom - // FlatButton, Variant - signInPrompt: merge(titlebarButton, { - inactive: { - default: { - margin: { - left: itemSpacing, - }, - }, - }, - }), - - // 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, - }, - 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"), - }, - }, - }), - 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"), - }, - }, - }, - }), - userMenuButton: merge(titlebarButton, { - inactive: { - default: { - buttonWidth: 20, - iconWidth: 12, - }, - }, - active: { - // posiewic: these properties are not currently set on main - default: { - iconWidth: 12, - button_width: 20, - }, - }, - }), - - toggleContactsBadge: { - cornerRadius: 3, - padding: 2, - margin: { top: 3, left: 3 }, - border: border(layer), - background: foreground(layer, "accent"), - }, - shareButton: { - ...titlebarButton, - }, - }, - + titlebar: titlebar(colorScheme), toolbar: { height: 34, background: background(colorScheme.highest),