54 lines
1.5 KiB
TypeScript
54 lines
1.5 KiB
TypeScript
import { Icon } from '@iconify/react/dist/iconify.js';
|
|
import cx from 'clsx';
|
|
import { useAtomValue } from 'jotai';
|
|
import { FC, useState } from 'react';
|
|
import { useDebounce } from 'react-use';
|
|
import { ScrollArea } from '../../components/ScrollArea';
|
|
import { PatternsAtom } from '../../context/Patterns';
|
|
import styles from './Patterns.module.css';
|
|
|
|
const Patterns: FC = () => {
|
|
const [rawKeyword, setRawKeyword] = useState<string>('');
|
|
const [keyword, setKeyword] = useState<string | null>(null);
|
|
const patterns = useAtomValue(PatternsAtom(keyword));
|
|
|
|
useDebounce(
|
|
() => {
|
|
if (rawKeyword.trim().length > 0) {
|
|
setKeyword(rawKeyword.trim());
|
|
} else {
|
|
setKeyword(null);
|
|
}
|
|
},
|
|
1500,
|
|
[rawKeyword],
|
|
);
|
|
|
|
return (
|
|
<div className={styles.patterns}>
|
|
<div className={styles.search_row}>
|
|
<div className={cx('input_wrapper', 'extendable')}>
|
|
<Icon icon="material-symbols-light:search" />
|
|
<input
|
|
type="text"
|
|
placeholder="Search patterns..."
|
|
value={rawKeyword}
|
|
onChange={(evt) => setRawKeyword(evt.currentTarget.value)}
|
|
/>
|
|
</div>
|
|
<button className="tonal secondary">
|
|
<Icon icon="material-symbols-light:add" />
|
|
New Pattern
|
|
</button>
|
|
</div>
|
|
<ScrollArea enableY>
|
|
<div className={styles.pattern_list}>
|
|
{patterns.length === 0 && <div className="empty_prompt">No pattern found.</div>}
|
|
</div>
|
|
</ScrollArea>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Patterns;
|