2021-05-13 06:24:12 -04:00
|
|
|
import { Tabs } from '@reach/tabs'
|
2021-06-23 05:37:08 -04:00
|
|
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
2021-05-13 06:24:12 -04:00
|
|
|
import { useTranslation } from 'react-i18next'
|
|
|
|
import PropTypes from 'prop-types'
|
|
|
|
import { matchSorter } from 'match-sorter'
|
|
|
|
|
|
|
|
import symbols from '../data/symbols.json'
|
|
|
|
import { buildCategorisedSymbols, createCategories } from '../utils/categories'
|
|
|
|
import SymbolPaletteSearch from './symbol-palette-search'
|
|
|
|
import SymbolPaletteBody from './symbol-palette-body'
|
|
|
|
import SymbolPaletteTabs from './symbol-palette-tabs'
|
2021-05-25 05:58:54 -04:00
|
|
|
// import SymbolPaletteInfoLink from './symbol-palette-info-link'
|
|
|
|
import BetaBadge from '../../../shared/components/beta-badge'
|
|
|
|
|
|
|
|
import '@reach/tabs/styles.css'
|
2021-05-13 06:24:12 -04:00
|
|
|
|
|
|
|
export default function SymbolPaletteContent({ handleSelect }) {
|
|
|
|
const [input, setInput] = useState('')
|
|
|
|
|
|
|
|
const { t } = useTranslation()
|
|
|
|
|
|
|
|
// build the list of categories with translated labels
|
|
|
|
const categories = useMemo(() => createCategories(t), [t])
|
|
|
|
|
|
|
|
// group the symbols by category
|
|
|
|
const categorisedSymbols = useMemo(
|
|
|
|
() => buildCategorisedSymbols(categories),
|
|
|
|
[categories]
|
|
|
|
)
|
|
|
|
|
|
|
|
// select symbols which match the input
|
|
|
|
const filteredSymbols = useMemo(() => {
|
|
|
|
if (input === '') {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2021-06-17 11:36:59 -04:00
|
|
|
const words = input.trim().split(/\s+/)
|
2021-05-25 05:54:59 -04:00
|
|
|
|
|
|
|
return words.reduceRight(
|
|
|
|
(symbols, word) =>
|
|
|
|
matchSorter(symbols, word, {
|
2021-06-17 11:36:59 -04:00
|
|
|
keys: ['command', 'description', 'character', 'aliases'],
|
2021-05-25 05:54:59 -04:00
|
|
|
threshold: matchSorter.rankings.CONTAINS,
|
|
|
|
}),
|
|
|
|
symbols
|
|
|
|
)
|
2021-05-13 06:24:12 -04:00
|
|
|
}, [input])
|
|
|
|
|
|
|
|
const inputRef = useRef(null)
|
|
|
|
|
|
|
|
// allow the input to be focused
|
|
|
|
const focusInput = useCallback(() => {
|
|
|
|
if (inputRef.current) {
|
|
|
|
inputRef.current.focus()
|
|
|
|
}
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
// focus the input when the symbol palette is opened
|
|
|
|
useEffect(() => {
|
|
|
|
if (inputRef.current) {
|
|
|
|
inputRef.current.focus()
|
|
|
|
}
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
return (
|
2021-05-17 07:50:19 -04:00
|
|
|
<Tabs className="symbol-palette-container">
|
2021-05-13 06:24:12 -04:00
|
|
|
<div className="symbol-palette">
|
|
|
|
<div className="symbol-palette-header">
|
2021-08-03 06:02:45 -04:00
|
|
|
{input.length <= 0 ? (
|
|
|
|
<SymbolPaletteTabs categories={categories} />
|
|
|
|
) : (
|
|
|
|
<div className="symbol-palette-search-hint">
|
|
|
|
{t('showing_symbol_search_results', { search: input })}
|
|
|
|
</div>
|
|
|
|
)}
|
2021-05-25 05:58:54 -04:00
|
|
|
<div className="symbol-palette-header-group">
|
|
|
|
<BetaBadge
|
|
|
|
tooltip={{
|
|
|
|
id: 'tooltip-symbol-palette-beta',
|
2021-06-17 11:37:48 -04:00
|
|
|
text:
|
|
|
|
'The Symbol Palette is a beta feature. Click here to give feedback.',
|
2021-05-25 05:58:54 -04:00
|
|
|
placement: 'top',
|
|
|
|
}}
|
2021-06-17 11:37:48 -04:00
|
|
|
url="https://forms.gle/BybHV5svGE8rJ6Ki9"
|
2021-05-25 05:58:54 -04:00
|
|
|
/>
|
|
|
|
{/* NOTE: replace the beta badge with this info link when rolling out to all users */}
|
|
|
|
{/* <SymbolPaletteInfoLink /> */}
|
|
|
|
<SymbolPaletteSearch setInput={setInput} inputRef={inputRef} />
|
|
|
|
</div>
|
2021-05-13 06:24:12 -04:00
|
|
|
</div>
|
|
|
|
<div className="symbol-palette-body">
|
|
|
|
<SymbolPaletteBody
|
|
|
|
categories={categories}
|
|
|
|
categorisedSymbols={categorisedSymbols}
|
|
|
|
filteredSymbols={filteredSymbols}
|
|
|
|
handleSelect={handleSelect}
|
|
|
|
focusInput={focusInput}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</Tabs>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
SymbolPaletteContent.propTypes = {
|
|
|
|
handleSelect: PropTypes.func.isRequired,
|
|
|
|
}
|