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
@@ -0,0 +1,120 @@
import { FC, useRef, useEffect, useMemo, useState } from 'react';
import { useParams } from 'react-router';
import { BackLink, TextProps } from '@toeverything/components/common';
import {
RenderBlockChildren,
BlockPendantProvider,
} from '@toeverything/components/editor-core';
import { ContentColumnValue } from '@toeverything/datasource/db-service';
import { CreateView } from '@toeverything/framework/virgo';
import { Theme, styled } from '@toeverything/components/ui';
import {
TextManage,
type ExtendedTextUtils,
} from '../../components/text-manage';
export const PageView: FC<CreateView> = ({ block, editor }) => {
const { workspace_id } = useParams();
const textRef = useRef<ExtendedTextUtils>(null);
const [backLinks, setBackLinks] =
useState<Awaited<ReturnType<typeof editor.search>>>();
const properties = useMemo(() => block.getProperties(), [block]);
const onTextEnter: TextProps['handleEnter'] = async props => {
const { splitContents } = props;
if (!splitContents) {
return false;
}
const { contentBeforeSelection, contentAfterSelection } = splitContents;
const before = [...contentBeforeSelection.content];
const after = [...contentAfterSelection.content];
const firstChild = await block.firstChild();
const maybeGroupBlock =
firstChild && firstChild.type === 'group' ? firstChild : null;
const groupBlock =
maybeGroupBlock ?? (await editor.createBlock('group', block.id));
if (!groupBlock) {
throw new Error('Failed to create group block');
}
const childBlock = await editor.createBlock('text', groupBlock.id);
if (!childBlock) {
throw new Error('Failed to create text block');
}
await childBlock.setProperties({
text: { value: after } as ContentColumnValue,
});
await block.setProperties({
text: { value: before } as ContentColumnValue,
});
await groupBlock.prepend(childBlock);
editor.selectionManager.activeNodeByNodeId(childBlock.id);
return true;
};
useEffect(() => {
// const title = properties['text']?.value?.[0]?.text;
// if (!title || !title.trim()) {
// try {
// const startSelection = text_ref.current.getStartSelection();
// text_ref.current.setSelection(startSelection);
// } catch (error) {
// console.error(error);
// }
// }
}, [properties]);
useEffect(() => {
editor
.search({ tag: `reference:${block.id}` })
.then(blocks => setBackLinks(blocks));
}, [block.id, editor]);
useEffect(() => {
// auto focus page title by default
editor.selectionManager.activeNodeByNodeId(block.id, 'end');
}, [block.id, editor]);
return (
<PageTitleBlock>
<BlockPendantProvider block={block}>
<TextManage
alwaysShowPlaceholder
ref={textRef}
className={'title'}
supportMarkdown={true}
handleEnter={onTextEnter}
placeholder={'Untitled'}
block={block}
editor={editor}
/>
</BlockPendantProvider>
{/* TODO: add back multi block select */}
{/* <div
contentEditable
className={style9(styles.content)}
suppressContentEditableWarning
> */}
<BackLink blocks={backLinks} workspaceId={workspace_id} />
{/*{block.childrenIds.map(childId => (*/}
{/* <RenderBlock key={childId} blockId={childId} />*/}
{/*))}*/}
<RenderBlockChildren block={block} />
</PageTitleBlock>
);
};
const PageTitleBlock = styled('div')({
'.title': {
fontSize: Theme.typography.page.fontSize,
lineHeight: Theme.typography.page.lineHeight,
},
'.content': {
outline: 'none',
},
});
@@ -0,0 +1,55 @@
import { withRecastTable } from '@toeverything/components/editor-core';
import {
Protocol,
DefaultColumnsValue,
} from '@toeverything/datasource/db-service';
import {
AsyncBlock,
BaseView,
ChildrenView,
getTextHtml,
getTextProperties,
SelectBlock,
} from '@toeverything/framework/virgo';
import { PageView } from './PageView';
import { ComponentType, FC } from 'react';
export const PageChildrenView: FC<ChildrenView> = props => props.children;
export class PageBlock extends BaseView {
type = Protocol.Block.Type.page;
View = withRecastTable(PageView);
// override ChildrenView = withRecastTable(PageChildrenView);
public override allowPendant = false;
override async onCreate(block: AsyncBlock): Promise<AsyncBlock> {
if (!block.getProperty('text')) {
await block.setProperty('text', {
value: [{ text: '' }],
});
}
return block;
}
override onExport(content: any): string {
return this.get_decoration<any>(content, 'text')?.value?.[0].text;
}
override getSelProperties(
block: AsyncBlock,
selectInfo: any
): DefaultColumnsValue {
const properties = super.getSelProperties(block, selectInfo);
return getTextProperties(properties, selectInfo);
}
override async block2html(
block: AsyncBlock,
children: SelectBlock[],
generateHtml: (el: any[]) => Promise<string>
): Promise<string> {
const content = getTextHtml(block);
const childrenContent = await generateHtml(children);
return `<h1>${content}</h1> ${childrenContent}`;
}
}
@@ -0,0 +1,4 @@
import { CustomText } from '@toeverything/components/common';
export interface PageProperties {
text: CustomText[];
}