init: the first public commit for AFFiNE

This commit is contained in:
DarkSky
2022-07-22 15:49:21 +08:00
commit e3e3741393
1451 changed files with 108124 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
{
"presets": [
[
"@nrwl/react/babel",
{
"runtime": "automatic",
"useBuiltIns": "usage"
}
]
],
"plugins": []
}
@@ -0,0 +1,18 @@
{
"extends": ["plugin:@nrwl/nx/react", "../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
+7
View File
@@ -0,0 +1,7 @@
# components-affine-board
This library was generated with [Nx](https://nx.dev).
## Running unit tests
Run `nx test components-affine-board` to execute the unit tests via [Jest](https://jestjs.io).
@@ -0,0 +1,10 @@
/* eslint-disable */
export default {
displayName: 'components-affine-board',
preset: '../../../jest.preset.js',
transform: {
'^.+\\.[tj]sx?$': 'babel-jest',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../../coverage/libs/components/affine-board',
};
@@ -0,0 +1,5 @@
{
"name": "@toeverything/components/affine-board",
"version": "0.0.1",
"license": "MIT"
}
+45
View File
@@ -0,0 +1,45 @@
{
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/components/affine-board/src",
"projectType": "library",
"tags": ["components"],
"targets": {
"build": {
"executor": "@nrwl/web:rollup",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/libs/components/affine-board",
"tsConfig": "libs/components/affine-board/tsconfig.lib.json",
"project": "libs/components/affine-board/package.json",
"entryFile": "libs/components/affine-board/src/index.ts",
"external": ["react/jsx-runtime"],
"rollupConfig": "libs/rollup.config.cjs",
"compiler": "babel",
"assets": [
{
"glob": "libs/components/affine-board/README.md",
"input": ".",
"output": "."
}
]
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": [
"libs/components/affine-board/**/*.{ts,tsx,js,jsx}"
]
}
},
"test": {
"executor": "@nrwl/jest:jest",
"outputs": ["coverage/libs/components/affine-board"],
"options": {
"jestConfig": "libs/components/affine-board/jest.config.ts",
"passWithNoTests": true
}
}
}
}
+136
View File
@@ -0,0 +1,136 @@
import { useEffect, useState } from 'react';
import { Tldraw } from '@toeverything/components/board-draw';
import { tools } from '@toeverything/components/board-tools';
import { getSession } from '@toeverything/components/board-sessions';
import * as commands from '@toeverything/components/board-commands';
import { TldrawApp, deepCopy } from '@toeverything/components/board-state';
import { TDShapeType } from '@toeverything/components/board-types';
import { services } from '@toeverything/datasource/db-service';
import { useShapes } from './hooks';
import { RecastBlockProvider } from '@toeverything/components/editor-core';
import { createEditor } from '@toeverything/components/affine-editor';
import { AsyncBlock, BlockEditor } from '@toeverything/framework/virgo';
interface AffineBoardProps {
workspace: string;
rootBlockId: string;
}
const AffineBoard = ({ workspace, rootBlockId }: AffineBoardProps) => {
const [app, set_app] = useState<TldrawApp>();
const [document] = useState(() => {
return {
...deepCopy(TldrawApp.default_document),
id: workspace,
pages: {
[rootBlockId]: {
id: rootBlockId,
name: `Page ${rootBlockId}`,
childIndex: 1,
shapes: {},
bindings: {},
},
},
pageStates: {
[rootBlockId]: {
id: rootBlockId,
camera: {
point: [0, 0],
zoom: 1,
},
selectedIds: [],
},
},
};
});
const shapes = useShapes(workspace, rootBlockId);
useEffect(() => {
if (app) {
app.replacePageContent(shapes || {}, {}, {});
}
}, [app, shapes]);
return (
<Tldraw
document={document}
commands={commands}
tools={tools}
getSession={getSession}
callbacks={{
onMount(app) {
set_app(app);
},
onChangePage(app, shapes, bindings, assets) {
Promise.all(
Object.entries(shapes).map(async ([id, shape]) => {
if (shape === undefined) {
return services.api.editorBlock.delete({
workspace: workspace,
id,
});
} else {
let block = (
await services.api.editorBlock.get({
workspace: workspace,
ids: [shape.affineId],
})
)?.[0];
if (!block) {
block =
await services.api.editorBlock.create({
workspace: workspace,
parentId:
app.appState.currentPageId,
type:
shape.type ===
TDShapeType.Editor
? 'group'
: 'shape',
});
}
shape.affineId = block.id;
return services.api.editorBlock.update({
workspace: shape.workspace,
id: block.id,
properties: {
shapeProps: {
value: JSON.stringify(shape),
},
},
});
}
})
);
},
}}
/>
);
};
export const AffineBoardWitchContext = ({
workspace,
rootBlockId,
}: AffineBoardProps) => {
const [editor, set_editor] = useState<BlockEditor>();
useEffect(() => {
const inner_editor = createEditor(workspace, true);
set_editor(inner_editor);
return () => {
inner_editor.dispose();
};
}, [workspace]);
const [page, set_page] = useState<AsyncBlock>();
useEffect(() => {
editor?.getBlockById(rootBlockId).then(block => {
set_page(block);
});
}, [editor, rootBlockId]);
return page ? (
<RecastBlockProvider block={page}>
<AffineBoard workspace={workspace} rootBlockId={rootBlockId} />
</RecastBlockProvider>
) : null;
};
@@ -0,0 +1 @@
export * from './use-shapes';
@@ -0,0 +1,73 @@
import { useEffect, useState } from 'react';
import { services } from '@toeverything/datasource/db-service';
import type { ReturnEditorBlock } from '@toeverything/datasource/db-service';
import type { TDShape } from '@toeverything/components/board-types';
import { Editor } from '@toeverything/components/board-shapes';
export const useShapes = (workspace: string, rootBlockId: string) => {
const [blocks, setBlocks] = useState<ReturnEditorBlock[]>();
useEffect(() => {
services.api.editorBlock
.get({ workspace, ids: [rootBlockId] })
.then(async blockData => {
const shapes = await Promise.all(
(blockData?.[0]?.children || []).map(async childId => {
const childBlock = (
await services.api.editorBlock.get({
workspace,
ids: [childId],
})
)?.[0];
return childBlock;
})
);
setBlocks(shapes);
});
let unobserve: () => void;
services.api.editorBlock
.observe({ workspace, id: rootBlockId }, async blockData => {
const shapes = await Promise.all(
(blockData?.children || []).map(async childId => {
const childBlock = (
await services.api.editorBlock.get({
workspace,
ids: [childId],
})
)?.[0];
return childBlock;
})
);
setBlocks(shapes);
})
.then(cb => {
unobserve = cb;
});
return () => {
unobserve?.();
};
}, [workspace, rootBlockId]);
let groupCount = 0;
return blocks?.reduce((acc, block) => {
const shapeProps = block.properties.shapeProps?.value
? JSON.parse(block.properties.shapeProps.value)
: {};
if (block.type === 'shape') {
acc[block.id] = { ...shapeProps, id: block.id };
} else {
acc[block.id] = Editor.getShape({
point: [groupCount * 740, 200],
id: block.id,
...shapeProps,
affineId: shapeProps.affineId ?? block.id,
workspace: block.workspace,
rootBlockId: block.id,
});
groupCount = groupCount + 1;
}
return acc;
}, {} as Record<string, TDShape>);
};
@@ -0,0 +1 @@
export { AffineBoardWitchContext as AffineBoard } from './Board';
@@ -0,0 +1,25 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
@@ -0,0 +1,23 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"types": ["node"]
},
"files": [
"../../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../../node_modules/@nrwl/react/typings/image.d.ts"
],
"exclude": [
"jest.config.ts",
"**/*.spec.ts",
"**/*.test.ts",
"**/*.spec.tsx",
"**/*.test.tsx",
"**/*.spec.js",
"**/*.test.js",
"**/*.spec.jsx",
"**/*.test.jsx"
],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
}
@@ -0,0 +1,20 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": [
"jest.config.ts",
"**/*.test.ts",
"**/*.spec.ts",
"**/*.test.tsx",
"**/*.spec.tsx",
"**/*.test.js",
"**/*.spec.js",
"**/*.test.jsx",
"**/*.spec.jsx",
"**/*.d.ts"
]
}