feat: Double-link: Search interaction

This commit is contained in:
xiaodong zuo
2022-08-24 15:26:27 +08:00
parent 7d35303395
commit 9169421460
7 changed files with 77 additions and 68 deletions
@@ -192,9 +192,10 @@ export const DoubleLinkMenu = ({
anchorNode.id !== curBlockId &&
editor.blockHelper.isSelectionCollapsed(anchorNode.id))
) {
const text = editor.blockHelper.getBlockTextBeforeSelection(
anchorNode.id
);
const text =
editor.blockHelper.getBlockTextBeforeSelection(
anchorNode.id
) || '';
if (text.endsWith('[[')) {
resetState(curBlockId, anchorNode.id);
}
@@ -5,7 +5,12 @@ import {
styled,
TransitionsModal,
} from '@toeverything/components/ui';
import { BlockEditor, Virgo } from '@toeverything/framework/virgo';
import {
BlockEditor,
HookType,
PluginHooks,
Virgo,
} from '@toeverything/framework/virgo';
import { throttle } from '@toeverything/utils';
import { useCallback, useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router';
@@ -31,7 +36,7 @@ const styles = style9.create({
export type QueryResult = Awaited<ReturnType<BlockEditor['search']>>;
const query_blocks = (
const queryBlocksExec = (
editor: Virgo,
search: string,
callback: (result: QueryResult) => void
@@ -39,45 +44,58 @@ const query_blocks = (
(editor as BlockEditor).search(search).then(pages => callback(pages));
};
export const QueryBlocks = throttle(query_blocks, 500);
export const QueryBlocks = throttle(queryBlocksExec, 500);
type SearchProps = {
onClose: () => void;
editor: Virgo;
hooks: PluginHooks;
};
export const Search = (props: SearchProps) => {
const { workspace_id } = useParams();
const { workspace_id: workspaceId } = useParams();
const navigate = useNavigate();
const [open, set_open] = useState(true);
const [search, set_search] = useState('');
const [result, set_result] = useState<QueryResult>([]);
const [open, setOpen] = useState(false);
const [search, setSearch] = useState<string>();
const [result, setResult] = useState<QueryResult>([]);
useEffect(() => {
QueryBlocks(props.editor, search, result => {
set_result(result);
});
search !== undefined &&
QueryBlocks(props.editor, search, result => {
setResult(result);
});
}, [props.editor, search]);
const handle_navigate = useCallback(
(id: string) => navigate(`/${workspace_id}/${id}`),
[navigate, workspace_id]
const handleNavigate = useCallback(
(id: string) => navigate(`/${workspaceId}/${id}`),
[navigate, workspaceId]
);
const handleSearch = useCallback(() => {
setOpen(true);
setSearch('');
}, []);
useEffect(() => {
const sub = props.hooks.get(HookType.ON_SEARCH).subscribe(handleSearch);
return () => {
sub.unsubscribe();
};
}, [props, handleSearch]);
return (
<TransitionsModal
open={open}
onClose={() => {
set_open(false);
props.onClose();
setOpen(false);
}}
>
<Box className={styles('wrapper')}>
<SearchInput
autoFocus
value={search}
onChange={e => set_search(e.target.value)}
onChange={e => setSearch(e.target.value)}
/>
<ResultContainer
sx={{ maxHeight: `${result.length * 28 + 32 + 20}px` }}
@@ -89,10 +107,12 @@ export const Search = (props: SearchProps) => {
<BlockPreview
className={styles('resultItem')}
key={block.id}
block={block}
block={{
...block,
content: block.content || 'Untitled',
}}
onClick={() => {
handle_navigate(block.id);
props.onClose();
handleNavigate(block.id);
}}
/>
))}
@@ -1,59 +1,40 @@
import { StrictMode } from 'react';
import { HookType } from '@toeverything/framework/virgo';
import { BasePlugin } from '../base-plugin';
import { PluginRenderRoot } from '../utils';
import { Search } from './Search';
export class FullTextSearchPlugin extends BasePlugin {
#root?: PluginRenderRoot;
private root?: PluginRenderRoot;
public static override get pluginName(): string {
return 'search';
}
public override init(): void {
this.sub.add(
this.hooks.get(HookType.ON_SEARCH).subscribe(this._handleSearch)
);
}
protected override _onRender(): void {
this.#root = new PluginRenderRoot({
this.root = new PluginRenderRoot({
name: FullTextSearchPlugin.pluginName,
render: this.editor.reactRenderRoot.render,
});
this._renderSearch();
}
private unmount() {
if (this.#root) {
this.editor.setHotKeysScope();
this.#root.unmount();
// this.#root = undefined;
}
this.sub.unsubscribe();
}
private _handleSearch = () => {
this.editor.setHotKeysScope('search');
this.render_search();
};
private render_search() {
if (this.#root) {
this.#root.mount();
this.#root.render(
private _renderSearch() {
if (this.root) {
this.root.mount();
this.root.render(
<StrictMode>
<Search
onClose={() => this.unmount()}
editor={this.editor}
/>
<Search editor={this.editor} hooks={this.hooks} />
</StrictMode>
);
}
}
public renderSearch() {
this.render_search();
this._renderSearch();
}
public override dispose() {
this.root?.unmount();
super.dispose();
}
}