Skip to main content

ui/components/
kbd.rs

1use gpui::{AnyElement, FontWeight};
2use smallvec::SmallVec;
3
4use crate::prelude::*;
5
6/// A styled keyboard key chip, mirroring shadcn's `<kbd>`.
7#[derive(IntoElement, RegisterComponent)]
8pub struct Kbd {
9    label: SharedString,
10}
11
12impl Kbd {
13    pub fn new(label: impl Into<SharedString>) -> Self {
14        Self {
15            label: label.into(),
16        }
17    }
18}
19
20impl RenderOnce for Kbd {
21    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
22        div()
23            .flex()
24            .flex_none()
25            .items_center()
26            .justify_center()
27            .h(px(20.))
28            .min_w(px(20.))
29            .px_1p5()
30            .rounded_md()
31            .border_1()
32            .border_color(semantic::border(cx))
33            .bg(semantic::secondary_bg(cx))
34            .text_color(semantic::text_muted(cx))
35            .child(
36                Label::new(self.label)
37                    .size(LabelSize::XSmall)
38                    .weight(FontWeight::MEDIUM),
39            )
40    }
41}
42
43/// Groups multiple [`Kbd`] chips for shortcut combos (e.g. ⌘ + K).
44#[derive(IntoElement)]
45pub struct KbdGroup {
46    children: SmallVec<[AnyElement; 4]>,
47}
48
49impl KbdGroup {
50    pub fn new() -> Self {
51        Self {
52            children: SmallVec::new(),
53        }
54    }
55}
56
57impl Default for KbdGroup {
58    fn default() -> Self {
59        Self::new()
60    }
61}
62
63impl ParentElement for KbdGroup {
64    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
65        self.children.extend(elements);
66    }
67}
68
69impl RenderOnce for KbdGroup {
70    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
71        h_flex().gap_1().items_center().children(self.children)
72    }
73}
74
75impl Component for Kbd {
76    fn scope() -> ComponentScope {
77        ComponentScope::Typography
78    }
79
80    fn description() -> Option<&'static str> {
81        Some("A styled keyboard key chip for displaying shortcuts.")
82    }
83
84    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
85        Some(
86            v_flex()
87                .gap_4()
88                .child(Kbd::new("⌘"))
89                .child(Kbd::new("Shift"))
90                .child(KbdGroup::new().child(Kbd::new("⌘")).child(Kbd::new("K")))
91                .into_any_element(),
92        )
93    }
94}