diff --git a/apps/docs/entries.ts b/apps/docs/entries.ts index 6103ac4d58..63d05f6bda 100644 --- a/apps/docs/entries.ts +++ b/apps/docs/entries.ts @@ -1,21 +1,17 @@ -import { defineEntries } from 'waku/server'; +import { defineRouter } from 'waku/router/server'; -export default defineEntries( - // getEntry +export default defineRouter( async id => { switch (id) { - case 'App': - return import('./src/app.js') as any; + case 'index': { + const { default: AppCreator } = await import('./src/app.js'); + return AppCreator(id); + } default: return null; } }, - // getBuildConfig async () => { - return { - '/': { - elements: [['App', {}]], - }, - }; + return ['index']; } ); diff --git a/apps/docs/src/app.tsx b/apps/docs/src/app.tsx index 5f54c19e50..e6c746f480 100644 --- a/apps/docs/src/app.tsx +++ b/apps/docs/src/app.tsx @@ -1,36 +1,44 @@ /// 'use server'; +import { existsSync, readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + import type { ReactElement } from 'react'; import { lazy } from 'react'; -import { Sidebar } from './components/sidebar.js'; +import { Sidebar } from './components/sidebar/index.js'; +import { saveFile } from './server-fns.js'; const Editor = lazy(() => import('./components/editor.js').then(({ Editor }) => ({ default: Editor })) ); -const markdown = `--- -title: AFFiNE Developer Documentation ---- +const __dirname = fileURLToPath(new URL('.', import.meta.url)); -## To Shape, not to adapt +const AppCreator = (pathname: string) => + function App(): ReactElement { + let path = resolve(__dirname, 'pages', 'binary'); + if (!existsSync(path)) { + path = resolve(__dirname, '..', '..', 'src', 'pages', 'binary'); + } + const buffer = [...readFileSync(path)]; ---- + return ( +
+ +
+ +
+
+ ); + }; -**Powered by BlockSuite** -`; - -const App = (): ReactElement => { - return ( -
- -
- -
-
- ); -}; - -export default App; +export default AppCreator; diff --git a/apps/docs/src/atom.ts b/apps/docs/src/atom.ts new file mode 100644 index 0000000000..4014bdc1e0 --- /dev/null +++ b/apps/docs/src/atom.ts @@ -0,0 +1,11 @@ +import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models'; +import { atom } from 'jotai/vanilla'; + +export const workspaceAtom = atom(async () => { + const { Workspace } = await import('@blocksuite/store'); + return new Workspace({ + id: 'test-workspace', + }) + .register(AffineSchemas) + .register(__unstableSchemas); +}); diff --git a/apps/docs/src/components/editor.tsx b/apps/docs/src/components/editor.tsx index ac9bd96cc5..a1bb47b881 100644 --- a/apps/docs/src/components/editor.tsx +++ b/apps/docs/src/components/editor.tsx @@ -2,54 +2,52 @@ import '@blocksuite/editor/themes/affine.css'; import { BlockSuiteEditor } from '@affine/component/block-suite-editor'; -import { ContentParser } from '@blocksuite/blocks/content-parser'; -import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models'; -import { assertExists, Workspace } from '@blocksuite/store'; +import type { Page } from '@blocksuite/store'; +import { useAtomValue } from 'jotai/react'; import type { ReactElement } from 'react'; -import { useCallback } from 'react'; +import { use } from 'react'; +import { applyUpdate } from 'yjs'; -const workspace = new Workspace({ - id: 'local-workspace', -}) - .register(AffineSchemas) - .register(__unstableSchemas); - -const page = workspace.createPage({ - id: 'example-page', -}); +import { workspaceAtom } from '../atom.js'; export type EditorProps = { - text: string; + workspaceId: string; + pageId: string; + binary?: number[]; + onSave: (binary: any) => Promise; }; export const Editor = (props: EditorProps): ReactElement => { - return ( - { - const text = props.text; - await page.waitForLoaded(); - const metadata = text.split('---\n')[1]; - assertExists(metadata); + const workspace = useAtomValue(workspaceAtom); + let page = workspace.getPage('page0') as Page; + if (!page) { + page = workspace.createPage({ + id: 'page0', + }); + } - // find title - const title = metadata.split('title: ')[1]?.split('\n')[0]; - const pageBlockId = page.addBlock('affine:page', { - title: new page.Text(title), - }); - page.addBlock('affine:surface', {}, pageBlockId); - const noteBlockId = page.addBlock('affine:note', {}, pageBlockId); - const contentParser = new ContentParser(page); - const content = text.split('---\n').splice(2).join('---\n'); - assertExists(content); - await contentParser.importMarkdown(content, noteBlockId); - page.awarenessStore.setReadonly(page, true); - page.awarenessStore.setFlag('enable_drag_handle', false); - }, - [props.text] - )} - /> - ); + if (props.binary && !page.root) { + use( + page.waitForLoaded().then(() => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + applyUpdate(page._ySpaceDoc, new Uint8Array(props.binary as number[])); + }) + ); + if (import.meta.env.MODE !== 'development') { + page.awarenessStore.setReadonly(page, true); + } + } else if (!page.root) { + use( + page.waitForLoaded().then(() => { + const pageBlockId = page.addBlock('affine:page', { + title: new page.Text(''), + }); + page.addBlock('affine:surface', {}, pageBlockId); + const noteBlockId = page.addBlock('affine:note', {}, pageBlockId); + page.addBlock('affine:paragraph', {}, noteBlockId); + }) + ); + } + return {}} />; }; diff --git a/apps/docs/src/components/sidebar.tsx b/apps/docs/src/components/sidebar/index.tsx similarity index 50% rename from apps/docs/src/components/sidebar.tsx rename to apps/docs/src/components/sidebar/index.tsx index eb401db0b1..d7c701a852 100644 --- a/apps/docs/src/components/sidebar.tsx +++ b/apps/docs/src/components/sidebar/index.tsx @@ -1,3 +1,15 @@ +'use server'; + +import { lazy } from 'react'; + +import { saveFile } from '../../server-fns.js'; + +const SaveToLocal = lazy(() => + import('./save-to-local.js').then(({ SaveToLocal }) => ({ + default: SaveToLocal, + })) +); + export const Sidebar = () => { return (
{ AFFiNE
+ {import.meta.env.MODE === 'development' && ( + + )} ); }; diff --git a/apps/docs/src/components/sidebar/save-to-local.tsx b/apps/docs/src/components/sidebar/save-to-local.tsx new file mode 100644 index 0000000000..d469a992ef --- /dev/null +++ b/apps/docs/src/components/sidebar/save-to-local.tsx @@ -0,0 +1,28 @@ +'use client'; +import { assertExists } from '@blocksuite/global/utils'; +import { useAtomValue } from 'jotai/react'; +import { useCallback } from 'react'; +import { encodeStateAsUpdate } from 'yjs'; + +import { workspaceAtom } from '../../atom.js'; + +type SaveToLocalProps = { + saveFile: (update: number[]) => void; +}; + +export const SaveToLocal = (props: SaveToLocalProps) => { + const workspace = useAtomValue(workspaceAtom); + const saveFile = props.saveFile; + const onSave = useCallback(() => { + const page = workspace.getPage('page0'); + assertExists(page); + saveFile([...encodeStateAsUpdate(page.spaceDoc)]); + }, [saveFile, workspace]); + return ( +
+
+ +
+
+ ); +}; diff --git a/apps/docs/src/index.tsx b/apps/docs/src/index.tsx index 652a0a60dc..4819407662 100644 --- a/apps/docs/src/index.tsx +++ b/apps/docs/src/index.tsx @@ -1,14 +1,14 @@ +import '@blocksuite/editor/themes/affine.css'; import './index.css'; import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; -import { serve } from 'waku/client'; +import { Router } from 'waku/router/client'; -const App = serve('App'); -const rootElement = ( +const root = createRoot(document.getElementById('root') as HTMLElement); + +root.render( - + ); - -createRoot(document.getElementById('root') as HTMLElement).render(rootElement); diff --git a/apps/docs/src/pages/binary b/apps/docs/src/pages/binary new file mode 100644 index 0000000000..3d63fdf2b7 Binary files /dev/null and b/apps/docs/src/pages/binary differ diff --git a/apps/docs/src/server-fns.ts b/apps/docs/src/server-fns.ts new file mode 100644 index 0000000000..2daf3708ea --- /dev/null +++ b/apps/docs/src/server-fns.ts @@ -0,0 +1,10 @@ +'use server'; +import { writeFile } from 'node:fs/promises'; +import { fileURLToPath } from 'node:url'; + +const __dirname = fileURLToPath(new URL('.', import.meta.url)); + +export async function saveFile(binary: any) { + const data = new Uint8Array(binary); + await writeFile(__dirname + 'pages' + '/binary', data); +}