mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-18 14:56:59 +08:00
Merge branch 'feat/poc' of github.com:toeverything/AFFiNE into feat/poc
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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 = () => {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
|
||||||
};
|
|
||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user