diff --git a/packages/ui/package.json b/packages/ui/package.json index a02e3c71e6..cac3a9e2fe 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -54,6 +54,7 @@ "@radix-ui/react-radio-group": "^1.3.8", "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-tooltip": "^1.2.8", "@radix-ui/react-use-controllable-state": "^1.2.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts index 01bda7bc6f..8e43bebba6 100644 --- a/packages/ui/src/components/index.ts +++ b/packages/ui/src/components/index.ts @@ -57,6 +57,7 @@ export * from './primitives/checkbox' export * from './primitives/combobox' export * from './primitives/command' export * from './primitives/dialog' +export * from './primitives/kbd' export * from './primitives/popover' export * from './primitives/radioGroup' export * from './primitives/select' diff --git a/packages/ui/src/components/primitives/kbd.tsx b/packages/ui/src/components/primitives/kbd.tsx new file mode 100644 index 0000000000..d1a2268e75 --- /dev/null +++ b/packages/ui/src/components/primitives/kbd.tsx @@ -0,0 +1,22 @@ +import { cn } from '@cherrystudio/ui/utils/index' + +function Kbd({ className, ...props }: React.ComponentProps<'kbd'>) { + return ( + + ) +} + +function KbdGroup({ className, ...props }: React.ComponentProps<'div'>) { + return +} + +export { Kbd, KbdGroup } diff --git a/packages/ui/stories/components/primitives/Kbd.stories.tsx b/packages/ui/stories/components/primitives/Kbd.stories.tsx new file mode 100644 index 0000000000..d37dcd89e2 --- /dev/null +++ b/packages/ui/stories/components/primitives/Kbd.stories.tsx @@ -0,0 +1,578 @@ +import type { Meta, StoryObj } from '@storybook/react' +import { Command, Copy, Save, Search } from 'lucide-react' + +import { Kbd, KbdGroup } from '../../../src/components/primitives/kbd' +import { Tooltip, TooltipContent, TooltipTrigger } from '../../../src/components/primitives/tooltip' + +const meta: Meta = { + title: 'Components/Primitives/Kbd', + component: Kbd, + parameters: { + layout: 'centered', + docs: { + description: { + component: '用于显示键盘快捷键的组件,支持单个按键和组合快捷键' + } + } + }, + tags: ['autodocs'], + argTypes: { + className: { + control: { type: 'text' }, + description: '自定义 CSS 类名' + }, + children: { + control: { type: 'text' }, + description: '键盘按键内容' + } + } +} + +export default meta +type Story = StoryObj + +// 基础示例 +export const Default: Story = { + args: { + children: 'Ctrl' + } +} + +// 单个按键 +export const SingleKeys: Story = { + render: () => ( +
+ Ctrl + Shift + Alt + Enter + Esc + Tab + Space + Delete +
+ ) +} + +// 字母和数字按键 +export const AlphanumericKeys: Story = { + render: () => ( +
+ A + B + C + 1 + 2 + 3 + F1 + F2 + F12 +
+ ) +} + +// 方向键 +export const ArrowKeys: Story = { + render: () => ( +
+ + + + +
+ ) +} + +// 组合快捷键 +export const KeyCombinations: Story = { + render: () => ( +
+
+ 保存: + + Ctrl + S + +
+
+ 复制: + + Ctrl + C + +
+
+ 粘贴: + + Ctrl + V + +
+
+ 查找: + + Ctrl + F + +
+
+ 全选: + + Ctrl + A + +
+
+ ) +} + +// Mac 快捷键 +export const MacKeys: Story = { + render: () => ( +
+
+ 保存: + + + S + +
+
+ 复制: + + + C + +
+
+ 粘贴: + + + V + +
+
+ 截图: + + + + 4 + +
+
+ ) +} + +// 三键组合 +export const ThreeKeyCombinations: Story = { + render: () => ( +
+
+ 撤销: + + Ctrl + Shift + Z + +
+
+ 重做: + + Ctrl + Alt + Z + +
+
+ 格式化: + + Ctrl + Shift + F + +
+
+ ) +} + +// 带图标的按键 +export const WithIcons: Story = { + render: () => ( +
+ + + + + + + + + + + + +
+ ) +} + +// 在 Tooltip 中使用 +export const InTooltip: Story = { + render: () => ( +
+ + + + + + Ctrl+S + + + + + + + + + Ctrl + C + + + + + + + + + + Ctrl + V + + + +
+ ) +} + +// 快捷键列表 +export const ShortcutList: Story = { + render: () => ( +
+

键盘快捷键

+
+
+ 保存文件 + + Ctrl + S + +
+
+ 打开文件 + + Ctrl + O + +
+
+ 查找 + + Ctrl + F + +
+
+ 替换 + + Ctrl + H + +
+
+ 撤销 + + Ctrl + Z + +
+
+ 重做 + + Ctrl + Y + +
+
+
+ ) +} + +// 编辑器快捷键 +export const EditorShortcuts: Story = { + render: () => ( +
+

编辑器快捷键

+ +
+
+

文件操作

+
+
+ 新建文件 + + Ctrl + N + +
+
+ 打开文件 + + Ctrl + O + +
+
+ 保存 + + Ctrl + S + +
+
+
+ +
+

编辑

+
+
+ 复制 + + Ctrl + C + +
+
+ 剪切 + + Ctrl + X + +
+
+ 粘贴 + + Ctrl + V + +
+
+
+ +
+

导航

+
+
+ 转到行 + + Ctrl + G + +
+
+ 查找 + + Ctrl + F + +
+
+ 全局搜索 + + Ctrl + Shift + F + +
+
+
+
+
+ ) +} + +// 游戏控制 +export const GameControls: Story = { + render: () => ( +
+

游戏控制

+ +
+
+

移动

+
+
+ 向前 + W +
+
+ 向后 + S +
+
+ 向左 + A +
+
+ 向右 + D +
+
+
+ +
+

动作

+
+
+ 跳跃 + Space +
+
+ 冲刺 + Shift +
+
+ 使用物品 + E +
+
+
+
+
+ ) +} + +// 特殊字符 +export const SpecialCharacters: Story = { + render: () => ( +
+ + + + + + + + + + +
+ ) +} + +// 不同尺寸 (通过自定义类名) +export const CustomSizes: Story = { + render: () => ( +
+ S + M + L + XL +
+ ) +} + +// 实际应用示例 +export const RealWorldExample: Story = { + render: () => ( +
+
+
+

命令面板

+ + Ctrl + K + +
+
+
+
+ + 保存当前文件 +
+ + Ctrl + S + +
+
+
+ + 复制选中内容 +
+ + Ctrl + C + +
+
+
+ + 在文件中查找 +
+ + Ctrl + F + +
+
+
+ + 显示所有命令 +
+ + Ctrl + Shift + P + +
+
+
+ +
+

提示信息

+
+

+ 按 Ctrl 并点击链接可在新标签页中打开 +

+

+ 使用{' '} + + Ctrl + + {' '} + 或{' '} + + Ctrl + + {' '} + 在选项之间导航 +

+

+ 按 Enter 确认,Esc 取消 +

+
+
+
+ ) +} diff --git a/yarn.lock b/yarn.lock index a35fdecfc9..145e911918 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2257,6 +2257,7 @@ __metadata: "@radix-ui/react-radio-group": "npm:^1.3.8" "@radix-ui/react-select": "npm:^2.2.6" "@radix-ui/react-slot": "npm:^1.2.3" + "@radix-ui/react-tooltip": "npm:^1.2.8" "@radix-ui/react-use-controllable-state": "npm:^1.2.2" "@storybook/addon-docs": "npm:^10.0.5" "@storybook/addon-themes": "npm:^10.0.5" @@ -7631,6 +7632,36 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-tooltip@npm:^1.2.8": + version: 1.2.8 + resolution: "@radix-ui/react-tooltip@npm:1.2.8" + dependencies: + "@radix-ui/primitive": "npm:1.1.3" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-dismissable-layer": "npm:1.1.11" + "@radix-ui/react-id": "npm:1.1.1" + "@radix-ui/react-popper": "npm:1.2.8" + "@radix-ui/react-portal": "npm:1.1.9" + "@radix-ui/react-presence": "npm:1.1.5" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-slot": "npm:1.2.3" + "@radix-ui/react-use-controllable-state": "npm:1.2.2" + "@radix-ui/react-visually-hidden": "npm:1.2.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/de0cbae9c571a00671f160928d819e59502f59be8749f536ab4b180181d9d70aee3925a5b2555f8f32d0bea622bc35f65b70ca7ff0449e4844f891302310cc48 + languageName: node + linkType: hard + "@radix-ui/react-use-callback-ref@npm:1.1.1": version: 1.1.1 resolution: "@radix-ui/react-use-callback-ref@npm:1.1.1"