diff --git a/.all-contributorsrc b/.all-contributorsrc
index 8993984505..4b1cc35879 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -12,6 +12,16 @@
"contributorsPerLine": 7,
"badgeTemplate": "\n[all-contributors-badge]: https://img.shields.io/badge/all_contributors-<%= contributors.length %>-orange.svg?style=flat-square\n",
"contributors": [
+ {
+ "login": "doodlewind",
+ "name": "Yifeng Wang",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7312949?v=4",
+ "profile": "https://github.com/doodlewind",
+ "contributions": [
+ "code",
+ "doc"
+ ]
+ },
{
"login": "darkskygit",
"name": "DarkSky",
@@ -303,6 +313,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "felixonmars",
+ "name": "Felix Yan",
+ "avatar_url": "https://avatars.githubusercontent.com/u/1006477?v=4",
+ "profile": "https://felixc.at/",
+ "contributions": [
+ "code"
+ ]
}
]
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index e69da8bc93..18f956c613 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -5,6 +5,7 @@
"editor.codeActionsOnSave": ["source.fixAll", "source.organizeImports"],
"prettier.prettierPath": "./node_modules/prettier",
"cSpell.words": [
+ "aboutus",
"AUTOINCREMENT",
"Backlinks",
"blockdb",
diff --git a/README.md b/README.md
index b2507efa5b..d4f92bc519 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ See https://github.com/all-?/all-contributors/issues/361#issuecomment-637166066
-->
-[all-contributors-badge]: https://img.shields.io/badge/all_contributors-31-orange.svg?style=flat-square
+[all-contributors-badge]: https://img.shields.io/badge/all_contributors-33-orange.svg?style=flat-square
@@ -58,9 +58,8 @@ See https://github.com/all-?/all-contributors/issues/361#issuecomment-637166066
[](https://affine.pro) No installation or registration required! Head over to our website and try it out now.
-Want to deploy it yourself? AFFiNE can run just about anywhere. Check our
-[documentation](#documentation)
-for more information.
+Want to deploy it yourself? AFFiNE can run just about anywhere.
+You can refer to our documentation which can be found from the [useful links](#useful-links) section - where you will also find ways to help contribute to the project and join our communities.
⚠️ Please note that AFFiNE is still under active development and is not yet ready for production use. ⚠️
@@ -119,7 +118,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:
@@ -148,45 +147,47 @@ Thanks a lot to the community for providing such powerful and simple libraries,
${text}`;
+ }
+ if (textValue.strikethrough) {
+ return `${content}`;
+ override async block2html(props: Block2HtmlProps) {
+ return `${await commonBlock2HtmlContent(props)}`;
}
}
diff --git a/libs/components/editor-blocks/src/blocks/divider/index.ts b/libs/components/editor-blocks/src/blocks/divider/index.ts
index 6d67611cda..f77722838f 100644
--- a/libs/components/editor-blocks/src/blocks/divider/index.ts
+++ b/libs/components/editor-blocks/src/blocks/divider/index.ts
@@ -1,39 +1,35 @@
import {
AsyncBlock,
BaseView,
+ BlockEditor,
+ HTML2BlockResult,
SelectBlock,
} from '@toeverything/framework/virgo';
import { Protocol } from '@toeverything/datasource/db-service';
import { DividerView } from './divider-view';
+import { Block2HtmlProps, commonHTML2block } from '../../utils/commonBlockClip';
export class DividerBlock extends BaseView {
type = Protocol.Block.Type.divider;
View = DividerView;
- override html2block(
- el: Element,
- parseEl: (el: Element) => any[]
- ): any[] | null {
- const tag_name = el.tagName;
- if (tag_name === 'HR') {
- return [
- {
- type: this.type,
- properties: {
- text: {},
- },
- children: [],
- },
- ];
- }
- return null;
+ override async html2block({
+ element,
+ editor,
+ }: {
+ element: Element;
+ editor: BlockEditor;
+ }): Promise {
+ return commonHTML2block({
+ element,
+ editor,
+ type: this.type,
+ tagName: 'HR',
+ ignoreEmptyElement: false,
+ });
}
- override async block2html(
- block: AsyncBlock,
- children: SelectBlock[],
- generateHtml: (el: any[]) => Promise
- ): Promise {
- return `
`;
+ override async block2html(props: Block2HtmlProps) {
+ return `
`;
}
}
diff --git a/libs/components/editor-blocks/src/blocks/embed-link/EmbedLinkView.tsx b/libs/components/editor-blocks/src/blocks/embed-link/EmbedLinkView.tsx
index 86b43908d1..c3e7199c29 100644
--- a/libs/components/editor-blocks/src/blocks/embed-link/EmbedLinkView.tsx
+++ b/libs/components/editor-blocks/src/blocks/embed-link/EmbedLinkView.tsx
@@ -33,7 +33,7 @@ export const EmbedLinkView = (props: EmbedLinkView) => {
};
return (
-
+
{embedLinkUrl ? (
any[]
- ): any[] | null {
- const tag_name = el.tagName;
- if (tag_name === 'A' && el.parentElement?.childElementCount === 1) {
- return [
- {
- type: this.type,
- properties: {
- // TODO: Not sure what value to fill for name
- embedLink: {
- name: this.type,
- value: el.getAttribute('href'),
- },
- },
- children: [],
- },
- ];
- }
-
- return null;
- }
-
- override async block2html(
- block: AsyncBlock,
- children: SelectBlock[],
- generateHtml: (el: any[]) => Promise
- ): Promise {
- const figma_url = block.getProperty('embedLink')?.value;
- return ``;
+ override async block2html({ block }: Block2HtmlProps) {
+ const url = block.getProperty('embedLink')?.value;
+ return ``;
}
}
diff --git a/libs/components/editor-blocks/src/blocks/figma/FigmaView.tsx b/libs/components/editor-blocks/src/blocks/figma/FigmaView.tsx
index 7375546dad..6949280646 100644
--- a/libs/components/editor-blocks/src/blocks/figma/FigmaView.tsx
+++ b/libs/components/editor-blocks/src/blocks/figma/FigmaView.tsx
@@ -1,13 +1,12 @@
-import { useState } from 'react';
-import { CreateView } from '@toeverything/framework/virgo';
import {
- useOnSelect,
BlockPendantProvider,
+ useOnSelect,
} from '@toeverything/components/editor-core';
-import { Upload } from '../../components/upload/upload';
+import { CreateView } from '@toeverything/framework/virgo';
+import { useState } from 'react';
import { SourceView } from '../../components/source-view';
-import { styled } from '@toeverything/components/ui';
import { LinkContainer } from '../../components/style-container';
+import { Upload } from '../../components/upload/upload';
const MESSAGES = {
ADD_FIGMA_LINK: 'Add figma link',
@@ -30,7 +29,7 @@ export const FigmaView = ({ block, editor }: FigmaView) => {
setIsSelect(isSelect);
});
return (
-
+
{figmaUrl ? (
any[]
- ): any[] | null {
- const tag_name = el.tagName;
- if (tag_name === 'A' && el.parentElement?.childElementCount === 1) {
- const href = el.getAttribute('href');
- const allowedHosts = ['www.figma.com'];
- const host = new URL(href).host;
-
- if (allowedHosts.includes(host)) {
- return [
- {
- type: this.type,
- properties: {
- // TODO: Not sure what value to fill for name
- embedLink: {
- name: this.type,
- value: el.getAttribute('href'),
- },
- },
- children: [],
- },
- ];
- }
- }
-
- return null;
- }
-
- override async block2html(
- block: AsyncBlock,
- children: SelectBlock[],
- generateHtml: (el: any[]) => Promise
- ): Promise {
- const figma_url = block.getProperty('embedLink')?.value;
- return ``;
+ override async block2html({ block }: Block2HtmlProps) {
+ const figmaUrl = block.getProperty('embedLink')?.value;
+ return ``;
}
}
diff --git a/libs/components/editor-blocks/src/blocks/file/index.ts b/libs/components/editor-blocks/src/blocks/file/index.ts
index e3119e9a16..c2f12c0c6d 100644
--- a/libs/components/editor-blocks/src/blocks/file/index.ts
+++ b/libs/components/editor-blocks/src/blocks/file/index.ts
@@ -9,25 +9,22 @@ import {
services,
} from '@toeverything/datasource/db-service';
import { FileView } from './FileView';
+import { Block2HtmlProps } from '../../utils/commonBlockClip';
export class FileBlock extends BaseView {
public override selectable = true;
public override editable = false;
type = Protocol.Block.Type.file;
View = FileView;
+ override async block2html({ block }: Block2HtmlProps) {
+ const fileProperty = block.getProperty('file');
+ const fileId = fileProperty?.value;
+ const fileInfo = fileId
+ ? await services.api.file.get(fileId, block.workspace)
+ : null;
- override async block2html(
- block: AsyncBlock,
- children: SelectBlock[],
- generateHtml: (el: any[]) => Promise
- ): Promise {
- const file_property =
- block.getProperty('file') || ({} as FileColumnValue);
- const file_id = file_property.value;
- let file_info = null;
- if (file_id) {
- file_info = await services.api.file.get(file_id, block.workspace);
- }
- return ``;
+ return fileInfo
+ ? ``
+ : '';
}
}
diff --git a/libs/components/editor-blocks/src/blocks/grid-item/GridItemRender.tsx b/libs/components/editor-blocks/src/blocks/grid-item/GridItemRender.tsx
index 3a598b3145..620a25dba6 100644
--- a/libs/components/editor-blocks/src/blocks/grid-item/GridItemRender.tsx
+++ b/libs/components/editor-blocks/src/blocks/grid-item/GridItemRender.tsx
@@ -1,4 +1,4 @@
-import { RenderBlock } from '@toeverything/components/editor-core';
+import { RenderBlockChildren } from '@toeverything/components/editor-core';
import { ChildrenView, CreateView } from '@toeverything/framework/virgo';
export const GridItemRender = function (
@@ -6,13 +6,7 @@ export const GridItemRender = function (
) {
const GridItem = function (props: CreateView) {
const { block } = props;
- const children = (
- <>
- {block.childrenIds.map(id => {
- return ;
- })}
- >
- );
+ const children = ;
return <>{creator({ ...props, children })}>;
};
return GridItem;
diff --git a/libs/components/editor-blocks/src/blocks/grid/Grid.tsx b/libs/components/editor-blocks/src/blocks/grid/Grid.tsx
index 4ecf47f3b5..a8e69125d0 100644
--- a/libs/components/editor-blocks/src/blocks/grid/Grid.tsx
+++ b/libs/components/editor-blocks/src/blocks/grid/Grid.tsx
@@ -1,16 +1,16 @@
-import { RenderBlock } from '@toeverything/components/editor-core';
-import { CreateView } from '@toeverything/framework/virgo';
-import React, { useEffect, useRef, useState } from 'react';
-import { GridHandle } from './GirdHandle';
+import { BlockRender } from '@toeverything/components/editor-core';
import { styled } from '@toeverything/components/ui';
+import { Protocol } from '@toeverything/datasource/db-service';
+import { CreateView } from '@toeverything/framework/virgo';
+import { debounce, domToRect, Point } from '@toeverything/utils';
+import clsx from 'clsx';
+import React, { useEffect, useRef, useState } from 'react';
import ReactDOM from 'react-dom';
import {
GRID_ITEM_CLASS_NAME,
GRID_ITEM_CONTENT_CLASS_NAME,
} from '../grid-item/GridItem';
-import { debounce, domToRect, Point } from '@toeverything/utils';
-import clsx from 'clsx';
-import { Protocol } from '@toeverything/datasource/db-service';
+import { GridHandle } from './GirdHandle';
const DB_UPDATE_DELAY = 50;
const GRID_ON_DRAG_CLASS = 'grid-layout-on-drag';
@@ -226,7 +226,7 @@ export const Grid = function (props: CreateView) {
key={id}
className={GRID_ITEM_CLASS_NAME}
>
-
+
handleDragGrid(event, i)}
editor={editor}
diff --git a/libs/components/editor-blocks/src/blocks/group/Group.tsx b/libs/components/editor-blocks/src/blocks/group/Group.tsx
index 787c537f18..ea27bbbd38 100644
--- a/libs/components/editor-blocks/src/blocks/group/Group.tsx
+++ b/libs/components/editor-blocks/src/blocks/group/Group.tsx
@@ -6,6 +6,10 @@ import {
SelectBlock,
} from '@toeverything/framework/virgo';
import { GroupView } from './GroupView';
+import {
+ Block2HtmlProps,
+ commonBlock2HtmlContent,
+} from '../../utils/commonBlockClip';
export class Group extends BaseView {
public override selectable = true;
@@ -25,13 +29,12 @@ export class Group extends BaseView {
override async onCreate(block: AsyncBlock): Promise {
return block;
}
-
- override async block2html(
- block: AsyncBlock,
- children: SelectBlock[],
- generateHtml: (el: any[]) => Promise
- ): Promise {
- const content = await generateHtml(children);
- return `${content}`;
+ override async block2html({ editor, selectInfo, block }: Block2HtmlProps) {
+ const childrenHtml =
+ await editor.clipboard.clipboardUtils.convertBlock2HtmlBySelectInfos(
+ block,
+ selectInfo?.children
+ );
+ return `${childrenHtml}`;
}
}
diff --git a/libs/components/editor-blocks/src/blocks/group/GroupView.tsx b/libs/components/editor-blocks/src/blocks/group/GroupView.tsx
index 791059e36c..f0d6e56cc5 100644
--- a/libs/components/editor-blocks/src/blocks/group/GroupView.tsx
+++ b/libs/components/editor-blocks/src/blocks/group/GroupView.tsx
@@ -21,19 +21,6 @@ const SceneMap: Record> = {
kanban: SceneKanban,
} as const;
-const GroupBox = styled('div')(({ theme }) => {
- return {
- '&:hover': {
- // Workaround referring to other components
- // See https://emotion.sh/docs/styled#targeting-another-emotion-component
- // [GroupActionWrapper.toString()]: {},
- '& > *': {
- visibility: 'visible',
- },
- },
- };
-});
-
const GroupActionWrapper = styled('div')(({ theme }) => ({
height: '30px',
display: 'flex',
@@ -59,6 +46,14 @@ const GroupActionWrapper = styled('div')(({ theme }) => ({
},
}));
+const GroupBox = styled('div')({
+ '&:hover': {
+ [GroupActionWrapper.toString()]: {
+ visibility: 'visible',
+ },
+ },
+});
+
const GroupContainer = styled('div')<{ isSelect?: boolean }>(
({ isSelect, theme }) => ({
background: theme.affine.palette.white,
diff --git a/libs/components/editor-blocks/src/blocks/group/ScenePage.tsx b/libs/components/editor-blocks/src/blocks/group/ScenePage.tsx
index 6145bec114..739927626d 100644
--- a/libs/components/editor-blocks/src/blocks/group/ScenePage.tsx
+++ b/libs/components/editor-blocks/src/blocks/group/ScenePage.tsx
@@ -2,5 +2,5 @@ import { RenderBlockChildren } from '@toeverything/components/editor-core';
import type { CreateView } from '@toeverything/framework/virgo';
export const ScenePage = ({ block }: CreateView) => {
- return ;
+ return ;
};
diff --git a/libs/components/editor-blocks/src/blocks/group/group-menu/AddViewMenu.tsx b/libs/components/editor-blocks/src/blocks/group/group-menu/AddViewMenu.tsx
index a376785b52..e1cee48f30 100644
--- a/libs/components/editor-blocks/src/blocks/group/group-menu/AddViewMenu.tsx
+++ b/libs/components/editor-blocks/src/blocks/group/group-menu/AddViewMenu.tsx
@@ -41,7 +41,7 @@ export const AddViewMenu = () => {
onClick={() => setActivePanel(!activePanel)}
>
- Add View
+ Add View
{activePanel && (
@@ -66,10 +66,10 @@ export const AddViewMenu = () => {
key={name}
active={viewType === scene}
onClick={() => {
- if (scene === RecastScene.Table) {
- // The table view is under progress
- return;
- }
+ // if (scene === RecastScene.Table) {
+ // // The table view is under progress
+ // return;
+ // }
setViewType(scene);
}}
style={{ textTransform: 'uppercase' }}
diff --git a/libs/components/editor-blocks/src/blocks/group/group-menu/MainMenu.tsx b/libs/components/editor-blocks/src/blocks/group/group-menu/MainMenu.tsx
index 92aa53566e..43b819aabe 100644
--- a/libs/components/editor-blocks/src/blocks/group/group-menu/MainMenu.tsx
+++ b/libs/components/editor-blocks/src/blocks/group/group-menu/MainMenu.tsx
@@ -82,7 +82,7 @@ const GroupMenuWrapper = ({
content={
-
+ {/* */}
{
// // Closed beta period temporarily
// filterSorterFlag && (
diff --git a/libs/components/editor-blocks/src/blocks/group/group-menu/ViewsMenu.tsx b/libs/components/editor-blocks/src/blocks/group/group-menu/ViewsMenu.tsx
index 1fee99465e..273911a94d 100644
--- a/libs/components/editor-blocks/src/blocks/group/group-menu/ViewsMenu.tsx
+++ b/libs/components/editor-blocks/src/blocks/group/group-menu/ViewsMenu.tsx
@@ -20,7 +20,7 @@ export const ViewsMenu = () => {
useRecastView();
const handleChange = (e: ChangeEvent) => {
- setViewName(e.target.value.trim());
+ setViewName(e.target.value);
};
const handleKeyDown = (event: KeyboardEvent) => {
@@ -36,7 +36,7 @@ export const ViewsMenu = () => {
}
await updateView({
...activeView,
- name: viewName,
+ name: viewName.trim(),
type: viewType,
});
setActiveView(null);
@@ -99,10 +99,10 @@ export const ViewsMenu = () => {
key={name}
active={viewType === scene}
onClick={() => {
- if (scene === RecastScene.Table) {
- // The table view is under progress
- return;
- }
+ // if (scene === RecastScene.Table) {
+ // // The table view is under progress
+ // return;
+ // }
setViewType(scene);
}}
style={{ textTransform: 'uppercase' }}
diff --git a/libs/components/editor-blocks/src/blocks/group/group-menu/constant.tsx b/libs/components/editor-blocks/src/blocks/group/group-menu/constant.tsx
index 0f2a1887d4..7a057eccbd 100644
--- a/libs/components/editor-blocks/src/blocks/group/group-menu/constant.tsx
+++ b/libs/components/editor-blocks/src/blocks/group/group-menu/constant.tsx
@@ -1,9 +1,5 @@
import { RecastScene } from '@toeverything/components/editor-core';
-import {
- KanBanIcon,
- TableIcon,
- TodoListIcon,
-} from '@toeverything/components/icons';
+import { KanBanIcon, TodoListIcon } from '@toeverything/components/icons';
export const VIEW_LIST = [
{
@@ -16,9 +12,9 @@ export const VIEW_LIST = [
scene: RecastScene.Kanban,
icon: ,
},
- {
- name: 'Table',
- scene: RecastScene.Table,
- icon: ,
- },
+ // {
+ // name: 'Table',
+ // scene: RecastScene.Table,
+ // icon: ,
+ // },
] as const;
diff --git a/libs/components/editor-blocks/src/blocks/group/scene-kanban/CardContext.tsx b/libs/components/editor-blocks/src/blocks/group/scene-kanban/CardContext.tsx
index 13fcaa45e3..74afbe087d 100644
--- a/libs/components/editor-blocks/src/blocks/group/scene-kanban/CardContext.tsx
+++ b/libs/components/editor-blocks/src/blocks/group/scene-kanban/CardContext.tsx
@@ -1,12 +1,12 @@
-import { useCallback } from 'react';
-import { CardItem } from './CardItem';
-import { styled } from '@toeverything/components/ui';
-import { useKanban } from '@toeverything/components/editor-core';
-import { CardItemPanelWrapper } from './dndable/wrapper/CardItemPanelWrapper';
import type {
KanbanCard,
KanbanGroup,
} from '@toeverything/components/editor-core';
+import { useKanban } from '@toeverything/components/editor-core';
+import { styled } from '@toeverything/components/ui';
+import { useCallback } from 'react';
+import { CardItem } from './CardItem';
+import { CardItemPanelWrapper } from './dndable/wrapper/CardItemPanelWrapper';
const AddCardWrapper = styled('div')({
display: 'flex',
@@ -48,7 +48,7 @@ export const CardContext = (props: Props) => {
item={item}
active={activeId === id}
>
-
+
);
diff --git a/libs/components/editor-blocks/src/blocks/group/scene-kanban/CardItem.tsx b/libs/components/editor-blocks/src/blocks/group/scene-kanban/CardItem.tsx
index 837772bed2..b527711217 100644
--- a/libs/components/editor-blocks/src/blocks/group/scene-kanban/CardItem.tsx
+++ b/libs/components/editor-blocks/src/blocks/group/scene-kanban/CardItem.tsx
@@ -1,6 +1,6 @@
import {
+ KanbanBlockRender,
KanbanCard,
- RenderBlock,
useEditor,
useKanban,
} from '@toeverything/components/editor-core';
@@ -10,7 +10,6 @@ import {
MuiClickAwayListener,
styled,
} from '@toeverything/components/ui';
-import { useFlag } from '@toeverything/datasource/feature-flags';
import { useState, type MouseEvent } from 'react';
import { useRefPage } from './RefPage';
@@ -82,41 +81,37 @@ const Overlay = styled('div')({
},
});
-export const CardItem = ({
- id,
- block,
-}: {
- id: KanbanCard['id'];
- block: KanbanCard['block'];
-}) => {
+export const CardItem = ({ block }: { block: KanbanCard['block'] }) => {
const { addSubItem } = useKanban();
const { openSubPage } = useRefPage();
- const [editable, setEditable] = useState(false);
- const showKanbanRefPageFlag = useFlag('ShowKanbanRefPage', false);
+ const [editableBlock, setEditableBlock] = useState(null);
const { editor } = useEditor();
const onAddItem = async () => {
- setEditable(true);
- await addSubItem(block);
+ const newItem = await addSubItem(block);
+ setEditableBlock(newItem.id);
};
const onClickCard = async () => {
- openSubPage(id);
+ openSubPage(block.id);
};
const onClickPen = (e: MouseEvent) => {
e.stopPropagation();
- setEditable(true);
+ setEditableBlock(block.id);
editor.selectionManager.activeNodeByNodeId(block.id);
};
return (
- setEditable(false)}>
+ setEditableBlock(null)}>
-
+
- {showKanbanRefPageFlag && !editable && (
+ {!editableBlock && (
diff --git a/libs/components/editor-blocks/src/blocks/group/scene-kanban/RefPage.tsx b/libs/components/editor-blocks/src/blocks/group/scene-kanban/RefPage.tsx
index 3d223d121d..34d6dbb583 100644
--- a/libs/components/editor-blocks/src/blocks/group/scene-kanban/RefPage.tsx
+++ b/libs/components/editor-blocks/src/blocks/group/scene-kanban/RefPage.tsx
@@ -21,13 +21,17 @@ const Modal = ({ open, children }: { open: boolean; children?: ReactNode }) => {
return createPortal(
void }) => {
+ // Prevent trigger the bottom editor's selection
+ e.stopPropagation();
+ }}
+ onClick={closeSubPage}
style={{
display: 'flex',
flexDirection: 'column',
background: 'rgba(58, 76, 92, 0.4)',
zIndex: theme.affine.zIndex.popover,
}}
- onClick={closeSubPage}
>