mirror of
https://github.com/ByteAtATime/raycast-linux.git
synced 2025-08-31 03:07:23 +00:00
feat(actions): improve keyboard shortcut display
Previously, the logic for displaying keyboard shortcuts was all over the place. This commit creates a single KeyboardShortcut component that is responsible for displaying it. It slightly changes some styles in the Kbd component, and also adds the Tauri `os` plugin to determine whether to display Mac symbols or Windows names. It also maps cmd to Ctrl on Windows.
This commit is contained in:
parent
4a580ce5b9
commit
8852c73f5a
16 changed files with 151 additions and 88 deletions
|
@ -24,6 +24,7 @@
|
|||
"@tauri-apps/plugin-global-shortcut": "~2.2.1",
|
||||
"@tauri-apps/plugin-http": "~2.4.4",
|
||||
"@tauri-apps/plugin-opener": "~2",
|
||||
"@tauri-apps/plugin-os": "~2.3.0",
|
||||
"@tauri-apps/plugin-shell": "~2.2.1",
|
||||
"embla-carousel-svelte": "^8.6.0",
|
||||
"fuse.js": "^7.1.0",
|
||||
|
|
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
|
@ -35,6 +35,9 @@ importers:
|
|||
'@tauri-apps/plugin-opener':
|
||||
specifier: ~2
|
||||
version: 2.2.7
|
||||
'@tauri-apps/plugin-os':
|
||||
specifier: ~2.3.0
|
||||
version: 2.3.0
|
||||
'@tauri-apps/plugin-shell':
|
||||
specifier: ~2.2.1
|
||||
version: 2.2.1
|
||||
|
@ -1031,6 +1034,9 @@ packages:
|
|||
'@tauri-apps/plugin-opener@2.2.7':
|
||||
resolution: {integrity: sha512-uduEyvOdjpPOEeDRrhwlCspG/f9EQalHumWBtLBnp3fRp++fKGLqDOyUhSIn7PzX45b/rKep//ZQSAQoIxobLA==}
|
||||
|
||||
'@tauri-apps/plugin-os@2.3.0':
|
||||
resolution: {integrity: sha512-dm3bDsMuUngpIQdJ1jaMkMfyQpHyDcaTIKTFaAMHoKeUd+Is3UHO2uzhElr6ZZkfytIIyQtSVnCWdW2Kc58f3g==}
|
||||
|
||||
'@tauri-apps/plugin-shell@2.2.1':
|
||||
resolution: {integrity: sha512-G1GFYyWe/KlCsymuLiNImUgC8zGY0tI0Y3p8JgBCWduR5IEXlIJS+JuG1qtveitwYXlfJrsExt3enhv5l2/yhA==}
|
||||
|
||||
|
@ -3542,6 +3548,10 @@ snapshots:
|
|||
dependencies:
|
||||
'@tauri-apps/api': 2.5.0
|
||||
|
||||
'@tauri-apps/plugin-os@2.3.0':
|
||||
dependencies:
|
||||
'@tauri-apps/api': 2.6.0
|
||||
|
||||
'@tauri-apps/plugin-shell@2.2.1':
|
||||
dependencies:
|
||||
'@tauri-apps/api': 2.5.0
|
||||
|
|
52
src-tauri/Cargo.lock
generated
52
src-tauri/Cargo.lock
generated
|
@ -2031,6 +2031,16 @@ dependencies = [
|
|||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gethostname"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55"
|
||||
dependencies = [
|
||||
"rustix 1.0.7",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
|
@ -3856,6 +3866,18 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_info"
|
||||
version = "3.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0e1ac5fde8d43c34139135df8ea9ee9465394b2d8d20f032d38998f64afffc3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"plist",
|
||||
"serde",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_pipe"
|
||||
version = "1.2.2"
|
||||
|
@ -4613,6 +4635,7 @@ dependencies = [
|
|||
"tauri-plugin-global-shortcut",
|
||||
"tauri-plugin-http",
|
||||
"tauri-plugin-opener",
|
||||
"tauri-plugin-os",
|
||||
"tauri-plugin-shell",
|
||||
"tauri-plugin-single-instance",
|
||||
"tokio",
|
||||
|
@ -5515,6 +5538,15 @@ dependencies = [
|
|||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sys-locale"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.6.1"
|
||||
|
@ -5878,6 +5910,24 @@ dependencies = [
|
|||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-os"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05bccb4c6de4299beec5a9b070878a01bce9e2c945aa7a75bcea38bcba4c675d"
|
||||
dependencies = [
|
||||
"gethostname 1.0.2",
|
||||
"log",
|
||||
"os_info",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serialize-to-javascript",
|
||||
"sys-locale",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-shell"
|
||||
version = "2.2.2"
|
||||
|
@ -7678,7 +7728,7 @@ version = "0.13.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12"
|
||||
dependencies = [
|
||||
"gethostname",
|
||||
"gethostname 0.4.3",
|
||||
"rustix 0.38.44",
|
||||
"x11rb-protocol",
|
||||
]
|
||||
|
|
|
@ -63,6 +63,7 @@ walkdir = "2.5.0"
|
|||
notify = "6.1.1"
|
||||
notify-debouncer-full = "0.3.1"
|
||||
percent-encoding = "2.3.1"
|
||||
tauri-plugin-os = "2"
|
||||
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||
tauri-plugin-global-shortcut = "2"
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
]
|
||||
},
|
||||
"dialog:default",
|
||||
"fs:default"
|
||||
"fs:default",
|
||||
"os:default"
|
||||
]
|
||||
}
|
|
@ -201,6 +201,7 @@ fn setup_input_listener(app: &tauri::AppHandle) {
|
|||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
let app = tauri::Builder::default()
|
||||
.plugin(tauri_plugin_os::init())
|
||||
.plugin(tauri_plugin_fs::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_http::init())
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
|
||||
import { Kbd } from './ui/kbd';
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
||||
import { shortcutToText } from '$lib/renderKey';
|
||||
import * as Select from './ui/select';
|
||||
import ActionBar from './nodes/shared/ActionBar.svelte';
|
||||
import ActionMenu from './nodes/shared/ActionMenu.svelte';
|
||||
import BaseList from './BaseList.svelte';
|
||||
import KeyboardShortcut from './KeyboardShortcut.svelte';
|
||||
|
||||
type Props = {
|
||||
onBack: () => void;
|
||||
|
@ -360,14 +360,14 @@
|
|||
<Pin class="mr-2 size-4" />
|
||||
<span>{selectedItem.isPinned ? 'Unpin' : 'Pin'}</span>
|
||||
<DropdownMenu.Shortcut>
|
||||
{shortcutToText({ key: 'P', modifiers: ['cmd', 'shift'] })}
|
||||
<KeyboardShortcut shortcut={{ key: 'P', modifiers: ['cmd', 'shift'] }} />
|
||||
</DropdownMenu.Shortcut>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={() => handleDelete(selectedItem)}>
|
||||
<Trash class="mr-2 size-4" />
|
||||
<span>Delete</span>
|
||||
<DropdownMenu.Shortcut>
|
||||
{shortcutToText({ key: 'x', modifiers: ['ctrl'] })}
|
||||
<KeyboardShortcut shortcut={{ key: 'x', modifiers: ['ctrl'] }} />
|
||||
</DropdownMenu.Shortcut>
|
||||
</DropdownMenu.Item>
|
||||
</ActionMenu>
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
|
||||
import { Kbd } from './ui/kbd';
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
||||
import { shortcutToText } from '$lib/renderKey';
|
||||
import ActionBar from './nodes/shared/ActionBar.svelte';
|
||||
import ActionMenu from './nodes/shared/ActionMenu.svelte';
|
||||
import BaseList from './BaseList.svelte';
|
||||
import { open } from '@tauri-apps/plugin-shell';
|
||||
import KeyboardShortcut from './KeyboardShortcut.svelte';
|
||||
|
||||
type Props = {
|
||||
onBack: () => void;
|
||||
|
@ -189,7 +189,7 @@
|
|||
<ActionBar>
|
||||
{#snippet primaryAction({ props })}
|
||||
<Button {...props} onclick={() => handleOpen(selectedItem)}>
|
||||
Open <Kbd>⏎</Kbd>
|
||||
Open <KeyboardShortcut shortcut={{ key: 'enter', modifiers: [] }} />
|
||||
</Button>
|
||||
{/snippet}
|
||||
{#snippet actions()}
|
||||
|
@ -198,14 +198,14 @@
|
|||
<Eye class="mr-2 size-4" />
|
||||
<span>Show in File Manager</span>
|
||||
<DropdownMenu.Shortcut>
|
||||
{shortcutToText({ key: 'Enter', modifiers: ['cmd'] })}
|
||||
<KeyboardShortcut shortcut={{ key: 'Enter', modifiers: ['cmd'] }} />
|
||||
</DropdownMenu.Shortcut>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={() => handleCopyPath(selectedItem)}>
|
||||
<Copy class="mr-2 size-4" />
|
||||
<span>Copy Path</span>
|
||||
<DropdownMenu.Shortcut>
|
||||
{shortcutToText({ key: 'c', modifiers: ['ctrl'] })}
|
||||
<KeyboardShortcut shortcut={{ key: 'c', modifiers: ['ctrl'] }} />
|
||||
</DropdownMenu.Shortcut>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
|
@ -213,7 +213,7 @@
|
|||
<Trash class="mr-2 size-4" />
|
||||
<span>Move to Trash</span>
|
||||
<DropdownMenu.Shortcut>
|
||||
{shortcutToText({ key: 'x', modifiers: ['ctrl'] })}
|
||||
<KeyboardShortcut shortcut={{ key: 'x', modifiers: ['ctrl'] }} />
|
||||
</DropdownMenu.Shortcut>
|
||||
</DropdownMenu.Item>
|
||||
</ActionMenu>
|
||||
|
|
48
src/lib/components/KeyboardShortcut.svelte
Normal file
48
src/lib/components/KeyboardShortcut.svelte
Normal file
|
@ -0,0 +1,48 @@
|
|||
<script lang="ts">
|
||||
import type { KeyboardShortcut } from '$lib/props';
|
||||
import { platform } from '@tauri-apps/plugin-os';
|
||||
import { Kbd } from './ui/kbd';
|
||||
|
||||
let { shortcut }: { shortcut: KeyboardShortcut } = $props();
|
||||
|
||||
const macModifierMap = {
|
||||
cmd: '⌘',
|
||||
ctrl: '⌃',
|
||||
opt: '⌥',
|
||||
shift: '⇧'
|
||||
};
|
||||
|
||||
const standardModifierMap = {
|
||||
cmd: 'Ctrl',
|
||||
ctrl: 'Ctrl',
|
||||
opt: 'Alt',
|
||||
shift: 'Shift'
|
||||
};
|
||||
|
||||
const modifierMap = platform() === 'macos' ? macModifierMap : standardModifierMap;
|
||||
|
||||
const keyMap: Partial<Record<KeyboardShortcut['key'], string>> = {
|
||||
return: '⏎',
|
||||
enter: '⏎',
|
||||
delete: '⌫',
|
||||
backspace: '⌫',
|
||||
deleteForward: '⌦',
|
||||
arrowUp: '↑',
|
||||
arrowDown: '↓',
|
||||
arrowLeft: '←',
|
||||
arrowRight: '→',
|
||||
tab: '⇥',
|
||||
escape: '⎋',
|
||||
space: '␣'
|
||||
};
|
||||
|
||||
const symbols = shortcut.modifiers
|
||||
.map((modifier) => modifierMap[modifier])
|
||||
.concat(keyMap[shortcut.key] ?? shortcut.key.toUpperCase());
|
||||
</script>
|
||||
|
||||
<div class="flex gap-0.5">
|
||||
{#each symbols as symbol}
|
||||
<Kbd>{symbol}</Kbd>
|
||||
{/each}
|
||||
</div>
|
|
@ -7,10 +7,10 @@
|
|||
import ListItemBase from './nodes/shared/ListItemBase.svelte';
|
||||
import { Kbd } from './ui/kbd';
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
||||
import { shortcutToText } from '$lib/renderKey';
|
||||
import ActionBar from './nodes/shared/ActionBar.svelte';
|
||||
import ActionMenu from './nodes/shared/ActionMenu.svelte';
|
||||
import BaseList from './BaseList.svelte';
|
||||
import KeyboardShortcut from './KeyboardShortcut.svelte';
|
||||
|
||||
type Props = {
|
||||
onBack: () => void;
|
||||
|
@ -245,7 +245,7 @@
|
|||
<Trash class="mr-2 size-4" />
|
||||
<span>Delete</span>
|
||||
<DropdownMenu.Shortcut>
|
||||
{shortcutToText({ key: 'x', modifiers: ['ctrl'] })}
|
||||
<KeyboardShortcut shortcut={{ key: 'x', modifiers: ['ctrl'] }} />
|
||||
</DropdownMenu.Shortcut>
|
||||
</DropdownMenu.Item>
|
||||
</ActionMenu>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import { Kbd } from '$lib/components/ui/kbd';
|
||||
import ActionMenu from '$lib/components/nodes/shared/ActionMenu.svelte';
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
||||
import { shortcutToText } from '$lib/renderKey';
|
||||
import KeyboardShortcut from '../KeyboardShortcut.svelte';
|
||||
|
||||
type Props = {
|
||||
selectedItem: UnifiedItem | undefined;
|
||||
|
@ -48,13 +48,13 @@
|
|||
<DropdownMenu.Item onclick={barActions.handleEnter}>
|
||||
Copy Answer
|
||||
<DropdownMenu.Shortcut>
|
||||
{shortcutToText({ key: 'c', modifiers: ['ctrl', 'shift'] })}
|
||||
<KeyboardShortcut shortcut={{ key: 'c', modifiers: ['ctrl', 'shift'] }} />
|
||||
</DropdownMenu.Shortcut>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={() => setSearchText(selectedItem.data.result)}>
|
||||
Put Answer in Search Bar
|
||||
<DropdownMenu.Shortcut>
|
||||
{shortcutToText({ key: 'enter', modifiers: ['ctrl', 'shift'] })}
|
||||
<KeyboardShortcut shortcut={{ key: 'enter', modifiers: ['ctrl', 'shift'] }} />
|
||||
</DropdownMenu.Shortcut>
|
||||
</DropdownMenu.Item>
|
||||
{:else if selectedItem.type === 'plugin'}
|
||||
|
@ -65,14 +65,14 @@
|
|||
<DropdownMenu.Item onclick={barActions.handleCopyDeeplink}>
|
||||
Copy Deeplink
|
||||
<DropdownMenu.Shortcut>
|
||||
{shortcutToText({ key: 'c', modifiers: ['ctrl', 'shift'] })}
|
||||
<KeyboardShortcut shortcut={{ key: 'c', modifiers: ['ctrl', 'shift'] }} />
|
||||
</DropdownMenu.Shortcut>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item onclick={barActions.handleConfigureCommand}>
|
||||
Configure Command
|
||||
<DropdownMenu.Shortcut>
|
||||
{shortcutToText({ key: ',', modifiers: ['ctrl', 'shift'] })}
|
||||
<KeyboardShortcut shortcut={{ key: ',', modifiers: ['ctrl', 'shift'] }} />
|
||||
</DropdownMenu.Shortcut>
|
||||
</DropdownMenu.Item>
|
||||
{:else if selectedItem.type === 'app'}
|
||||
|
@ -83,20 +83,20 @@
|
|||
<DropdownMenu.Item onclick={barActions.handleCopyAppName}>
|
||||
Copy Name
|
||||
<DropdownMenu.Shortcut>
|
||||
{shortcutToText({ key: '.', modifiers: ['ctrl'] })}
|
||||
<KeyboardShortcut shortcut={{ key: '.', modifiers: ['ctrl'] }} />
|
||||
</DropdownMenu.Shortcut>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item onclick={barActions.handleCopyAppPath}>
|
||||
Copy Path
|
||||
<DropdownMenu.Shortcut>
|
||||
{shortcutToText({ key: '.', modifiers: ['ctrl', 'shift'] })}
|
||||
<KeyboardShortcut shortcut={{ key: '.', modifiers: ['ctrl', 'shift'] }} />
|
||||
</DropdownMenu.Shortcut>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Separator />
|
||||
<DropdownMenu.Item onclick={barActions.handleHideApp}>
|
||||
Hide Application
|
||||
<DropdownMenu.Shortcut>
|
||||
{shortcutToText({ key: 'h', modifiers: ['ctrl'] })}
|
||||
<KeyboardShortcut shortcut={{ key: 'h', modifiers: ['ctrl'] }} />
|
||||
</DropdownMenu.Shortcut>
|
||||
</DropdownMenu.Item>
|
||||
{/if}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<script lang="ts">
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
||||
import { Kbd } from '../ui/kbd';
|
||||
import { keyEventMatches, type KeyboardShortcut } from '$lib/props';
|
||||
import { shortcutToText } from '$lib/renderKey';
|
||||
import { keyEventMatches, type KeyboardShortcut as KeyboardShortcutType } from '$lib/props';
|
||||
import type { Toast } from '$lib/ui.svelte';
|
||||
import KeyboardShortcut from '../KeyboardShortcut.svelte';
|
||||
|
||||
type Props = {
|
||||
toast: Toast;
|
||||
|
@ -17,7 +17,7 @@
|
|||
const availableActions: {
|
||||
type: 'primary' | 'secondary';
|
||||
title: string;
|
||||
shortcut?: KeyboardShortcut;
|
||||
shortcut?: KeyboardShortcutType;
|
||||
}[] = [];
|
||||
|
||||
if (toast?.primaryAction) {
|
||||
|
@ -88,7 +88,9 @@
|
|||
<DropdownMenu.Item onselect={() => handleActionSelect(action.type)}>
|
||||
{action.title}
|
||||
{#if action.shortcut}
|
||||
<DropdownMenu.Shortcut>{shortcutToText(action.shortcut)}</DropdownMenu.Shortcut>
|
||||
<DropdownMenu.Shortcut>
|
||||
<KeyboardShortcut shortcut={action.shortcut} />
|
||||
</DropdownMenu.Shortcut>
|
||||
{/if}
|
||||
</DropdownMenu.Item>
|
||||
{/each}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<script lang="ts">
|
||||
import type { KeyboardShortcut } from '$lib/props/actions';
|
||||
import type { KeyboardShortcut as KeyboardShortcutType } from '$lib/props/actions';
|
||||
import { DropdownMenuItem, DropdownMenuShortcut } from '$lib/components/ui/dropdown-menu';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { shortcutToText } from '$lib/renderKey';
|
||||
import type { ImageLike } from '$lib/props';
|
||||
import Icon from '$lib/components/Icon.svelte';
|
||||
import { Kbd } from '$lib/components/ui/kbd';
|
||||
import KeyboardShortcut from '$lib/components/KeyboardShortcut.svelte';
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
shortcut?: KeyboardShortcut | null;
|
||||
shortcut?: KeyboardShortcutType | null;
|
||||
icon?: ImageLike;
|
||||
isPrimaryAction?: boolean;
|
||||
isSecondaryAction?: boolean;
|
||||
|
@ -41,14 +41,16 @@
|
|||
{title}
|
||||
{#if isPrimaryAction}
|
||||
<DropdownMenuShortcut>
|
||||
{shortcutToText({ key: 'enter', modifiers: [] })}
|
||||
<KeyboardShortcut shortcut={{ key: 'enter', modifiers: [] }} />
|
||||
</DropdownMenuShortcut>
|
||||
{:else if isSecondaryAction}
|
||||
<DropdownMenuShortcut>
|
||||
{shortcutToText({ key: 'enter', modifiers: ['ctrl'] })}
|
||||
<KeyboardShortcut shortcut={{ key: 'enter', modifiers: ['ctrl'] }} />
|
||||
</DropdownMenuShortcut>
|
||||
{:else if shortcut}
|
||||
<DropdownMenuShortcut>{shortcutToText(shortcut)}</DropdownMenuShortcut>
|
||||
<DropdownMenuShortcut>
|
||||
<KeyboardShortcut {shortcut} />
|
||||
</DropdownMenuShortcut>
|
||||
{/if}
|
||||
</DropdownMenuItem>
|
||||
{/if}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
import { Kbd } from '$lib/components/ui/kbd';
|
||||
import type { Snippet } from 'svelte';
|
||||
import { setContext } from 'svelte';
|
||||
import KeyboardShortcut from '$lib/components/KeyboardShortcut.svelte';
|
||||
|
||||
type Props = {
|
||||
children: Snippet;
|
||||
|
@ -33,7 +34,8 @@
|
|||
<DropdownMenu.Trigger>
|
||||
{#snippet child({ props })}
|
||||
<Button {...props} variant="ghost" size="sm">
|
||||
Actions <Kbd>⌘ K</Kbd>
|
||||
Actions
|
||||
<KeyboardShortcut shortcut={{ key: 'k', modifiers: ['cmd'] }} />
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DropdownMenu.Trigger>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import type { WithChildren } from 'bits-ui';
|
||||
|
||||
const style = tv({
|
||||
base: 'inline-flex place-items-center justify-center gap-1 rounded-md p-0.5',
|
||||
base: 'inline-flex place-items-center justify-center gap-1 rounded-md p-0.5 font-sans',
|
||||
variants: {
|
||||
variant: {
|
||||
outline: 'border-border bg-transparent text-muted-foreground border',
|
||||
|
@ -12,7 +12,7 @@
|
|||
},
|
||||
size: {
|
||||
sm: 'min-w-6 gap-1.5 p-0.5 px-1 text-sm',
|
||||
default: 'gap-1.5 p-1 px-2',
|
||||
default: 'min-w-6 gap-1.5 p-1 text-xs',
|
||||
lg: 'min-w-9 gap-2 p-1 px-3 text-lg'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
import type { KeyboardShortcut } from '$lib/props/actions';
|
||||
|
||||
function formatShortcutParts(parts: KeyboardShortcut, isMac: boolean): string {
|
||||
const modifierMap = {
|
||||
mac: {
|
||||
cmd: '⌘',
|
||||
ctrl: '⌃',
|
||||
opt: '⌥',
|
||||
shift: '⇧'
|
||||
},
|
||||
other: {
|
||||
cmd: 'Win',
|
||||
ctrl: 'Ctrl',
|
||||
opt: 'Alt',
|
||||
shift: 'Shift'
|
||||
}
|
||||
};
|
||||
|
||||
const keyMap: Partial<Record<KeyboardShortcut['key'], string>> = {
|
||||
return: '⏎',
|
||||
enter: '⏎',
|
||||
delete: '⌫',
|
||||
backspace: '⌫',
|
||||
deleteForward: '⌦',
|
||||
arrowUp: '↑',
|
||||
arrowDown: '↓',
|
||||
arrowLeft: '←',
|
||||
arrowRight: '→',
|
||||
tab: '⇥',
|
||||
escape: '⎋',
|
||||
space: '␣'
|
||||
};
|
||||
|
||||
const currentModifiers = isMac ? modifierMap.mac : modifierMap.other;
|
||||
|
||||
const modifierStrings = parts.modifiers.map((mod) => currentModifiers[mod]);
|
||||
|
||||
const keyString = keyMap[parts.key] ?? parts.key.toUpperCase();
|
||||
|
||||
const allParts = [...modifierStrings, keyString];
|
||||
|
||||
return allParts.join(' + ');
|
||||
}
|
||||
|
||||
export function shortcutToText(shortcut: KeyboardShortcut, forceOS?: 'macOS' | 'windows'): string {
|
||||
const isMac = forceOS
|
||||
? forceOS === 'macOS'
|
||||
: typeof navigator !== 'undefined' && /Mac/i.test(navigator.platform);
|
||||
|
||||
if ('modifiers' in shortcut) {
|
||||
return formatShortcutParts(shortcut, isMac);
|
||||
} else {
|
||||
return formatShortcutParts(shortcut, true);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue