Merge branch 'feat/dev' into feat/quick-search

This commit is contained in:
JimmFly
2022-12-09 13:34:30 +08:00
committed by GitHub
30 changed files with 561 additions and 220 deletions
@@ -1,25 +1,64 @@
import type { EditorContainer } from '@blocksuite/editor';
import { createContext, useContext, useEffect, useState } from 'react';
import { createContext, useContext, useEffect, useRef, useState } from 'react';
import type { PropsWithChildren } from 'react';
import dynamic from 'next/dynamic';
import Loading from './loading';
import { Page, Workspace } from '@blocksuite/store';
import { BlockSchema } from '@blocksuite/editor/dist/block-loader';
import { useRouter } from 'next/router';
export interface PageMeta {
id: string;
title: string;
favorite: boolean;
trash: boolean;
createDate: number;
trashDate: number | null;
}
// Blocksuite has to be imported dynamically since it has a lot of effects
const DynamicEditor = dynamic(() => import('./initial-editor'), {
ssr: false,
});
type EditorContextValue = {
editor: EditorContainer | null;
mode: EditorContainer['mode'];
setMode: (mode: EditorContainer['mode']) => void;
currentPage: Page | null;
editor: EditorContainer | null;
pageList: PageMeta[];
} & EditorHandlers;
type EditorHandlers = {
createPage: (pageId?: string) => void;
openPage: (
pageId: string,
query?: { [key: string]: string }
) => Promise<boolean>;
deletePage: (pageId: string) => void;
recyclePage: (pageId: string) => void;
toggleDeletePage: (pageId: string) => void;
favoritePage: (pageId: string) => void;
unFavoritePage: (pageId: string) => void;
toggleFavoritePage: (pageId: string) => void;
};
type EditorContextProps = PropsWithChildren<{}>;
export const EditorContext = createContext<EditorContextValue>({
editor: null,
mode: 'page',
setMode: () => {},
pageList: [],
currentPage: null,
editor: null,
createPage: () => {},
openPage: async () => {
return false;
},
deletePage: () => {},
recyclePage: () => {},
toggleDeletePage: () => {},
favoritePage: () => {},
unFavoritePage: () => {},
toggleFavoritePage: () => {},
});
export const useEditor = () => useContext(EditorContext);
@@ -27,6 +66,11 @@ export const useEditor = () => useContext(EditorContext);
export const EditorProvider = ({
children,
}: PropsWithChildren<EditorContextProps>) => {
const router = useRouter();
const blockSchemaRef = useRef<typeof BlockSchema | null>(null);
const [workspace, setWorkspace] = useState<Workspace | null>(null);
const [currentPage, setCurrentPage] = useState<Page | null>(null);
const [pageList, setPageList] = useState<PageMeta[]>([]);
const [editor, setEditor] = useState<EditorContainer | null>(null);
const [mode, setMode] = useState<EditorContainer['mode']>('page');
@@ -35,10 +79,77 @@ export const EditorProvider = ({
window.dispatchEvent(event);
}, [mode]);
useEffect(() => {
if (!workspace) {
return;
}
setPageList(workspace.meta.pages as PageMeta[]);
workspace.meta.pagesUpdated.on(res => {
setPageList(workspace.meta.pages as PageMeta[]);
});
return () => {
// TODO: Does it need to be removed?
workspace.meta.pagesUpdated.dispose();
};
}, [workspace]);
const editorHandler: EditorHandlers = {
createPage: (pageId = new Date().getTime().toString()) => {
blockSchemaRef.current &&
workspace?.createPage(pageId).register(blockSchemaRef.current);
},
openPage: (pageId, query = {}) => {
return router.push({
pathname: '/',
query: {
pageId,
...query,
},
});
},
deletePage: pageId => {
workspace?.setPage(pageId, { trash: true });
},
recyclePage: pageId => {
workspace?.setPage(pageId, { trash: false });
},
toggleDeletePage: pageId => {
const pageMeta = workspace?.meta.pages.find(p => p.id === pageId);
if (pageMeta) {
workspace?.setPage(pageId, { trash: !pageMeta.trash });
}
},
favoritePage: pageId => {
workspace?.setPage(pageId, { favorite: true });
},
unFavoritePage: pageId => {
workspace?.setPageMeta(pageId, { favorite: true });
},
toggleFavoritePage: pageId => {
const pageMeta = workspace?.meta.pages.find(p => p.id === pageId);
if (pageMeta) {
workspace?.setPageMeta(pageId, { favorite: !pageMeta.favorite });
}
},
};
return (
<EditorContext.Provider value={{ editor, mode, setMode }}>
<DynamicEditor setEditor={setEditor} />
{editor ? children : <Loading />}
<EditorContext.Provider
value={{ editor, currentPage, mode, setMode, pageList, ...editorHandler }}
>
<DynamicEditor
workspace={workspace}
currentPage={currentPage}
setBlockSchema={blockSchema => {
if (!blockSchemaRef.current) {
blockSchemaRef.current = blockSchema;
}
}}
setEditor={setEditor}
setWorkspace={setWorkspace}
setCurrentPage={setCurrentPage}
/>
{workspace && currentPage && editor ? children : <Loading />}
</EditorContext.Provider>
);
};
@@ -4,45 +4,103 @@ import type { EditorContainer } from '@blocksuite/editor';
import { BlockSchema, createEditor } from '@blocksuite/editor';
import { useEffect } from 'react';
import pkg from '../../../package.json';
import { createWebsocketDocProvider, Workspace } from '@blocksuite/store';
import {
createWebsocketDocProvider,
Workspace,
IndexedDBDocProvider,
Page,
} from '@blocksuite/store';
import { useRouter } from 'next/router';
const getEditorParams = () => {
const providers = [];
const params = new URLSearchParams(location.search);
if (params.get('syncModes') === 'websocket') {
const room = params.get('room') ?? 'AFFINE-pathfinder';
if (params.get('syncMode') === 'websocket') {
const WebsocketDocProvider = createWebsocketDocProvider(
'ws://127.0.0.1:3000/collaboration/AFFiNE'
);
providers.push(WebsocketDocProvider);
}
if (params.get('syncMode') === 'indexeddb') {
providers.push(IndexedDBDocProvider);
}
return {
room,
providers,
};
};
const InitialEditor = ({
workspace,
currentPage,
setBlockSchema,
setEditor,
setWorkspace,
setCurrentPage,
}: {
workspace: Workspace | null;
currentPage: Page | null;
setBlockSchema: (blockSchema: typeof BlockSchema) => void;
setEditor: (editor: EditorContainer) => void;
setWorkspace: (workspace: Workspace) => void;
setCurrentPage: (Page: Page) => void;
}) => {
setBlockSchema(BlockSchema);
const router = useRouter();
useEffect(() => {
const store = new Workspace({
const workspace = new Workspace({
...getEditorParams(),
});
const page = store.createPage('page0').register(BlockSchema);
const editor = createEditor(page);
//@ts-ignore
window.workspace = workspace;
const indexDBProvider = workspace.providers.find(
p => p instanceof IndexedDBDocProvider
);
if (indexDBProvider) {
(indexDBProvider as IndexedDBDocProvider)?.on('synced', () => {
setWorkspace(workspace);
});
} else {
setWorkspace(workspace);
}
}, [setWorkspace]);
setEditor(editor);
useEffect(() => {
if (!workspace) {
return;
}
return () => {
editor.remove();
};
}, [setEditor]);
// const initialPageId =
// workspace.meta.pages.find(p => p.id === (router.query.pageId as string))
// ?.id ??
// workspace.meta.pages[0]?.id ??
// 'page0';
const initialPageId =
workspace.meta.pages.find(p => p.id === (router.query.pageId as string))
?.id ?? 'page0';
console.log('initialPageId', initialPageId);
const initialPage = workspace
.createPage(initialPageId)
.register(BlockSchema);
setCurrentPage(initialPage);
}, [workspace, router.query.pageId, setCurrentPage]);
useEffect(() => {
if (!currentPage) {
return;
}
setEditor(createEditor(currentPage));
}, [currentPage, setEditor]);
useEffect(() => {
const version = pkg.dependencies['@blocksuite/editor'].substring(1);
console.log(`BlockSuite live demo ${version}`);
console.log(`BlockSuite version: ${version}`);
}, []);
return <div />;