menu: Add external link icon to link menu item. (#734)

<img width="403" alt="image"
src="https://github.com/user-attachments/assets/ad6682b6-2114-4f55-be84-d06c02ae401e"
/>
This commit is contained in:
Jason Lee 2025-03-24 22:30:29 +08:00 committed by GitHub
parent e0f4a7d3cd
commit f650491605
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 46 additions and 3 deletions

View file

@ -0,0 +1,14 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-external-link"
><path d="M15 3h6v6" /><path d="M10 14 21 3" /><path
d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"
/></svg>

After

Width:  |  Height:  |  Size: 392 B

View file

@ -175,7 +175,9 @@ impl Render for PopupStory {
.min_h(px(400.)) .min_h(px(400.))
.context_menu({ .context_menu({
move |this, window, cx| { 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("Cut", Box::new(Cut))
.menu("Copy", Box::new(Copy)) .menu("Copy", Box::new(Copy))
.menu("Paste", Box::new(Paste)) .menu("Paste", Box::new(Paste))
@ -255,7 +257,9 @@ impl Render for PopupStory {
Button::new("popup-menu-1") Button::new("popup-menu-1")
.icon(IconName::Ellipsis) .icon(IconName::Ellipsis)
.popup_menu(move |this, window, cx| { .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("Cut", Box::new(Cut))
.menu("Paste", Box::new(Paste)) .menu("Paste", Box::new(Paste))
.separator() .separator()

View file

@ -33,6 +33,7 @@ pub enum IconName {
Delete, Delete,
Ellipsis, Ellipsis,
EllipsisVertical, EllipsisVertical,
ExternalLink,
Eye, Eye,
EyeOff, EyeOff,
Frame, Frame,
@ -110,6 +111,7 @@ impl IconName {
Self::Delete => "icons/delete.svg", Self::Delete => "icons/delete.svg",
Self::Ellipsis => "icons/ellipsis.svg", Self::Ellipsis => "icons/ellipsis.svg",
Self::EllipsisVertical => "icons/ellipsis-vertical.svg", Self::EllipsisVertical => "icons/ellipsis-vertical.svg",
Self::ExternalLink => "icons/external-link.svg",
Self::Eye => "icons/eye.svg", Self::Eye => "icons/eye.svg",
Self::EyeOff => "icons/eye-off.svg", Self::EyeOff => "icons/eye-off.svg",
Self::Frame => "icons/frame.svg", Self::Frame => "icons/frame.svg",

View file

@ -66,6 +66,7 @@ enum PopupMenuItem {
icon: Option<Icon>, icon: Option<Icon>,
label: SharedString, label: SharedString,
disabled: bool, disabled: bool,
is_link: bool,
action: Option<Box<dyn Action>>, action: Option<Box<dyn Action>>,
handler: Rc<dyn Fn(&mut Window, &mut App)>, handler: Rc<dyn Fn(&mut Window, &mut App)>,
}, },
@ -107,6 +108,7 @@ pub struct PopupMenu {
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
scrollable: bool, scrollable: bool,
external_link_icon: bool,
scroll_handle: ScrollHandle, scroll_handle: ScrollHandle,
scroll_state: Rc<Cell<ScrollbarState>>, scroll_state: Rc<Cell<ScrollbarState>>,
@ -144,6 +146,7 @@ impl PopupMenu {
scrollable: false, scrollable: false,
scroll_handle: ScrollHandle::default(), scroll_handle: ScrollHandle::default(),
scroll_state: Rc::new(Cell::new(ScrollbarState::default())), scroll_state: Rc::new(Cell::new(ScrollbarState::default())),
external_link_icon: true,
_subscriptions, _subscriptions,
}; };
f(menu, window, cx) f(menu, window, cx)
@ -176,6 +179,12 @@ impl PopupMenu {
self 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 /// Add Menu Item
pub fn menu(self, label: impl Into<SharedString>, action: Box<dyn Action>) -> Self { pub fn menu(self, label: impl Into<SharedString>, action: Box<dyn Action>) -> Self {
self.menu_with_disabled(label, action, false) self.menu_with_disabled(label, action, false)
@ -216,6 +225,7 @@ impl PopupMenu {
label: label.into(), label: label.into(),
disabled, disabled,
action: None, action: None,
is_link: true,
handler: Rc::new(move |_, cx| cx.open_url(&href)), handler: Rc::new(move |_, cx| cx.open_url(&href)),
}); });
self self
@ -245,6 +255,7 @@ impl PopupMenu {
label: label.into(), label: label.into(),
disabled, disabled,
action: None, action: None,
is_link: true,
handler: Rc::new(move |_, cx| cx.open_url(&href)), handler: Rc::new(move |_, cx| cx.open_url(&href)),
}); });
self self
@ -499,6 +510,7 @@ impl PopupMenu {
label: label.into(), label: label.into(),
disabled, disabled,
action: Some(action.boxed_clone()), action: Some(action.boxed_clone()),
is_link: false,
handler: self.wrap_handler(action), handler: self.wrap_handler(action),
}); });
self self
@ -730,8 +742,10 @@ impl PopupMenu {
label, label,
action, action,
disabled, disabled,
is_link,
.. ..
} => { } => {
let show_link_icon = *is_link && self.external_link_icon;
let action = action.as_ref().map(|action| action.boxed_clone()); let action = action.as_ref().map(|action| action.boxed_clone());
let key = Self::render_keybinding(action, window, cx); let key = Self::render_keybinding(action, window, cx);
@ -753,7 +767,16 @@ impl PopupMenu {
.gap_2() .gap_2()
.items_center() .items_center()
.justify_between() .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), .children(key),
), ),
) )