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 { useState } from 'react';
import { createWorkspace } from '@/hooks/mock-data/mock'; import { createWorkspace } from '@/hooks/mock-data/mock';
import Input from '@/ui/input'; import Input from '@/ui/input';
interface ModalProps { interface ModalProps {
open: boolean; open: boolean;
onClose: () => void; onClose: () => void;

View File

@@ -12,9 +12,14 @@ import {
SignOut, SignOut,
} from '@/hooks/mock-data/mock'; } from '@/hooks/mock-data/mock';
import { CreateWorkspaceModal } from '../create-workspace'; import { CreateWorkspaceModal } from '../create-workspace';
import {
CloudUnsyncedIcon,
CloudInsyncIcon,
UsersIcon,
AddIcon,
} from '@blocksuite/icons';
import { useConfirm } from '@/providers/confirm-provider'; import { useConfirm } from '@/providers/confirm-provider';
import { toast } from '@/ui/toast'; import { toast } from '@/ui/toast';
interface LoginModalProps { interface LoginModalProps {
open: boolean; open: boolean;
onClose: () => void; onClose: () => void;
@@ -42,12 +47,11 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => {
<div> <div>
<Modal open={open} onClose={onClose}> <Modal open={open} onClose={onClose}>
<ModalWrapper <ModalWrapper
width={620} width={820}
height={334}
style={{ padding: '10px', display: 'flex', flexDirection: 'column' }} style={{ padding: '10px', display: 'flex', flexDirection: 'column' }}
> >
<Header> <Header>
<ContentTitle>My Workspace List</ContentTitle> <ContentTitle>My Workspaces</ContentTitle>
<ModalCloseButton <ModalCloseButton
top={6} top={6}
right={6} right={6}
@@ -67,11 +71,48 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => {
}} }}
key={item.id} key={item.id}
> >
<span>{item.name}</span>/ <span style={{ width: '100px', marginRight: '20px' }}>
{item.type === 'local' && <b>local</b>} <svg
{item.type === 'join' && <b>join</b>}/ style={{
{item.isPublish ? 'isPublish' : 'isPrivate'}/ float: 'left',
{item.isLocal ? 'isLocal' : ''}/ 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> </WorkspaceItem>
); );
})} })}
@@ -82,10 +123,22 @@ export const WorkspaceModal = ({ open, onClose }: LoginModalProps) => {
setCreateWorkspaceOpen(true); setCreateWorkspaceOpen(true);
}} }}
> >
Create Workspace <AddIcon
style={{
fontSize: '20px',
top: '4px',
position: 'relative',
marginRight: '10px',
}}
/>
Create Or Import
</Button> </Button>
</li> </li>
</WorkspaceList> </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> </Content>
<Footer> <Footer>
{!user ? ( {!user ? (
@@ -172,9 +225,10 @@ const WorkspaceList = styled('div')({
}); });
const WorkspaceItem = styled('div')({ const WorkspaceItem = styled('div')({
border: '1px solid #e5e5e5',
padding: '10px',
cursor: 'pointer', cursor: 'pointer',
padding: '8px',
border: '1px solid #eee',
fontWeight: 'bold',
':hover': { ':hover': {
background: '#eee', background: '#eee',
}, },

View File

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

View File

@@ -2,31 +2,13 @@ import { useEffect } from 'react';
import type { Page } from '@blocksuite/store'; import type { Page } from '@blocksuite/store';
import '@blocksuite/blocks'; import '@blocksuite/blocks';
import { EditorContainer } from '@blocksuite/editor'; import { EditorContainer } from '@blocksuite/editor';
import type { LoadWorkspaceHandler, CreateEditorHandler } from './context'; import type { CreateEditorHandler } from './context';
import { getDataCenter } from '@affine/datacenter';
interface Props { interface Props {
setLoadWorkspaceHandler: (handler: LoadWorkspaceHandler) => void;
setCreateEditorHandler: (handler: CreateEditorHandler) => void; setCreateEditorHandler: (handler: CreateEditorHandler) => void;
} }
const DynamicBlocksuite = ({ const DynamicBlocksuite = ({ setCreateEditorHandler }: Props) => {
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]);
useEffect(() => { useEffect(() => {
const createEditorHandler: CreateEditorHandler = (page: Page) => { const createEditorHandler: CreateEditorHandler = (page: Page) => {
const editor = new EditorContainer(); 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 type { ReactNode } from 'react';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { getDataCenter } from '@affine/datacenter'; import { getDataCenter } from '@affine/datacenter';
@@ -8,12 +8,20 @@ import type {
CreateEditorHandler, CreateEditorHandler,
LoadWorkspaceHandler, LoadWorkspaceHandler,
} from './context'; } from './context';
import { Page, Workspace as StoreWorkspace } from '@blocksuite/store'; import { Page } from '@blocksuite/store';
import { EditorContainer } from '@blocksuite/editor'; import { EditorContainer } from '@blocksuite/editor';
const DynamicBlocksuite = dynamic(() => import('./dynamic-blocksuite'), { const DynamicBlocksuite = dynamic(() => import('./dynamic-blocksuite'), {
ssr: false, 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 }) => { export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
const refreshWorkspacesMeta = async () => { const refreshWorkspacesMeta = async () => {
const dc = await getDataCenter(); const dc = await getDataCenter();
@@ -30,43 +38,10 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
currentWorkspace: null, currentWorkspace: null,
currentPage: null, currentPage: null,
editor: 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, 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] = const [createEditorHandler, _setCreateEditorHandler] =
useState<CreateEditorHandler>(); useState<CreateEditorHandler>();
@@ -85,7 +60,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
return state.currentWorkspace; return state.currentWorkspace;
} }
const workspace = const workspace =
(await loadWorkspaceHandler?.(workspaceId, state.user)) || null; (await loadWorkspaceHandler(workspaceId, state.user)) || null;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error // @ts-expect-error
@@ -103,6 +78,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
})); }));
return workspace; return workspace;
}; };
const loadPage = useRef<AppStateContext['loadPage']>(() => const loadPage = useRef<AppStateContext['loadPage']>(() =>
Promise.resolve(null) Promise.resolve(null)
); );
@@ -147,17 +123,6 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
setState(state => ({ ...state, editor })); setState(state => ({ ...state, editor }));
}; };
useEffect(() => {
if (!loadWorkspaceHandler) {
return;
}
setState(state => ({
...state,
workspacesMeta: [],
synced: true,
}));
}, [loadWorkspaceHandler]);
const context = useMemo( const context = useMemo(
() => ({ () => ({
...state, ...state,
@@ -172,10 +137,7 @@ export const AppStateProvider = ({ children }: { children?: ReactNode }) => {
return ( return (
<AppState.Provider value={context}> <AppState.Provider value={context}>
<DynamicBlocksuite <DynamicBlocksuite setCreateEditorHandler={setCreateEditorHandler} />
setLoadWorkspaceHandler={setLoadWorkspaceHandler}
setCreateEditorHandler={setCreateEditorHandler}
/>
{children} {children}
</AppState.Provider> </AppState.Provider>
); );