Merge pull request #297 from toeverything/feat/shapes-bindings

Feat/shapes bindings
This commit is contained in:
DarkSky
2022-08-19 23:42:15 +08:00
committed by GitHub
11 changed files with 246 additions and 50 deletions
+3 -2
View File
@@ -1,8 +1,9 @@
FROM node:16-alpine as builder
WORKDIR /app
COPY . .
RUN apk add g++ make python3 git libpng-dev
RUN npm i -g pnpm@7 && pnpm i --frozen-lockfile --store=node_modules/.pnpm-store && pnpm run build:local --skip-nx-cache
# RUN apk add g++ make python3 git libpng-dev
RUN apk add git
RUN npm i -g pnpm@7 && pnpm i --frozen-lockfile --store=node_modules/.pnpm-store --filter "!ligo-virgo-e2e" --filter "!keck" --filter "!venus" && pnpm run build:local --skip-nx-cache
FROM node:16-alpine as relocate
WORKDIR /app
+3 -2
View File
@@ -1,8 +1,9 @@
FROM node:16-alpine as builder
WORKDIR /app
COPY . .
RUN apk add g++ make python3 git libpng-dev
RUN npm i -g pnpm@7 && pnpm i --frozen-lockfile --store=node_modules/.pnpm-store && pnpm run build
# RUN apk add g++ make python3 git libpng-dev
RUN apk add git
RUN npm i -g pnpm@7 && pnpm i --frozen-lockfile --store=node_modules/.pnpm-store --filter "!ligo-virgo-e2e" --filter "!keck" --filter "!venus" && pnpm run build
FROM node:16-alpine as relocate
WORKDIR /app
+45 -6
View File
@@ -6,8 +6,8 @@ import { deepCopy, TldrawApp } from '@toeverything/components/board-state';
import { tools } from '@toeverything/components/board-tools';
import { TDShapeType } from '@toeverything/components/board-types';
import {
RecastBlockProvider,
getClipDataOfBlocksById,
RecastBlockProvider,
} from '@toeverything/components/editor-core';
import { services } from '@toeverything/datasource/db-service';
import { AsyncBlock, BlockEditor } from '@toeverything/framework/virgo';
@@ -25,7 +25,6 @@ const AffineBoard = ({
editor,
}: AffineBoardProps & { editor: BlockEditor }) => {
const [app, set_app] = useState<TldrawApp>();
const [document] = useState(() => {
return {
...deepCopy(TldrawApp.default_document),
@@ -52,10 +51,10 @@ const AffineBoard = ({
};
});
const shapes = useShapes(workspace, rootBlockId);
const { shapes, bindings } = useShapes(workspace, rootBlockId);
useEffect(() => {
if (app) {
app.replacePageContent(shapes || {}, {}, {});
app.replacePageContent(shapes || {}, bindings, {});
}
}, [app, shapes]);
@@ -69,6 +68,7 @@ const AffineBoard = ({
onMount(app) {
set_app(app);
},
async onCopy(e, groupIds) {
const clip = await getClipDataOfBlocksById(
editor,
@@ -80,7 +80,7 @@ const AffineBoard = ({
clip.getData()
);
},
onChangePage(app, shapes, bindings, assets) {
async onChangePage(app, shapes, bindings, assets) {
Promise.all(
Object.entries(shapes).map(async ([id, shape]) => {
if (shape === undefined) {
@@ -109,7 +109,20 @@ const AffineBoard = ({
});
}
shape.affineId = block.id;
return services.api.editorBlock.update({
Object.keys(bindings).forEach(bilingKey => {
if (
bindings[bilingKey]?.fromId === shape.id
) {
bindings[bilingKey].fromId = block.id;
}
if (
bindings[bilingKey]?.toId === shape.id
) {
bindings[bilingKey].toId = block.id;
}
});
return await services.api.editorBlock.update({
workspace: shape.workspace,
id: block.id,
properties: {
@@ -121,6 +134,32 @@ const AffineBoard = ({
}
})
);
let pageBindingsString = (
await services.api.editorBlock.get({
workspace: workspace,
ids: [rootBlockId],
})
)?.[0].properties.bindings?.value;
console.log(123123123);
let pageBindings = JSON.parse(pageBindingsString ?? '{}');
console.log(pageBindings, 3333, bindings);
Object.keys(bindings).forEach(bindingsKey => {
console.log(345345345345345);
if (!bindings[bindingsKey]) {
delete pageBindings[bindingsKey];
} else {
Object.assign(pageBindings, bindings);
}
});
services.api.editorBlock.update({
workspace: workspace,
id: rootBlockId,
properties: {
bindings: {
value: JSON.stringify(pageBindings),
},
},
});
},
}}
/>
@@ -5,32 +5,56 @@ import { services } from '@toeverything/datasource/db-service';
import { usePageClientWidth } from '@toeverything/datasource/state';
import { useEffect, useState } from 'react';
const getBindings = (workspace: string, rootBlockId: string) => {
return services.api.editorBlock
.get({
workspace: workspace,
ids: [rootBlockId],
})
.then(blcoks => {
return blcoks[0].properties.bindings?.value;
});
};
export const useShapes = (workspace: string, rootBlockId: string) => {
const { pageClientWidth } = usePageClientWidth();
// page padding left and right total 300px
const editorShapeInitSize = pageClientWidth - 300;
const [blocks, setBlocks] = useState<ReturnEditorBlock[]>();
const [blocks, setBlocks] = useState<{
shapes: [ReturnEditorBlock[]];
bindings: string;
}>();
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);
Promise.all([
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;
})
);
return shapes;
}),
]).then(shapes => {
getBindings(workspace, rootBlockId).then(bindings => {
setBlocks({
shapes,
bindings: bindings,
});
});
});
let unobserve: () => void;
services.api.editorBlock
.observe({ workspace, id: rootBlockId }, async blockData => {
const shapes = await Promise.all(
Promise.all(
(blockData?.children || []).map(async childId => {
const childBlock = (
await services.api.editorBlock.get({
@@ -40,8 +64,14 @@ export const useShapes = (workspace: string, rootBlockId: string) => {
)?.[0];
return childBlock;
})
);
setBlocks(shapes);
).then(shapes => {
getBindings(workspace, rootBlockId).then(bindings => {
setBlocks({
shapes: [shapes],
bindings: bindings,
});
});
});
})
.then(cb => {
unobserve = cb;
@@ -53,8 +83,7 @@ export const useShapes = (workspace: string, rootBlockId: string) => {
}, [workspace, rootBlockId]);
let groupCount = 0;
return blocks?.reduce((acc, block) => {
let blocksShapes = blocks?.shapes[0]?.reduce((acc, block) => {
const shapeProps = block.properties.shapeProps?.value
? JSON.parse(block.properties.shapeProps.value)
: {};
@@ -75,4 +104,8 @@ export const useShapes = (workspace: string, rootBlockId: string) => {
return acc;
}, {} as Record<string, TDShape>);
return {
shapes: blocksShapes,
bindings: JSON.parse(blocks?.bindings ?? '{}'),
};
};
+9 -10
View File
@@ -13,6 +13,8 @@ import {
TDStatus,
} from '@toeverything/components/board-types';
import { styled } from '@toeverything/components/ui';
// import { FocusButton } from '~components/FocusButton';
import { usePageClientWidth } from '@toeverything/datasource/state';
import {
memo,
useEffect,
@@ -22,22 +24,20 @@ import {
useState,
type RefObject,
} from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { CommandPanel } from './components/command-panel';
// import { TopPanel } from '~components/TopPanel';
import { ContextMenu } from './components/context-menu';
import { ErrorFallback } from './components/error-fallback';
import { Loading } from './components/loading';
import { ToolsPanel } from './components/tools-panel';
import { ZoomBar } from './components/zoom-bar';
import {
TldrawContext,
useKeyboardShortcuts,
useStylesheet,
useTldrawApp,
} from './hooks';
// import { TopPanel } from '~components/TopPanel';
import { ContextMenu } from './components/context-menu';
// import { FocusButton } from '~components/FocusButton';
import { usePageClientWidth } from '@toeverything/datasource/state';
import { ErrorBoundary } from 'react-error-boundary';
import { CommandPanel } from './components/command-panel';
import { ErrorFallback } from './components/error-fallback';
import { Loading } from './components/loading';
import { ZoomBar } from './components/zoom-bar';
export interface TldrawProps extends TldrawAppCtorProps {
/**
@@ -295,7 +295,6 @@ const InnerTldraw = memo(function InnerTldraw({
const pageState = document.pageStates[page.id];
const assets = document.assets;
const { selectedIds } = pageState;
const isHideBoundsShape =
selectedIds.length === 1 &&
page.shapes[selectedIds[0]] &&
@@ -0,0 +1,78 @@
import type { TldrawApp } from '@toeverything/components/board-state';
import type {
ArrowBinding,
TDShape,
} from '@toeverything/components/board-types';
import { ConnectorIcon } from '@toeverything/components/icons';
import { IconButton, Popover, Tooltip } from '@toeverything/components/ui';
import { useEffect, useState } from 'react';
import { ListItemContainer, ListItemTitle } from './FontSizeConfig';
interface GroupAndUnGroupProps {
app: TldrawApp;
shapes: TDShape[];
}
export const ArrowTo = ({ app, shapes }: GroupAndUnGroupProps) => {
const [arrowToArr, setarrowToArr] = useState([]);
useEffect(() => {
let allShape = app.shapes;
let bindings = app.page.bindings;
let activeShape = shapes[0];
let toNextShapBindings: ArrowBinding[] = [];
let bindingId = '';
Object.keys(bindings).forEach(key => {
if (bindings[key].toId === activeShape.id) {
bindingId = bindings[key].fromId;
}
});
Object.keys(bindings).forEach(key => {
if (bindings[key].fromId === bindingId) {
toNextShapBindings.push(bindings[key]);
}
});
let ArrowToArr: TDShape[] = [];
toNextShapBindings.forEach(binding => {
if (binding.toId !== activeShape.id) {
allShape.forEach(item => {
console.log(item);
if (item.id === binding.toId) {
ArrowToArr.push(item);
}
});
}
});
setarrowToArr(ArrowToArr);
return () => {};
}, [app.page.bindings, app.shapes]);
const jumpToNextShap = (shape: TDShape) => {
app.zoomToShapes([shape]);
};
return (
<Popover
trigger="hover"
placement="bottom-start"
content={
<div>
{arrowToArr.map((arrow: any) => {
return (
<ListItemContainer
key={arrow.id}
onClick={() => jumpToNextShap(arrow)}
>
<ListItemTitle>{arrow.name}</ListItemTitle>
</ListItemContainer>
);
})}
</div>
}
>
<Tooltip content="Font Size" placement="top-start">
<IconButton>
<ConnectorIcon></ConnectorIcon>
</IconButton>
</Tooltip>
</Popover>
);
};
@@ -2,6 +2,7 @@ import { TLDR, TldrawApp } from '@toeverything/components/board-state';
import { Divider, Popover, styled } from '@toeverything/components/ui';
import { Fragment } from 'react';
import { AlignOperation } from './AlignOperation';
import { ArrowTo } from './ArrowTo';
import { BorderColorConfig } from './BorderColorConfig';
import { DeleteShapes } from './DeleteOperation';
import { FillColorConfig } from './FillColorConfig';
@@ -106,6 +107,12 @@ export const CommandPanel = ({ app }: { app: TldrawApp }) => {
shapes={config.deleteShapes.selectedShapes}
></AlignOperation>
) : null,
toNextShap: (
<ArrowTo
app={app}
shapes={config.deleteShapes.selectedShapes}
></ArrowTo>
),
};
const nodes = Object.entries(configNodes).filter(([key, node]) => !!node);
@@ -86,7 +86,7 @@ export const FontSizeConfig = ({ app, shapes }: FontSizeConfigProps) => {
);
};
const ListItemContainer = styled('div')(({ theme }) => ({
export const ListItemContainer = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
@@ -100,7 +100,7 @@ const ListItemContainer = styled('div')(({ theme }) => ({
},
}));
const ListItemTitle = styled('span')(({ theme }) => ({
export const ListItemTitle = styled('span')(({ theme }) => ({
marginLeft: '12px',
color: theme.affine.palette.primaryText,
}));
@@ -444,7 +444,6 @@ export class TldrawApp extends StateManager<TDSnapshot> {
if (visitedShapes.has(fromShape)) {
return;
}
// We only need to update the binding's "from" shape (an arrow)
const fromDelta = TLDR.update_arrow_bindings(
page,
@@ -860,7 +859,6 @@ export class TldrawApp extends StateManager<TDSnapshot> {
if (!page.bindings[binding.id]) {
return;
}
const fromShape = page.shapes[binding.fromId] as ArrowShape;
if (visitedShapes.has(fromShape)) {
@@ -868,6 +866,7 @@ export class TldrawApp extends StateManager<TDSnapshot> {
}
// We only need to update the binding's "from" shape (an arrow)
const fromDelta = TLDR.update_arrow_bindings(page, fromShape);
visitedShapes.add(fromShape);
@@ -53,6 +53,7 @@ export type DefaultColumnsValue = {
filterConstraint: FilterConstraint;
filterWeakSqlConstraint: string;
sorterConstraint: SorterConstraint;
bindings: StringColumnValue;
};
export const DEFAULT_COLUMN_KEYS = {
+43 -5
View File
@@ -288,7 +288,7 @@ importers:
'@tldraw/intersect': ^1.7.1
'@tldraw/vec': ^1.7.0
dependencies:
'@tldraw/core': 1.14.1_mobx@6.6.1
'@tldraw/core': 1.14.1
'@tldraw/intersect': 1.7.1
'@tldraw/vec': 1.7.1
@@ -299,7 +299,7 @@ importers:
'@tldraw/vec': ^1.7.0
perfect-freehand: ^1.0.16
dependencies:
'@tldraw/core': 1.14.1_mobx@6.6.1
'@tldraw/core': 1.14.1
'@tldraw/intersect': 1.7.1
'@tldraw/vec': 1.7.1
perfect-freehand: 1.1.0
@@ -312,7 +312,7 @@ importers:
idb-keyval: ^6.2.0
zustand: ^3.7.2
dependencies:
'@tldraw/core': 1.14.1_mobx@6.6.1
'@tldraw/core': 1.14.1
'@tldraw/intersect': 1.7.1
'@tldraw/vec': 1.7.1
idb-keyval: 6.2.0
@@ -324,7 +324,7 @@ importers:
'@tldraw/intersect': ^1.7.1
'@tldraw/vec': ^1.7.0
dependencies:
'@tldraw/core': 1.14.1_mobx@6.6.1
'@tldraw/core': 1.14.1
'@tldraw/intersect': 1.7.1
'@tldraw/vec': 1.7.1
@@ -334,7 +334,7 @@ importers:
'@tldraw/intersect': ^1.7.1
'@tldraw/vec': ^1.7.0
dependencies:
'@tldraw/core': 1.14.1_mobx@6.6.1
'@tldraw/core': 1.14.1
'@tldraw/intersect': 1.7.1
'@tldraw/vec': 1.7.1
@@ -6200,6 +6200,28 @@ packages:
react-dom: 18.2.0_react@18.2.0
dev: true
/@tldraw/core/1.14.1:
resolution: {integrity: sha512-FAiX/TD/tl5eMvTk0IHhFUSmldCe/UTTOnLL5aWQHqhicF/iTP5m3H12L6kyjN60yfssN8U9g4E/7y70TY7JxA==}
peerDependencies:
react: '>=16.8'
react-dom: '>=16.8'
peerDependenciesMeta:
react:
optional: true
react-dom:
optional: true
dependencies:
'@tldraw/intersect': 1.7.1
'@tldraw/vec': 1.7.1
'@use-gesture/react': 10.2.16
mobx-react-lite: 3.4.0
perfect-freehand: 1.1.0
resize-observer-polyfill: 1.5.1
transitivePeerDependencies:
- mobx
- react-native
dev: false
/@tldraw/core/1.14.1_mobx@6.6.1:
resolution: {integrity: sha512-FAiX/TD/tl5eMvTk0IHhFUSmldCe/UTTOnLL5aWQHqhicF/iTP5m3H12L6kyjN60yfssN8U9g4E/7y70TY7JxA==}
peerDependencies:
@@ -13810,6 +13832,22 @@ packages:
hasBin: true
dev: true
/mobx-react-lite/3.4.0:
resolution: {integrity: sha512-bRuZp3C0itgLKHu/VNxi66DN/XVkQG7xtoBVWxpvC5FhAqbOCP21+nPhULjnzEqd7xBMybp6KwytdUpZKEgpIQ==}
peerDependencies:
mobx: ^6.1.0
react: ^16.8.0 || ^17 || ^18
react-dom: '*'
react-native: '*'
peerDependenciesMeta:
react:
optional: true
react-dom:
optional: true
react-native:
optional: true
dev: false
/mobx-react-lite/3.4.0_mobx@6.6.1:
resolution: {integrity: sha512-bRuZp3C0itgLKHu/VNxi66DN/XVkQG7xtoBVWxpvC5FhAqbOCP21+nPhULjnzEqd7xBMybp6KwytdUpZKEgpIQ==}
peerDependencies: