init: the first public commit for AFFiNE

This commit is contained in:
DarkSky
2022-07-22 15:49:21 +08:00
commit e3e3741393
1451 changed files with 108124 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
import { StrictMode } from 'react';
import { HookType } from '@toeverything/framework/virgo';
import { BasePlugin } from '../base-plugin';
import { Search } from './search';
import { PluginRenderRoot } from '../utils';
export class FullTextSearchPlugin extends BasePlugin {
#root?: PluginRenderRoot;
public static override get pluginName(): string {
return 'search';
}
public override init(): void {
this.hooks.addHook(HookType.ON_SEARCH, this.handle_search, this);
}
private unmount() {
if (this.#root) {
this.editor.setHotKeysScope();
this.#root.unmount();
this.#root = undefined;
}
}
private handle_search() {
this.editor.setHotKeysScope('search');
this.render_search();
}
private render_search() {
this.#root = new PluginRenderRoot({
name: FullTextSearchPlugin.pluginName,
render: this.editor.reactRenderRoot.render,
});
this.#root.mount();
this.#root.render(
<StrictMode>
<Search onClose={() => this.unmount()} editor={this.editor} />
</StrictMode>
);
}
public renderSearch() {
this.render_search();
}
}
export type { QueryResult } from './search';
export { QueryBlocks } from './search';

View File

@@ -0,0 +1,117 @@
import { useCallback, useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router';
import style9 from 'style9';
import { BlockPreview } from '@toeverything/components/common';
import {
TransitionsModal,
MuiBox as Box,
MuiBox,
} from '@toeverything/components/ui';
import { Virgo, BlockEditor } from '@toeverything/framework/virgo';
import { throttle } from '@toeverything/utils';
const styles = style9.create({
wrapper: {
position: 'absolute',
top: '20%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: '50vw',
display: 'flex',
flexDirection: 'column',
},
search: {
margin: '0.5em',
backgroundColor: 'white',
boxShadow: '0px 1px 10px rgb(152 172 189 / 60%)',
padding: '16px 32px',
borderRadius: '10px',
},
result: {
margin: '0.5em',
backgroundColor: 'white',
boxShadow: '0px 1px 10px rgb(152 172 189 / 60%)',
padding: '16px 32px',
borderRadius: '10px',
transitionProperty: 'max-height',
transitionDuration: '300ms',
transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
transitionDelay: '0ms',
overflowX: 'hidden',
overflowY: 'hidden',
},
result_hide: {
opacity: 0,
},
});
export type QueryResult = Awaited<ReturnType<BlockEditor['search']>>;
const query_blocks = (
editor: Virgo,
search: string,
callback: (result: QueryResult) => void
) => {
(editor as BlockEditor).search(search).then(pages => callback(pages));
};
export const QueryBlocks = throttle(query_blocks, 500);
type SearchProps = {
onClose: () => void;
editor: Virgo;
};
export const Search = (props: SearchProps) => {
const { workspace_id } = useParams();
const navigate = useNavigate();
const [open, set_open] = useState(true);
const [search, set_search] = useState('');
const [result, set_result] = useState<QueryResult>([]);
useEffect(() => {
QueryBlocks(props.editor, search, result => {
set_result(result);
});
}, [props.editor, search]);
const handle_navigate = useCallback(
(id: string) => navigate(`/${workspace_id}/${id}`),
[navigate, workspace_id]
);
return (
<TransitionsModal
open={open}
onClose={() => {
set_open(false);
props.onClose();
}}
>
<Box className={styles('wrapper')}>
<input
className={styles('search')}
autoFocus
value={search}
onChange={e => set_search(e.target.value)}
/>
<MuiBox
sx={{ maxHeight: `${result.length * 28 + 32 + 20}px` }}
className={styles('result', {
result_hide: !result.length,
})}
>
{result.map(block => (
<BlockPreview
key={block.id}
block={block}
onClick={() => handle_navigate(block.id)}
/>
))}
</MuiBox>
</Box>
</TransitionsModal>
);
};