Skip to content

Commit 1f28ed3

Browse files
committed
feat(registry): add kbd component with keycap profiles and color schemes
Keyboard shortcut keys rendered as styled keycaps. Three visual profiles: flat, raised, sculpted. 12 built-in color schemes inspired by popular keycap sets (dolch, olivia, botanical, laser, mizu, dracula, etc.). Custom { bg, text, border } color prop for full control. Includes KbdCombo helper for multi-key shortcuts. Interactive playground on docs page.
1 parent f3e3b27 commit 1f28ed3

8 files changed

Lines changed: 656 additions & 0 deletions

File tree

app/docs/components/kbd/page.tsx

Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
import type { Metadata } from "next"
2+
import { Kbd, KbdCombo, builtInSchemes, type BuiltInColorScheme } from "@/registry/kbd/kbd"
3+
import { ApiRefTable } from "@/registry/api-ref-table/api-ref-table"
4+
import { ComponentDocsPage } from "@/components/docs/component-docs-page"
5+
import { VariantGrid } from "@/components/docs/variant-grid"
6+
import { CodeLine } from "@/registry/code-line/code-line"
7+
import { KbdPlayground } from "./playground"
8+
9+
export const metadata: Metadata = {
10+
title: "Kbd",
11+
description:
12+
"Keyboard shortcut key rendered as a styled keycap. Three visual profiles: flat, raised, and sculpted.",
13+
}
14+
15+
const sourceFiles = ["registry/kbd/kbd.tsx"]
16+
17+
export default function KbdPage() {
18+
return (
19+
<ComponentDocsPage
20+
title="Kbd"
21+
description="Keyboard shortcut key rendered as a styled keycap. Three visual profiles: flat, raised, and sculpted."
22+
registryName="kbd"
23+
sourceFiles={sourceFiles}
24+
preview={
25+
<div className="flex items-center gap-4">
26+
<KbdCombo keys={["⌘", "K"]} variant="raised" />
27+
<KbdCombo keys={["Ctrl", "Shift", "P"]} variant="sculpted" />
28+
<KbdCombo keys={["⌥", "↑"]} variant="flat" />
29+
</div>
30+
}
31+
usage={
32+
<>
33+
<CodeLine
34+
code={`import { Kbd, KbdCombo } from "@/components/kbd"`}
35+
/>
36+
<CodeLine code={`<Kbd>⌘</Kbd>`} />
37+
<CodeLine
38+
code={`<KbdCombo keys={["⌘", "Shift", "K"]} />`}
39+
/>
40+
</>
41+
}
42+
>
43+
{/* Playground */}
44+
<section className="flex flex-col gap-4">
45+
<h2 className="text-xl font-semibold tracking-tight">Playground</h2>
46+
<KbdPlayground />
47+
</section>
48+
49+
{/* Variants */}
50+
<section className="flex flex-col gap-4">
51+
<h2 className="text-xl font-semibold tracking-tight">Variants</h2>
52+
<VariantGrid
53+
items={[
54+
{
55+
label: "Flat",
56+
preview: (
57+
<div className="flex items-center gap-3">
58+
<Kbd variant="flat">Esc</Kbd>
59+
<KbdCombo keys={["⌘", "C"]} variant="flat" />
60+
<KbdCombo keys={["Ctrl", "Shift", "P"]} variant="flat" />
61+
</div>
62+
),
63+
code: `<Kbd variant="flat">Esc</Kbd>`,
64+
},
65+
{
66+
label: "Raised",
67+
preview: (
68+
<div className="flex items-center gap-3">
69+
<Kbd variant="raised">Esc</Kbd>
70+
<KbdCombo keys={["⌘", "C"]} variant="raised" />
71+
<KbdCombo keys={["Ctrl", "Shift", "P"]} variant="raised" />
72+
</div>
73+
),
74+
code: `<Kbd variant="raised">Esc</Kbd>`,
75+
},
76+
{
77+
label: "Sculpted",
78+
preview: (
79+
<div className="flex items-center gap-3">
80+
<Kbd variant="sculpted">Esc</Kbd>
81+
<KbdCombo keys={["⌘", "C"]} variant="sculpted" />
82+
<KbdCombo keys={["Ctrl", "Shift", "P"]} variant="sculpted" />
83+
</div>
84+
),
85+
code: `<Kbd variant="sculpted">Esc</Kbd>`,
86+
},
87+
]}
88+
files={sourceFiles}
89+
columns={1}
90+
registryName="kbd"
91+
/>
92+
</section>
93+
94+
{/* Sizes */}
95+
<section className="flex flex-col gap-4">
96+
<h2 className="text-xl font-semibold tracking-tight">Sizes</h2>
97+
<VariantGrid
98+
items={[
99+
{
100+
label: "Small",
101+
preview: (
102+
<div className="flex items-center gap-2">
103+
<KbdCombo keys={["⌘", "K"]} size="sm" />
104+
<span className="text-xs text-muted-foreground">
105+
Open command palette
106+
</span>
107+
</div>
108+
),
109+
code: `<Kbd size="sm">⌘</Kbd>`,
110+
},
111+
{
112+
label: "Medium",
113+
preview: (
114+
<div className="flex items-center gap-2">
115+
<KbdCombo keys={["⌘", "K"]} size="md" />
116+
<span className="text-sm text-muted-foreground">
117+
Open command palette
118+
</span>
119+
</div>
120+
),
121+
code: `<Kbd size="md">⌘</Kbd>`,
122+
},
123+
{
124+
label: "Large",
125+
preview: (
126+
<div className="flex items-center gap-2">
127+
<KbdCombo keys={["⌘", "K"]} size="lg" />
128+
<span className="text-sm text-muted-foreground">
129+
Open command palette
130+
</span>
131+
</div>
132+
),
133+
code: `<Kbd size="lg">⌘</Kbd>`,
134+
},
135+
]}
136+
files={sourceFiles}
137+
columns={3}
138+
registryName="kbd"
139+
/>
140+
</section>
141+
142+
{/* Examples */}
143+
<section className="flex flex-col gap-4">
144+
<h2 className="text-xl font-semibold tracking-tight">Examples</h2>
145+
<VariantGrid
146+
items={[
147+
{
148+
label: "With separator",
149+
preview: (
150+
<KbdCombo
151+
keys={["Ctrl", "Alt", "Del"]}
152+
separator="+"
153+
variant="raised"
154+
/>
155+
),
156+
code: `<KbdCombo keys={["Ctrl", "Alt", "Del"]} separator="+" />`,
157+
},
158+
{
159+
label: "Arrow keys",
160+
preview: (
161+
<div className="flex items-center gap-1">
162+
<Kbd variant="sculpted"></Kbd>
163+
<Kbd variant="sculpted"></Kbd>
164+
<Kbd variant="sculpted"></Kbd>
165+
<Kbd variant="sculpted"></Kbd>
166+
</div>
167+
),
168+
code: `<Kbd variant="sculpted">←</Kbd>`,
169+
},
170+
{
171+
label: "Inline with text",
172+
preview: (
173+
<p className="text-sm text-muted-foreground">
174+
Press{" "}
175+
<KbdCombo keys={["⌘", "K"]} size="sm" variant="raised" />{" "}
176+
to open the command palette
177+
</p>
178+
),
179+
code: `<p>Press <KbdCombo keys={["⌘", "K"]} size="sm" /> to open the command palette</p>`,
180+
},
181+
]}
182+
files={sourceFiles}
183+
columns={3}
184+
registryName="kbd"
185+
/>
186+
</section>
187+
188+
{/* Color Schemes */}
189+
<section className="flex flex-col gap-4">
190+
<h2 className="text-xl font-semibold tracking-tight">Color Schemes</h2>
191+
<p className="text-sm text-muted-foreground">
192+
Built-in color palettes inspired by popular keycap sets. Pass a name
193+
string or a custom{" "}
194+
<code className="rounded bg-muted px-1 py-0.5 text-xs">
195+
{"{ bg, text, border }"}
196+
</code>{" "}
197+
object.
198+
</p>
199+
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-4">
200+
{(Object.keys(builtInSchemes) as BuiltInColorScheme[]).map((name) => (
201+
<div
202+
key={name}
203+
className="flex flex-col items-center gap-2 rounded-xl border border-border/60 bg-card p-4"
204+
>
205+
<div className="flex items-center gap-1">
206+
<Kbd variant="sculpted" colorScheme={name}></Kbd>
207+
<Kbd variant="sculpted" colorScheme={name}>K</Kbd>
208+
</div>
209+
<span className="text-[11px] font-medium text-muted-foreground">
210+
{name}
211+
</span>
212+
</div>
213+
))}
214+
</div>
215+
<VariantGrid
216+
items={[
217+
{
218+
label: "Dolch",
219+
preview: (
220+
<KbdCombo
221+
keys={["Ctrl", "Shift", "P"]}
222+
variant="sculpted"
223+
colorScheme="dolch"
224+
/>
225+
),
226+
code: `<KbdCombo keys={["Ctrl", "Shift", "P"]} variant="sculpted" colorScheme="dolch" />`,
227+
},
228+
{
229+
label: "Olivia",
230+
preview: (
231+
<KbdCombo
232+
keys={["⌘", "K"]}
233+
variant="sculpted"
234+
colorScheme="olivia"
235+
/>
236+
),
237+
code: `<KbdCombo keys={["⌘", "K"]} variant="sculpted" colorScheme="olivia" />`,
238+
},
239+
{
240+
label: "Botanical",
241+
preview: (
242+
<KbdCombo
243+
keys={["⌥", "↑"]}
244+
variant="sculpted"
245+
colorScheme="botanical"
246+
/>
247+
),
248+
code: `<KbdCombo keys={["⌥", "↑"]} variant="sculpted" colorScheme="botanical" />`,
249+
},
250+
{
251+
label: "Laser",
252+
preview: (
253+
<KbdCombo
254+
keys={["Fn", "F12"]}
255+
variant="sculpted"
256+
colorScheme="laser"
257+
/>
258+
),
259+
code: `<KbdCombo keys={["Fn", "F12"]} variant="sculpted" colorScheme="laser" />`,
260+
},
261+
{
262+
label: "Custom colors",
263+
preview: (
264+
<KbdCombo
265+
keys={["⌘", "S"]}
266+
variant="sculpted"
267+
colorScheme={{ bg: "#1E3A5F", text: "#7FDBCA", border: "#152E4A" }}
268+
/>
269+
),
270+
code: `<KbdCombo keys={["⌘", "S"]} colorScheme={{ bg: "#1E3A5F", text: "#7FDBCA", border: "#152E4A" }} />`,
271+
},
272+
]}
273+
files={sourceFiles}
274+
columns={3}
275+
registryName="kbd"
276+
/>
277+
</section>
278+
279+
{/* API Reference */}
280+
<section className="flex flex-col gap-4">
281+
<h2 className="text-xl font-semibold tracking-tight">API Reference</h2>
282+
<ApiRefTable
283+
title="Kbd"
284+
props={[
285+
{
286+
name: "children",
287+
type: "ReactNode",
288+
required: true,
289+
description: "Key label (e.g. \"⌘\", \"K\", \"Shift\").",
290+
},
291+
{
292+
name: "variant",
293+
type: '"flat" | "raised" | "sculpted"',
294+
description:
295+
"Visual profile. Flat is minimal, raised has subtle depth, sculpted is a pronounced 3D keycap.",
296+
},
297+
{
298+
name: "size",
299+
type: '"sm" | "md" | "lg"',
300+
description: "Keycap size.",
301+
},
302+
{
303+
name: "colorScheme",
304+
type: "string | { bg, text, border }",
305+
description:
306+
"Named palette (dolch, olivia, botanical, etc.) or custom color object.",
307+
},
308+
{
309+
name: "className",
310+
type: "string",
311+
description: "Additional CSS classes.",
312+
},
313+
]}
314+
/>
315+
<ApiRefTable
316+
title="KbdCombo"
317+
props={[
318+
{
319+
name: "keys",
320+
type: "string[]",
321+
required: true,
322+
description:
323+
"Array of key labels rendered as a combo (e.g. [\"⌘\", \"Shift\", \"K\"]).",
324+
},
325+
{
326+
name: "separator",
327+
type: "ReactNode",
328+
description:
329+
"Separator between keys (e.g. \"+\"). No separator when omitted.",
330+
},
331+
{
332+
name: "variant",
333+
type: '"flat" | "raised" | "sculpted"',
334+
description: "Visual profile applied to all keys in the combo.",
335+
},
336+
{
337+
name: "size",
338+
type: '"sm" | "md" | "lg"',
339+
description: "Size applied to all keys in the combo.",
340+
},
341+
{
342+
name: "colorScheme",
343+
type: "string | { bg, text, border }",
344+
description:
345+
"Named palette or custom color object applied to all keys in the combo.",
346+
},
347+
{
348+
name: "className",
349+
type: "string",
350+
description: "Additional CSS classes on the combo wrapper.",
351+
},
352+
]}
353+
/>
354+
</section>
355+
</ComponentDocsPage>
356+
)
357+
}

0 commit comments

Comments
 (0)