@@ -203,10 +203,10 @@ module.exports = function (webpackConfig) {
|
|||||||
new BundleAnalyzerPlugin({ analyzerMode: 'static' }),
|
new BundleAnalyzerPlugin({ analyzerMode: 'static' }),
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
|
|
||||||
// Workaround for webpack infinite recompile errors
|
|
||||||
config.watchOptions = {
|
config.watchOptions = {
|
||||||
// followSymlinks: false,
|
// followSymlinks: false,
|
||||||
ignored: ['**/*.css'],
|
// Ignore css to workaround webpack infinite recompile errors
|
||||||
|
ignored: ['**/node_modules', '**/*.css'],
|
||||||
};
|
};
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
|
|||||||
@@ -80,7 +80,8 @@ const AffineBoard = ({
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
async onChangePage(app, shapes, bindings, assets) {
|
async onChangePage(app, shapes, bindings, assets) {
|
||||||
Promise.all(
|
await services.api.editorBlock.suspend(workspace, true);
|
||||||
|
await Promise.all(
|
||||||
Object.entries(shapes).map(async ([id, shape]) => {
|
Object.entries(shapes).map(async ([id, shape]) => {
|
||||||
if (shape === undefined) {
|
if (shape === undefined) {
|
||||||
return services.api.editorBlock.delete({
|
return services.api.editorBlock.delete({
|
||||||
@@ -120,6 +121,7 @@ const AffineBoard = ({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
await services.api.editorBlock.suspend(workspace, false);
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Editor } from '@toeverything/components/board-shapes';
|
import { defaultStyle, Editor } from '@toeverything/components/board-shapes';
|
||||||
import type { TDShape } from '@toeverything/components/board-types';
|
import type { TDShape } from '@toeverything/components/board-types';
|
||||||
import type { ReturnEditorBlock } from '@toeverything/datasource/db-service';
|
import type { ReturnEditorBlock } from '@toeverything/datasource/db-service';
|
||||||
import { services } from '@toeverything/datasource/db-service';
|
import { services } from '@toeverything/datasource/db-service';
|
||||||
@@ -12,7 +12,35 @@ export const useShapes = (workspace: string, rootBlockId: string) => {
|
|||||||
const [blocks, setBlocks] = useState<{
|
const [blocks, setBlocks] = useState<{
|
||||||
shapes: [ReturnEditorBlock[]];
|
shapes: [ReturnEditorBlock[]];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const unobservesMap = new Map();
|
||||||
|
const observeChild = async (childId: string) => {
|
||||||
|
unobservesMap.set(
|
||||||
|
childId,
|
||||||
|
await services.api.editorBlock.observe(
|
||||||
|
{ workspace, id: childId },
|
||||||
|
blockData => {
|
||||||
|
setBlocks(data => {
|
||||||
|
const blockShapes = data?.shapes?.[0];
|
||||||
|
const idx =
|
||||||
|
blockShapes.findIndex(
|
||||||
|
s => s.id === blockData.id
|
||||||
|
) || -1;
|
||||||
|
const newBlockShapes = [...blockShapes];
|
||||||
|
if (idx > -1) {
|
||||||
|
newBlockShapes[idx] = blockData;
|
||||||
|
} else {
|
||||||
|
newBlockShapes.push(blockData);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
shapes: [newBlockShapes],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
Promise.all([
|
Promise.all([
|
||||||
services.api.editorBlock
|
services.api.editorBlock
|
||||||
.get({ workspace, ids: [rootBlockId] })
|
.get({ workspace, ids: [rootBlockId] })
|
||||||
@@ -25,6 +53,7 @@ export const useShapes = (workspace: string, rootBlockId: string) => {
|
|||||||
ids: [childId],
|
ids: [childId],
|
||||||
})
|
})
|
||||||
)?.[0];
|
)?.[0];
|
||||||
|
observeChild(childBlock.id);
|
||||||
return childBlock;
|
return childBlock;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -47,6 +76,9 @@ export const useShapes = (workspace: string, rootBlockId: string) => {
|
|||||||
ids: [childId],
|
ids: [childId],
|
||||||
})
|
})
|
||||||
)?.[0];
|
)?.[0];
|
||||||
|
if (!unobservesMap.has(childBlock.id)) {
|
||||||
|
observeChild(childBlock.id);
|
||||||
|
}
|
||||||
return childBlock;
|
return childBlock;
|
||||||
})
|
})
|
||||||
).then(shapes => {
|
).then(shapes => {
|
||||||
@@ -65,17 +97,27 @@ export const useShapes = (workspace: string, rootBlockId: string) => {
|
|||||||
}, [workspace, rootBlockId]);
|
}, [workspace, rootBlockId]);
|
||||||
|
|
||||||
let groupCount = 0;
|
let groupCount = 0;
|
||||||
let blocksShapes = blocks?.shapes[0]?.reduce((acc, block) => {
|
const blocksShapes = blocks?.shapes[0]?.reduce((acc, block) => {
|
||||||
const shapeProps = block.properties.shapeProps?.value
|
const shapeProps = block.properties.shapeProps?.value
|
||||||
? JSON.parse(block.properties.shapeProps.value)
|
? JSON.parse(block.properties.shapeProps.value)
|
||||||
: {};
|
: {};
|
||||||
if (block.type === 'shape') {
|
if (block.type === 'shape') {
|
||||||
acc[block.id] = { ...shapeProps, id: block.id };
|
acc[block.id] = {
|
||||||
|
type: 'rectangle',
|
||||||
|
size: [0, 0],
|
||||||
|
point: [0, 0],
|
||||||
|
parentId: rootBlockId,
|
||||||
|
...shapeProps,
|
||||||
|
id: block.id,
|
||||||
|
style: { ...defaultStyle },
|
||||||
|
workspace,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
acc[block.id] = Editor.getShape({
|
acc[block.id] = Editor.getShape({
|
||||||
point: [groupCount * editorShapeInitSize + 200, 200],
|
point: [groupCount * editorShapeInitSize + 200, 200],
|
||||||
id: block.id,
|
id: block.id,
|
||||||
size: [editorShapeInitSize, 200],
|
size: [editorShapeInitSize, 200],
|
||||||
|
parentId: rootBlockId,
|
||||||
...shapeProps,
|
...shapeProps,
|
||||||
affineId: shapeProps.affineId ?? block.id,
|
affineId: shapeProps.affineId ?? block.id,
|
||||||
workspace: block.workspace,
|
workspace: block.workspace,
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ export abstract class ServiceBaseClass {
|
|||||||
name: string,
|
name: string,
|
||||||
callback: (meta: Map<string, any>) => void
|
callback: (meta: Map<string, any>) => void
|
||||||
) {
|
) {
|
||||||
const db = await this.database.getDatabase(workspace);
|
// const db = await this.database.getDatabase(workspace);
|
||||||
db.history.onPush(name, callback);
|
// db.history.onPush(name, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onHistoryRevoke(
|
async onHistoryRevoke(
|
||||||
@@ -44,8 +44,8 @@ export abstract class ServiceBaseClass {
|
|||||||
name: string,
|
name: string,
|
||||||
callback: (meta: Map<string, any>) => void
|
callback: (meta: Map<string, any>) => void
|
||||||
) {
|
) {
|
||||||
const db = await this.database.getDatabase(workspace);
|
// const db = await this.database.getDatabase(workspace);
|
||||||
db.history.onPop(name, callback);
|
// db.history.onPop(name, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
async undo(workspace: string) {
|
async undo(workspace: string) {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ async function _getCurrentToken() {
|
|||||||
|
|
||||||
const _enabled = {
|
const _enabled = {
|
||||||
demo: [],
|
demo: [],
|
||||||
AFFiNE: process.env['NX_KECK'] ? ['idb', 'keck'] : ['idb'],
|
AFFiNE: process.env['NX_KECK'] ? ['keck'] : ['idb'],
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
async function _getBlockDatabase(
|
async function _getBlockDatabase(
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
// To overwrite this, please overwrite download.ts
|
// To overwrite this, please overwrite download.ts
|
||||||
import en from './en.json';
|
import en from './en.json';
|
||||||
import zh_Hans from './zh-Hans.json';
|
import zh_Hans from './zh-Hans.json';
|
||||||
|
import zh_Hant from './zh-Hant.json';
|
||||||
|
import sr from './sr.json';
|
||||||
|
|
||||||
export const LOCALES = [
|
export const LOCALES = [
|
||||||
{
|
{
|
||||||
@@ -25,4 +27,24 @@ export const LOCALES = [
|
|||||||
completeRate: 1,
|
completeRate: 1,
|
||||||
res: zh_Hans,
|
res: zh_Hans,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 1000016012,
|
||||||
|
name: 'Traditional Chinese',
|
||||||
|
tag: 'zh-Hant',
|
||||||
|
originalName: '繁體中文',
|
||||||
|
flagEmoji: '🇭🇰',
|
||||||
|
base: false,
|
||||||
|
completeRate: 1,
|
||||||
|
res: zh_Hant,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1000034005,
|
||||||
|
name: 'Serbian',
|
||||||
|
tag: 'sr',
|
||||||
|
originalName: 'српски',
|
||||||
|
flagEmoji: '🇷🇸',
|
||||||
|
base: false,
|
||||||
|
completeRate: 0.9166666666666666,
|
||||||
|
res: sr,
|
||||||
|
},
|
||||||
] as const;
|
] as const;
|
||||||
|
|||||||
27
libs/datasource/i18n/src/resources/sr.json
Normal file
27
libs/datasource/i18n/src/resources/sr.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.": "",
|
||||||
|
"Clear Workspace": "Očisti radni prostor",
|
||||||
|
"ComingSoon": "Podešavanja za izgled dolaze",
|
||||||
|
"Comment": "Komentar",
|
||||||
|
"Copy Page Link": "Kopiraj link stranice",
|
||||||
|
"Delete": "Obriši",
|
||||||
|
"Duplicate Page": "Dupliraj stranicu",
|
||||||
|
"Export As HTML": "Izvezi kao HTML",
|
||||||
|
"Export As Markdown": "Izvezi kao Markdown",
|
||||||
|
"Export As PDF (Unsupported)": "Izvezi kao PDF (nepodržano)",
|
||||||
|
"Export Workspace": "Izvezi radnu površinu",
|
||||||
|
"Import Workspace": "Poboljšaj radnu površinu",
|
||||||
|
"Language": "Jezik",
|
||||||
|
"Last edited by": "Zadnju promenu uradio {{ime}}",
|
||||||
|
"Layout": "Izgled",
|
||||||
|
"Logout": "Odjava",
|
||||||
|
"Settings": "Podešavanja",
|
||||||
|
"Share": "Podeli",
|
||||||
|
"Sync to Disk": "Sinhroniziraj sa diskom",
|
||||||
|
"Turn into": "Promeni u",
|
||||||
|
"WarningTips": {
|
||||||
|
"DoNotStore": "AFFiNE je u stanju aktivnog razvoja i trenutna verzija je NESTABILNA. Molimo vas, NEMOJTE čuvati informacije ili podatke.",
|
||||||
|
"IsNotLocalWorkspace": "Dobrodošli u AFFiNE demo. Da bi započeli proces čuvanja promena možete kliknuti SINHRONIZUJ SA DISKOM.",
|
||||||
|
"IsNotfsApiSupported": "Dobrodošli u AFFiNE demo. Da bi započeli proces čuvanja promena možete SINHRONIZOVATI NA DISK sa poslednjom verzijom pretraživača tipa Chromium, kao što su Chrome/Edge."
|
||||||
|
}
|
||||||
|
}
|
||||||
29
libs/datasource/i18n/src/resources/zh-Hant.json
Normal file
29
libs/datasource/i18n/src/resources/zh-Hant.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.": "",
|
||||||
|
"Add A Below Block": "在下方新添塊",
|
||||||
|
"Clear Workspace": "清空工作區",
|
||||||
|
"ComingSoon": "自定義佈局功能即將與您見面",
|
||||||
|
"Comment": "評論",
|
||||||
|
"Copy Page Link": "拷貝頁面鏈接",
|
||||||
|
"Delete": "刪除",
|
||||||
|
"Divide Here As A New Group": "從此地劃分成新組",
|
||||||
|
"Duplicate Page": "複製界面",
|
||||||
|
"Export As HTML": "導出 HTML",
|
||||||
|
"Export As Markdown": "以 Markdown 導出",
|
||||||
|
"Export As PDF (Unsupported)": "導出為 PDF(即將可用)",
|
||||||
|
"Export Workspace": "導出 Workspace",
|
||||||
|
"Import Workspace": "導入 Workspace",
|
||||||
|
"Language": "語言",
|
||||||
|
"Last edited by": "最後編輯者為 {{name}}",
|
||||||
|
"Layout": "佈局",
|
||||||
|
"Logout": "退出登錄",
|
||||||
|
"Settings": "設置",
|
||||||
|
"Share": "分享",
|
||||||
|
"Sync to Disk": "同步到磁盤",
|
||||||
|
"Turn into": "轉換為",
|
||||||
|
"WarningTips": {
|
||||||
|
"DoNotStore": "我們正在積極開發 AFFiNE,目前版本尚不穩定,請避免存儲信息或數據。",
|
||||||
|
"IsNotLocalWorkspace": "歡迎來到 AFFiNE 演示界面。您可以通過「同步到磁盤」來保存更改。",
|
||||||
|
"IsNotfsApiSupported": "歡迎進入AFFINE演示!使用最新版本的基於 Chromium 內核的瀏覽器如Chrome/Edge,您可以通過「同步到磁盤」來保存更改"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,6 +65,26 @@ export const registerWebsocket = (
|
|||||||
|
|
||||||
let websocket: WebSocket | undefined = undefined;
|
let websocket: WebSocket | undefined = undefined;
|
||||||
|
|
||||||
|
const broadcastMessage = (buf: ArrayBuffer) => {
|
||||||
|
if (state === WebSocketState.connected) {
|
||||||
|
websocket?.send(buf);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const disconnect = () => {
|
||||||
|
if (websocket != null) {
|
||||||
|
websocket.close();
|
||||||
|
websocket = undefined;
|
||||||
|
state = WebSocketState.disconnected;
|
||||||
|
if (resyncInterval !== 0) {
|
||||||
|
clearInterval(resyncInterval);
|
||||||
|
}
|
||||||
|
clearInterval(checkInterval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ret = { broadcastMessage, disconnect };
|
||||||
|
|
||||||
_getToken(
|
_getToken(
|
||||||
provider.url,
|
provider.url,
|
||||||
token,
|
token,
|
||||||
@@ -126,15 +146,26 @@ export const registerWebsocket = (
|
|||||||
if (reconnect <= 0) provider.emit('lost-connection', []);
|
if (reconnect <= 0) provider.emit('lost-connection', []);
|
||||||
// Start with no reconnect timeout and increase timeout by
|
// Start with no reconnect timeout and increase timeout by
|
||||||
// using exponential backoff starting with 100ms
|
// using exponential backoff starting with 100ms
|
||||||
setTimeout(
|
setTimeout(() => {
|
||||||
registerWebsocket,
|
const newRet = registerWebsocket(
|
||||||
_getTimeout(provider),
|
provider,
|
||||||
provider,
|
token,
|
||||||
token,
|
resyncInterval,
|
||||||
resyncInterval,
|
reconnect > 0 ? reconnect - 1 : 3,
|
||||||
reconnect > 0 ? reconnect - 1 : 3,
|
protocol
|
||||||
protocol
|
);
|
||||||
);
|
ret.broadcastMessage = newRet.broadcastMessage;
|
||||||
|
ret.disconnect = newRet.disconnect;
|
||||||
|
}, _getTimeout(provider));
|
||||||
|
// setTimeout(
|
||||||
|
// registerWebsocket,
|
||||||
|
// _getTimeout(provider),
|
||||||
|
// provider,
|
||||||
|
// token,
|
||||||
|
// resyncInterval,
|
||||||
|
// reconnect > 0 ? reconnect - 1 : 3,
|
||||||
|
// protocol
|
||||||
|
// );
|
||||||
};
|
};
|
||||||
websocket.onopen = () => {
|
websocket.onopen = () => {
|
||||||
lastMessageReceived = time.getUnixTime();
|
lastMessageReceived = time.getUnixTime();
|
||||||
@@ -172,14 +203,24 @@ export const registerWebsocket = (
|
|||||||
.catch(err => {
|
.catch(err => {
|
||||||
provider.emit('lost-connection', []);
|
provider.emit('lost-connection', []);
|
||||||
provider.wsUnsuccessfulReconnects++;
|
provider.wsUnsuccessfulReconnects++;
|
||||||
setTimeout(
|
setTimeout(() => {
|
||||||
registerWebsocket,
|
const newRet = registerWebsocket(
|
||||||
_getTimeout(provider),
|
provider,
|
||||||
provider,
|
token,
|
||||||
token,
|
resyncInterval,
|
||||||
resyncInterval,
|
reconnect > 0 ? reconnect - 1 : 3
|
||||||
reconnect > 0 ? reconnect - 1 : 3
|
);
|
||||||
);
|
ret.broadcastMessage = newRet.broadcastMessage;
|
||||||
|
ret.disconnect = newRet.disconnect;
|
||||||
|
}, _getTimeout(provider));
|
||||||
|
// setTimeout(
|
||||||
|
// registerWebsocket,
|
||||||
|
// _getTimeout(provider),
|
||||||
|
// provider,
|
||||||
|
// token,
|
||||||
|
// resyncInterval,
|
||||||
|
// reconnect > 0 ? reconnect - 1 : 3
|
||||||
|
// );
|
||||||
});
|
});
|
||||||
|
|
||||||
let resyncInterval = 0;
|
let resyncInterval = 0;
|
||||||
@@ -206,23 +247,5 @@ export const registerWebsocket = (
|
|||||||
}
|
}
|
||||||
}, WEBSOCKET_RECONNECT / 10);
|
}, WEBSOCKET_RECONNECT / 10);
|
||||||
|
|
||||||
const broadcastMessage = (buf: ArrayBuffer) => {
|
return ret;
|
||||||
if (state === WebSocketState.connected) {
|
|
||||||
websocket?.send(buf);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const disconnect = () => {
|
|
||||||
if (websocket != null) {
|
|
||||||
websocket.close();
|
|
||||||
websocket = undefined;
|
|
||||||
state = WebSocketState.disconnected;
|
|
||||||
if (resyncInterval !== 0) {
|
|
||||||
clearInterval(resyncInterval);
|
|
||||||
}
|
|
||||||
clearInterval(checkInterval);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return { broadcastMessage, disconnect };
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
// eslint-disable-next-line no-restricted-imports
|
// eslint-disable-next-line no-restricted-imports
|
||||||
export {
|
export {
|
||||||
debounce,
|
|
||||||
throttle,
|
|
||||||
cloneDeep,
|
cloneDeep,
|
||||||
isEqual,
|
countBy,
|
||||||
sum,
|
|
||||||
has,
|
|
||||||
forEach,
|
|
||||||
upperFirst,
|
|
||||||
curry,
|
curry,
|
||||||
isFunction,
|
debounce,
|
||||||
isString,
|
|
||||||
isPlainObject,
|
|
||||||
lowerFirst,
|
|
||||||
last,
|
|
||||||
first,
|
|
||||||
without,
|
|
||||||
difference,
|
difference,
|
||||||
escape,
|
escape,
|
||||||
countBy,
|
first,
|
||||||
|
forEach,
|
||||||
|
has,
|
||||||
|
isEqual,
|
||||||
|
isFunction,
|
||||||
|
isPlainObject,
|
||||||
|
isString,
|
||||||
|
last,
|
||||||
|
lowerFirst,
|
||||||
maxBy,
|
maxBy,
|
||||||
|
pickBy,
|
||||||
|
sum,
|
||||||
|
throttle,
|
||||||
|
upperFirst,
|
||||||
|
without,
|
||||||
} from 'lodash-es';
|
} from 'lodash-es';
|
||||||
|
|||||||
Reference in New Issue
Block a user