fix: get page preview based on block order (#4888)

Co-authored-by: Peng Xiao <pengxiao@outlook.com>
This commit is contained in:
Whitewater
2023-11-12 23:09:57 +08:00
committed by GitHub
parent a8d89254ce
commit eded501123
2 changed files with 54 additions and 12 deletions
@@ -76,12 +76,25 @@ describe('useBlockSuitePagePreview', () => {
page.getBlockByFlavour('affine:note')[0].id page.getBlockByFlavour('affine:note')[0].id
); );
const hook = renderHook(() => useAtomValue(useBlockSuitePagePreview(page))); const hook = renderHook(() => useAtomValue(useBlockSuitePagePreview(page)));
expect(hook.result.current).toBe('\nHello, world!'); expect(hook.result.current).toBe('Hello, world!');
page.transact(() => { page.transact(() => {
page.getBlockById(id)!.text!.insert('Test', 0); page.getBlockById(id)!.text!.insert('Test', 0);
}); });
await new Promise(resolve => setTimeout(resolve, 100)); await new Promise(resolve => setTimeout(resolve, 100));
hook.rerender(); hook.rerender();
expect(hook.result.current).toBe('\nTestHello, world!'); expect(hook.result.current).toBe('TestHello, world!');
// Insert before
page.addBlock(
'affine:paragraph',
{
text: new page.Text('First block!'),
},
page.getBlockByFlavour('affine:note')[0].id,
0
);
await new Promise(resolve => setTimeout(resolve, 100));
hook.rerender();
expect(hook.result.current).toBe('First block! TestHello, world!');
}); });
}); });
@@ -1,20 +1,49 @@
import type { ParagraphBlockModel } from '@blocksuite/blocks/models';
import type { Page } from '@blocksuite/store'; import type { Page } from '@blocksuite/store';
import type { Atom } from 'jotai'; import type { Atom } from 'jotai';
import { atom } from 'jotai'; import { atom } from 'jotai';
const MAX_PREVIEW_LENGTH = 150;
const MAX_SEARCH_BLOCK_COUNT = 30;
const weakMap = new WeakMap<Page, Atom<string>>(); const weakMap = new WeakMap<Page, Atom<string>>();
export const getPagePreviewText = (page: Page) => { export const getPagePreviewText = (page: Page) => {
// TODO this is incorrect, since the order of blocks is not guaranteed const pageRoot = page.root;
const paragraphBlocks = page.getBlockByFlavour( if (!pageRoot) {
'affine:paragraph' return '';
) as ParagraphBlockModel[]; }
const text = paragraphBlocks const preview: string[] = [];
.slice(0, 10) // DFS
.map(block => block.text.toString()) const queue = [pageRoot];
.join('\n'); let previewLenNeeded = MAX_PREVIEW_LENGTH;
return text.slice(0, 300); let count = MAX_SEARCH_BLOCK_COUNT;
while (queue.length && previewLenNeeded > 0 && count-- > 0) {
const block = queue.shift();
if (!block) {
console.error('Unexpected empty block');
break;
}
if (block.children) {
queue.unshift(...block.children);
}
if (block.role !== 'content') {
continue;
}
if (block.text) {
const text = block.text.toString();
if (!text.length) {
continue;
}
previewLenNeeded -= text.length;
preview.push(text);
} else {
// image/attachment/bookmark
const type = block.flavour.split('affine:')[1] ?? null;
previewLenNeeded -= type.length + 2;
type && preview.push(`[${type}]`);
}
}
return preview.join(' ');
}; };
const emptyAtom = atom<string>(''); const emptyAtom = atom<string>('');