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,38 @@
import { StrictMode } from 'react';
import { createRoot, type Root } from 'react-dom/client';
import { BasePlugin } from './../base-plugin';
import { PlaceholderPanel } from './PlaceholderPanel';
const PLUGIN_NAME = 'placeholder';
export class PlaceholderPlugin extends BasePlugin {
private root?: Root;
public static override get pluginName(): string {
return PLUGIN_NAME;
}
protected override on_render(): void {
const container = document.createElement('div');
// TODO remove
container.classList.add(`id-${PLUGIN_NAME}`);
window.document.body.appendChild(container);
this.root = createRoot(container);
this._renderPlugin();
}
private _renderPlugin(): void {
this.root?.render(
<StrictMode>
<PlaceholderPanel
editor={this.editor}
onClickTips={() => this.dispose()}
/>
</StrictMode>
);
}
public override dispose(): void {
this.root?.unmount();
}
}
@@ -0,0 +1,194 @@
import { useCallback, useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router';
import { Virgo, BlockEditor } from '@toeverything/framework/virgo';
import { debounce } from '@toeverything/utils';
import { MuiBox as Box, styled, BaseButton } from '@toeverything/components/ui';
import {
services,
type ReturnUnobserve,
TemplateFactory,
TemplateMeta,
} from '@toeverything/datasource/db-service';
const PlaceholderPanelContainer = styled('div')({
position: 'fixed',
top: '0px',
fontSize: '16px',
lineHeight: '22px',
opacity: '0.333',
});
const TemplateItemContainer = styled('div')({
'&:hover': {
backgroundColor: '#eee',
cursor: 'pointer',
},
});
const EmptyPageTipContainer = styled('div')({
cursor: 'pointer',
'&:hover': {
backgroundColor: '#eee',
cursor: 'pointer',
},
});
type PlaceholderPanelProps = {
editor: Virgo;
onClickTips?: () => void;
};
export const PlaceholderPanel = (props: PlaceholderPanelProps) => {
const editor = props.editor;
const workspaceId = editor.workspace;
const [point, setPoint] = useState({
x: 0,
y: 0,
});
const [open, setOpen] = useState(false);
// const navigate = useNavigate();
const ifPageChildrenExist = useCallback(async () => {
const rootId = await editor.getRootBlockId();
const dbPageBlock = await services.api.editorBlock.getBlock(
workspaceId,
rootId
);
if (!dbPageBlock) return;
if (dbPageBlock.children && dbPageBlock.children.length > 0) {
setOpen(false);
} else {
if (open) {
return;
}
setOpen(true);
adjustPosition();
}
}, [
editor,
workspaceId,
editor.getRootBlockId,
open,
services.api.editorBlock.getBlock,
]);
useEffect(() => {
let unobserve: ReturnUnobserve | undefined = undefined;
const observe = async () => {
const rootId = await editor.getRootBlockId();
unobserve = await services.api.editorBlock.observe(
{
workspace: workspaceId,
id: rootId,
},
() => {
ifPageChildrenExist();
}
);
};
observe();
return () => {
unobserve?.();
};
}, [editor, workspaceId, editor.getRootBlockId, ifPageChildrenExist]);
const adjustPosition = useCallback(async () => {
//@ts-ignore
const rootBlockDom = await editor.getBlockDomById(
editor.getRootBlockId()
);
const { x, y } = rootBlockDom.getBoundingClientRect();
setPoint({
x,
y: y + 60,
});
//@ts-ignore
}, [editor, editor.getRootBlockId, editor.getBlockDomById]);
useEffect(() => {
let unobserve: () => void;
const observerePageTreeChange = async () => {
unobserve = await services.api.pageTree.observe(
{ workspace: workspaceId, page: editor.getRootBlockId() },
ifPageChildrenExist
);
};
observerePageTreeChange();
return () => {
unobserve?.();
};
}, [editor, workspaceId, editor.getRootBlockId, ifPageChildrenExist, open]);
useEffect(() => {
ifPageChildrenExist();
}, [editor, ifPageChildrenExist, open]);
const handleClickEmptyPage = async () => {
const rootBlockId = await editor.getRootBlockId();
await services.api.editorBlock.copyTemplateToPage(
workspaceId,
rootBlockId,
TemplateFactory.generatePageTemplateByGroupKeys({
name: 'Empty Page',
groupKeys: ['empty'],
})
);
setOpen(false);
props.onClickTips();
};
const templateList: Array<TemplateMeta> =
TemplateFactory.defaultTemplateList;
const handleNewFromTemplate = async (template: TemplateMeta) => {
const pageId = await editor.getRootBlockId();
const newPage = await services.api.editorBlock.getBlock(
workspaceId,
pageId
);
await services.api.editorBlock.copyTemplateToPage(
workspaceId,
newPage.id,
TemplateFactory.generatePageTemplateByGroupKeys(template)
);
// redirectToPage(workspaceId, newPage.id);
// handleClose();
setOpen(false);
};
return (
<>
<PlaceholderPanelContainer
style={{
top: point.y + 'px',
left: point.x + 'px',
display: open ? 'block' : 'none',
}}
>
<EmptyPageTipContainer onClick={handleClickEmptyPage}>
Press Enter to continue with an empty page, or pick a
template
</EmptyPageTipContainer>
<div style={{ marginTop: '4px', marginLeft: '-8px' }}>
{templateList.map((template, index) => {
return (
<TemplateItemContainer
key={index}
onClick={() => {
handleNewFromTemplate(template);
}}
>
<BaseButton>{template.name}</BaseButton>
</TemplateItemContainer>
);
})}
</div>
</PlaceholderPanelContainer>
</>
);
};
@@ -0,0 +1 @@
export * from './Placeholder';