
- Don't require ui component docs (this isn't really working) - Add more component previews - Update component preview style & navigation Release Notes: - N/A
236 lines
6.7 KiB
Rust
236 lines
6.7 KiB
Rust
use gpui::{Action, AnyElement, AnyView, AppContext as _, FocusHandle, IntoElement, Render};
|
|
use settings::Settings;
|
|
use theme::ThemeSettings;
|
|
|
|
use crate::prelude::*;
|
|
use crate::{h_flex, v_flex, Color, KeyBinding, Label, LabelSize, StyledExt};
|
|
|
|
#[derive(IntoComponent)]
|
|
pub struct Tooltip {
|
|
title: SharedString,
|
|
meta: Option<SharedString>,
|
|
key_binding: Option<KeyBinding>,
|
|
}
|
|
|
|
impl Tooltip {
|
|
pub fn simple(title: impl Into<SharedString>, cx: &mut App) -> AnyView {
|
|
cx.new(|_| Self {
|
|
title: title.into(),
|
|
meta: None,
|
|
key_binding: None,
|
|
})
|
|
.into()
|
|
}
|
|
|
|
pub fn text(title: impl Into<SharedString>) -> impl Fn(&mut Window, &mut App) -> AnyView {
|
|
let title = title.into();
|
|
move |_, cx| {
|
|
cx.new(|_| Self {
|
|
title: title.clone(),
|
|
meta: None,
|
|
key_binding: None,
|
|
})
|
|
.into()
|
|
}
|
|
}
|
|
|
|
pub fn for_action_title(
|
|
title: impl Into<SharedString>,
|
|
action: &dyn Action,
|
|
) -> impl Fn(&mut Window, &mut App) -> AnyView {
|
|
let title = title.into();
|
|
let action = action.boxed_clone();
|
|
move |window, cx| {
|
|
cx.new(|cx| Self {
|
|
title: title.clone(),
|
|
meta: None,
|
|
key_binding: KeyBinding::for_action(action.as_ref(), window, cx),
|
|
})
|
|
.into()
|
|
}
|
|
}
|
|
|
|
pub fn for_action_title_in(
|
|
title: impl Into<SharedString>,
|
|
action: &dyn Action,
|
|
focus_handle: &FocusHandle,
|
|
) -> impl Fn(&mut Window, &mut App) -> AnyView {
|
|
let title = title.into();
|
|
let action = action.boxed_clone();
|
|
let focus_handle = focus_handle.clone();
|
|
move |window, cx| {
|
|
cx.new(|cx| Self {
|
|
title: title.clone(),
|
|
meta: None,
|
|
key_binding: KeyBinding::for_action_in(action.as_ref(), &focus_handle, window, cx),
|
|
})
|
|
.into()
|
|
}
|
|
}
|
|
|
|
pub fn for_action(
|
|
title: impl Into<SharedString>,
|
|
action: &dyn Action,
|
|
window: &mut Window,
|
|
cx: &mut App,
|
|
) -> AnyView {
|
|
cx.new(|cx| Self {
|
|
title: title.into(),
|
|
meta: None,
|
|
key_binding: KeyBinding::for_action(action, window, cx),
|
|
})
|
|
.into()
|
|
}
|
|
|
|
pub fn for_action_in(
|
|
title: impl Into<SharedString>,
|
|
action: &dyn Action,
|
|
focus_handle: &FocusHandle,
|
|
window: &mut Window,
|
|
cx: &mut App,
|
|
) -> AnyView {
|
|
cx.new(|cx| Self {
|
|
title: title.into(),
|
|
meta: None,
|
|
key_binding: KeyBinding::for_action_in(action, focus_handle, window, cx),
|
|
})
|
|
.into()
|
|
}
|
|
|
|
pub fn with_meta(
|
|
title: impl Into<SharedString>,
|
|
action: Option<&dyn Action>,
|
|
meta: impl Into<SharedString>,
|
|
window: &mut Window,
|
|
cx: &mut App,
|
|
) -> AnyView {
|
|
cx.new(|cx| Self {
|
|
title: title.into(),
|
|
meta: Some(meta.into()),
|
|
key_binding: action.and_then(|action| KeyBinding::for_action(action, window, cx)),
|
|
})
|
|
.into()
|
|
}
|
|
|
|
pub fn with_meta_in(
|
|
title: impl Into<SharedString>,
|
|
action: Option<&dyn Action>,
|
|
meta: impl Into<SharedString>,
|
|
focus_handle: &FocusHandle,
|
|
window: &mut Window,
|
|
cx: &mut App,
|
|
) -> AnyView {
|
|
cx.new(|cx| Self {
|
|
title: title.into(),
|
|
meta: Some(meta.into()),
|
|
key_binding: action
|
|
.and_then(|action| KeyBinding::for_action_in(action, focus_handle, window, cx)),
|
|
})
|
|
.into()
|
|
}
|
|
|
|
pub fn new(title: impl Into<SharedString>) -> Self {
|
|
Self {
|
|
title: title.into(),
|
|
meta: None,
|
|
key_binding: None,
|
|
}
|
|
}
|
|
|
|
pub fn meta(mut self, meta: impl Into<SharedString>) -> Self {
|
|
self.meta = Some(meta.into());
|
|
self
|
|
}
|
|
|
|
pub fn key_binding(mut self, key_binding: impl Into<Option<KeyBinding>>) -> Self {
|
|
self.key_binding = key_binding.into();
|
|
self
|
|
}
|
|
}
|
|
|
|
impl Render for Tooltip {
|
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
tooltip_container(window, cx, |el, _, _| {
|
|
el.child(
|
|
h_flex()
|
|
.gap_4()
|
|
.child(div().max_w_72().child(self.title.clone()))
|
|
.when_some(self.key_binding.clone(), |this, key_binding| {
|
|
this.justify_between().child(key_binding)
|
|
}),
|
|
)
|
|
.when_some(self.meta.clone(), |this, meta| {
|
|
this.child(Label::new(meta).size(LabelSize::Small).color(Color::Muted))
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
pub fn tooltip_container<V>(
|
|
window: &mut Window,
|
|
cx: &mut Context<V>,
|
|
f: impl FnOnce(Div, &mut Window, &mut Context<V>) -> Div,
|
|
) -> impl IntoElement {
|
|
let ui_font = ThemeSettings::get_global(cx).ui_font.clone();
|
|
|
|
// padding to avoid tooltip appearing right below the mouse cursor
|
|
div().pl_2().pt_2p5().child(
|
|
v_flex()
|
|
.elevation_2(cx)
|
|
.font(ui_font)
|
|
.text_ui(cx)
|
|
.text_color(cx.theme().colors().text)
|
|
.py_1()
|
|
.px_2()
|
|
.map(|el| f(el, window, cx)),
|
|
)
|
|
}
|
|
|
|
pub struct LinkPreview {
|
|
link: SharedString,
|
|
}
|
|
|
|
impl LinkPreview {
|
|
pub fn new(url: &str, cx: &mut App) -> AnyView {
|
|
let mut wrapped_url = String::new();
|
|
for (i, ch) in url.chars().enumerate() {
|
|
if i == 500 {
|
|
wrapped_url.push('…');
|
|
break;
|
|
}
|
|
if i % 100 == 0 && i != 0 {
|
|
wrapped_url.push('\n');
|
|
}
|
|
wrapped_url.push(ch);
|
|
}
|
|
cx.new(|_| LinkPreview {
|
|
link: wrapped_url.into(),
|
|
})
|
|
.into()
|
|
}
|
|
}
|
|
|
|
impl Render for LinkPreview {
|
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
tooltip_container(window, cx, |el, _, _| {
|
|
el.child(
|
|
Label::new(self.link.clone())
|
|
.size(LabelSize::XSmall)
|
|
.color(Color::Muted),
|
|
)
|
|
})
|
|
}
|
|
}
|
|
|
|
// View this component preview using `workspace: open component-preview`
|
|
impl ComponentPreview for Tooltip {
|
|
fn preview(_window: &mut Window, _cx: &App) -> AnyElement {
|
|
example_group(vec![single_example(
|
|
"Text only",
|
|
Button::new("delete-example", "Delete")
|
|
.tooltip(Tooltip::text("This is a tooltip!"))
|
|
.into_any_element(),
|
|
)])
|
|
.into_any_element()
|
|
}
|
|
}
|