diff --git a/assets/icons/external-link.svg b/assets/icons/external-link.svg
new file mode 100644
index 00000000..dfef5df4
--- /dev/null
+++ b/assets/icons/external-link.svg
@@ -0,0 +1,14 @@
+
diff --git a/crates/story/src/popup_story.rs b/crates/story/src/popup_story.rs
index d6ad2cb3..854a18e5 100644
--- a/crates/story/src/popup_story.rs
+++ b/crates/story/src/popup_story.rs
@@ -175,7 +175,9 @@ impl Render for PopupStory {
.min_h(px(400.))
.context_menu({
move |this, window, cx| {
- this.separator()
+ this.external_link_icon(false)
+ .link("About", "https://github.com/longbridge/gpui-component")
+ .separator()
.menu("Cut", Box::new(Cut))
.menu("Copy", Box::new(Copy))
.menu("Paste", Box::new(Paste))
@@ -255,7 +257,9 @@ impl Render for PopupStory {
Button::new("popup-menu-1")
.icon(IconName::Ellipsis)
.popup_menu(move |this, window, cx| {
- this.menu("Copy", Box::new(Copy))
+ this.link("About", "https://github.com/longbridge/gpui-component")
+ .separator()
+ .menu("Copy", Box::new(Copy))
.menu("Cut", Box::new(Cut))
.menu("Paste", Box::new(Paste))
.separator()
diff --git a/crates/ui/src/icon.rs b/crates/ui/src/icon.rs
index 74c3d701..33d733ee 100644
--- a/crates/ui/src/icon.rs
+++ b/crates/ui/src/icon.rs
@@ -33,6 +33,7 @@ pub enum IconName {
Delete,
Ellipsis,
EllipsisVertical,
+ ExternalLink,
Eye,
EyeOff,
Frame,
@@ -110,6 +111,7 @@ impl IconName {
Self::Delete => "icons/delete.svg",
Self::Ellipsis => "icons/ellipsis.svg",
Self::EllipsisVertical => "icons/ellipsis-vertical.svg",
+ Self::ExternalLink => "icons/external-link.svg",
Self::Eye => "icons/eye.svg",
Self::EyeOff => "icons/eye-off.svg",
Self::Frame => "icons/frame.svg",
diff --git a/crates/ui/src/popup_menu.rs b/crates/ui/src/popup_menu.rs
index 43c90a38..718f7f49 100644
--- a/crates/ui/src/popup_menu.rs
+++ b/crates/ui/src/popup_menu.rs
@@ -66,6 +66,7 @@ enum PopupMenuItem {
icon: Option,
label: SharedString,
disabled: bool,
+ is_link: bool,
action: Option>,
handler: Rc,
},
@@ -107,6 +108,7 @@ pub struct PopupMenu {
bounds: Bounds,
scrollable: bool,
+ external_link_icon: bool,
scroll_handle: ScrollHandle,
scroll_state: Rc| >,
@@ -144,6 +146,7 @@ impl PopupMenu {
scrollable: false,
scroll_handle: ScrollHandle::default(),
scroll_state: Rc::new(Cell::new(ScrollbarState::default())),
+ external_link_icon: true,
_subscriptions,
};
f(menu, window, cx)
@@ -176,6 +179,12 @@ impl PopupMenu {
self
}
+ /// Set the menu to show external link icon, default is true.
+ pub fn external_link_icon(mut self, visible: bool) -> Self {
+ self.external_link_icon = visible;
+ self
+ }
+
/// Add Menu Item
pub fn menu(self, label: impl Into, action: Box) -> Self {
self.menu_with_disabled(label, action, false)
@@ -216,6 +225,7 @@ impl PopupMenu {
label: label.into(),
disabled,
action: None,
+ is_link: true,
handler: Rc::new(move |_, cx| cx.open_url(&href)),
});
self
@@ -245,6 +255,7 @@ impl PopupMenu {
label: label.into(),
disabled,
action: None,
+ is_link: true,
handler: Rc::new(move |_, cx| cx.open_url(&href)),
});
self
@@ -499,6 +510,7 @@ impl PopupMenu {
label: label.into(),
disabled,
action: Some(action.boxed_clone()),
+ is_link: false,
handler: self.wrap_handler(action),
});
self
@@ -730,8 +742,10 @@ impl PopupMenu {
label,
action,
disabled,
+ is_link,
..
} => {
+ let show_link_icon = *is_link && self.external_link_icon;
let action = action.as_ref().map(|action| action.boxed_clone());
let key = Self::render_keybinding(action, window, cx);
@@ -753,7 +767,16 @@ impl PopupMenu {
.gap_2()
.items_center()
.justify_between()
- .child(label.clone())
+ .when(!show_link_icon, |this| this.child(label.clone()))
+ .when(show_link_icon, |this| {
+ this.child(
+ h_flex().gap_1p5().child(label.clone()).child(
+ Icon::new(IconName::ExternalLink)
+ .xsmall()
+ .text_color(cx.theme().muted_foreground),
+ ),
+ )
+ })
.children(key),
),
)
|