mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
refactor: extract keyboard shortcut setting
This commit is contained in:
parent
c6fe580d33
commit
3476ed1072
3 changed files with 76 additions and 63 deletions
58
src/components/settings/KeyboardShortcutSetting.tsx
Normal file
58
src/components/settings/KeyboardShortcutSetting.tsx
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { Box, Button, FormControl, TextInput } from '@primer/react'
|
||||
import * as React from 'react'
|
||||
import { useUpdateEffect } from 'react-use'
|
||||
import { friendlyFormatShortcut, noop } from 'utils/general'
|
||||
import { useStateIO } from 'utils/hooks/useStateIO'
|
||||
import * as keyHelper from 'utils/keyHelper'
|
||||
|
||||
type Props = IO<string | undefined> & {
|
||||
label: React.ReactNode
|
||||
}
|
||||
|
||||
export function KeyboardShortcutSetting({ label, value, onChange }: Props) {
|
||||
const $focused = useStateIO(false)
|
||||
const $shortcut = useStateIO(value)
|
||||
useUpdateEffect(() => $shortcut.onChange(value), [value])
|
||||
|
||||
const id = React.useMemo(() => Math.random() + '', [])
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<FormControl.Label htmlFor={id}>{label}</FormControl.Label>
|
||||
<Box display="inline-flex" width="100%">
|
||||
<TextInput
|
||||
id={id}
|
||||
sx={{ marginRight: 1, flex: 1 }}
|
||||
onFocus={() => $focused.onChange(true)}
|
||||
onBlur={() => $focused.onChange(false)}
|
||||
placeholder={$focused.value ? 'Press key combination' : 'Click here to set'}
|
||||
value={friendlyFormatShortcut($shortcut.value)}
|
||||
onChange={noop}
|
||||
onKeyDown={e => {
|
||||
switch (e.key) {
|
||||
case 'Esc':
|
||||
case 'Tab':
|
||||
return
|
||||
case 'Delete':
|
||||
case 'Backspace':
|
||||
// Clear shortcut with backspace
|
||||
$shortcut.onChange(undefined)
|
||||
return
|
||||
default:
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}
|
||||
$shortcut.onChange(keyHelper.parseEvent(e))
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
disabled={!value && !$shortcut.value}
|
||||
onClick={() => onChange(value === $shortcut.value ? undefined : $shortcut.value)}
|
||||
>
|
||||
{/* Show clear when shortcut equal to input value */}
|
||||
{value === $shortcut.value ? 'Clear' : 'Save'}
|
||||
</Button>
|
||||
</Box>
|
||||
</FormControl>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
import { Box, Button, FormControl, TextInput } from '@primer/react'
|
||||
import { SimpleConfigFieldCheckbox } from 'components/settings/SimpleConfigField/Checkbox'
|
||||
import { useConfigs } from 'containers/ConfigsContext'
|
||||
import * as React from 'react'
|
||||
import { friendlyFormatShortcut, noop } from 'utils/general'
|
||||
import { useStateIO } from 'utils/hooks/useStateIO'
|
||||
import * as keyHelper from 'utils/keyHelper'
|
||||
import { subIO } from 'utils/general'
|
||||
import { KeyboardShortcutSetting } from './KeyboardShortcutSetting'
|
||||
import { SettingsSection } from './SettingsSection'
|
||||
|
||||
export function SidebarSettings() {
|
||||
|
|
@ -12,7 +10,10 @@ export function SidebarSettings() {
|
|||
|
||||
return (
|
||||
<SettingsSection title={'Sidebar'}>
|
||||
<ToggleSidebarShortcutSettings />
|
||||
<KeyboardShortcutSetting
|
||||
label={'Keyboard shortcut to toggle visibility'}
|
||||
{...subIO(useConfigs(), 'shortcut')}
|
||||
/>
|
||||
<SimpleConfigFieldCheckbox
|
||||
field={{
|
||||
key: 'intelligentToggle',
|
||||
|
|
@ -30,61 +31,3 @@ export function SidebarSettings() {
|
|||
</SettingsSection>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleSidebarShortcutSettings() {
|
||||
const configContext = useConfigs()
|
||||
const { shortcut } = configContext.value
|
||||
const id = 'toggle-show-sidebar-shortcut'
|
||||
|
||||
React.useEffect(() => {
|
||||
useToggleShowSideBarShortcut.onChange(shortcut)
|
||||
}, [shortcut]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const useToggleShowSideBarShortcut = useStateIO(shortcut)
|
||||
const { value: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut
|
||||
const focused = useStateIO(false)
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<FormControl.Label htmlFor={id}>Keyboard shortcut to toggle visibility</FormControl.Label>
|
||||
<Box display="inline-flex" width="100%">
|
||||
<TextInput
|
||||
id={id}
|
||||
sx={{ marginRight: 1, flex: 1 }}
|
||||
onFocus={() => focused.onChange(true)}
|
||||
onBlur={() => focused.onChange(false)}
|
||||
placeholder={focused.value ? 'Press key combination' : 'Click here to set'}
|
||||
value={friendlyFormatShortcut(toggleShowSideBarShortcut)}
|
||||
onChange={noop}
|
||||
onKeyDown={e => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
// Clear shortcut with backspace
|
||||
const shortcut = e.key === 'Backspace' ? '' : keyHelper.parseEvent(e)
|
||||
useToggleShowSideBarShortcut.onChange(shortcut)
|
||||
}}
|
||||
/>
|
||||
{shortcut === toggleShowSideBarShortcut ? (
|
||||
<Button
|
||||
disabled={!shortcut}
|
||||
onClick={() => {
|
||||
configContext.onChange({ shortcut: '' })
|
||||
}}
|
||||
>
|
||||
Clear
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
onClick={() => {
|
||||
const { value: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut
|
||||
if (typeof toggleShowSideBarShortcut !== 'string') return
|
||||
configContext.onChange({ shortcut: toggleShowSideBarShortcut })
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</FormControl>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,18 @@ import { ReactElement } from 'react'
|
|||
import * as ReactDOM from 'react-dom'
|
||||
import { is } from './is'
|
||||
|
||||
export function subIO<T, K extends keyof T>(io: IO<T>, field: K): IO<T[K]> {
|
||||
return {
|
||||
value: io.value[field],
|
||||
onChange(value) {
|
||||
io.onChange({
|
||||
...io.value,
|
||||
[field]: value,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function pick<T>(source: T, keys: string[]): Partial<T> {
|
||||
if (keys && typeof keys === 'object') {
|
||||
return (Array.isArray(keys) ? keys : Object.keys(keys)).reduce((copy, key) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue