Files
overleaf-cep/services/web/frontend/js/features/command-palette/hooks/use-command-registry-source.tsx
T
Mathias Jakobsen 912fb2dcd8 Merge pull request #35056 from overleaf/mj-command-palette-improvements
[web] Command palette improvements

GitOrigin-RevId: 3d6e11697ed4726b7ecada1744d24a15291ad646
2026-09-17 11:25:26 +00:00

134 lines
3.5 KiB
TypeScript

import { useCallback, useMemo } from 'react'
import MiniSearch from 'minisearch'
import { CommandPaletteSearchResult, CommandPaletteSource } from '../types'
import {
Command,
useCommandRegistry,
} from '@/features/ide-react/context/command-registry-context'
import { useTranslation } from 'react-i18next'
type CommandGroup = {
label: string
actions: string[]
}
const useCommandRegistrySource = (): CommandPaletteSource => {
const { t } = useTranslation()
const elements: (CommandGroup | string)[] = useMemo(
() => [
{
label: t('file'),
actions: ['new_file', 'new_folder', 'upload_file'],
},
{
label: t('view'),
actions: [
'change-layout-side-by-side',
'change-layout-editor-only',
'change-layout-pdf-only',
'change-layout-detached-pdf',
'change-layout-focus-mode',
],
},
{
label: t('insert'),
actions: [
'insert-inline-math',
'insert-display-math',
'insert-figure-from-computer',
'insert-figure-from-project-files',
'insert-figure-from-another-project',
'insert-figure-from-url',
'insert-table',
'insert-citation',
'insert-link',
'insert-cross-reference',
],
},
'open-settings',
'show_version_history',
'word_count',
'view-pdf-presentation-mode',
'comment',
'compile',
'stop-compile',
'recompile-from-scratch',
'synctex-sync-to-pdf',
'synctex-sync-to-code',
'close-tab',
'close-other-tabs',
],
[t]
)
const { registry } = useCommandRegistry()
const commands = useMemo(() => {
const ret: Command[] = []
for (const element of elements) {
if (typeof element === 'string') {
const command = registry.get(element)
if (command && !command.disabled && command.handler) {
ret.push(command)
}
} else {
for (const action of element.actions) {
const command = registry.get(action)
if (command && !command.disabled && command.handler) {
ret.push({
...command,
label: `${element.label}: ${command.label}`,
})
}
}
}
}
return ret
}, [registry, elements])
const defaults = useCallback((): CommandPaletteSearchResult[] => {
return commands.map(command => ({
title: command.label,
onSelect: () => command.handler!({ location: 'command-palette' }),
score: 1,
}))
}, [commands])
const index = useMemo(() => {
const miniSearch = new MiniSearch<Command>({
fields: ['label'],
storeFields: ['id', 'label'],
idField: 'id',
})
miniSearch.addAll(commands)
return miniSearch
}, [commands])
return useMemo<CommandPaletteSource>(
() => ({
id: 'command-registry',
prefix: '>',
search(query) {
const results = index.search(query, {
prefix: true,
fuzzy: term => (term.length > 3 ? 0.2 : false),
})
return results.flatMap(({ id, label, score }) => {
const command = registry.get(id)
if (!command?.handler) return []
return [
{
title: label,
onSelect: () => command.handler!({ location: 'command-palette' }),
score,
},
]
})
},
defaults,
}),
[index, registry, defaults]
)
}
export default useCommandRegistrySource