1use gpui::{AnyElement, FontWeight};
2use smallvec::SmallVec;
3
4use crate::prelude::*;
5
6#[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#[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}