Merge branch 'feat/poc' of github.com:toeverything/AFFiNE into feat/poc

This commit is contained in:
DiamondThree
2023-01-05 19:04:38 +08:00
6 changed files with 84 additions and 138 deletions

View File

@@ -4,7 +4,6 @@ import { Button } from '@/ui/button';
import { useState } from 'react';
import { createWorkspace } from '@/hooks/mock-data/mock';
import Input from '@/ui/input';
interface ModalProps {
open: boolean;
onClose: () => void;

View File

@@ -12,9 +12,14 @@ import {
SignOut,
} from '@/hooks/mock-data/mock';
import { CreateWorkspaceModal } from '../create-workspace';
import {
CloudUnsyncedIcon,
CloudInsyncIcon,
UsersIcon,
AddIcon,
} from '@blocksuite/icons';
import { useConfirm } from '@/providers/confirm-provider';
import { toast } from '@/ui/toast';
interface LoginModalProps {
open: boolean;
onClose: () => void;
@@ -42,12 +47,11 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => {
<div>
<Modal open={open} onClose={onClose}>
<ModalWrapper
width={620}
height={334}
width={820}
style={{ padding: '10px', display: 'flex', flexDirection: 'column' }}
>
<Header>
<ContentTitle>My Workspace List</ContentTitle>
<ContentTitle>My Workspaces</ContentTitle>
<ModalCloseButton
top={6}
right={6}
@@ -67,11 +71,48 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => {
}}
key={item.id}
>
<span>{item.name}</span>/
{item.type === 'local' && <b>local</b>}
{item.type === 'join' && <b>join</b>}/
{item.isPublish ? 'isPublish' : 'isPrivate'}/
{item.isLocal ? 'isLocal' : ''}/
<span style={{ width: '100px', marginRight: '20px' }}>
<svg
style={{
float: 'left',
marginTop: '6px',
marginLeft: '10px',
marginRight: '10px',
}}
width="24"
height="24"
viewBox="0 0 40 40"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect
x="0.5"
y="0.5"
width="39"
height="39"
rx="19.5"
stroke="#6880FF"
fill="#FFF"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M18.6303 8.79688L11.2559 29.8393H15.5752L20.2661 15.2858L24.959 29.8393H29.2637L21.8881 8.79688H18.6303Z"
fill="#6880FF"
/>
</svg>
{item.name}
</span>
<span style={{ position: 'relative', top: '6px' }}>
{item.type === 'local' && (
<CloudUnsyncedIcon fontSize={24} />
)}
{item.type === 'cloud' && (
<CloudInsyncIcon fontSize={24} />
)}
{item.isPublish && <UsersIcon fontSize={24} />}
</span>
{/* {item.isLocal ? 'isLocal' : ''}/ */}
</WorkspaceItem>
);
})}
@@ -82,10 +123,22 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => {
setCreateWorkspaceOpen(true);
}}
>
Create Workspace
<AddIcon
style={{
fontSize: '20px',
top: '4px',
position: 'relative',
marginRight: '10px',
}}
/>
Create Or Import
</Button>
</li>
</WorkspaceList>
<p style={{ fontSize: '14px', color: '#ccc', margin: '12px 0' }}>
Tips:Workspace is your virtual space to capture, create and plan
as just one person or together as a team.
</p>
</Content>
<Footer>
{!user ? (
@@ -172,9 +225,10 @@ const WorkspaceList = styled('div')({
});
const WorkspaceItem = styled('div')({
border: '1px solid #e5e5e5',
padding: '10px',
cursor: 'pointer',
padding: '8px',
border: '1px solid #eee',
fontWeight: 'bold',
':hover': {
background: '#eee',
},

View File

@@ -5,6 +5,7 @@ import type {
Workspace as StoreWorkspace,
} from '@blocksuite/store';
import type { EditorContainer } from '@blocksuite/editor';
export type LoadWorkspaceHandler = (
workspaceId: string,
user?: AccessTokenMessage | null
@@ -20,7 +21,7 @@ export interface AppStateValue {
currentPage: StorePage | null;
workspaces: Record<string, StoreWorkspace | null>;
// workspaces: Record<string, StoreWorkspace | null>;
editor: EditorContainer | null;
synced: boolean;
@@ -53,7 +54,6 @@ export const AppState = createContext<AppStateContext>({
synced: false,
// eslint-disable-next-line @typescript-eslint/no-empty-function
refreshWorkspacesMeta: () => {},
workspaces: {},
});
export const useAppState = () => {

View File

@@ -2,31 +2,13 @@ import { useEffect } from 'react';
import type { Page } from '@blocksuite/store';
import '@blocksuite/blocks';
import { EditorContainer } from '@blocksuite/editor';
import type { LoadWorkspaceHandler, CreateEditorHandler } from './context';
import { getDataCenter } from '@affine/datacenter';
import type { CreateEditorHandler } from './context';
interface Props {
setLoadWorkspaceHandler: (handler: LoadWorkspaceHandler) => void;
setCreateEditorHandler: (handler: CreateEditorHandler) => void;
}
const DynamicBlocksuite = ({
setLoadWorkspaceHandler,
setCreateEditorHandler,
}: Props) => {
useEffect(() => {
const openWorkspace: LoadWorkspaceHandler = async (workspaceId: string) => {
if (workspaceId) {
const dc = await getDataCenter();
return dc.load(workspaceId, { providerId: 'affine' });
} else {
return null;
}
};
setLoadWorkspaceHandler(openWorkspace);
}, [setLoadWorkspaceHandler]);
const DynamicBlocksuite = ({ setCreateEditorHandler }: Props) => {
useEffect(() => {
const createEditorHandler: CreateEditorHandler = (page: Page) => {
const editor = new EditorContainer();

View File

@@ -1,51 +0,0 @@
import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { useAppState } from './context';
import { usePageHelper } from '@/hooks/use-page-helper';
export const useLoadWorkspace = () => {
const router = useRouter();
const { loadWorkspace, currentWorkspace, currentWorkspaceId } = useAppState();
const workspaceId = router.query.workspaceId as string;
useEffect(() => {
loadWorkspace?.(workspaceId);
}, [workspaceId, loadWorkspace]);
return currentWorkspaceId === workspaceId ? currentWorkspace : null;
};
export const useLoadPage = () => {
const router = useRouter();
const { loadPage, currentPage, currentWorkspaceId } = useAppState();
const { createPage } = usePageHelper();
const workspace = useLoadWorkspace();
const pageId = router.query.pageId as string;
useEffect(() => {
if (!workspace) {
return;
}
const page = pageId ? workspace?.getPage(pageId) : null;
if (page) {
loadPage?.(pageId);
return;
}
const savedPageId = workspace.meta.pageMetas[0]?.id;
if (savedPageId) {
router.push(`/workspace/${currentWorkspaceId}/${savedPageId}`);
return;
}
createPage().then(async pageId => {
if (!pageId) {
return;
}
router.push(`/workspace/${currentWorkspaceId}/${pageId}`);
});
}, [workspace, pageId, loadPage, createPage, router, currentWorkspaceId]);
return currentPage?.id === pageId ? currentPage : null;
};

View File

@@ -1,4 +1,4 @@
import { useMemo, useState, useEffect, useCallback, useRef } from 'react';
import { useMemo, useState, useCallback, useRef } from 'react';
import type { ReactNode } from 'react';
import dynamic from 'next/dynamic';
import { getDataCenter } from '@affine/datacenter';
@@ -8,12 +8,20 @@ import type {
CreateEditorHandler,
LoadWorkspaceHandler,
} from './context';
import { Page, Workspace as StoreWorkspace } from '@blocksuite/store';
import { Page } from '@blocksuite/store';
import { EditorContainer } from '@blocksuite/editor';
const DynamicBlocksuite = dynamic(() => import('./dynamic-blocksuite'), {
ssr: false,
});
const loadWorkspaceHandler: LoadWorkspaceHandler = async workspaceId => {
if (workspaceId) {
const dc = await getDataCenter();
return dc.load(workspaceId, { providerId: 'affine' });
} else {
return null;
}
};
export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
const refreshWorkspacesMeta = async () => {
const dc = await getDataCenter();
@@ -30,43 +38,10 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
currentWorkspace: null,
currentPage: null,
editor: null,
// Synced is used to ensure that the provider has synced with the server,
// So after Synced set to true, the other state is sure to be set.
synced: false,
refreshWorkspacesMeta,
workspaces: {},
synced: true,
});
useEffect(() => {
(async () => {
const workspacesList = await Promise.all(
state.workspacesMeta.map(async ({ id }) => {
const workspace =
(await loadWorkspaceHandler?.(id, state.user)) || null;
return { id, workspace };
})
);
const workspaces: Record<string, StoreWorkspace | null> = {};
workspacesList.forEach(({ id, workspace }) => {
workspaces[id] = workspace;
});
setState(state => ({
...state,
workspaces,
}));
})();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [state.workspacesMeta]);
const [loadWorkspaceHandler, _setLoadWorkspaceHandler] =
useState<LoadWorkspaceHandler>();
const setLoadWorkspaceHandler = useCallback(
(handler: LoadWorkspaceHandler) => {
_setLoadWorkspaceHandler(() => handler);
},
[_setLoadWorkspaceHandler]
);
const [createEditorHandler, _setCreateEditorHandler] =
useState<CreateEditorHandler>();
@@ -85,7 +60,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
return state.currentWorkspace;
}
const workspace =
(await loadWorkspaceHandler?.(workspaceId, state.user)) || null;
(await loadWorkspaceHandler(workspaceId, state.user)) || null;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
@@ -103,6 +78,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
}));
return workspace;
};
const loadPage = useRef<AppStateContext['loadPage']>(() =>
Promise.resolve(null)
);
@@ -147,17 +123,6 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
setState(state => ({ ...state, editor }));
};
useEffect(() => {
if (!loadWorkspaceHandler) {
return;
}
setState(state => ({
...state,
workspacesMeta: [],
synced: true,
}));
}, [loadWorkspaceHandler]);
const context = useMemo(
() => ({
...state,
@@ -172,10 +137,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
return (
<AppState.Provider value={context}>
<DynamicBlocksuite
setLoadWorkspaceHandler={setLoadWorkspaceHandler}
setCreateEditorHandler={setCreateEditorHandler}
/>
<DynamicBlocksuite setCreateEditorHandler={setCreateEditorHandler} />
{children}
</AppState.Provider>
);