feat: support subpage (#1663)

This commit is contained in:
Qi 2023-03-23 13:47:07 +08:00 committed by GitHub
parent 2551785451
commit 6a7b5601aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 824 additions and 82 deletions

View File

@ -14,10 +14,10 @@
"build:app": "tauri build"
},
"dependencies": {
"@blocksuite/blocks": "0.5.0-20230320164115-e612d17",
"@blocksuite/editor": "0.5.0-20230320164115-e612d17",
"@blocksuite/blocks": "0.5.0-20230323032255-e75ed32",
"@blocksuite/editor": "0.5.0-20230323032255-e75ed32",
"@blocksuite/icons": "2.0.23",
"@blocksuite/store": "0.5.0-20230320164115-e612d17",
"@blocksuite/store": "0.5.0-20230323032255-e75ed32",
"@emotion/react": "^11.10.6",
"@emotion/styled": "^11.10.6",
"@tauri-apps/api": "^1.2.0",

View File

@ -15,3 +15,4 @@ PREFETCH_WORKSPACE=1
ENABLE_BC_PROVIDER=1
EXPOSE_INTERNAL=1
ENABLE_DEBUG_PAGE=
ENABLE_SUBPAGE=

View File

@ -15,10 +15,10 @@
"@affine/env": "workspace:*",
"@affine/i18n": "workspace:*",
"@affine/templates": "workspace:*",
"@blocksuite/blocks": "0.5.0-20230320164115-e612d17",
"@blocksuite/editor": "0.5.0-20230320164115-e612d17",
"@blocksuite/blocks": "0.5.0-20230323032255-e75ed32",
"@blocksuite/editor": "0.5.0-20230323032255-e75ed32",
"@blocksuite/icons": "2.0.23",
"@blocksuite/store": "0.5.0-20230320164115-e612d17",
"@blocksuite/store": "0.5.0-20230323032255-e75ed32",
"@emotion/cache": "^11.10.5",
"@emotion/react": "^11.10.6",
"@emotion/server": "^11.10.0",

View File

@ -10,5 +10,6 @@ const config = {
enableDebugPage: Boolean(
process.env.ENABLE_DEBUG_PAGE ?? process.env.NODE_ENV === 'development'
),
enableSubpage: Boolean(process.env.ENABLE_SUBPAGE),
};
export default config;

View File

@ -21,7 +21,7 @@ import {
} from '@mui/material';
import { useAtomValue } from 'jotai';
import type React from 'react';
import { useMemo } from 'react';
import { useCallback, useMemo } from 'react';
import { workspacePreferredModeAtom } from '../../../../atoms';
import {
@ -87,9 +87,13 @@ type PageListProps = {
};
const filter = {
all: (pageMeta: PageMeta) => !pageMeta.trash,
trash: (pageMeta: PageMeta) => pageMeta.trash,
favorite: (pageMeta: PageMeta) => pageMeta.favorite,
all: (pageMeta: PageMeta, allMetas: PageMeta[]) => !pageMeta.trash,
trash: (pageMeta: PageMeta, allMetas: PageMeta[]) => {
const parentMeta = allMetas.find(m => m.subpageIds?.includes(pageMeta.id));
return !parentMeta?.trash && pageMeta.trash;
},
favorite: (pageMeta: PageMeta, allMetas: PageMeta[]) =>
pageMeta.favorite && !pageMeta.trash,
};
export const PageList: React.FC<PageListProps> = ({
@ -106,9 +110,26 @@ export const PageList: React.FC<PageListProps> = ({
const isTrash = listType === 'trash';
const record = useAtomValue(workspacePreferredModeAtom);
const list = useMemo(
() => pageList.filter(filter[listType ?? 'all']),
() =>
pageList.filter(pageMeta =>
filter[listType ?? 'all'](pageMeta, pageList)
),
[pageList, listType]
);
const restorePage = useCallback(
(pageMeta: PageMeta, allMetas: PageMeta[]) => {
helper.setPageMeta(pageMeta.id, {
trash: false,
});
allMetas
.filter(m => pageMeta?.subpageIds.includes(m.id))
.forEach(m => {
restorePage(m, allMetas);
});
},
[helper]
);
if (list.length === 0) {
return <Empty listType={listType} />;
}
@ -194,9 +215,7 @@ export const PageList: React.FC<PageListProps> = ({
blockSuiteWorkspace.removePage(pageId);
}}
onRestorePage={() => {
helper.setPageMeta(pageMeta.id, {
trash: false,
});
restorePage(pageMeta, pageList);
}}
onOpenPage={pageId => {
onClickPage(pageId, false);

View File

@ -1,5 +1,6 @@
import { MuiCollapse } from '@affine/component';
import { IconButton } from '@affine/component';
import { config } from '@affine/env';
import { useTranslation } from '@affine/i18n';
import {
ArrowDownSmallIcon,
@ -20,6 +21,7 @@ import { useSidebarStatus } from '../../../hooks/affine/use-sidebar-status';
import { usePageMeta } from '../../../hooks/use-page-meta';
import type { RemWorkspace } from '../../../shared';
import { SidebarSwitch } from '../../affine/sidebar-switch';
import { Pivot } from './pivot';
import {
StyledLink,
StyledListItem,
@ -168,6 +170,15 @@ export const WorkSpaceSliderBar: React.FC<WorkSpaceSliderBarProps> = ({
<span data-testid="all-pages">{t('All pages')}</span>
</StyledListItem>
</Link>
{config.enableSubpage && !!currentWorkspace && (
<Pivot
currentWorkspace={currentWorkspace}
openPage={openPage}
allMetas={pageMeta}
/>
)}
<StyledListItem
active={
currentPath ===

View File

@ -0,0 +1,232 @@
import { IconButton, MuiCollapse, TreeView } from '@affine/component';
import { DebugLogger } from '@affine/debug';
import { ArrowDownSmallIcon, FolderIcon } from '@blocksuite/icons';
import type { PageMeta } from '@blocksuite/store';
import { nanoid } from '@blocksuite/store';
import { useCallback, useMemo, useState } from 'react';
import { useBlockSuiteWorkspaceHelper } from '../../../../hooks/use-blocksuite-workspace-helper';
import { usePageMetaHelper } from '../../../../hooks/use-page-meta';
import type { RemWorkspace } from '../../../../shared';
import { StyledListItem } from '../style';
import type { TreeNode } from './types';
import { flattenToTree } from './utils';
const logger = new DebugLogger('pivot');
export const PivotInternal = ({
currentWorkspace,
openPage,
allMetas,
}: {
currentWorkspace: RemWorkspace;
openPage: (pageId: string) => void;
allMetas: PageMeta[];
}) => {
const { createPage } = useBlockSuiteWorkspaceHelper(
currentWorkspace.blockSuiteWorkspace
);
const { getPageMeta, setPageMeta, shiftPageMeta } = usePageMetaHelper(
currentWorkspace.blockSuiteWorkspace
);
const treeData = useMemo(
() => flattenToTree(allMetas, { openPage }),
[allMetas, openPage]
);
const handleAdd = useCallback(
(node: TreeNode) => {
const id = nanoid();
createPage(id, node.id);
openPage(id);
},
[createPage, openPage]
);
const handleDelete = useCallback(
(node: TreeNode) => {
const removeToTrash = (pageMeta: PageMeta) => {
const { subpageIds = [] } = pageMeta;
setPageMeta(pageMeta.id, { trash: true, trashDate: +new Date() });
subpageIds.forEach(id => {
const subpageMeta = getPageMeta(id);
subpageMeta && removeToTrash(subpageMeta);
});
};
removeToTrash(node as PageMeta);
},
[getPageMeta, setPageMeta]
);
const handleDrop = useCallback(
(
dragNode: TreeNode,
dropNode: TreeNode,
position: {
topLine: boolean;
bottomLine: boolean;
internal: boolean;
}
) => {
const { topLine, bottomLine } = position;
logger.info('handleDrop', { dragNode, dropNode, bottomLine, allMetas });
const dragParentMeta = allMetas.find(meta =>
meta.subpageIds?.includes(dragNode.id)
);
if (bottomLine || topLine) {
const insertOffset = bottomLine ? 1 : 0;
const dropParentMeta = allMetas.find(m =>
m.subpageIds?.includes(dropNode.id)
);
if (!dropParentMeta) {
// drop into root
logger.info('drop into root and resort');
if (dragParentMeta) {
const newSubpageIds = [...(dragParentMeta.subpageIds ?? [])];
const deleteIndex = dragParentMeta.subpageIds?.findIndex(
id => id === dragNode.id
);
newSubpageIds.splice(deleteIndex, 1);
setPageMeta(dragParentMeta.id, {
subpageIds: newSubpageIds,
});
}
logger.info('resort root meta');
const insertIndex =
allMetas.findIndex(m => m.id === dropNode.id) + insertOffset;
shiftPageMeta(dragNode.id, insertIndex);
return;
}
if (
dragParentMeta &&
(dragParentMeta.id === dropNode.id ||
dragParentMeta.id === dropParentMeta!.id)
) {
logger.info('drop to resort');
// need to resort
const newSubpageIds = [...(dragParentMeta.subpageIds ?? [])];
const deleteIndex = newSubpageIds.findIndex(id => id === dragNode.id);
newSubpageIds.splice(deleteIndex, 1);
const insertIndex =
newSubpageIds.findIndex(id => id === dropNode.id) + insertOffset;
newSubpageIds.splice(insertIndex, 0, dragNode.id);
setPageMeta(dropParentMeta.id, {
subpageIds: newSubpageIds,
});
return;
}
logger.info('drop into drop node parent and resort');
if (dragParentMeta) {
const metaIndex = dragParentMeta.subpageIds.findIndex(
id => id === dragNode.id
);
const newSubpageIds = [...dragParentMeta.subpageIds];
newSubpageIds.splice(metaIndex, 1);
setPageMeta(dragParentMeta.id, {
subpageIds: newSubpageIds,
});
}
const newSubpageIds = [...(dropParentMeta!.subpageIds ?? [])];
const insertIndex =
newSubpageIds.findIndex(id => id === dropNode.id) + 1;
newSubpageIds.splice(insertIndex, 0, dragNode.id);
setPageMeta(dropParentMeta.id, {
subpageIds: newSubpageIds,
});
return;
}
logger.info('drop into the drop node');
// drop into the node
if (dragParentMeta && dragParentMeta.id === dropNode.id) {
return;
}
if (dragParentMeta) {
const metaIndex = dragParentMeta.subpageIds.findIndex(
id => id === dragNode.id
);
const newSubpageIds = [...dragParentMeta.subpageIds];
newSubpageIds.splice(metaIndex, 1);
setPageMeta(dragParentMeta.id, {
subpageIds: newSubpageIds,
});
}
const dropMeta = allMetas.find(meta => meta.id === dropNode.id)!;
const newSubpageIds = [dragNode.id, ...(dropMeta.subpageIds ?? [])];
setPageMeta(dropMeta.id, {
subpageIds: newSubpageIds,
});
},
[allMetas, setPageMeta, shiftPageMeta]
);
return (
<TreeView
data={treeData}
onAdd={handleAdd}
onDelete={handleDelete}
onDrop={handleDrop}
/>
);
};
export const Pivot = ({
currentWorkspace,
openPage,
allMetas,
}: {
currentWorkspace: RemWorkspace;
openPage: (pageId: string) => void;
allMetas: PageMeta[];
}) => {
const [showPivot, setShowPivot] = useState(true);
return (
<>
<StyledListItem>
<FolderIcon />
Pivot
<IconButton
darker={true}
onClick={useCallback(() => {
setShowPivot(!showPivot);
}, [showPivot])}
>
<ArrowDownSmallIcon
style={{
transform: `rotate(${showPivot ? '180' : '0'}deg)`,
}}
/>
</IconButton>
</StyledListItem>
<MuiCollapse
in={showPivot}
style={{
maxHeight: 300,
paddingLeft: '12px',
overflowY: 'auto',
}}
>
<PivotInternal
currentWorkspace={currentWorkspace}
openPage={openPage}
allMetas={allMetas}
/>
</MuiCollapse>
</>
);
};
export default Pivot;

View File

@ -0,0 +1,69 @@
import { IconButton } from '@affine/component';
import {
ArrowDownSmallIcon,
DeleteTemporarilyIcon,
PlusIcon,
} from '@blocksuite/icons';
import { useRouter } from 'next/router';
import { StyledCollapsedButton, StyledPivotItem } from './styles';
import type { TreeNode } from './types';
export const TreeNodeRender: TreeNode['render'] = (
node,
{ onAdd, onDelete, collapsed, setCollapsed },
extendProps
) => {
const { openPage } = extendProps as { openPage: (pageId: string) => void };
const router = useRouter();
const active = router.query.pageId === node.id;
return (
<StyledPivotItem
onClick={() => {
if (active) {
return;
}
openPage(node.id);
}}
active={active}
>
<StyledCollapsedButton
show={!!node.children?.length}
onClick={e => {
e.stopPropagation();
setCollapsed(!collapsed);
}}
size="small"
>
<ArrowDownSmallIcon
style={{
transform: `rotate(${collapsed ? '0' : '180'}deg)`,
}}
/>
</StyledCollapsedButton>
<span>{node.title || 'Untitled'}</span>
<IconButton
onClick={e => {
e.stopPropagation();
onAdd();
}}
size="small"
className="pivot-item-button"
>
<PlusIcon />
</IconButton>
<IconButton
onClick={e => {
e.stopPropagation();
onDelete();
}}
size="small"
className="pivot-item-button"
>
<DeleteTemporarilyIcon />
</IconButton>
</StyledPivotItem>
);
};

View File

@ -0,0 +1,2 @@
export * from './Pivot';
export * from './types';

View File

@ -0,0 +1,47 @@
import {
displayFlex,
IconButton,
styled,
textEllipsis,
} from '@affine/component';
export const StyledPivotItem = styled('div')<{ active: boolean }>(
({ active, theme }) => {
return {
width: '100%',
height: '32px',
...displayFlex('flex-start', 'center'),
paddingLeft: '24px',
position: 'relative',
color: active ? theme.colors.primaryColor : theme.colors.textColor,
cursor: 'pointer',
span: {
flexGrow: '1',
...textEllipsis(1),
},
'.pivot-item-button': {
display: 'none',
},
':hover': {
'.pivot-item-button': {
display: 'flex',
},
},
};
}
);
export const StyledCollapsedButton = styled(IconButton, {
shouldForwardProp: prop => {
return !['show'].includes(prop as string);
},
})<{ show: boolean }>(({ show }) => {
return {
display: show ? 'block' : 'none',
position: 'absolute',
left: '0px',
top: '0px',
bottom: '0px',
margin: 'auto',
};
});

View File

@ -0,0 +1,4 @@
import type { Node } from '@affine/component';
import type { PageMeta } from '@blocksuite/store';
export type TreeNode = Node<PageMeta>;

View File

@ -0,0 +1,43 @@
import type { PageMeta } from '@blocksuite/store';
import { TreeNodeRender } from './TreeNodeRender';
import type { TreeNode } from './types';
export const flattenToTree = (
handleMetas: PageMeta[],
renderProps: { openPage: (pageId: string) => void }
): TreeNode[] => {
// Compatibility process: the old data not has `subpageIds`, it is a root page
const metas = JSON.parse(JSON.stringify(handleMetas)) as PageMeta[];
const rootMetas = metas
.filter(meta => {
if (meta.subpageIds) {
return (
metas.find(m => {
return m.subpageIds?.includes(meta.id);
}) === undefined
);
}
return true;
})
.filter(meta => !meta.trash);
const helper = (internalMetas: PageMeta[]): TreeNode[] => {
return internalMetas.reduce<TreeNode[]>((returnedMetas, internalMeta) => {
const { subpageIds = [] } = internalMeta;
const childrenMetas = subpageIds
.map(id => metas.find(m => m.id === id)!)
.filter(meta => !meta.trash);
// FIXME: remove ts-ignore after blocksuite update
// @ts-ignore
const returnedMeta: TreeNode = {
...internalMeta,
children: helper(childrenMetas),
render: (node, props) => TreeNodeRender!(node, props, renderProps),
};
// @ts-ignore
returnedMetas.push(returnedMeta);
return returnedMetas;
}, []);
};
return helper(rootMetas);
};

View File

@ -9,9 +9,9 @@ export function useBlockSuiteWorkspaceHelper(
) {
return useMemo(
() => ({
createPage: (pageId: string, title?: string): Page => {
createPage: (pageId: string, parentId?: string): Page => {
assertExists(blockSuiteWorkspace);
return blockSuiteWorkspace.createPage(pageId);
return blockSuiteWorkspace.createPage(pageId, parentId);
},
}),
[blockSuiteWorkspace]

View File

@ -22,7 +22,6 @@ declare global {
callback: Set<() => void>;
};
}
if (!globalThis.featureFlag) {
globalThis.featureFlag = featureFlag;
}

View File

@ -6,6 +6,7 @@ import type { BlockSuiteWorkspace } from '../shared';
declare module '@blocksuite/store' {
interface PageMeta {
favorite?: boolean;
subpageIds: string[];
trash?: boolean;
trashDate?: number;
// whether to create the page with the default template
@ -45,6 +46,12 @@ export function usePageMetaHelper(blockSuiteWorkspace: BlockSuiteWorkspace) {
setPageMeta: (pageId: string, pageMeta: Partial<PageMeta>) => {
blockSuiteWorkspace.meta.setPageMeta(pageId, pageMeta);
},
getPageMeta: (pageId: string) => {
return blockSuiteWorkspace.meta.getPageMeta(pageId);
},
shiftPageMeta: (pageId: string, index: number) => {
return blockSuiteWorkspace.meta.shiftPageMeta(pageId, index);
},
}),
[blockSuiteWorkspace]
);

View File

@ -15,11 +15,11 @@
"dependencies": {
"@affine/debug": "workspace:*",
"@affine/i18n": "workspace:*",
"@blocksuite/blocks": "0.5.0-20230320164115-e612d17",
"@blocksuite/editor": "0.5.0-20230320164115-e612d17",
"@blocksuite/global": "0.5.0-20230320164115-e612d17",
"@blocksuite/blocks": "0.5.0-20230323032255-e75ed32",
"@blocksuite/editor": "0.5.0-20230323032255-e75ed32",
"@blocksuite/global": "0.5.0-20230323032255-e75ed32",
"@blocksuite/icons": "2.0.23",
"@blocksuite/store": "0.5.0-20230320164115-e612d17",
"@blocksuite/store": "0.5.0-20230323032255-e75ed32",
"@emotion/cache": "^11.10.5",
"@emotion/react": "^11.10.6",
"@emotion/server": "^11.10.0",
@ -29,6 +29,8 @@
"@mui/material": "^5.11.13",
"lit": "^2.6.1",
"react": "^18.2.0",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.2.0",
"react-is": "^18.2.0"
},
@ -44,6 +46,7 @@
"@storybook/test-runner": "0.10.0-next.11",
"@storybook/testing-library": "0.0.14-next.1",
"@types/react": "^18.0.28",
"@types/react-dnd": "^3.0.2",
"@types/react-dom": "18.0.11",
"@vitejs/plugin-react": "^3.1.0",
"jest-mock": "^29.5.0",

View File

@ -15,6 +15,7 @@ export * from './ui/shared/Container';
export * from './ui/table';
export * from './ui/toast';
export * from './ui/tooltip';
export * from './ui/tree-view';
declare module '@mui/material/styles' {
interface Theme {

View File

@ -0,0 +1,128 @@
import { useState } from 'react';
import { useDrag, useDrop } from 'react-dnd';
import {
StyledCollapse,
StyledNodeLine,
StyledTreeNodeContainer,
StyledTreeNodeItem,
} from './styles';
import type { Node, NodeLIneProps, TreeNodeProps } from './types';
const NodeLine = <N,>({
node,
onDrop,
allowDrop = true,
isTop = false,
}: NodeLIneProps<N>) => {
const [{ isOver }, drop] = useDrop(
() => ({
accept: 'node',
drop: (item: Node<N>, monitor) => {
const didDrop = monitor.didDrop();
if (didDrop) {
return;
}
onDrop?.(item, node, {
internal: false,
topLine: isTop,
bottomLine: !isTop,
});
},
collect: monitor => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
}),
[onDrop]
);
return <StyledNodeLine ref={drop} show={isOver && allowDrop} isTop={isTop} />;
};
export const TreeNode = <N,>({
node,
index,
allDrop = true,
...otherProps
}: TreeNodeProps<N>) => {
const { onAdd, onDelete, onDrop } = otherProps;
const [collapsed, setCollapsed] = useState(false);
const [{ isDragging }, drag] = useDrag(() => ({
type: 'node',
item: node,
collect: monitor => ({
isDragging: monitor.isDragging(),
}),
}));
const [{ canDrop, isOver }, drop] = useDrop(
() => ({
accept: 'node',
drop: (item: Node<N>, monitor) => {
const didDrop = monitor.didDrop();
if (didDrop || item.id === node.id || !allDrop) {
return;
}
onDrop?.(item, node, {
internal: true,
topLine: false,
bottomLine: false,
});
},
collect: monitor => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
}),
[onDrop, allDrop]
);
return (
<StyledTreeNodeContainer ref={drag} isDragging={isDragging}>
<StyledTreeNodeItem
ref={drop}
isOver={isOver && !isDragging}
canDrop={canDrop}
>
{index === 0 && (
<NodeLine
node={node}
{...otherProps}
allowDrop={!isDragging && allDrop}
isTop={true}
/>
)}
{node.render?.(node, {
onAdd: () => onAdd?.(node),
onDelete: () => onDelete?.(node),
collapsed,
setCollapsed,
})}
{(!node.children?.length || collapsed) && (
<NodeLine
node={node}
{...otherProps}
allowDrop={!isDragging && allDrop}
/>
)}
</StyledTreeNodeItem>
<StyledCollapse in={!collapsed}>
{node.children &&
node.children.map((childNode, index) => (
<TreeNode
key={childNode.id}
node={childNode}
index={index}
allDrop={isDragging ? false : allDrop}
{...otherProps}
/>
))}
</StyledCollapse>
</StyledTreeNodeContainer>
);
};
export default TreeNode;

View File

@ -0,0 +1,16 @@
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { TreeNode } from './TreeNode';
import type { TreeViewProps } from './types';
export const TreeView = <N,>({ data, ...otherProps }: TreeViewProps<N>) => {
return (
<DndProvider backend={HTML5Backend}>
{data.map((node, index) => (
<TreeNode key={node.id} index={index} node={node} {...otherProps} />
))}
</DndProvider>
);
};
export default TreeView;

View File

@ -0,0 +1,3 @@
export * from './TreeNode';
export * from './TreeView';
export * from './types';

View File

@ -0,0 +1,40 @@
import MuiCollapse from '@mui/material/Collapse';
import { styled } from '../../styles';
export const StyledCollapse = styled(MuiCollapse)(() => {
return {
paddingLeft: '12px',
};
});
export const StyledTreeNodeItem = styled('div')<{
isOver?: boolean;
canDrop?: boolean;
}>(({ isOver, canDrop, theme }) => {
return {
background: isOver && canDrop ? theme.colors.hoverBackground : '',
position: 'relative',
};
});
export const StyledTreeNodeContainer = styled('div')<{ isDragging: boolean }>(
({ isDragging, theme }) => {
return {
background: isDragging ? theme.colors.hoverBackground : '',
};
}
);
export const StyledNodeLine = styled('div')<{ show: boolean; isTop?: boolean }>(
({ show, isTop = false, theme }) => {
return {
position: 'absolute',
left: '0',
...(isTop ? { top: '0' } : { bottom: '0' }),
width: '100%',
paddingTop: '3px',
borderBottom: '3px solid',
borderColor: show ? theme.colors.primaryColor : 'transparent',
zIndex: 1,
};
}
);

View File

@ -0,0 +1,45 @@
import type { ReactNode } from 'react';
export type Node<N> = {
id: string;
children?: Node<N>[];
render?: (
node: Node<N>,
eventsAndStatus: {
onAdd: () => void;
onDelete: () => void;
collapsed: boolean;
setCollapsed: (collapsed: boolean) => void;
},
extendProps?: unknown
) => ReactNode;
} & N;
type CommonProps<N> = {
onAdd?: (node: Node<N>) => void;
onDelete?: (node: Node<N>) => void;
onDrop?: (
dragNode: Node<N>,
dropNode: Node<N>,
position: {
topLine: boolean;
bottomLine: boolean;
internal: boolean;
}
) => void;
};
export type TreeNodeProps<N> = {
node: Node<N>;
index: number;
allDrop?: boolean;
} & CommonProps<N>;
export type TreeViewProps<N> = {
data: Node<N>[];
} & CommonProps<N>;
export type NodeLIneProps<N> = {
allowDrop: boolean;
isTop?: boolean;
} & Pick<TreeNodeProps<N>, 'node' | 'onDrop'>;

View File

@ -14,8 +14,8 @@
},
"dependencies": {
"@affine/debug": "workspace:*",
"@blocksuite/blocks": "0.5.0-20230320164115-e612d17",
"@blocksuite/store": "0.5.0-20230320164115-e612d17",
"@blocksuite/blocks": "0.5.0-20230323032255-e75ed32",
"@blocksuite/store": "0.5.0-20230323032255-e75ed32",
"@tauri-apps/api": "^1.2.0",
"encoding": "^0.1.13",
"firebase": "^9.18.0",

View File

@ -9,7 +9,7 @@
"zod": "^3.21.4"
},
"dependencies": {
"@blocksuite/global": "0.5.0-20230320164115-e612d17",
"@blocksuite/global": "0.5.0-20230323032255-e75ed32",
"lit": "^2.6.1"
}
}

View File

@ -112,6 +112,7 @@ export const publicRuntimeConfigSchema = z.object({
prefetchWorkspace: z.boolean(),
// expose internal api to globalThis, **development only**
exposeInternal: z.boolean(),
enableSubpage: z.boolean(),
});
export type PublicRuntimeConfig = z.infer<typeof publicRuntimeConfigSchema>;

186
yarn.lock
View File

@ -22,10 +22,10 @@ __metadata:
"@affine/env": "workspace:*"
"@affine/i18n": "workspace:*"
"@affine/templates": "workspace:*"
"@blocksuite/blocks": 0.5.0-20230320164115-e612d17
"@blocksuite/editor": 0.5.0-20230320164115-e612d17
"@blocksuite/blocks": 0.5.0-20230323032255-e75ed32
"@blocksuite/editor": 0.5.0-20230323032255-e75ed32
"@blocksuite/icons": 2.0.23
"@blocksuite/store": 0.5.0-20230320164115-e612d17
"@blocksuite/store": 0.5.0-20230323032255-e75ed32
"@emotion/cache": ^11.10.5
"@emotion/react": ^11.10.6
"@emotion/server": ^11.10.0
@ -83,10 +83,10 @@ __metadata:
version: 0.0.0-use.local
resolution: "@affine/client-app@workspace:apps/desktop"
dependencies:
"@blocksuite/blocks": 0.5.0-20230320164115-e612d17
"@blocksuite/editor": 0.5.0-20230320164115-e612d17
"@blocksuite/blocks": 0.5.0-20230323032255-e75ed32
"@blocksuite/editor": 0.5.0-20230323032255-e75ed32
"@blocksuite/icons": 2.0.23
"@blocksuite/store": 0.5.0-20230320164115-e612d17
"@blocksuite/store": 0.5.0-20230323032255-e75ed32
"@emotion/react": ^11.10.6
"@emotion/styled": ^11.10.6
"@tauri-apps/api": ^1.2.0
@ -118,11 +118,11 @@ __metadata:
dependencies:
"@affine/debug": "workspace:*"
"@affine/i18n": "workspace:*"
"@blocksuite/blocks": 0.5.0-20230320164115-e612d17
"@blocksuite/editor": 0.5.0-20230320164115-e612d17
"@blocksuite/global": 0.5.0-20230320164115-e612d17
"@blocksuite/blocks": 0.5.0-20230323032255-e75ed32
"@blocksuite/editor": 0.5.0-20230323032255-e75ed32
"@blocksuite/global": 0.5.0-20230323032255-e75ed32
"@blocksuite/icons": 2.0.23
"@blocksuite/store": 0.5.0-20230320164115-e612d17
"@blocksuite/store": 0.5.0-20230323032255-e75ed32
"@emotion/cache": ^11.10.5
"@emotion/react": ^11.10.6
"@emotion/server": ^11.10.0
@ -141,11 +141,14 @@ __metadata:
"@storybook/test-runner": 0.10.0-next.11
"@storybook/testing-library": 0.0.14-next.1
"@types/react": ^18.0.28
"@types/react-dnd": ^3.0.2
"@types/react-dom": 18.0.11
"@vitejs/plugin-react": ^3.1.0
jest-mock: ^29.5.0
lit: ^2.6.1
react: ^18.2.0
react-dnd: ^16.0.1
react-dnd-html5-backend: ^16.0.1
react-dom: ^18.2.0
react-is: ^18.2.0
storybook: 7.0.0-rc.1
@ -161,8 +164,8 @@ __metadata:
resolution: "@affine/datacenter@workspace:packages/data-center"
dependencies:
"@affine/debug": "workspace:*"
"@blocksuite/blocks": 0.5.0-20230320164115-e612d17
"@blocksuite/store": 0.5.0-20230320164115-e612d17
"@blocksuite/blocks": 0.5.0-20230323032255-e75ed32
"@blocksuite/store": 0.5.0-20230323032255-e75ed32
"@tauri-apps/api": ^1.2.0
encoding: ^0.1.13
fake-indexeddb: 4.0.1
@ -215,7 +218,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@affine/env@workspace:packages/env"
dependencies:
"@blocksuite/global": 0.5.0-20230320164115-e612d17
"@blocksuite/global": 0.5.0-20230323032255-e75ed32
lit: ^2.6.1
next: =13.2.3
react: ^18.2.0
@ -1752,15 +1755,14 @@ __metadata:
languageName: node
linkType: hard
"@blocksuite/blocks@npm:0.5.0-20230320164115-e612d17":
version: 0.5.0-20230320164115-e612d17
resolution: "@blocksuite/blocks@npm:0.5.0-20230320164115-e612d17"
"@blocksuite/blocks@npm:0.5.0-20230323032255-e75ed32":
version: 0.5.0-20230323032255-e75ed32
resolution: "@blocksuite/blocks@npm:0.5.0-20230323032255-e75ed32"
dependencies:
"@blocksuite/global": 0.5.0-20230320164115-e612d17
"@blocksuite/phasor": 0.5.0-20230320164115-e612d17
"@blocksuite/virgo": 0.5.0-20230320164115-e612d17
"@blocksuite/global": 0.5.0-20230323032255-e75ed32
"@blocksuite/phasor": 0.5.0-20230323032255-e75ed32
"@blocksuite/virgo": 0.5.0-20230323032255-e75ed32
"@popperjs/core": ^2.11.6
highlight.js: ^11.7.0
hotkeys-js: ^3.10.1
lit: ^2.6.1
marked: ^4.2.12
@ -1768,29 +1770,29 @@ __metadata:
turndown: ^7.1.1
zod: ^3.21.4
peerDependencies:
"@blocksuite/store": 0.5.0-20230320164115-e612d17
checksum: ebbe156f0e0320ecac28e744bde121671d7c2eedfb222a89c454c98662d27a59dc362f9b1d00c236ac5e8ffd5af900e70b4fe0e8d2c6e5acea3260ea96bd9ce7
"@blocksuite/store": 0.5.0-20230323032255-e75ed32
checksum: 6b850678b983ca7a0e85abf32a32dba2b52b95935d15ae831f23505933bc98b651972417a986a5d43aabe26e7497773d9e12a263dcfafb690665d0f88bc6224b
languageName: node
linkType: hard
"@blocksuite/editor@npm:0.5.0-20230320164115-e612d17":
version: 0.5.0-20230320164115-e612d17
resolution: "@blocksuite/editor@npm:0.5.0-20230320164115-e612d17"
"@blocksuite/editor@npm:0.5.0-20230323032255-e75ed32":
version: 0.5.0-20230323032255-e75ed32
resolution: "@blocksuite/editor@npm:0.5.0-20230323032255-e75ed32"
dependencies:
"@blocksuite/global": 0.5.0-20230320164115-e612d17
"@blocksuite/global": 0.5.0-20230323032255-e75ed32
lit: ^2.6.1
marked: ^4.2.12
turndown: ^7.1.1
peerDependencies:
"@blocksuite/blocks": 0.5.0-20230320164115-e612d17
"@blocksuite/store": 0.5.0-20230320164115-e612d17
checksum: 8e797059cd2df4ae3f17d9c39ae3b8493d40cb26303a0aee53113a6dc5d60943fc7bea008f8928543267e2883fb729230aedb90a142b5c01c330d044befbb0a3
"@blocksuite/blocks": 0.5.0-20230323032255-e75ed32
"@blocksuite/store": 0.5.0-20230323032255-e75ed32
checksum: dec95740eacca9294a53547503480fa5681c10ca914c7b214e8a367fe52e8fe5e0dc1de4cf63439b49acb69b95220b1d9f70cd1d3ca55775a70087ef7922d900
languageName: node
linkType: hard
"@blocksuite/global@npm:0.5.0-20230320164115-e612d17":
version: 0.5.0-20230320164115-e612d17
resolution: "@blocksuite/global@npm:0.5.0-20230320164115-e612d17"
"@blocksuite/global@npm:0.5.0-20230323032255-e75ed32":
version: 0.5.0-20230323032255-e75ed32
resolution: "@blocksuite/global@npm:0.5.0-20230323032255-e75ed32"
dependencies:
ansi-colors: ^4.1.3
zod: ^3.21.4
@ -1799,7 +1801,7 @@ __metadata:
peerDependenciesMeta:
lit:
optional: true
checksum: 78f4b473a7d0fa1caa9c4fccb020064f56ca8d9d7585fdd706d8a6bd88e5abeda899596bce56cb7ef19309535144ec817267b032a8567f179ea6e580e1b57526
checksum: 2a72cb1407bf4a8438a385b7c7421b6c7c053641b20a20d7a2c43230933d75460331ff8d810c239dafa7769e13723a4caeb56fb1067ccda77011654ea936c533
languageName: node
linkType: hard
@ -1813,26 +1815,26 @@ __metadata:
languageName: node
linkType: hard
"@blocksuite/phasor@npm:0.5.0-20230320164115-e612d17":
version: 0.5.0-20230320164115-e612d17
resolution: "@blocksuite/phasor@npm:0.5.0-20230320164115-e612d17"
"@blocksuite/phasor@npm:0.5.0-20230323032255-e75ed32":
version: 0.5.0-20230323032255-e75ed32
resolution: "@blocksuite/phasor@npm:0.5.0-20230323032255-e75ed32"
dependencies:
"@blocksuite/global": 0.5.0-20230320164115-e612d17
"@blocksuite/global": 0.5.0-20230323032255-e75ed32
fractional-indexing: ^3.2.0
perfect-freehand: ^1.2.0
peerDependencies:
nanoid: ^4
yjs: ^13
checksum: 06fb6d531aa84838cbcaf0b5ddb0e1da40a98da165e570ac70348e76e459a6a9c93ee71bd4b536b05e4dd51e89bf243d96eb6add755ffda20d2dcd6e497bd2fa
checksum: 083f5932edf4366274406b979be90af54898c7c788d8243ffc0013124e67e520ffb35ad3ae8a0120d2399a12c85659454afc743f3a73498dabbc72ed6164d122
languageName: node
linkType: hard
"@blocksuite/store@npm:0.5.0-20230320164115-e612d17":
version: 0.5.0-20230320164115-e612d17
resolution: "@blocksuite/store@npm:0.5.0-20230320164115-e612d17"
"@blocksuite/store@npm:0.5.0-20230323032255-e75ed32":
version: 0.5.0-20230323032255-e75ed32
resolution: "@blocksuite/store@npm:0.5.0-20230323032255-e75ed32"
dependencies:
"@blocksuite/global": 0.5.0-20230320164115-e612d17
"@blocksuite/virgo": 0.5.0-20230320164115-e612d17
"@blocksuite/global": 0.5.0-20230323032255-e75ed32
"@blocksuite/virgo": 0.5.0-20230323032255-e75ed32
"@types/flexsearch": ^0.7.3
buffer: ^6.0.3
flexsearch: 0.7.21
@ -1846,20 +1848,20 @@ __metadata:
zod: ^3.21.4
peerDependencies:
yjs: ^13
checksum: 5e8f0f6d37a2ae66bd3df1cca67fb21322a78220cbc4114ba19e6486c6e9edab9b24bd14e99045822eae4af9c0116c86de463e87ad45503268d71a96dbc126b0
checksum: ff5ec05f74a397fe29302b61e87b13e26029e0cf03356029058cc2cc1f791f3bd0643ed9b29950718c58c67e374922610ab91b2546feeee8e26828d7e99089d7
languageName: node
linkType: hard
"@blocksuite/virgo@npm:0.5.0-20230320164115-e612d17":
version: 0.5.0-20230320164115-e612d17
resolution: "@blocksuite/virgo@npm:0.5.0-20230320164115-e612d17"
"@blocksuite/virgo@npm:0.5.0-20230323032255-e75ed32":
version: 0.5.0-20230323032255-e75ed32
resolution: "@blocksuite/virgo@npm:0.5.0-20230323032255-e75ed32"
dependencies:
"@blocksuite/global": 0.5.0-20230320164115-e612d17
"@blocksuite/global": 0.5.0-20230323032255-e75ed32
zod: ^3.21.4
peerDependencies:
lit: ^2
yjs: ^13
checksum: 3e9154f4abe501f5a880a4c2fed45077451b55bbf6386cb1cd8fb7efd4e621818961b9cdcadcd1f00d1b97760b6b509557b866addd9b18fab0f8410f7ac9139c
checksum: 9407ea1707ca586926f4cf417adcba89928255840f645865443d791d988cb2cb8d2bfb4cad5ce1eaead1fbdb75f6a5f9cf41c7e5f7d181380854b9cc9b85d3d2
languageName: node
linkType: hard
@ -4598,6 +4600,27 @@ __metadata:
languageName: node
linkType: hard
"@react-dnd/asap@npm:^5.0.1":
version: 5.0.2
resolution: "@react-dnd/asap@npm:5.0.2"
checksum: 18f040e53512983f11c542ef21e6e4cac605d585a10cd764b13bc1b2f3ac7490e0fa40503adc348d8387aa45bc8e7eebe9cb33003b960a30bb5fde666ff2adde
languageName: node
linkType: hard
"@react-dnd/invariant@npm:^4.0.1":
version: 4.0.2
resolution: "@react-dnd/invariant@npm:4.0.2"
checksum: 594f6d78896c19bb8f023e101334fd91a9fdff686117bd8e830ba53737ec0a6042dab66971d3d63c7afbc622103909aff7a64c5c6767e0aa8d9561fd42705016
languageName: node
linkType: hard
"@react-dnd/shallowequal@npm:^4.0.1":
version: 4.0.2
resolution: "@react-dnd/shallowequal@npm:4.0.2"
checksum: 7f21d691bddbfd4d2830948cbeefecca1600b2b46bcb1934926795f07ae8a1fa60a3dfd3a2112be5ef682c3820c80a99711e9fa15843f7e300acb25a4ecb70ab
languageName: node
linkType: hard
"@redux-devtools/extension@npm:^3.2.5":
version: 3.2.5
resolution: "@redux-devtools/extension@npm:3.2.5"
@ -6846,6 +6869,15 @@ __metadata:
languageName: node
linkType: hard
"@types/react-dnd@npm:^3.0.2":
version: 3.0.2
resolution: "@types/react-dnd@npm:3.0.2"
dependencies:
react-dnd: "*"
checksum: 3013caff425f1b3c0cd2b79e7b7763f88f100a6ef5aa5e5cec7636119a71976827ee7bd316d7724f3a179e1f076b1fa1726fefcb9743b780d4bec4f0cd8aacfb
languageName: node
linkType: hard
"@types/react-dom@npm:18.0.11, @types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.0.11":
version: 18.0.11
resolution: "@types/react-dom@npm:18.0.11"
@ -9707,6 +9739,17 @@ __metadata:
languageName: node
linkType: hard
"dnd-core@npm:^16.0.1":
version: 16.0.1
resolution: "dnd-core@npm:16.0.1"
dependencies:
"@react-dnd/asap": ^5.0.1
"@react-dnd/invariant": ^4.0.1
redux: ^4.2.0
checksum: b7d3ef4664f433af796f440ddd27ad9d7fef0205f26c4b7c0af6ebf612ffa9b33e64d095d3e79190c4baaed34aa36570f321ebe0d2cc8ff1031ff158a0907b3f
languageName: node
linkType: hard
"doctrine@npm:^2.1.0":
version: 2.1.0
resolution: "doctrine@npm:2.1.0"
@ -12493,14 +12536,7 @@ __metadata:
languageName: node
linkType: hard
"highlight.js@npm:^11.7.0":
version: 11.7.0
resolution: "highlight.js@npm:11.7.0"
checksum: 19e3fb8b56f4b361b057a8523b989dfeb6479bbd1e29cec3fac6fa5c78d09927d5fa61b7dba6631fdb57cfdca9b3084aa4da49405ceaf4a67f67beae2ed5b77d
languageName: node
linkType: hard
"hoist-non-react-statics@npm:^3.3.1":
"hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2":
version: 3.3.2
resolution: "hoist-non-react-statics@npm:3.3.2"
dependencies:
@ -17053,6 +17089,40 @@ __metadata:
languageName: node
linkType: hard
"react-dnd-html5-backend@npm:^16.0.1":
version: 16.0.1
resolution: "react-dnd-html5-backend@npm:16.0.1"
dependencies:
dnd-core: ^16.0.1
checksum: e2368bf85d5632a5cd867b743feb54c9052d909ea5331608860fa455edf3c633ac791f5b338e3db29b19ea8670c0ba5fb43c9c1c2510760bea030811d726cdfa
languageName: node
linkType: hard
"react-dnd@npm:*, react-dnd@npm:^16.0.1":
version: 16.0.1
resolution: "react-dnd@npm:16.0.1"
dependencies:
"@react-dnd/invariant": ^4.0.1
"@react-dnd/shallowequal": ^4.0.1
dnd-core: ^16.0.1
fast-deep-equal: ^3.1.3
hoist-non-react-statics: ^3.3.2
peerDependencies:
"@types/hoist-non-react-statics": ">= 3.3.1"
"@types/node": ">= 12"
"@types/react": ">= 16"
react: ">= 16.14"
peerDependenciesMeta:
"@types/hoist-non-react-statics":
optional: true
"@types/node":
optional: true
"@types/react":
optional: true
checksum: e8da2186aaafcd5bb41c090a995c963a7c3c73c20991667a2cfc0c800d7f7f73913414b2e61c437cdb6221bb2151bd5174088b8b42c17056a896fc4d1da5729f
languageName: node
linkType: hard
"react-docgen-typescript@npm:^2.2.2":
version: 2.2.2
resolution: "react-docgen-typescript@npm:2.2.2"
@ -17401,7 +17471,7 @@ __metadata:
languageName: node
linkType: hard
"redux@npm:^4.2.1":
"redux@npm:^4.2.0, redux@npm:^4.2.1":
version: 4.2.1
resolution: "redux@npm:4.2.1"
dependencies: