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);
+}