diff --git a/packages/app/src/components/workspace-slider-bar/index.tsx b/packages/app/src/components/workspace-slider-bar/index.tsx index 4291d310d2..44603c990c 100644 --- a/packages/app/src/components/workspace-slider-bar/index.tsx +++ b/packages/app/src/components/workspace-slider-bar/index.tsx @@ -50,7 +50,7 @@ export const WorkSpaceSliderBar = () => { const { triggerQuickSearchModal, triggerImportModal } = useModal(); const [show, setShow] = useState(false); const [showSubFavorite, setShowSubFavorite] = useState(false); - const { createPage } = useEditor(); + const { createPage, getPageMeta, openPage } = useEditor(); const router = useRouter(); return ( @@ -116,8 +116,10 @@ export const WorkSpaceSliderBar = () => { { - createPage(); + onClick={async () => { + const page = await createPage(); + const pageMeta = getPageMeta(page.id); + pageMeta && openPage(pageMeta.id); }} > New Page diff --git a/packages/app/src/providers/editor-provider/editor-provider.tsx b/packages/app/src/providers/editor-provider/editor-provider.tsx index 8d1931e967..212427b0ae 100644 --- a/packages/app/src/providers/editor-provider/editor-provider.tsx +++ b/packages/app/src/providers/editor-provider/editor-provider.tsx @@ -1,69 +1,34 @@ import type { EditorContainer } from '@blocksuite/editor'; -import { createContext, useContext, useEffect, useRef, useState } from 'react'; +import { createContext, useContext, useEffect, 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'; -import { QueryContent } from '@blocksuite/store/dist/workspace/search'; -export interface PageMeta { - id: string; - title: string; - favorite: boolean; - trash: boolean; - createDate: number; - trashDate: number | null; -} +import useEditorHandler from './useEditorHandler'; +import { EditorHandlers, PageMeta } from './interface'; + // Blocksuite has to be imported dynamically since it has a lot of effects -const DynamicEditor = dynamic(() => import('./initial-editor'), { +const DynamicEditor = dynamic(() => import('./editor-reactor'), { ssr: false, }); type EditorContextValue = { mode: EditorContainer['mode']; setMode: (mode: EditorContainer['mode']) => void; - currentPage: Page | null; - editor: EditorContainer | null; + currentPage: Page | void; + editor: EditorContainer | void; pageList: PageMeta[]; } & EditorHandlers; -type EditorHandlers = { - createPage: (pageId?: string) => void; - openPage: ( - pageId: string, - query?: { [key: string]: string } - ) => Promise; - deletePage: (pageId: string) => void; - recyclePage: (pageId: string) => void; - toggleDeletePage: (pageId: string) => void; - favoritePage: (pageId: string) => void; - unFavoritePage: (pageId: string) => void; - toggleFavoritePage: (pageId: string) => void; - permanentlyDeletePage: (pageId: string) => void; - search: (query: QueryContent) => any; -}; - type EditorContextProps = PropsWithChildren<{}>; export const EditorContext = createContext({ mode: 'page', setMode: () => {}, pageList: [], - currentPage: null, - editor: null, - createPage: () => {}, - openPage: async () => { - return false; - }, - deletePage: () => {}, - recyclePage: () => {}, - toggleDeletePage: () => {}, - favoritePage: () => {}, - unFavoritePage: () => {}, - toggleFavoritePage: () => {}, - permanentlyDeletePage: () => {}, - search: () => {}, + currentPage: undefined, + editor: undefined, + ...({} as EditorHandlers), }); export const useEditor = () => useContext(EditorContext); @@ -71,14 +36,14 @@ export const useEditor = () => useContext(EditorContext); export const EditorProvider = ({ children, }: PropsWithChildren) => { - const router = useRouter(); - const blockSchemaRef = useRef(null); - const [workspace, setWorkspace] = useState(null); - const [currentPage, setCurrentPage] = useState(null); + const [workspace, setWorkspace] = useState(); + const [currentPage, setCurrentPage] = useState(); const [pageList, setPageList] = useState([]); - const [editor, setEditor] = useState(null); + const [editor, setEditor] = useState(); const [mode, setMode] = useState('page'); + const editorHandlers = useEditorHandler(workspace); + useEffect(() => { const event = new CustomEvent('affine.switch-mode', { detail: mode }); window.dispatchEvent(event); @@ -88,9 +53,9 @@ export const EditorProvider = ({ if (!workspace) { return; } - setPageList(workspace.meta.pages as PageMeta[]); + setPageList(workspace.meta.pageMetas as PageMeta[]); workspace.meta.pagesUpdated.on(res => { - setPageList(workspace.meta.pages as PageMeta[]); + setPageList(workspace.meta.pageMetas as PageMeta[]); }); return () => { // TODO: Does it need to be removed? @@ -98,67 +63,20 @@ export const EditorProvider = ({ }; }, [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?.setPageMeta(pageId, { trash: true }); - }, - recyclePage: pageId => { - workspace?.setPageMeta(pageId, { trash: false }); - }, - toggleDeletePage: pageId => { - const pageMeta = workspace?.meta.pages.find(p => p.id === pageId); - if (pageMeta) { - workspace?.setPageMeta(pageId, { trash: !pageMeta.trash }); - } - }, - favoritePage: pageId => { - workspace?.setPageMeta(pageId, { favorite: true }); - }, - permanentlyDeletePage: pageId => { - // TODO: workspace.meta.removePage or workspace.removePage? - workspace?.meta.removePage(pageId); - }, - 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 }); - } - }, - search: (query: QueryContent) => { - if (query) { - return workspace?.search(query); - } - }, - }; - return ( { - if (!blockSchemaRef.current) { - blockSchemaRef.current = blockSchema; - } - }} setEditor={setEditor} setWorkspace={setWorkspace} setCurrentPage={setCurrentPage} diff --git a/packages/app/src/providers/editor-provider/initial-editor.tsx b/packages/app/src/providers/editor-provider/editor-reactor.tsx similarity index 71% rename from packages/app/src/providers/editor-provider/initial-editor.tsx rename to packages/app/src/providers/editor-provider/editor-reactor.tsx index 7cff95d876..982030d892 100644 --- a/packages/app/src/providers/editor-provider/initial-editor.tsx +++ b/packages/app/src/providers/editor-provider/editor-reactor.tsx @@ -2,6 +2,7 @@ import '@blocksuite/blocks'; import '@blocksuite/blocks/style'; import type { EditorContainer } from '@blocksuite/editor'; import { BlockSchema, createEditor } from '@blocksuite/editor'; +import { generateDefaultPageId, initialPage } from './utils'; import { useEffect } from 'react'; import pkg from '../../../package.json'; import { @@ -11,6 +12,7 @@ import { Page, } from '@blocksuite/store'; import { useRouter } from 'next/router'; +import { createPage } from '@/providers/editor-provider/utils'; const getEditorParams = () => { const providers = []; @@ -22,9 +24,8 @@ const getEditorParams = () => { ); providers.push(WebsocketDocProvider); } - if (params.get('syncMode') === 'indexeddb') { - providers.push(IndexedDBDocProvider); - } + + providers.push(IndexedDBDocProvider); return { room, @@ -32,29 +33,25 @@ const getEditorParams = () => { }; }; -const InitialEditor = ({ +const EditorReactor = ({ workspace, currentPage, - setBlockSchema, setEditor, setWorkspace, setCurrentPage, }: { - workspace: Workspace | null; - currentPage: Page | null; - setBlockSchema: (blockSchema: typeof BlockSchema) => void; + workspace: Workspace | void; + currentPage: Page | void; setEditor: (editor: EditorContainer) => void; setWorkspace: (workspace: Workspace) => void; setCurrentPage: (Page: Page) => void; }) => { - setBlockSchema(BlockSchema); - const router = useRouter(); useEffect(() => { const workspace = new Workspace({ ...getEditorParams(), - }); + }).register(BlockSchema); //@ts-ignore window.workspace = workspace; const indexDBProvider = workspace.providers.find( @@ -74,21 +71,20 @@ const InitialEditor = ({ return; } - // 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); + workspace.meta.pageMetas.find( + p => p.id === (router.query.pageId as string) + )?.id ?? workspace.meta.pageMetas[0]?.id; - const initialPage = workspace - .createPage(initialPageId) - .register(BlockSchema); - setCurrentPage(initialPage); + if (!initialPageId) { + createPage(workspace!, generateDefaultPageId()).then(page => { + initialPage(page); + setCurrentPage(page); + }); + } else { + const page = workspace.getPage(initialPageId); + setCurrentPage(page); + } }, [workspace, router.query.pageId, setCurrentPage]); useEffect(() => { @@ -106,4 +102,4 @@ const InitialEditor = ({ return
; }; -export default InitialEditor; +export default EditorReactor; diff --git a/packages/app/src/providers/editor-provider/interface.ts b/packages/app/src/providers/editor-provider/interface.ts new file mode 100644 index 0000000000..3b5a2290ce --- /dev/null +++ b/packages/app/src/providers/editor-provider/interface.ts @@ -0,0 +1,28 @@ +import { Page } from '@blocksuite/store'; +import { QueryContent } from '@blocksuite/store/dist/workspace/search'; + +export interface PageMeta { + id: string; + title: string; + favorite: boolean; + trash: boolean; + createDate: number; + trashDate: number | null; +} + +export type EditorHandlers = { + createPage: (pageId?: string) => Promise; + openPage: ( + pageId: string, + query?: { [key: string]: string } + ) => Promise; + getPageMeta: (pageId: string) => PageMeta | void; + deletePage: (pageId: string) => void; + recyclePage: (pageId: string) => void; + toggleDeletePage: (pageId: string) => void; + favoritePage: (pageId: string) => void; + unFavoritePage: (pageId: string) => void; + toggleFavoritePage: (pageId: string) => void; + permanentlyDeletePage: (pageId: string) => void; + search: (query: QueryContent) => any; +}; diff --git a/packages/app/src/providers/editor-provider/useEditorHandler.ts b/packages/app/src/providers/editor-provider/useEditorHandler.ts new file mode 100644 index 0000000000..b5cf1f114a --- /dev/null +++ b/packages/app/src/providers/editor-provider/useEditorHandler.ts @@ -0,0 +1,65 @@ +import { QueryContent } from '@blocksuite/store/dist/workspace/search'; +import { createPage, initialPage, generateDefaultPageId } from './utils'; +import { Workspace } from '@blocksuite/store'; +import { useRouter } from 'next/router'; +import { EditorHandlers } from './interface'; + +export const useEditorHandler = (workspace?: Workspace): EditorHandlers => { + const router = useRouter(); + + return { + createPage: async (pageId = generateDefaultPageId()) => { + const page = await createPage(workspace!, pageId); + initialPage(page); + return page; + }, + getPageMeta(pageId: string) { + pageId = pageId.replace('space:', ''); + return workspace!.meta.pageMetas.find(page => page.id === pageId); + }, + openPage: (pageId, query = {}) => { + return router.push({ + pathname: '/', + query: { + pageId, + ...query, + }, + }); + }, + deletePage: pageId => { + workspace!.setPageMeta(pageId, { trash: true }); + }, + recyclePage: pageId => { + workspace!.setPageMeta(pageId, { trash: false }); + }, + toggleDeletePage: pageId => { + const pageMeta = workspace!.meta.pageMetas.find(p => p.id === pageId); + if (pageMeta) { + workspace!.setPageMeta(pageId, { trash: !pageMeta.trash }); + } + }, + favoritePage: pageId => { + workspace!.setPageMeta(pageId, { favorite: true }); + }, + permanentlyDeletePage: pageId => { + // TODO: workspace.meta.removePage or workspace.removePage? + workspace!.meta.removePage(pageId); + }, + unFavoritePage: pageId => { + workspace!.setPageMeta(pageId, { favorite: true }); + }, + toggleFavoritePage: pageId => { + const pageMeta = workspace?.meta.pageMetas.find(p => p.id === pageId); + if (pageMeta) { + workspace!.setPageMeta(pageId, { favorite: !pageMeta.favorite }); + } + }, + search: (query: QueryContent) => { + if (query) { + return workspace!.search(query); + } + }, + }; +}; + +export default useEditorHandler; diff --git a/packages/app/src/providers/editor-provider/utils.ts b/packages/app/src/providers/editor-provider/utils.ts index 262836b380..39bb4b68b0 100644 --- a/packages/app/src/providers/editor-provider/utils.ts +++ b/packages/app/src/providers/editor-provider/utils.ts @@ -1,5 +1,6 @@ import { EditorContainer } from '@blocksuite/editor'; import exampleMarkdown from '@/providers/editor-provider/example-markdown'; +import { Page, Workspace } from '@blocksuite/store'; export const initDefaultContent = (editor: EditorContainer) => { const { page } = editor; @@ -11,3 +12,27 @@ export const initDefaultContent = (editor: EditorContainer) => { editor.clipboard.importMarkdown(exampleMarkdown, `${groupId}`); page.resetHistory(); }; + +export const createPage = ( + workspace: Workspace, + pageId: string +): Promise => { + return new Promise(resolve => { + workspace.createPage(pageId); + workspace.signals.pageAdded.once(addedPageId => { + const page = workspace!.getPage(addedPageId); + resolve(page); + }); + }); +}; + +export const initialPage = (page: Page) => { + const pageBlockId = page.addBlock({ flavour: 'affine:page' }); + const groupId = page.addBlock({ flavour: 'affine:group' }, pageBlockId); + page.addBlock({ flavour: 'affine:paragraph' }, groupId); + return page; +}; + +export const generateDefaultPageId = () => { + return new Date().getTime().toString(); +};