diff --git a/.all-contributorsrc b/.all-contributorsrc
index 01e5d122de..8993984505 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -266,6 +266,43 @@
"contributions": [
"doc"
]
+ },
+ {
+ "login": "LuciNyan",
+ "name": "子瞻 Luci",
+ "avatar_url": "https://avatars.githubusercontent.com/u/22126563?v=4",
+ "profile": "https://github.com/LuciNyan",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "m1911star",
+ "name": "Horus",
+ "avatar_url": "https://avatars.githubusercontent.com/u/4948120?v=4",
+ "profile": "http://blog.ipili.me/",
+ "contributions": [
+ "code",
+ "platform"
+ ]
+ },
+ {
+ "login": "fanshyiis",
+ "name": "Super.x",
+ "avatar_url": "https://avatars.githubusercontent.com/u/15103283?v=4",
+ "profile": "https://segmentfault.com/u/qzuser_584786517d31a",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "wangyu-1999",
+ "name": "Wang Yu",
+ "avatar_url": "https://avatars.githubusercontent.com/u/80874770?v=4",
+ "profile": "https://wangyu-1999.github.io/",
+ "contributions": [
+ "code"
+ ]
}
]
}
diff --git a/.github/deployment/Dockerfile-affine b/.github/deployment/Dockerfile-affine
index 5cf4243eab..9d54eb0cf4 100644
--- a/.github/deployment/Dockerfile-affine
+++ b/.github/deployment/Dockerfile-affine
@@ -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
diff --git a/.github/deployment/Dockerfile-lisa b/.github/deployment/Dockerfile-lisa
index 471e4d0d48..f469a7fce8 100644
--- a/.github/deployment/Dockerfile-lisa
+++ b/.github/deployment/Dockerfile-lisa
@@ -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
diff --git a/README.md b/README.md
index 5352732aa9..8789712501 100644
--- a/README.md
+++ b/README.md
@@ -2,12 +2,13 @@
AFFiNE.PRO
- The Next-Gen Knowledge Base to Replace Notion & Miro.
+ The Next-Gen Collaborative Knowledge Base
-Planning, Sorting and Creating all Together. Open-source, Privacy-First, and Free to use.
+Open-source and privacy-first.
+A free replacement for Notion & Miro.
@@ -48,96 +50,53 @@ See https://github.com/all-?/all-contributors/issues/361#issuecomment-637166066
-# Stay Up-to-Date and Support Us
+# :star: Support Us and Keep Updated :star:

-# How to use
+# Getting Started
-
-🥳🥳🥳 Our web live demo is ready! 🥳🥳🥳
-
+[](https://affine.pro) No installation or registration required! Head over to our website and try it out now.
-
-
-If you have experience in front-end development, you may wish to refer to our [documentation](https://docs.affine.pro/affine/basic-documentation/contribute-to-affine) to learn more about deploying your own version or contributing further to development.
-Also, thanks to Lee who has made a [desktop build with Tauri](https://github.com/m1911star/affine-client) for you to try out.
-Please notice that AFFiNE is still under Alpha stage and is not ready for production use.
-
-# Table of contents
-
-- [Stay Up-to-Date and Support Us](#stay-up-to-date-and-support-us)
-- [How to Use](#how-to-use)
-- [Table of contents](#table-of-contents)
- - [Shape your page](#shape-your-page)
- - [Plan your task](#plan-your-task)
- - [Sort your knowledge](#sort-your-knowledge)
- - [Create your story](#create-your-story)
-- [Documentation](#documentation)
- - [Getting Started with development](#getting-started-with-development)
-- [Roadmap](#roadmap)
-- [Releases](#releases)
-- [Feature requests](#feature-requests)
-- [FAQ](#faq)
-- [The Philosophy of AFFiNE](#the-philosophy-of-affine)
-- [Community](#community)
-- [Contributors](#contributors)
-- [Acknowledgments](#acknowledgments)
-- [License](#license)
-
-## Shape your page
-
-
-
-## Plan your task
-
-
-
-## Sort your knowledge
-
-
+Want to deploy it yourself? AFFiNE can run just about anywhere. Check our
+[documentation](#documentation)
+for more information.
+
+⚠️ Please note that AFFiNE is still under active development and is not yet ready for production use. ⚠️
## Create your story
-We want your data always to be yours, without any sacrifice to your accessibility. Your data is always stored local first, yet we support real-time collaboration on a peer-to-peer basis. We don't think "privacy-first" is a good excuse for not supporting modern web features.
-And when it comes to collaboration, these features are not just necessarily for teams -- you can take and insert pictures on your phone, edit them from your desktop, and then share them with your collaborators.
-Affine is fully built with web technologies to ensure consistency and accessibility on Mac, Windows and Linux. The local file system support will be available when version 0.0.1beta is released.
+There can be more than Notion and Miro. AFFiNE is a next-gen knowledge base that brings planning, sorting and creating all together. Privacy first, open-source, customizable and ready to use, built with web technologies to ensure consistency and accessibility on Mac, Windows and Linux. We want your data always to be yours, without any sacrifice to your accessibility. Your data is always stored local first, with full support for real-time collaboration through peer-to-peer technology. We don't think "privacy-first" is a good excuse for not supporting modern web features.
+And when it comes to collaboration, these features are not just necessarily for teams - you can take and insert pictures on your phone, edit them from your desktop, and then share them with your collaborators.
-# Documentation
+### Shape your page
-AFFiNE is not yet ready for production use. For installation, you may check how to build or deploy AFFiNE from our [quick-start](https://docs.affine.pro/affine/basic-documentation/contribute-to-affine/quick-start) guide. Alternatively, you can view our [full documentation](https://docs.affine.pro/affine/).
+
-## Getting Started with development
+### Plan your task
-Please view the path Contribute-to-AFFiNE/Software-Contributions/Quick-Start in the documentation.
+
-# Roadmap
+### Sort your knowledge
-Coming Soon...
+
-# Releases
+# Useful Links
-Get our latest [release notes](https://github.com/toeverything/AFFiNE/wiki) from here.
+- [AFFiNE Documentation](https://docs.affine.pro/affine/) - More detailed documentation on how to use and develop with AFFiNE
-# Feature requests
+- [Feature Roadmap](https://github.com/toeverything/AFFiNE/issues/293) - Looking for a feature? It might already be planned for release - you can check here
+- [Release Notes](https://github.com/toeverything/AFFiNE/wiki) - Find out what changes we are making and how we are improving AFFiNE
-Please go to [feature requests](https://github.com/toeverything/AFFiNE/issues).
+- [Contributing Guide](/docs/CONTRIBUTING.md) - Want to help improve AFFiNE? You might not even need to write a line of code. Find out how you can contribute.
+- [Code of Conduct](/docs/CODE_OF_CONDUCT.md) - How we promote and maintain a harassment-free experience for everyone in our community.
-# FAQ
+- AFFiNE Communities: [Discord](https://discord.gg/yz6tGVsf5p) | [Telegram](https://t.me/affineworkos) | [Twitter](https://twitter.com/AffineOfficial) |
+ [Medium](https://medium.com/@affineworkos) | [AFFiNE Blog](https://blog.affine.pro)
-Get quick help on [Telegram](https://t.me/affineworkos) or [Discord](https://discord.gg/yz6tGVsf5p) and join our community of developers and contributors.
+# Contact Us
-Our latest news can be found on [Twitter](https://twitter.com/AffineOfficial), [Medium](https://medium.com/@affineworkos) and the [AFFiNE Blog](https://blog.affine.pro/).
+Feel free to send us an email: contact@toeverything.info
# The Philosophy of AFFiNE
@@ -160,7 +119,7 @@ That's why we are making AFFiNE. Some of the most important features are:
- Data is always stored locally by default
- CRDTs are applied so that peer-to-peer collaboration is possible.
-We appreciate the ideas of Monday, Airtable, and Notion databases. They have inspired us and shaped our product, helping us get it right when it comes to task management. But we also do things differently. We don't like doing things again and again. It's easy to set a todo with Markdown, but then why do you need to repeat and recreate data for a kanban or other databases. This is the power of AFFiNE. With AFFiNE, every block group has infinite views, for you to keep your single source of data, a signle source of truth.
+We appreciate the ideas of Monday, Airtable, and Notion databases. They have inspired us and shaped our product, helping us get it right when it comes to task management. But we also do things differently. We don't like doing things again and again. It's easy to set a todo with Markdown, but then why do you need to repeat and recreate data for a kanban or other databases. This is the power of AFFiNE. With AFFiNE, every block group has infinite views, for you to keep your single source of data, a single source of truth.
We would like to give special thanks to the innovators and pioneers who greatly inspired us:
@@ -182,12 +141,6 @@ We would also like to give thanks to open-source projects that make affine possi
Thanks a lot to the community for providing such powerful and simple libraries, so that we can focus more on the implementation of the product logic, and we hope that in the future our projects will also provide a more easy-to-use knowledge base for everyone.
-# Community
-
-For help, discussion about best practices, or any other conversation that would benefit from being searchable:
-
-[Discuss AFFiNE on GitHub](https://github.com/toeverything/AFFiNE/discussions)
-
# Contributors
@@ -228,6 +181,12 @@ For help, discussion about best practices, or any other conversation that would
@@ -240,4 +199,4 @@ For help, discussion about best practices, or any other conversation that would
AFFiNE is distributed under the terms of MIT license.
-See LICENSE for details.
+See [LICENSE](/LICENSE) for details.
diff --git a/apps/ligo-virgo/src/pages/workspace/docs/Page.tsx b/apps/ligo-virgo/src/pages/workspace/docs/Page.tsx
index a2440a1757..183adc6094 100644
--- a/apps/ligo-virgo/src/pages/workspace/docs/Page.tsx
+++ b/apps/ligo-virgo/src/pages/workspace/docs/Page.tsx
@@ -175,7 +175,7 @@ const WorkspaceSidebar = styled('div')(({ theme }) => ({
width: 300,
minWidth: 300,
borderRadius: '0px 10px 10px 0px',
- boxShadow: theme.affine.shadows.shadow1,
+ boxShadow: theme.affine.shadows.shadow2,
backgroundColor: '#FFFFFF',
transitionProperty: 'left',
transitionDuration: '0.35s',
diff --git a/apps/venus/package.json b/apps/venus/package.json
index fe69da1b8e..321da2b80d 100644
--- a/apps/venus/package.json
+++ b/apps/venus/package.json
@@ -7,16 +7,18 @@
"keywords": [],
"author": "DarkSky ",
"dependencies": {
- "@mui/joy": "^5.0.0-alpha.39",
"@emotion/react": "^11.10.0",
"@emotion/styled": "^11.10.0",
- "lozad": "^1.16.0"
+ "@mui/joy": "^5.0.0-alpha.39",
+ "i18next": "^21.9.1",
+ "lozad": "^1.16.0",
+ "react-i18next": "^11.18.4"
},
"devDependencies": {
- "mini-css-extract-plugin": "^2.6.1",
"image-minimizer-webpack-plugin": "^3.2.3",
"imagemin": "^8.0.1",
"imagemin-optipng": "^8.0.0",
+ "mini-css-extract-plugin": "^2.6.1",
"webpack": "^5.74.0"
}
}
diff --git a/apps/venus/src/app/i18n/index.ts b/apps/venus/src/app/i18n/index.ts
new file mode 100644
index 0000000000..9ddaa8330d
--- /dev/null
+++ b/apps/venus/src/app/i18n/index.ts
@@ -0,0 +1,25 @@
+import i18next from 'i18next';
+import { initReactI18next } from 'react-i18next';
+import en_US from './resources/en.json';
+import zh_CN from './resources/zh.json';
+
+const resources = {
+ en: en_US,
+ zh: zh_CN,
+} as const;
+
+i18next.use(initReactI18next).init({
+ lng: 'en',
+ fallbackLng: 'en',
+ resources,
+ interpolation: {
+ escapeValue: false, // not needed for react as it escapes by default
+ },
+});
+
+export const options = [
+ { value: 'en', text: 'English' },
+ { value: 'zh', text: '简体中文' },
+];
+
+export { i18next };
diff --git a/apps/venus/src/app/i18n/resources/en.json b/apps/venus/src/app/i18n/resources/en.json
new file mode 100644
index 0000000000..cd7a377352
--- /dev/null
+++ b/apps/venus/src/app/i18n/resources/en.json
@@ -0,0 +1,34 @@
+{
+ "translation": {
+ "Open Source": "Open Source",
+ "Privacy First": "Privacy First",
+ "Alternative": "Alternative",
+ "Check GitHub": "Check GitHub",
+ "Try it Online": "Try it Online",
+ "description1": {
+ "part1": "Affine is the next-generation collaborative knowledge base for professionals.",
+ "part2": "It's not just a collection of Docs, whiteboard, and tables.",
+ "part3": "Transform any building block as you like.",
+ "part4": "Say goodbye to redundancy. Store your data once, and keep your data as you like it."
+ },
+ "description2": {
+ "part1": "Shape Your Page",
+ "part2": "Docs, Kanbans, and Databases are all fully functional anywhere, anytime. A truly what-you-see-is-what-you-get environment for your data.",
+ "part3": "All pages come with a document (Paper Mode) and whiteboard (Edgeless Mode) view."
+ },
+ "description3": {
+ "part1": "Plan Your Task",
+ "part2": "No more chaos managing multiple views.",
+ "part3": "Set a TODO with Markdown, and seamlessly edit it within a Kanban.",
+ "part4": "Managing multi-dimensional tables should be this simple - and now it is."
+ },
+ "description4": {
+ "part1": "Privacy-first, and collaborative. No compromises whatsoever.",
+ "part2": "We don't like being locked-in, and neither should you. Privacy is at the foundation of everything we do, but it should not limit us that's why there are no compromises.",
+ "part3": "Your data is yours;it is always locally stored and secured - available to you always. While still being able to enjoy collaboration features such as real-time editing and sharing with others, without any cloud setup."
+ },
+ "BuildFor": "Build for an open and semantic future",
+ "KeepUpdated": "Keep Updated on",
+ "Join": "Join Our Community"
+ }
+}
diff --git a/apps/venus/src/app/i18n/resources/zh.json b/apps/venus/src/app/i18n/resources/zh.json
new file mode 100644
index 0000000000..eb4cf432dd
--- /dev/null
+++ b/apps/venus/src/app/i18n/resources/zh.json
@@ -0,0 +1,34 @@
+{
+ "translation": {
+ "Open Source": "开源",
+ "Privacy First": "隐私第一",
+ "Alternative": "的另一种选择",
+ "Check GitHub": "GitHub中查看",
+ "Try it Online": "在线上试试",
+ "description1": {
+ "part1": "Affine是面向专业人士的下一代协同知识库",
+ "part2": "它不仅仅是一个文档、白板和表格的集合。",
+ "part3": "可以根据需要转换任何构建块。",
+ "part4": "向冗余说再见吧。将数据存储一次,并保留您喜欢的数据。"
+ },
+ "description2": {
+ "part1": "塑造您的页面",
+ "part2": "文档、看板和数据库在任何地方、任何时候都是完全可用的,一个真正的“所见即所得”的数据环境。",
+ "part3": "所有页面都有一个文档(纸张模式)和白板(无边缘模式)视图。"
+ },
+ "description3": {
+ "part1": "计划您的任务",
+ "part2": "不再混乱地管理多个视图。",
+ "part3": "使用 Markdown 设置 TODO,并在看板中无缝地编辑它。",
+ "part4": "管理多维表格本应该就这么简单——现在的它就是这么简单。"
+ },
+ "description4": {
+ "part1": "隐私第一,合作无间,绝不妥协。",
+ "part2": "我们不喜欢被关起来,您也不应该。隐私是我们做任何事情的基础,但它不应该限制我们,这就是为什么我们决不妥协。",
+ "part3": "您的数据是您自己的,它总是安全的在本地存储并随时供您使用。您不需要任何云设置就可以享受协作功能,即时编辑和与他人共享。"
+ },
+ "BuildFor": "构建一个开放和语义化的未来",
+ "KeepUpdated": "持续更新在",
+ "Join": "加入我们的社区"
+ }
+}
diff --git a/apps/venus/src/app/index.tsx b/apps/venus/src/app/index.tsx
index 71db02985e..e4d9c7854e 100644
--- a/apps/venus/src/app/index.tsx
+++ b/apps/venus/src/app/index.tsx
@@ -7,12 +7,15 @@ import GitHubIcon from '@mui/icons-material/GitHub';
import RedditIcon from '@mui/icons-material/Reddit';
import TelegramIcon from '@mui/icons-material/Telegram';
import { Box, Button, Container, Grid, SvgIcon, Typography } from '@mui/joy';
+import Option from '@mui/joy/Option';
+import Select from '@mui/joy/Select';
import { CssVarsProvider, styled } from '@mui/joy/styles';
import { LogoIcon } from '@toeverything/components/icons';
// eslint-disable-next-line no-restricted-imports
import { useMediaQuery } from '@mui/material';
-
+import { useTranslation } from 'react-i18next';
import CollaborationImage from './collaboration.png';
+import { options } from './i18n';
import LogoImage from './logo.png';
import PageImage from './page.png';
import ShapeImage from './shape.png';
@@ -199,6 +202,7 @@ const AffineImage = styled('img')({
const GitHub = (props: { center?: boolean; flat?: boolean }) => {
const matches = useMediaQuery('(max-width: 1024px)');
+ const { t } = useTranslation();
return (
);
};
const AFFiNEOnline = (props: { center?: boolean; flat?: boolean }) => {
const matches = useMediaQuery('(max-width: 1024px)');
-
+ const { t } = useTranslation();
return (
);
};
export function App() {
const matches = useMediaQuery('(max-width: 1024px)');
+ const { t, i18n } = useTranslation();
+ const changeLanguage = (event: any) => {
+ i18n.changeLanguage(event);
+ };
return (
Blog
+
- Open Source,
+ {t('Open Source')},
- Privacy First
+ {t('Privacy First')}
@@ -413,7 +428,7 @@ export function App() {
},
}}
>
- Alternative
+ {t('Alternative')}
@@ -432,8 +447,7 @@ export function App() {
fontWeight={'400'}
sx={{ color: '#888' }}
>
- Affine is the next-generation collaborative
- knowledge base for professionals.
+ {t('description1.part1')}
@@ -488,8 +502,7 @@ export function App() {
level={matches ? 'h2' : 'h1'}
fontWeight={'bold'}
>
- It’s not just a collection of Docs, whiteboard, and
- tables.
+ {t('description1.part2')}
@@ -506,11 +519,10 @@ export function App() {
}}
>
- Transform any building block as you like.
+ {t('description1.part3')}
- Say goodbye to redundancy. Store your data once, and
- keep your data as you like it.
+ {t('description1.part4')}
@@ -547,23 +559,19 @@ export function App() {
fontWeight={'bold'}
style={{ marginBottom: '0.5em' }}
>
- Shape Your Page
+ {t('description2.part1')}
- Docs, Kanbans, and Databases are all fully
- functional anywhere, anytime. A truly
- what-you-see-is-what-you-get environment for
- your data.
+ {t('description2.part2')}
- All pages come with a document (Paper Mode) and
- whiteboard (Edgeless Mode) view.
+ {t('description2.part3')}
@@ -625,27 +633,25 @@ export function App() {
fontWeight={'bold'}
style={{ marginBottom: '0.5em' }}
>
- Plan Your Task
+ {t('description3.part1')}
- No more chaos managing multiple views.
+ {t('description3.part2')}
- Set a TODO with Markdown, and seamlessly edit it
- within a Kanban.
+ {t('description3.part3')}
- Managing multi-dimensional tables should be this
- simple – and now it is.
+ {t('description3.part4')}
@@ -697,27 +703,19 @@ export function App() {
fontWeight={'bold'}
style={{ marginBottom: '0.5em' }}
>
- Privacy-first, and collaborative. No compromises
- whatsoever.
+ {t('description4.part1')}
- We don’t like being locked-in, and neither should
- you. Privacy is at the foundation of everything we
- do, but it should not limit us that’s+ why there are
- no compromises.
+ {t('description4.part2')}
- Your data is yours; it is always locally stored and
- secured - available to you always. While still being
- able to enjoy collaboration features such as
- real-time editing and sharing with others, without
- any cloud setup.
+ {t('description4.part3')}
@@ -762,7 +760,7 @@ export function App() {
}}
>
- Build for an open and semantic future
+ {t('BuildFor')}
@@ -778,7 +776,7 @@ export function App() {
>
- Keep Updated on
+ {t('KeepUpdated')}
@@ -795,7 +793,7 @@ export function App() {
}}
>
- Join Our Community
+ {t('Join')}
diff --git a/apps/venus/src/index.tsx b/apps/venus/src/index.tsx
index f76f9a6f20..5fdc926e59 100644
--- a/apps/venus/src/index.tsx
+++ b/apps/venus/src/index.tsx
@@ -1,6 +1,7 @@
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
+import './app/i18n';
import App from './app';
diff --git a/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md
similarity index 100%
rename from CODE_OF_CONDUCT.md
rename to docs/CODE_OF_CONDUCT.md
diff --git a/CONTRIBUTING.md b/docs/CONTRIBUTING.md
similarity index 84%
rename from CONTRIBUTING.md
rename to docs/CONTRIBUTING.md
index 7b7b63a1a5..94806e00f8 100644
--- a/CONTRIBUTING.md
+++ b/docs/CONTRIBUTING.md
@@ -1,4 +1,4 @@
-# Welcome to ourcontributing guide
+# Welcome to our contributing guide
Thank you for investing your time in contributing to our project! Any contribution you make will be reflected on our GitHub :sparkles:.
@@ -10,7 +10,7 @@ Use the table of contents icon on the top left corner of this document to get to
## New contributor guide
-To get an overview of the project, read the [README](README.md). Here are some resources to help you get started with open source contributions:
+To get an overview of the project, read the [README](../README.md). Here are some resources to help you get started with open source contributions:
- [Finding ways to contribute to open source on GitHub](https://docs.github.com/en/get-started/exploring-projects-on-github/finding-ways-to-contribute-to-open-source-on-github)
- [Set up Git](https://docs.github.com/en/get-started/quickstart/set-up-git)
@@ -19,19 +19,17 @@ To get an overview of the project, read the [README](README.md). Here are some r
## Getting started
-To navigate our codebase with confidence, see [the introduction to working in the docs repository](/contributing/working-in-docs-repository.md) :confetti_ball:. For more information on how we write our markdown files, see [the GitHub Markdown reference](contributing/content-markup-reference.md).
-
-Check to see what [types of contributions](/contributing/types-of-contributions.md) we accept before making changes. Some of them don't even require writing a single line of code :sparkles:.
+Check to see what [types of contributions](types-of-contributions.md) we accept before making changes. Some of them don't even require writing a single line of code :sparkles:.
### Issues
-#### Create a new issue
+#### Create a new issue or feature request
If you spot a problem, [search if an issue already exists](https://docs.github.com/en/github/searching-for-information-on-github/searching-on-github/searching-issues-and-pull-requests#search-by-the-title-body-or-comments). If a related issue doesn't exist, you can open a new issue using a relevant [issue form](https://github.com/toeverything/AFFiNE/issues/new/choose).
#### Solve an issue
-Scan through our [existing issues](https://github.com/toeverything/AFFiNE/issues) to find one that interests you. You can narrow down the search using `labels` as filters. See [Labels](/contributing/how-to-use-labels.md) for more information. As a general rule, we don’t assign issues to anyone. If you find an issue to work on, you are welcome to open a PR with a fix.
+Scan through our [existing issues](https://github.com/toeverything/AFFiNE/issues) to find one that interests you. You can narrow down the search using `labels` as filters. See our [Labels](https://github.com/toeverything/AFFiNE/labels) for more information. As a general rule, we don’t assign issues to anyone. If you find an issue to work on, you are welcome to open a PR with a fix.
### Make Changes
diff --git a/docs/types-of-contributions.md b/docs/types-of-contributions.md
new file mode 100644
index 0000000000..fd448200e9
--- /dev/null
+++ b/docs/types-of-contributions.md
@@ -0,0 +1,31 @@
+# Types of contributions :memo:
+
+You can contribute to AFFiNE in several ways. This repo is a place to discuss and collaborate on AFFiNE!
+
+### :mega: Discussions
+
+Discussions are where we have conversations.
+
+If you'd like help troubleshooting a docs PR you're working on, have a great new idea, or want to share something amazing you've learned in our docs, join us in [discussions](https://github.com/toeverything/AFFiNE/discussions).
+
+### :lady_beetle: Issues
+
+[Issues](https://docs.github.com/en/github/managing-your-work-on-github/about-issues) are used to track tasks that contributors can help with. If an issue has a triage label, we haven't reviewed it yet, and you shouldn't begin work on it.
+
+If you've found something in the content or the website that should be updated, search open issues to see if someone else has reported the same thing. If it's something new, open an issue using a [template](https://github.com/toeverything/AFFiNE/issues/new/choose). We'll use the issue to have a conversation about the problem you want to fix.
+
+### :hammer_and_wrench: Pull requests
+
+A [pull request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) is a way to suggest changes in our repository. When we merge those changes, they should be deployed to the live site within 24 hours. :earth_africa:
+You can [create a new pull request](https://github.com/toeverything/AFFiNE/compare) and view [current pull requests](https://github.com/toeverything/AFFiNE/pulls).
+
+### :question: Support
+
+We are a small team working hard to keep up with the documentation demands of a continuously changing product.
+You may be able to find additional help and information on our social media platforms and groups - the links to these can be found in our [README](../README.md).
+
+### :earth_asia: Translations
+
+AFFiNE is internationalized and available in multiple languages. The source content in this repository is written in English. We integrate with an external localization platform to work with the community in localizing the English content.
+
+**We do not currently offer this feature**, but we hope to in the future.
diff --git a/libs/components/affine-board/src/Board.tsx b/libs/components/affine-board/src/Board.tsx
index 5730649545..8c521705e7 100644
--- a/libs/components/affine-board/src/Board.tsx
+++ b/libs/components/affine-board/src/Board.tsx
@@ -22,7 +22,6 @@ const AffineBoard = ({
editor,
}: AffineBoardProps & { editor: BlockEditor }) => {
const [app, set_app] = useState();
-
const [document] = useState(() => {
return {
...deepCopy(TldrawApp.default_document),
@@ -49,7 +48,7 @@ const AffineBoard = ({
};
});
- const shapes = useShapes(workspace, rootBlockId);
+ const { shapes } = useShapes(workspace, rootBlockId);
useEffect(() => {
if (app) {
app.replacePageContent(shapes || {}, {}, {});
@@ -66,6 +65,9 @@ const AffineBoard = ({
onMount(app) {
set_app(app);
},
+ async onPaste(e, data) {
+ console.log('e,data: ', e, data);
+ },
async onCopy(e, groupIds) {
const clip =
await editor.clipboard.clipboardUtils.getClipDataOfBlocksById(
@@ -77,7 +79,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) {
@@ -106,7 +108,7 @@ const AffineBoard = ({
});
}
shape.affineId = block.id;
- return services.api.editorBlock.update({
+ return await services.api.editorBlock.update({
workspace: shape.workspace,
id: block.id,
properties: {
diff --git a/libs/components/affine-board/src/hooks/use-shapes.ts b/libs/components/affine-board/src/hooks/use-shapes.ts
index 7d07a25957..23270b6c19 100644
--- a/libs/components/affine-board/src/hooks/use-shapes.ts
+++ b/libs/components/affine-board/src/hooks/use-shapes.ts
@@ -9,28 +9,37 @@ 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();
+ const [blocks, setBlocks] = useState<{
+ shapes: [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);
+ 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 => {
+ setBlocks({
+ shapes: shapes,
});
+ });
+
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 +49,11 @@ export const useShapes = (workspace: string, rootBlockId: string) => {
)?.[0];
return childBlock;
})
- );
- setBlocks(shapes);
+ ).then(shapes => {
+ setBlocks({
+ shapes: [shapes],
+ });
+ });
})
.then(cb => {
unobserve = cb;
@@ -53,8 +65,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 +86,8 @@ export const useShapes = (workspace: string, rootBlockId: string) => {
return acc;
}, {} as Record);
+
+ return {
+ shapes: blocksShapes,
+ };
};
diff --git a/libs/components/affine-editor/src/Editor.tsx b/libs/components/affine-editor/src/Editor.tsx
index c280bea984..f1edb2ce74 100644
--- a/libs/components/affine-editor/src/Editor.tsx
+++ b/libs/components/affine-editor/src/Editor.tsx
@@ -1,7 +1,6 @@
import { forwardRef, useEffect, useImperativeHandle, useRef } from 'react';
import {
- RenderBlock,
RenderRoot,
type BlockEditor,
} from '@toeverything/components/editor-core';
@@ -88,9 +87,7 @@ export const AffineEditor = forwardRef(
editor={editor}
editorElement={AffineEditor as any}
scrollBlank={scrollBlank}
- >
-
-
+ />
);
}
);
diff --git a/libs/components/board-draw/src/TlDraw.tsx b/libs/components/board-draw/src/TlDraw.tsx
index 338fffeeaf..a1444b76c0 100644
--- a/libs/components/board-draw/src/TlDraw.tsx
+++ b/libs/components/board-draw/src/TlDraw.tsx
@@ -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]] &&
@@ -363,7 +362,7 @@ const InnerTldraw = memo(function InnerTldraw({
// Hide bounds when not using the select tool, or when the only selected shape has handles
const hideBounds =
- (isInSession && app.session?.constructor.name !== 'BrushSession') ||
+ (isInSession && app.session?.constructor.name === 'BrushSession') ||
!isSelecting ||
isHideBoundsShape ||
!!pageState.editingId;
diff --git a/libs/components/board-draw/src/components/align-panel/index.tsx b/libs/components/board-draw/src/components/align-panel/index.tsx
index d0ff48390d..ddc43b1254 100644
--- a/libs/components/board-draw/src/components/align-panel/index.tsx
+++ b/libs/components/board-draw/src/components/align-panel/index.tsx
@@ -56,7 +56,8 @@ const SelectableContainer = styled('div')<{ selected?: boolean }>(
borderRadius: '5px',
overflow: 'hidden',
margin: '5px',
- padding: '3px',
+ width: '24px',
+ height: '24px',
cursor: 'pointer',
boxSizing: 'border-box',
'&:hover': {
diff --git a/libs/components/board-draw/src/components/command-panel/ArrowTo.tsx b/libs/components/board-draw/src/components/command-panel/ArrowTo.tsx
new file mode 100644
index 0000000000..84ef142ef0
--- /dev/null
+++ b/libs/components/board-draw/src/components/command-panel/ArrowTo.tsx
@@ -0,0 +1,80 @@
+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 = '';
+ if (!activeShape) {
+ return;
+ }
+ 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 => {
+ if (item.id === binding.toId) {
+ ArrowToArr.push(item);
+ }
+ });
+ }
+ });
+ setarrowToArr(ArrowToArr);
+ return () => {};
+ }, [app.page.bindings]);
+ const jumpToNextShap = (shape: TDShape) => {
+ app.zoomToShapes([shape]);
+ };
+
+ return (
+
+ {arrowToArr.map((arrow: any) => {
+ return (
+ jumpToNextShap(arrow)}
+ >
+ {arrow.name}
+
+ );
+ })}
+